Files
Learn_System/.claude/memory/project_pet_assistant.md
Maxim Dolgolyov 8a7091ddec chore(memory): снимок файлов памяти Claude в репозиторий для переноса
Копия пользовательской автопамяти (29 фактов + индекс MEMORY.md) в
.claude/memory/, чтобы переносить между машинами через git.
README.md — как восстановить в пользовательскую папку на другой машине.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 08:32:16 +03:00

126 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: project_pet_assistant
description: «Квантик-ассистент» — сквозной помощник поверх питомца; Ф0/Ф1/«Спроси» РЕАЛИЗОВАНЫ на master (правиловый движок)
metadata:
node_type: memory
type: project
originSessionId: 60467058-b40e-4bd9-9f7f-d1e362e8039a
---
Дизайн-доку: `plans/pet-assistant/PLAN.md`. Реализация: commit **3f8009c** (2026-06-04), на master.
Суть: питомец «Квантик» стал плавающим помощником (низ-слева) на всех страницах — контекстные
подсказки, проактивные напоминания, поздравления, панель «Спроси Квантика». Движок **правиловый**
(без LLM), правила инлайн в `frontend/js/assistant.js`.
Фича-гейт: **отдельный `assistant`** (commit e1cde83 — сменили с reuse 'pet'), `requireFeature('assistant')`,
дефолт ON; админ включает/выключает в Управление→фичи (adminController allowed + games.js GAME_FEATURES,
key 'assistant'). Включён **всем** (assistant_enabled DEFAULT 1 — личный тумблер в профиле);
«видел» — **серверная** таблица `assistant_seen` (cross-device); ассистент **и на учебнике** (через
DEEPLINK_INJECT в server.js); тон **консервативный** (дневной лимит 2, кулдауны, «не показывать»);
«Спроси» — **поиск по FAQ + точка расширения под локальную модель**`ask()` контроллера).
Файлы: миграция `062_assistant.sql` (assistant_enabled + assistant_seen); `assistantController.js`
(FAQ инлайн — `backend/src/data/` в .gitignore!) + `routes/assistant.js`; mount `/api/assistant`
под `requireFeature('pet')`; `js/api.js` (assistantContext/Seen/Dismiss/Settings/Ask); загрузчик в
`js/sidebar.js` (как flashcard-fab); тумблер в `profile.html` («Настройки» → prefAssistant).
Эндпоинты: GET /context, POST /seen, /dismiss, /ask, PATCH /settings. Лицо — `pet-sprite.js`,
данные — `/api/pet` + `/api/assistant/context` (dueCards, homework).
Сделано: Ф0 (каркас+контекстные подсказки) + Ф1 (проактив: домашка/карточки/серия/квест/
activeLesson «продолжи урок» + поздравления левелап/серия) + Ф2 (коачмарк-тур новичка по разделам,
офер на дашборде, повтор Assistant.tour()) + Ф3-lite (FAQ-«Спроси»). Тур-правило id 'onboarding'
в assistant_seen. activeLesson (commit 9baaca7) — запрос как «продолжить чтение» из courseController.
+ Контент-апгрейд (commit c33295e): контекстные подсказки на ВСЕ разделы (PAGE_HINTS),
«Совет дня» (tip-daily, дашборд), FAQ ~10→~50, «Спроси» ищет и по платформе (LS.globalSearch),
умный проактив weakSubject (слабый предмет по test_sessions, в /api/assistant/context) +
daily-plan (из квестов+карточек). LLM подключена (commit 9dbc044): ask() вызывает OpenAI-совместимую модель с грунтовкой по топ-FAQ,
source:'model', таймаут 12с, откат на FAQ при ошибке/без ключа. Конфиг ENV в backend/.env(.example):
ASSISTANT_LLM_URL (дефолт Groq chat/completions), ASSISTANT_LLM_KEY (пусто → FAQ), ASSISTANT_LLM_MODEL
(дефолт llama-3.3-70b-versatile); локальный Ollama без ключа поддержан (localhost → зовётся без Bearer).
АКТИВНО (2026-06-04): подключён **Google Gemini** через OpenAI-совместимый эндпоинт
(ASSISTANT_LLM_URL=https://generativelanguage.googleapis.com/v1beta/openai/chat/completions),
рабочая модель **gemini-2.5-flash** (ключ в backend/.env, не в гите). Гочи по моделям на этом ключе:
gemini-2.0-flash / -lite → 429 limit:0 (нет free-квоты); gemini-1.5-* → 404; gemini-2.5-flash / gemini-flash-latest → 200.
Ключ валиден (auth ок). Сменить провайдера/модель — только через backend/.env + рестарт.
Возможности-апгрейд (commit 479c621): ответы модели рендерятся markdown + KaTeX (ленивая загрузка
katex с jsdelivr; модель просим LaTeX $...$); ask принимает context; «Объяснить выделенное» (запоминаем
selection на mouseup) и «Объяснить/Конспект параграфа» на учебнике (getPageContext по .sec.active);
«Флешкарты из параграфа» → POST /api/assistant/flashcards (модель→JSON, есть починка обрезанного,
max_tokens 1400) → колода через LS.fcCreateDeck/fcAddCard; репетитор на экзамене — кнопка «Спросить
Квантика» в task-card.js (tc-ask) → Assistant.ask(условие+ответ+решение). Экспорт Assistant.ask(q,context)
и explainSelection(). Гочи: на этом Gemini-ключе free-квота есть только у gemini-2.5-flash; placeholder
в renderRich — @@M..@@ (не цифры-в-пробелах, иначе коллизии).
Админ-панель + чат (commit dc073e2): конфиг LLM теперь в **app_settings** (assistant_llm_url/key/model),
правится из Управление→игры (карточка «Помощник Квантик — модель»: пресеты Gemini/Groq/OpenRouter/Ollama,
URL/модель/ключ, Сохранить/Проверить/Очистить, статус). Эндпоинты GET/PUT/POST /api/admin/assistant(/test)
admin-only. llmConfig() читает app_settings→ENV→дефолт; нет ключа → FAQ-режим. Текущий Gemini-ключ пока
в backend/.env (DB пусто → берётся ENV; можно перенести в БД через админку). «Спроси» — многоходовой чат
(history последние 6 реплик уходят модели, лента сообщений, «Очистить»).
RAG+кэш+учитель (commit 2252bbd, миграция 063): **RAG** — индексатор backend/scripts/index-textbooks.js
→ таблица textbook_chunks; ask() подмешивает релевантные куски (LIKE-скоринг, ≥2 слова). ГОЧА: бол-во
учебников рендерят текст ЧЕРЕЗ JS-движки → в статическом HTML только заголовки §, поэтому индекс берёт
только статично-текстовые (≈132 чанка: chemistry, часть physics); JS-рендеримые покрываются контекстом
страницы (getPageContext читает отрендеренный DOM). Полное покрытие = headless-рендер — СДЕЛАНО (commit 0119ea0): scripts/index-textbooks-headless.js
(puppeteer-core + системный Chrome, служебный JWT в localStorage т.к. /textbook требует логина) рендерит
учебники через локальный сервер, кликает §, забирает рендерный текст движков. Прогон: 87/107 книг, индекс
132→**746 чанков** (physics-9 и др. JS-учебники теперь покрыты). npm: index:textbooks:full. Сервер не
требует рестарта — ragContext читает БД на каждом запросе.
Батч 4 фич (commit 4224a22, миграция 064): **Источники** — ragContext отдаёт sources (slug/section/section_ref),
под ответом ссылка «по учебнику X, §N» на /textbook/slug#sec-<ref>; section_ref заполняет headless-индексатор
(psel-card data-id); статический индексатор больше НЕ делает delAll (per-book — не затирает headless).
**Режим-наставник**: ask(mode: answer/hint/check) + промпт; в «Спроси» переключатель из 3 кнопок; на карточке
экзамена (task-card.js) кнопка «Подсказка» (mode hint) рядом со «Спросить Квантика»; Assistant.ask(q,ctx,{mode}).
**Оценка**: лайк/дизлайк под ответом (assistant_feedback, POST /assistant/feedback) + сводка в админке (up/down/recent).
**Утренний бриф**: rule 'brief' на дашборде до 12:00 (PET.weeklyXP «N из 5 дн» + план), daily-plan сдвинут на день.
НЕ сделано: цели недели (явная установка) + напоминания по расписанию (нужен планировщик/push); голосовой ввод/TTS;
генератор заданий учителю; авто-cron на index:textbooks:full.
Мета-фильтр + тумблер экзамена (commit 961504b): вопросы про модель/нейросеть/провайдера/системный промпт
отбиваются шаблоном META_RE (саморефренция ты/тебя/твой РЯДОМ с термином модель/gpt/промпт — не блокирует
«модель атома/газа») + запрет в системном промпте. Кнопки «Подсказка»/«Спросить Квантика» на карточках
экзамена по умолчанию СКРЫТЫ (assistant_exam_buttons='0'); тумблер в админке → /context examButtons →
assistant.js вешает html.asst-exam-on (CSS показывает .tc-asst-btn). Память чата: последние 6 реплик уходят
модели, живёт в памяти вкладки до «Очистить»/reload. §-ссылки источников: section_ref у 531/746 чанков (после
headless-reindex); у остальных ссылка ведёт на главу.
Лимит-UX + отдельный раздел админки (commit 7830084): «не помнит» оказалось free-лимитом Gemini (HTTP 429,
≈20 req/min). callLLM теперь возвращает {text,error}; ask отдаёт source:'limit' («много запросов, подожди,
память не потеряется») или 'error'; фронт показывает это и НЕ ломает историю (pop неудачного вопроса). Многоходовость
работала и раньше — глушил лимит. В окне «Спроси» добавлено пояснение про память (≈6 реплик = рабочая память) +
аватар Квантика в шапке, окно шире/мягче. Управление вынесено в **отдельный раздел админки «Помощник Квантик»**
(frontend/js/admin/sections/assistant.js; AdminSections.assistant; ROUTE_TO_SECTION+ADMIN_ONLY_TABS+btn-tab-assistant;
из games.js конфиг и фича-запись удалены) — там системный вкл/выкл (feature 'assistant' через /api/admin/features) +
модель/ключ/тест/RAG/кнопки экзамена/счётчик/качество. ВАЖНО: free-квота Gemini gemini-2.5-flash = **20 запросов В СУТКИ** (quotaId GenerateRequestsPerDayPerProjectPerModel-FreeTier),
остальные модели Gemini на ключе — limit:0. Это мизер → постоянный 429. Решение: сменить провайдера на **Groq**
(free-тариф щедрый, ~тысячи/день, 30 RPM) — создать ключ console.groq.com, в админ-разделе «Помощник Квантик»
выбрать пресет Groq + вставить ключ; ИЛИ включить billing Gemini; ИЛИ локальная Ollama. Провайдер меняется в админке.
Мульти-провайдер (commit e2bff24): конфиг = список провайдеров app_settings.assistant_providers (JSON
[{id,name,url,model,key}]) + assistant_active. llmConfig=активный; providersOrdered=активный первым + остальные
с ключом; callLLMFailover перебирает их при 429/timeout/network/http (askModel и flashcards идут через него) —
второй ключ авто-подхватывает при исчерпании квоты первого. Legacy assistant_llm_* мигрируются в список при
первом GET админки. Админ-раздел «Помощник Квантик»: список провайдеров (радио=активный, Тест/Изменить/Удалить
по каждому) + форма с пресетами. Эндпоинты POST/DELETE /admin/assistant/provider(/:id), POST /admin/assistant/active.
Решение лимита Gemini (20/сутки): добавить Groq вторым провайдером — failover сам переключит.
ГОЧА: **Groq гео-заблокирован в Беларуси** («Access denied» на console.groq.com) — ключ не создать без VPN.
Железо машины подходит для ЛОКАЛЬНОЙ модели: 32 ГБ ОЗУ, GTX 1080 8 ГБ VRAM (WMI врёт 4 ГБ) → Qwen2.5-7B через
Ollama идеально. Выбор «локально vs Gemini billing vs OpenRouter» пока НЕ сделан (вопрос прерван). Failover-
уведомление (commit aac1240): callLLMFailover пишет app_settings.assistant_failover {failedName,servedName,reason,at};
при успехе активного снимается; админ-раздел показывает баннер «провайдер X недоступен — работаю на Y» / «все недоступны».
ПОДКЛЮЧЁН Kilo Code (работает из Беларуси!) как АКТИВНЫЙ провайдер: URL
**https://kilocode.ai/api/openrouter/chat/completions**, ключ — JWT (в app_settings, не в репо), модель
**nvidia/nemotron-3-ultra-550b-a55b:free** (бесплатно, чистый русский + LaTeX). Gemini остался вторым (failover).
Гочи Kilo на этом ключе: публичные `:free` (deepseek/mistral) → 404 «No endpoints»; платные → 401 «need to sign in»
(нет кредитов); kilo-auto/free → пустой ответ; рабочие бесплатные: nvidia/nemotron-3-ultra-550b-a55b:free и
openrouter/owl-alpha. Наш callLLM (без HTTP-Referer) Kilo принимает. nemotron — reasoning-модель → в промпт добавлено
«не выводи рассуждения вслух» (commit d1be2c1). Список моделей Kilo: GET .../api/openrouter/models (342 шт).
Админка (games.js, карточка): тумблер RAG, «Переиндексировать», число фрагментов. **Кэш** assistant_cache
(7 дней, только вопросы без контекста/истории) + **счётчик** assistant_usage (ИИ/кэш/FAQ, в админке).
**Учитель**: role в /context, доп. системный промпт для teacher/admin + teacher-чипы в «Спроси».
**Ключ перенесён в БД** (app_settings assistant_llm_url/key/model), из backend/.env удалён — конфиг
теперь только через админку. НЕ сделано: headless-RAG для JS-учебников; голосовой ввод; редактор промпта.
Связано: [[reference_quick_lesson]] [[reference_student_materials]] [[feedback_no_emoji]].