feat(assistant): админ-панель LLM (ключ/URL/модель/тест) + многоходовой чат

Админка (Управление → игры/фичи): карточка «Помощник Квантик — модель» —
пресеты провайдеров, URL/модель, поле ключа, кнопки Сохранить/Проверить/
Очистить ключ, индикатор статуса. Конфиг в app_settings (без рестарта),
откат на ENV/дефолты; нет ключа → автоматически FAQ-режим. Эндпоинты
GET/PUT/POST /api/admin/assistant(/test), admin-only.

«Спроси Квантика» теперь многоходовой чат: история диалога (последние 6
реплик) уходит модели, ответы рендерятся как чат-лента, кнопка «Очистить».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-04 18:04:42 +03:00
parent 479c621e2e
commit dc073e2114
6 changed files with 244 additions and 67 deletions
+5 -1
View File
@@ -1051,6 +1051,7 @@ window.LS = {
listMaterials, saveMaterial, updateMaterial, deleteMaterial, shareMaterial, getActivity,
createMaterialCollection, updateMaterialCollection, deleteMaterialCollection,
assistantContext, assistantSeen, assistantDismiss, assistantSettings, assistantAsk, assistantFlashcards,
adminGetAssistant, adminSaveAssistant, adminTestAssistant,
fcListDecks, fcCreateDeck, fcAddCard,
escapeHtml, esc,
parseDate, fmtRelTime, safeHref,
@@ -1272,8 +1273,11 @@ async function assistantContext() { return req('GET', '/assistant/context'
async function assistantSeen(ruleId) { return req('POST', '/assistant/seen', { ruleId }); }
async function assistantDismiss(rid) { return req('POST', '/assistant/dismiss', { ruleId: rid }); }
async function assistantSettings(d) { return req('PATCH', '/assistant/settings', d); }
async function assistantAsk(q, context) { return req('POST', '/assistant/ask', { q, context: context || undefined }); }
async function assistantAsk(q, context, history) { return req('POST', '/assistant/ask', { q, context: context || undefined, history: history || undefined }); }
async function assistantFlashcards(text, title) { return req('POST', '/assistant/flashcards', { text, title }); }
async function adminGetAssistant() { return req('GET', '/admin/assistant'); }
async function adminSaveAssistant(d) { return req('PUT', '/admin/assistant', d); }
async function adminTestAssistant(d) { return req('POST', '/admin/assistant/test', d || {}); }
async function fcListDecks() { return req('GET', '/flashcards/decks'); }
async function fcCreateDeck(d) { return req('POST', '/flashcards/decks', d); }
async function fcAddCard(deckId, d) { return req('POST', `/flashcards/decks/${deckId}/cards`, d); }