feat(assistant): контекст урока/страницы для Квантика (фича 2/6)

Квантик теперь знает, где находится ученик:
- pageHint() — лёгкий ситуативный контекст («ученик на странице учебник:
  «Физика 7, §12»») подмешивается к ЛЮБОМУ свободному вопросу автоматически
- getPageContext() расширен с учебника на уроки (theory/course/lesson):
  «Объяснить этот урок / Конспект урока / Флешкарты из урока»
- метки чипов адаптируются (параграф/урок)

Бэкенд уже принимал context (pageCtx) — правок не потребовалось.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-24 14:52:42 +03:00
parent 089f93b8ee
commit 2506a72806
+31 -5
View File
@@ -480,12 +480,35 @@
var h = sec.querySelector('.sec-h');
var title = (h && h.textContent.trim()) || (document.title || 'Параграф').split('·')[0].trim();
var text = (sec.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 3500);
if (text.length > 40) return { title: title, text: text };
if (text.length > 40) return { title: title, text: text, kind: 'textbook' };
}
}
if (PAGE === 'theory') {
var c = document.querySelector('.lesson-content, .lsn-content, .lesson-body, #lesson-content, article.lesson, .course-lesson, .lesson-view');
if (c) {
var lt = document.querySelector('h1, .lsn-title, .lesson-title');
var ltitle = (lt && lt.textContent.trim()) || (document.title || 'Урок').split('·')[0].trim();
var ltext = (c.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 3500);
if (ltext.length > 60) return { title: ltitle, text: ltext, kind: 'lesson' };
}
}
} catch (e) {}
return null;
}
// Лёгкий ситуативный контекст для ЛЮБОГО вопроса — где сейчас ученик (заголовок+раздел).
var PAGE_LABEL = { textbook: 'учебник', theory: 'урок/курс', exam: 'экзамен или тест', flashcards: 'флешкарты',
lab: 'лаборатория', homework: 'домашние задания', dashboard: 'главная', knowledge: 'карта знаний',
library: 'библиотека', analytics: 'аналитика', gradebook: 'журнал', qbank: 'банк вопросов' };
function pageHint() {
try {
var label = PAGE_LABEL[PAGE] || '';
var hEl = document.querySelector('.sec.active .sec-h, h1, .lsn-title, .lesson-title, .page-title');
var title = (hEl && hEl.textContent.trim()) || (document.title || '').split('·')[0].split('|')[0].trim();
title = title.replace(/\s+/g, ' ').slice(0, 120);
if (!title && !label) return '';
return 'Ученик сейчас на странице платформы' + (label ? ' («' + label + '»)' : '') + (title ? ': «' + title + '»' : '') + '. Учитывай это, если вопрос относится к материалу страницы.';
} catch (e) { return ''; }
}
/* ── «Спроси Квантика» ───────────────────────────────────────────────── */
var SUGGESTIONS = ['Как вырезать кусок учебника?', 'Как создать карточки?', 'Как начать тест?', 'Объясни теорему Пифагора', 'Где мои домашние задания?', 'Как включить тёмную тему?'];
@@ -508,11 +531,13 @@
var MODE_PH = { answer: 'Спроси что угодно: «объясни…», «как…»', hint: 'Задача, по которой нужна подсказка…', check: 'Вставь своё решение — проверю…', draw: 'Опиши картинку: «кот-учёный, плоская иллюстрация»' };
function openAsk(prefill) {
var sel = _lastSel, pc = getPageContext();
var noun = pc && pc.kind === 'lesson' ? 'этот урок' : 'этот параграф';
var noun2 = pc && pc.kind === 'lesson' ? 'урока' : 'параграфа';
var ctxBtns = '';
if (sel) ctxBtns += '<button class="asst-chip asst-chip-ctx" data-ctx="sel" type="button">Объяснить выделенное</button>';
if (pc) ctxBtns += '<button class="asst-chip asst-chip-ctx" data-ctx="sec" type="button">Объяснить этот параграф</button>' +
'<button class="asst-chip asst-chip-ctx" data-ctx="sum" type="button">Конспект параграфа</button>' +
'<button class="asst-chip asst-chip-ctx" data-ctx="cards" type="button">Флешкарты из параграфа</button>';
if (pc) ctxBtns += '<button class="asst-chip asst-chip-ctx" data-ctx="sec" type="button">Объяснить ' + noun + '</button>' +
'<button class="asst-chip asst-chip-ctx" data-ctx="sum" type="button">Конспект ' + noun2 + '</button>' +
'<button class="asst-chip asst-chip-ctx" data-ctx="cards" type="button">Флешкарты из ' + noun2 + '</button>';
var sug = (_role === 'teacher' || _role === 'admin') ? TEACHER_SUGGESTIONS : SUGGESTIONS;
var chips = '<div class="asst-chips">' + ctxBtns +
sug.map(function (q) { return '<button class="asst-chip" type="button">' + esc(q) + '</button>'; }).join('') + '</div>';
@@ -534,7 +559,8 @@
var mode = 'answer';
renderChat(chatEl);
if (_chat.length) chipsEl.style.display = 'none';
function go(q, context, m) { if (chipsEl) chipsEl.style.display = 'none'; inp.value = ''; send(q, context, chatEl, m || mode); }
// свободный вопрос (context не задан явно) → подмешиваем лёгкий ситуативный контекст страницы
function go(q, context, m) { if (chipsEl) chipsEl.style.display = 'none'; inp.value = ''; if (context == null) context = pageHint() || undefined; send(q, context, chatEl, m || mode); }
inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') go(inp.value); });
bubble.querySelectorAll('.asst-mode').forEach(function (b) {
b.addEventListener('click', function () {