fix(assistant): «Забыть всё» теперь сбрасывает и производный профиль
clearMemory ставит точку отсчёта asst_forget_<uid> (datetime now); слабые предметы/темы в _studentProfile считаются только по активности после неё, так что панель памяти видимо очищается. Кнопка «Забыть всё» в виджете показывается лишь при наличии заметок/слабых тем, профиль помечен как авто-обновляемый. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -156,13 +156,16 @@ function weakSubject(uid) {
|
||||
// Производный профиль (без LLM) — из уже накопленных сигналов.
|
||||
function _studentProfile(uid) {
|
||||
const out = { weakSubjects: [], weakTopics: [], exam: null, streak: 0 };
|
||||
// «Забыть всё» ставит точку отсчёта: производный профиль учитывает только активность ПОСЛЕ неё.
|
||||
let forget = null;
|
||||
try { const fr = db.prepare("SELECT value FROM app_settings WHERE key = ?").get('asst_forget_' + uid); forget = (fr && fr.value) || null; } catch (e) {}
|
||||
try {
|
||||
out.weakSubjects = db.prepare(`
|
||||
SELECT s.name AS name, ROUND(AVG(ts.score * 100.0 / ts.total)) AS avg, COUNT(*) AS n
|
||||
FROM test_sessions ts JOIN subjects s ON s.id = ts.subject_id
|
||||
WHERE ts.user_id = ? AND ts.status = 'completed' AND ts.total > 0
|
||||
WHERE ts.user_id = ? AND ts.status = 'completed' AND ts.total > 0${forget ? ' AND ts.finished_at > ?' : ''}
|
||||
GROUP BY ts.subject_id HAVING n >= 2 AND avg < 70 ORDER BY avg ASC LIMIT 3
|
||||
`).all(uid).map(r => ({ name: r.name, avg: r.avg }));
|
||||
`).all(...(forget ? [uid, forget] : [uid])).map(r => ({ name: r.name, avg: r.avg }));
|
||||
} catch (e) {}
|
||||
try {
|
||||
const cand = {}; // трудные темы по ВСЕМ предметам: банк тестов + экзамен
|
||||
@@ -170,17 +173,17 @@ function _studentProfile(uid) {
|
||||
db.prepare(`
|
||||
SELECT t.name AS topic, COUNT(*) AS attempts, SUM(ua.is_correct) AS correct
|
||||
FROM user_answers ua JOIN questions q ON q.id = ua.question_id JOIN topics t ON t.id = q.topic_id
|
||||
WHERE ua.session_id IN (SELECT id FROM test_sessions WHERE user_id = ? AND status = 'completed')
|
||||
WHERE ua.session_id IN (SELECT id FROM test_sessions WHERE user_id = ? AND status = 'completed')${forget ? ' AND ua.answered_at > ?' : ''}
|
||||
GROUP BY q.topic_id HAVING attempts >= 3
|
||||
`).all(uid).forEach(r => { cand[r.topic] = { topic: r.topic, attempts: r.attempts, correct: r.correct || 0 }; });
|
||||
`).all(...(forget ? [uid, forget] : [uid])).forEach(r => { cand[r.topic] = { topic: r.topic, attempts: r.attempts, correct: r.correct || 0 }; });
|
||||
} catch (e) {}
|
||||
try {
|
||||
db.prepare(`
|
||||
SELECT et.topic AS topic, COUNT(*) AS attempts, SUM(ea.is_correct) AS correct
|
||||
FROM exam_attempts ea JOIN exam_tasks et ON et.id = ea.exam_task_id
|
||||
WHERE ea.user_id = ? AND et.topic IS NOT NULL AND et.topic <> ''
|
||||
WHERE ea.user_id = ? AND et.topic IS NOT NULL AND et.topic <> ''${forget ? ' AND ea.created_at > ?' : ''}
|
||||
GROUP BY et.topic HAVING attempts >= 3
|
||||
`).all(uid).forEach(r => {
|
||||
`).all(...(forget ? [uid, forget] : [uid])).forEach(r => {
|
||||
const c = cand[r.topic];
|
||||
if (c) { c.attempts += r.attempts; c.correct += (r.correct || 0); }
|
||||
else cand[r.topic] = { topic: r.topic, attempts: r.attempts, correct: r.correct || 0 };
|
||||
@@ -319,7 +322,11 @@ function clearMemory(req, res) {
|
||||
const uid = req.user.id, id = req.params.id ? Number(req.params.id) : null;
|
||||
try {
|
||||
if (id) db.prepare('DELETE FROM assistant_memory WHERE id = ? AND user_id = ?').run(id, uid);
|
||||
else db.prepare('DELETE FROM assistant_memory WHERE user_id = ?').run(uid);
|
||||
else {
|
||||
db.prepare('DELETE FROM assistant_memory WHERE user_id = ?').run(uid);
|
||||
// «Забыть всё»: сбрасываем и точку отсчёта производного профиля (слабые предметы/темы)
|
||||
db.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES (?, datetime('now'))").run('asst_forget_' + uid);
|
||||
}
|
||||
} catch (e) {}
|
||||
res.json({ ok: true });
|
||||
}
|
||||
|
||||
@@ -631,12 +631,13 @@
|
||||
var cat = MEM_CAT[n.kind] || 'заметка';
|
||||
return '<div class="asst-mem-note"><span><span class="asst-mem-cat">' + esc(cat) + '</span>' + esc(n.text) + '</span><button class="asst-mem-x" data-id="' + n.id + '" title="Забыть">×</button></div>';
|
||||
}).join('');
|
||||
var forgettable = (m.notes && m.notes.length) || (p.weakSubjects && p.weakSubjects.length) || (p.weakTopics && p.weakTopics.length);
|
||||
var body = m.enabled === false
|
||||
? '<div class="asst-mem-off">Персональная память выключена администратором.</div>'
|
||||
: '<div class="asst-mem-body">' +
|
||||
(prof.length ? '<div class="asst-mem-prof">' + prof.map(function (x) { return '<div>• ' + x + '</div>'; }).join('') + '</div>' : '') +
|
||||
(prof.length ? '<div class="asst-mem-prof">' + prof.map(function (x) { return '<div>• ' + x + '</div>'; }).join('') + '<div style="font-size:.66rem;color:#9aa5b4;margin-top:7px">Считается по твоей активности и обновляется автоматически.</div></div>' : '') +
|
||||
(notes ? '<div class="asst-mem-notes-h">Заметки</div>' + notes : (prof.length ? '' : '<div class="asst-empty">Пока я ничего не запомнил — позанимайся, и здесь появятся слабые темы и заметки.</div>')) +
|
||||
((notes || prof.length) ? '<button class="asst-link" data-a="forget" style="margin-top:12px;color:#e0335e">Забыть всё</button>' : '') +
|
||||
(forgettable ? '<button class="asst-link" data-a="forget" style="margin-top:12px;color:#e0335e">Забыть всё</button>' : '') +
|
||||
'</div>';
|
||||
openBubble(
|
||||
'<div class="asst-name"><span class="asst-name-face">' + faceSVG('happy') + '</span>Что я о тебе помню' +
|
||||
|
||||
Reference in New Issue
Block a user