feat(assistant): чёткий ответ при лимите ИИ (память не теряется), напоминание о памяти, отдельный раздел в админке
- Баг «не помнит»: на самом деле free-лимит Gemini (429). callLLM теперь возвращает ошибку; при 429 показываем «много запросов, подожди минутку — память не потеряется» и НЕ ломаем историю (убираем неудачный вопрос); при сбое — «не получилось, попробуй позже». Раньше показывалось «не нашёл ответ». - В окне «Спроси» — пояснение, сколько помнит Квантик (≈6 реплик, рабочая память). - Окна красивее: шире, аватар Квантика в шапке, мягкая анимация. - Управление помощником вынесено в отдельный раздел админки «Помощник Квантик» (системный вкл/выкл + модель/ключ/тест/RAG/кнопки экзамена/статистика/качество); из раздела «Игры» конфиг убран. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -280,9 +280,12 @@
|
||||
'.asst-dot{position:absolute;top:0;right:0;width:13px;height:13px;border-radius:50%;background:#F15BB5;border:2px solid #fff;}',
|
||||
reduceMotion ? '' : '.asst-fab.pulse{animation:asstPulse 2.2s ease-in-out infinite;}',
|
||||
'@keyframes asstPulse{0%,100%{box-shadow:0 8px 24px rgba(139,92,246,.32);}50%{box-shadow:0 8px 30px rgba(241,91,181,.5);}}',
|
||||
'.asst-bubble{position:absolute;left:0;bottom:64px;width:300px;max-width:78vw;background:#fff;border-radius:16px;',
|
||||
' box-shadow:0 18px 50px rgba(15,23,42,.22);padding:14px 16px;border:1px solid rgba(15,23,42,.07);',
|
||||
' opacity:0;transform:translateY(8px);pointer-events:none;transition:opacity .18s,transform .18s;}',
|
||||
'.asst-bubble{position:absolute;left:0;bottom:66px;width:330px;max-width:88vw;background:#fff;border-radius:18px;',
|
||||
' box-shadow:0 20px 56px rgba(15,23,42,.24);padding:15px 17px;border:1px solid rgba(15,23,42,.07);',
|
||||
' opacity:0;transform:translateY(8px) scale(.98);pointer-events:none;transition:opacity .18s,transform .18s;transform-origin:bottom left;}',
|
||||
'.asst-name-face{display:inline-block;width:20px;height:20px;vertical-align:-4px;margin-right:7px;}',
|
||||
'.asst-name-face svg{width:100%;height:100%;display:block;}',
|
||||
'.asst-memnote{font-size:.66rem;color:#9aa5b4;margin-top:9px;line-height:1.45;border-top:1px solid rgba(15,23,42,.05);padding-top:8px;}',
|
||||
'.asst-bubble.open{opacity:1;transform:translateY(0);pointer-events:auto;}',
|
||||
'.asst-x{position:absolute;top:8px;right:8px;width:26px;height:26px;border:none;background:transparent;color:#8a94a6;',
|
||||
' cursor:pointer;border-radius:7px;font-size:18px;line-height:1;}',
|
||||
@@ -493,9 +496,10 @@
|
||||
'<button class="asst-mode" data-m="hint">Подсказка</button>' +
|
||||
'<button class="asst-mode" data-m="check">Проверить решение</button></div>';
|
||||
openBubble(
|
||||
'<div class="asst-name">Спроси Квантика' + (_chat.length ? '<button class="asst-link" data-a="clear" style="float:right;font-weight:600;margin-right:24px">Очистить</button>' : '') + '</div>' +
|
||||
'<div class="asst-name"><span class="asst-name-face">' + faceSVG('happy') + '</span>Спроси Квантика' + (_chat.length ? '<button class="asst-link" data-a="clear" style="float:right;font-weight:600;margin-right:24px">Очистить</button>' : '') + '</div>' +
|
||||
'<div class="asst-chat"></div>' + chips + modes +
|
||||
'<input class="asst-ask-in" type="text" placeholder="' + MODE_PH.answer + '" maxlength="500" />', {});
|
||||
'<input class="asst-ask-in" type="text" placeholder="' + MODE_PH.answer + '" maxlength="500" />' +
|
||||
'<div class="asst-memnote">Я помню последние ~6 сообщений этого разговора — как рабочая память: что было раньше, понимаю; старое постепенно забывается. «Очистить» — начать с чистого листа.</div>', {});
|
||||
var inp = bubble.querySelector('.asst-ask-in');
|
||||
var chatEl = bubble.querySelector('.asst-chat');
|
||||
var chipsEl = bubble.querySelector('.asst-chips');
|
||||
@@ -540,9 +544,16 @@
|
||||
(LS.globalSearch ? LS.globalSearch(q, 'all', 3) : Promise.resolve({ results: [] })).catch(function () { return { results: [] }; }),
|
||||
]).then(function (res) {
|
||||
ph.remove();
|
||||
var model = res[0] && res[0].answer;
|
||||
var ans = (res[0] && res[0].answers) || [];
|
||||
var sources = (res[0] && res[0].sources) || [];
|
||||
var r0 = res[0] || {};
|
||||
// лимит/ошибка ИИ — не ломаем память диалога: убираем последний вопрос, показываем сообщение
|
||||
if (r0.source === 'limit' || r0.source === 'error') {
|
||||
_chat.pop();
|
||||
var em = msgEl('assistant'); em.className += ' asst-msg-ph'; em.textContent = r0.answer || 'Сейчас не получилось. Попробуй ещё раз.';
|
||||
chatEl.appendChild(em); chatEl.scrollTop = chatEl.scrollHeight; return;
|
||||
}
|
||||
var model = r0.source === 'model' ? r0.answer : null;
|
||||
var ans = r0.answers || [];
|
||||
var sources = r0.sources || [];
|
||||
var found = (res[1] && res[1].results) || [];
|
||||
var content = model || (ans[0] && (ans[0].q + '\n' + ans[0].a)) || 'Не нашёл точного ответа. Попробуй переформулировать или поищи (Ctrl+K).';
|
||||
_chat.push({ role: 'assistant', content: content });
|
||||
|
||||
Reference in New Issue
Block a user