feat(assistant): сканер бесплатных моделей Kilo в админке

Кнопка «Сканировать модели» в /admin#assistant: тянет live-список со шлюза
провайдера, отбирает бесплатные чат-модели (музыка/картинки/модерация
отсекаются), прогоняет каждую тест-запросом на русском и показывает отчёт
(новые / исчезнувшие / % кириллицы / скорость). «Применить выбранные»
сохраняет список в app_settings (assistant_kilo_models); хардкод KILO_MODELS
остаётся сидом, есть «Вернуть встроенный список».

Backend: scanModels/probeModel/applyModels (admin-only роуты), _kiloModels()
делает список динамическим. Переиспользует _fetchModels. Клиент: adminAssistantScan/Probe/ApplyModels.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-24 14:18:04 +03:00
parent dc5501d723
commit d15c15ef2a
4 changed files with 191 additions and 1 deletions
+4
View File
@@ -1186,6 +1186,7 @@ window.LS = {
assistantContext, assistantSeen, assistantDismiss, assistantSettings, assistantAsk, assistantFlashcards, assistantFeedback, assistantMemory, assistantMemoryClear, imageGen, imageGenStatus,
adminGetAssistant, adminSaveAssistant, adminTestAssistant, adminReindexTextbooks,
adminSaveProvider, adminDeleteProvider, adminSetActiveProvider, adminAssistantModels,
adminAssistantScan, adminAssistantProbe, adminAssistantApplyModels,
fcListDecks, fcCreateDeck, fcAddCard, fcStudySession, fcReview,
prepListTracks, prepMyTracks, prepStudentTracks, prepSetStudent, prepUnsetStudent, prepClassStatus, prepSetClass,
escapeHtml, esc,
@@ -1436,6 +1437,9 @@ async function adminSaveProvider(d) { return req('POST', '/admin/assistant
async function adminDeleteProvider(id) { return req('DELETE', `/admin/assistant/provider/${id}`); }
async function adminSetActiveProvider(id) { return req('POST', '/admin/assistant/active', { id }); }
async function adminAssistantModels(params) { const q = new URLSearchParams(params || {}).toString(); return req('GET', '/admin/assistant/models' + (q ? '?' + q : '')); }
async function adminAssistantScan(id) { return req('POST', '/admin/assistant/scan', id ? { id } : {}); }
async function adminAssistantProbe(id, model) { return req('POST', '/admin/assistant/probe', { id, model }); }
async function adminAssistantApplyModels(models, reset) { return req('POST', '/admin/assistant/models/apply', reset ? { reset: true } : { models }); }
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); }