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

Админ-раздел переделан: провайдеры — карточки (активный подсвечен, бейджи
ключ/активен, кнопки Сделать активным/Тест/Изменить/Удалить, hover-подъём).
Форма с лейблами и пресетами. Для Kilo — выпадающий список проверенных бесплатных
моделей (Nemotron 550B / Owl Alpha / Nemotron Nano 30B / Laguna XS) и инлайн-
переключатель модели прямо на карточке. Бэкенд: пресет Kilo + kiloModels в /admin/assistant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-04 20:47:28 +03:00
parent d1be2c1a62
commit 0e08e5775d
2 changed files with 140 additions and 98 deletions
+9 -1
View File
@@ -879,11 +879,19 @@ function broadcast(req, res) {
/* ── Ассистент «Квантик»: конфиг LLM из админки ──────────────────────── */
const ASSISTANT_PRESETS = [
{ name: 'Kilo Code (бесплатно)', url: 'https://kilocode.ai/api/openrouter/chat/completions', model: 'nvidia/nemotron-3-ultra-550b-a55b:free' },
{ name: 'Google Gemini', url: 'https://generativelanguage.googleapis.com/v1beta/openai/chat/completions', model: 'gemini-2.5-flash' },
{ name: 'Groq', url: 'https://api.groq.com/openai/v1/chat/completions', model: 'llama-3.3-70b-versatile' },
{ name: 'OpenRouter', url: 'https://openrouter.ai/api/v1/chat/completions', model: 'meta-llama/llama-3.3-70b-instruct:free' },
{ name: 'Ollama (локально)', url: 'http://localhost:11434/v1/chat/completions', model: 'qwen2.5:3b' },
];
// Проверенные бесплатные модели Kilo (чистый русский) — для выпадающего списка
const KILO_MODELS = [
{ id: 'nvidia/nemotron-3-ultra-550b-a55b:free', label: 'Nemotron 550B (флагман)' },
{ id: 'openrouter/owl-alpha', label: 'Owl Alpha' },
{ id: 'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free', label: 'Nemotron Nano 30B (быстрее)' },
{ id: 'poolside/laguna-xs.2:free', label: 'Laguna XS (лёгкая)' },
];
function _aset(k) { const r = db.prepare('SELECT value FROM app_settings WHERE key = ?').get(k); return r && r.value != null ? r.value : null; }
function _aProviders() { try { return JSON.parse(_aset('assistant_providers') || '[]') || []; } catch (e) { return []; } }
@@ -926,7 +934,7 @@ function getAssistant(_req, res) {
res.json({
providers, activeId, active,
rag: _aset('assistant_rag') !== '0', examButtons: _aset('assistant_exam_buttons') === '1',
chunks, usage, usage30, feedback, failover, presets: ASSISTANT_PRESETS,
chunks, usage, usage30, feedback, failover, presets: ASSISTANT_PRESETS, kiloModels: KILO_MODELS,
});
}