Руководство по сборке локального AI-стека
Часть 3. Наполнение моделями и HTML-шпаргалка
На этом шаге мы наполняем папку models/ моделями под разные задачи, раскладываем их по правилам (плоско vs подпапки с mmproj) и делаем HTML-шпаргалку — статическую страницу, которая отвечает на вопрос «какая модель для какой задачи», не требуя лезть в конфиги или документацию.
Зачем это нужно
После части 2 у нас есть одна тестовая модель (Qwen3.5-2B) и рабочий llama-server. Но для реальной работы нужен набор моделей: одна сильна в коде, другая — в ролевом общении, третья — в русском, четвёртая — в OCR. Держать это в голове сложно, а лезть в интернет за описанием каждой — долго.
HTML-шпаргалка решает две задачи:
-
Быстрый выбор. Таблица «задача -> модель -> почему» вверху страницы: 80% случаев решаются за 5 секунд.
-
Карточки моделей. Плюсы, минусы, «лучше всего для», кнопка «Копировать
-m <модель>» — чтобы не набирать имя вручную.
Страница статическая, открывается через file:// в браузере, работает без сервера и без интернета.
Правила раскладки моделей
Из части 2: обычные модели — плоско, мультимодальные — в подпапке с mmproj. Финальная структура models/ в этом проекте выглядит так:
models/├── Blitzar-Coder-4B-F.1.Q4_K_M.gguf <- кодинг, компактно├── MN-12B-Runeweaver-RP-RU.Q4_K_M.gguf <- РП без цензуры├── OxCoder-9B.Q4_K_M.gguf <- кодинг, агентский├── qwen2.5-coder-7b-instruct-q4_k_m.gguf <- кодинг, быстрый├── Qwen3-4B-Instruct-2507-Q4_K_M.gguf <- чат, альтернатива├── RusMind-Momentum-4.7-Q4_K_M.gguf <- русский, перевод│├── gemma-4-E2B-it-Q4_K_M/ <- РП + vision│ ├── gemma-4-E2B-it-Q4_K_M.gguf│ └── mmproj-F16.gguf├── gemma-4-E4B-it-Q4_K_M/ <- РП + vision (чемпион)│ ├── gemma-4-E4B-it-Q4_K_M.gguf│ └── mmproj-F16.gguf├── Qwen3.5-2B-Q4_K_M/ <- сверхбыстрый чат + vision│ ├── Qwen3.5-2B-Q4_K_M.gguf│ └── mmproj-F16.gguf├── Qwen3.5-4B-Q4_K_M/ <- быстрый чат + vision│ ├── Qwen3.5-4B-Q4_K_M.gguf│ └── mmproj-F16.gguf├── Qwen3.5-9B-Q4_K_M/ <- универсал + vision│ ├── Qwen3.5-9B-Q4_K_M.gguf│ └── mmproj-F16.gguf├── Qwen3VL-4B-Instruct-Q4_K_M/ <- vision, OCR│ ├── Qwen3VL-4B-Instruct-Q4_K_M.gguf│ └── mmproj-Qwen3VL-4B-Instruct-F16.gguf <- имя проектора другое — норм│└── media/ <- diffusion (часть 4) ├── z_image_turbo-Q4_K.gguf ├── mage_flow_turbo_bf16.safetensors └── vae/
Важные моменты:
-
Имя
mmprojне обязано точно совпадать с именем модели. Главное — начинается сmmproj.mmproj-Qwen3VL-4B-Instruct-F16.ggufиmmproj-F16.ggufодинаково валидны. Режим роутера подхватывает любой файл в папке модели, имя которого начинается сmmproj. -
models/media/исключается из списка LLM. Скриптrun_llama_mmap.shявно отсекает эту папку (! -path "$MEDIA_MODELS_DIR/*"), чтобы диффузионные модели не попадали в дропдаун чата. -
llama.cppне проверяет «правильность» имени. Файлqwen2.5-coder-7b-instruct-q4_k_m.ggufв нижнем регистре — это нормально, скрипт найдёт его по*.gguf.
Каталог моделей по задачам
Ниже — что скачано и зачем. Все модели — в квантовании Q4_K_M (если не указано иное), это оптимум «качество/размер» для CPU.
Универсальные (чат, саммари)
|
Модель |
Размер |
Зачем |
|---|---|---|
|
Qwen3.5-9B |
~6 ГБ |
Основная «рабочая лошадка». Лучший баланс качества и скорости, хороший русский, контекст до 160 страниц. Для большинства задач — первый выбор. |
|
Qwen3.5-4B |
~3 ГБ |
Когда 9B долго думает. Достаточно умна для чата и лёгких саммари, в 2–3 раза быстрее. |
|
Qwen3.5-2B |
~1.5 ГБ |
Сверхбыстрая: черновики, проверка идей, «спросить и забыть». Тестовая модель из части 2. |
|
Qwen3-4B-Instruct-2507 |
~3 ГБ |
Альтернатива Qwen3.5-4B с другим стилем ответа. Полезна для «второго мнения» на технических вопросах. |
|
Gemma-4-E4B |
~3 ГБ |
Хорошо держит контекст и понимает смысл. В саммари на уровне qwen3.5-9b. |
Кодинг
|
Модель |
Размер |
Зачем |
|---|---|---|
|
Qwen2.5-Coder-7B |
~4.5 ГБ |
Быстрый и сильный в коде. HumanEval 76.0 — один из лучших в классе 7–8B. Для повседневных правок и объяснений. |
|
OxCoder-9B |
~6 ГБ |
Специализация Qwen3.5-9B под агентский кодинг: планы рефакторинга, работа с проектами. Медленнее 7B, но глубже. |
|
Blitzar-Coder-4B |
~2.5 ГБ |
Компактный кодер. Только с ручным контролем: зацикливается на генерации тестов, «тесты» в виде голых |
Ролевое общение
|
Модель |
Размер |
Зачем |
|---|---|---|
|
Gemma-4-E4B |
~3 ГБ |
Чемпион по русскому РП. Живой язык, действия в скобках, без перебора с «йо-хо-хо». Также сильна в саммари (глубина вопросов) и анализе перевода с иронией. Vision (с |
|
Gemma-4-E2B |
~1.5 ГБ |
Лёгкая версия E4B: атмосферная, быстрая, но иногда забывает детали промпта. Для коротких РП-сессий. Vision (с |
|
MN-12B-Runeweaver-RP-RU |
~7 ГБ |
Специализированная русскоязычная RP-модель без цензуры. В тестах склонна к морализаторству («поговори с ребёнком о самооценке» вместо драмы) — требует точных промптов и |
Русский язык
|
Модель |
Размер |
Зачем |
|---|---|---|
|
RusMind-4.7-Momentum |
~3.4 ГБ |
Специализированная русскоязычная модель. Лучший перевод с сохранением иронии (8.5/10 в тестах). В саммари «додумывает» — не для фактологии, а для «живого» русского. |
Vision (изображения, OCR)
|
Модель |
Размер |
Зачем |
|---|---|---|
|
Qwen3VL-4B |
~3 ГБ |
Отдельная VL-модель: OCR (включая рукописный), описание фото, вопросы по скриншотам. Как текстовый чат слабее Qwen3.5-4B. |
|
Qwen3.5-2B/4B/9B + mmproj |
+300–600 МБ |
Уже есть в списке «Универсальные». С |
|
Gemma-4-E2B/E4B + mmproj |
+300–600 МБ |
Уже есть в списке «Ролевое». С |
Что скачать в первую очередь: Qwen3.5-9B (универсал), OxCoder-9B (кодинг), Gemma-4-E4B (РП + саммари + vision), Qwen3VL-4B (OCR). Это 4 модели, которые покрывают 90% задач. Остальные — по мере необходимости.
HTML-шпаргалка
web/models.html — статическая страница. Устроена так:
-
Таблица «Быстрый выбор по задаче» — 12 строк «задача -> модель -> почему». Самое полезное: не нужно читать карточки, чтобы найти «чем сделать OCR».
-
Фильтры по задачам — кнопки «Чат», «Код», «РП», «Тексты», «Зрение», «Быстро». Нажатие скрывает карточки, не относящиеся к задаче.
-
Карточки моделей — для каждой: описание, теги задач, плюсы/минусы, «лучше всего для», кнопка «Копировать
-m <модель>». -
Адаптивность — на телефоне карточки в один столбец, таблица сжимается.
-
Печать — ссылка в футере, если захотите распечатать.
Как открыть:
file:///path/to/llama_server/web/models.html
Или из плашки run_llama_mmap.sh — там есть строка Шпаргалка: file://....
Как добавить новую модель. В <script>, в массив MODELS, добавить объект:
{ name: 'Название-модели-Q4_K_M', size: '7B', vision: false, tasks: ['code', 'fast'], // теги из TASKS desc: 'Краткое описание одной строкой.', pros: ['плюс 1', 'плюс 2'], cons: ['минус 1'], best_for: 'Для чего лучше всего'}
И, если нужно, добавить строку в <tbody> таблицы quick-table. Больше ничего править не надо — карточка и фильтры подхватят автоматически.
Как добавить новую задачу. В объект TASKS:
const TASKS = { // ... audio: { label: 'Аудио', color: '#9c27b0' }};
Кнопка фильтра появится сама.
Код HTML-шпаргалки (web/models.html)
<!DOCTYPE html><html lang="ru"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>LLM Cheat Sheet — выбор модели</title><style>:root { --bg: #121212; --surface: #1e1e1e; --surface-hover: #2a2a2a; --primary: #bb86fc; --primary-dim: #9a67ea; --text: #e1e1e1; --text-dim: #9e9e9e; --border: #333; --green: #4caf7d; --orange: #ffb74d; --blue: #64b5f6; --pink: #f06292; --purple: #ba68c8; --cyan: #4dd0e1;}* { box-sizing: border-box; margin: 0; padding: 0; }body { background: var(--bg); color: var(--text); font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; line-height: 1.55; padding: 32px 16px;}.container { max-width: 1200px; margin: 0 auto; }header { margin-bottom: 32px; padding-bottom: 20px; border-bottom: 1px solid var(--border);}h1 { font-size: 1.8rem; font-weight: 400; margin-bottom: 8px; }h1 .accent { color: var(--primary); }.subtitle { color: var(--text-dim); font-size: 0.95rem; }h2 { font-size: 1.2rem; font-weight: 500; margin: 32px 0 16px; color: var(--text); display: flex; align-items: center; gap: 8px;}h2::before { content: ''; width: 3px; height: 20px; background: var(--primary); border-radius: 2px;}/* Quick picks table */.quick-table { width: 100%; border-collapse: collapse; background: var(--surface); border-radius: 12px; overflow: hidden;}.quick-table th, .quick-table td { padding: 12px 16px; text-align: left; border-bottom: 1px solid var(--border); font-size: 0.92rem;}.quick-table th { background: #252525; color: var(--text-dim); font-weight: 500; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.5px;}.quick-table tr:last-child td { border-bottom: none; }.quick-table tr:hover { background: var(--surface-hover); }.quick-table .task { color: var(--primary); font-weight: 500; white-space: nowrap; }.quick-table .model { font-family: 'Consolas', monospace; font-size: 0.85rem; color: var(--text); }/* Filters */.filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px;}.filter-btn { background: var(--surface); color: var(--text-dim); border: 1px solid var(--border); padding: 6px 14px; border-radius: 16px; cursor: pointer; font-size: 0.85rem; font-family: inherit; transition: all 0.2s;}.filter-btn:hover { color: var(--text); border-color: var(--primary-dim); }.filter-btn.active { background: var(--primary); color: #000; border-color: var(--primary); font-weight: 500;}/* Cards */.models-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 16px;}.card { background: var(--surface); border-radius: 12px; padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.4); transition: transform 0.15s, box-shadow 0.15s; display: flex; flex-direction: column;}.card:hover { transform: translateY(-2px); box-shadow: 0 4px 16px rgba(0,0,0,0.6);}.card-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px;}.card-title { font-size: 1.05rem; font-weight: 500; font-family: 'Consolas', monospace; word-break: break-word;}.card-badges { display: flex; gap: 4px; flex-shrink: 0; }.badge { font-size: 0.7rem; padding: 2px 8px; border-radius: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px;}.badge.size { background: #2a2a2a; color: var(--text-dim); }.badge.vision { background: var(--blue); color: #000; }.card-desc { font-size: 0.9rem; color: var(--text-dim); margin-bottom: 14px;}.section-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); margin-bottom: 4px;}.pros-list, .cons-list { list-style: none; margin-bottom: 12px;}.pros-list li, .cons-list li { font-size: 0.87rem; padding-left: 18px; position: relative; margin-bottom: 3px;}.pros-list li::before { content: '+'; position: absolute; left: 4px; color: var(--green); font-weight: bold;}.cons-list li::before { content: '−'; position: absolute; left: 4px; color: var(--orange); font-weight: bold;}.best-for { background: #252525; border-radius: 8px; padding: 10px 12px; margin-bottom: 12px; font-size: 0.87rem;}.best-for strong { color: var(--primary); font-weight: 500; }.tasks-row { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 12px;}.task-tag { font-size: 0.72rem; padding: 2px 8px; border-radius: 10px; background: #252525; color: var(--text-dim);}.launch-row { display: flex; align-items: center; gap: 8px; padding-top: 12px; border-top: 1px solid var(--border); margin-top: auto;}.launch-cmd { flex: 1; font-family: 'Consolas', monospace; font-size: 0.8rem; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}.copy-btn { background: var(--surface-hover); color: var(--text-dim); border: 1px solid var(--border); padding: 4px 10px; border-radius: 6px; cursor: pointer; font-size: 0.75rem; font-family: inherit; transition: all 0.2s;}.copy-btn:hover { color: var(--primary); border-color: var(--primary); }.copy-btn.copied { color: var(--green); border-color: var(--green); }.hidden { display: none !important; }footer { margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--border); color: var(--text-dim); font-size: 0.85rem; text-align: center;}@media (max-width: 600px) { body { padding: 16px 8px; } h1 { font-size: 1.4rem; } .quick-table th, .quick-table td { padding: 8px 10px; font-size: 0.82rem; } .models-grid { grid-template-columns: 1fr; } .card { padding: 16px; }}</style></head><body><div class="container"><header> <h1>LLM <span class="accent">Cheat Sheet</span></h1> <div class="subtitle">Быстрый выбор модели по задаче. Все модели: Q4_K_M, запуск через <code>llama-server</code>.</div></header><h2>Быстрый выбор по задаче</h2><table class="quick-table"> <thead> <tr><th>Задача</th><th>Модель</th><th>Почему</th></tr> </thead> <tbody> <tr><td class="task">Универсальный чат</td><td class="model">Qwen3.5-9B</td><td>Лучший баланс качества/скорости, хороший русский</td></tr> <tr><td class="task">Быстрый чат</td><td class="model">Qwen3.5-4B/2B</td><td>Когда нужен простой чат без сложных контекстов</td></tr> <tr><td class="task">Ролевое (чемпион)</td><td class="model">Gemma-4-E4B</td><td>Живой русский, действия в скобках, без перебора</td></tr> <tr><td class="task">Ролевое (лёгкое)</td><td class="model">Gemma-4-E2B</td><td>2B, но атмосферно — быстрая альтернатива</td></tr> <tr><td class="task">Ролевое (без цензуры)</td><td class="model">MN-12B-Runeweaver</td><td>Поддерживает все кроме реальных правонарушений (план действий)</td></tr> <tr><td class="task">Кодинг (агентский)</td><td class="model">OxCoder-9B</td><td>План рефакторинга 9/10, хороший кодинг</td></tr> <tr><td class="task">Кодинг (быстро)</td><td class="model">Qwen2.5-Coder-7B</td><td>HumanEval 76, но нужно проверять вручную (есть упущения)</td></tr> <tr><td class="task">Кодинг (компактно)</td><td class="model">Blitzar-Coder-4B</td><td>Только с контролем: зацикливается на тестах</td></tr> <tr><td class="task">Саммари / ключевые мысли</td><td class="model">Qwen3.5 (9B, 4B), Gemma-4 (E2B, E4B)</td><td>9B, E4B - самые сильные кандидаты. 4B, E2B - для простых задач</td></tr> <tr><td class="task">Перевод с иронией</td><td class="model">RusMind / Gemma-E4B</td><td>RusMind — лучше результат; Gemma — выдает варианты</td></tr> <tr><td class="task">Изображения / OCR</td><td class="model">Qwen3VL-4B, Qwen3.5 (2B, 4B, 9B), Gemma (e2b, e4b)</td><td>VL, рукописный текст, контекст</td></tr> <tr><td class="task">Сверхбыстро</td><td class="model">Gemma-4-E2B, Qwen3.5-2B</td><td>Мгновенно, минимум RAM</td></tr> </tbody></table><h2>Все модели</h2><div class="filters" id="filters"></div><div class="models-grid" id="models-grid"></div><footer> <div>Шпаргалка по моделям в <code>models/</code> · <a href="#" onclick="window.print(); return false;" style="color: var(--primary);">Печать</a></div></footer></div><script>const TASKS = { chat: { label: 'Чат', color: '#64b5f6' }, code: { label: 'Код', color: '#4dd0e1' }, roleplay: { label: 'РП', color: '#f06292' }, text: { label: 'Тексты', color: '#ba68c8' }, vision: { label: 'Зрение', color: '#ffb74d' }, fast: { label: 'Быстро', color: '#4caf7d' }};const MODELS = [ { name: 'Qwen3.5-9B-Q4_K_M', size: '9B', vision: true, tasks: ['chat', 'text', 'vision'], desc: 'Универсальная рабочая лошадка: связность, грамматика, длинный контекст.', pros: ['Лучший баланс качества и скорости', 'Хороший русский', 'Точнее RusMind в саммари', 'Vision (с mmproj)'], cons: ['Медленнее младших версий', 'В коде пропускает edge case с пустой строкой'], best_for: 'Основной чат, саммари, перевод, обработка результатов поиска' }, { name: 'Qwen3.5-4B-Q4_K_M', size: '4B', vision: true, tasks: ['chat', 'text', 'fast', 'vision'], desc: 'Хороший компромисс между скоростью и качеством.', pros: ['Заметно быстрее 9B', 'Достаточно умен для большинства задач', 'Vision (с mmproj)'], cons: ['Сложные тексты хуже, чем у 9B', 'В РП склонна к «маньячному» тону'], best_for: 'Быстрый чат, простой перевод, лёгкие саммари' }, { name: 'Qwen3.5-2B-Q4_K_M', size: '2B', vision: true, tasks: ['fast', 'vision'], desc: 'Сверхбыстрая, для черновиков и проверки идей.', pros: ['Мгновенный отклик', 'Минимум RAM', 'Vision (с mmproj)'], cons: ['Простое качество', 'Перевод с сарказмом проваливает (3/10)', 'Не для сложных рассуждений'], best_for: 'Черновики, быстрые вопросы, проверка идей' }, { name: 'Qwen3-4B-Instruct-2507-Q4_K_M', size: '4B', vision: false, tasks: ['chat', 'text', 'fast'], desc: 'Альтернатива Qwen3.5-4B с другим стилем ответа, только текст.', pros: ['Другой стиль ответа', 'Хорош для технических вопросов'], cons: ['Нет зрения', 'Слабее Qwen3.5-4B в целом'], best_for: 'Текстовые задачи без vision, альтернативный взгляд' }, { name: 'qwen2.5-coder-7b-instruct-q4_k_m', size: '7B', vision: false, tasks: ['code'], desc: 'Один из сильнейших в классе 7-8B для кодинга.', pros: ['HumanEval 76.0', 'Хорош в Python, JS, C++, Go', 'Понимает длинные файлы'], cons: ['Слабее в общем чате, чем 9B', 'Не защищает от пустой строки в edge case'], best_for: 'Генерация, редактирование кода, объяснение кода' }, { name: 'OxCoder-9B', size: '9B', vision: false, tasks: ['code'], desc: 'Специализация Qwen3.5-9B под агентский кодинг и длинные задачи.', pros: ['Лучший в тестах: план рефакторинга 9/10, код 9/10', 'Обрабатывает edge cases', 'Не зацикливается'], cons: ['Тяжелее 7B-кодеров', 'Избыточен для простых скриптов'], best_for: 'Агентские задачи, рефакторинг больших проектов, сложный код' }, { name: 'Blitzar-Coder-4B-F.1', size: '4B', vision: false, tasks: ['code', 'fast'], desc: 'Компактный кодер на базе Qwen3-4B, обучен на большом кодовом датасете.', pros: ['4B — быстрый', 'Мультиязычный кодинг', 'Мало RAM', 'Защищает от пустой строки'], cons: ['Зацикливается на генерации тестов', '«Тесты» в виде голых assert — мёртвый код', 'Просит запустить инструмент'], best_for: 'Простые скрипты — только с ручным контролем и без автоматики' }, { name: 'Qwen3VL-4B-Instruct-Q4_K_M', size: '4B', vision: true, tasks: ['vision', 'chat'], desc: 'VL-модель: читает изображения, OCR, отвечает по картинкам.', pros: ['Понимает изображения', 'OCR (включая рукописный)', 'Отвечает по контексту картинки'], cons: ['Как текстовик слабее Qwen3.5-4B'], best_for: 'Описание фото, распознавание текста, вопросы по скриншотам' }, { name: 'Gemma-4-E4B-it-Q4_K_M', size: '4B', vision: true, tasks: ['roleplay', 'chat', 'fast', 'vision', 'text'], desc: 'Лучшая для русского РП: живой язык, действия в скобках, без перебора.', pros: ['Естественный диалог', 'Держит персонажа', 'Отличный анализ перевода с иронией', 'Сильна в саммари: глубина вопросов, точность терминов', 'Vision (с mmproj)'], cons: ['Меньше знаний, чем у Qwen3.5-9B', 'Иногда переименовывает объекты из промпта'], best_for: 'Ролевое общение, перевод с анализом нюансов, саммари, живой русский' }, { name: 'Gemma-4-E2B-it-Q4_K_M', size: '2B', vision: true, tasks: ['roleplay', 'fast', 'vision'], desc: 'Сверхлёгкая Gemma для быстрых РП-сессий и черновиков.', pros: ['Мгновенная', 'Минимум RAM', 'Атмосферная для 2B', 'Саммари на уровне 4B-моделей, несмотря на размер', 'Vision (с mmproj)'], cons: ['Простое качество', 'Иногда забывает ключевые детали промпта'], best_for: 'Быстрое РП, черновики, быстрые саммари, простые диалоги' }, { name: 'RusMind-4.7-Momentum', size: '4.7B', vision: false, tasks: ['text', 'chat'], desc: 'Специализированная русскоязычная модель, высокие баллы MERA v2.', pros: ['«Живой» русский', 'Лучший перевод с сохранением иронии (8.5/10)', 'Q4_K_M ~3.4 ГБ'], cons: ['Слабее в коде и математике', 'В саммари «додумывает» (философия, сленг)'], best_for: 'Перевод с сохранением тона, работа с русскими текстами (не фактология)' }, { name: 'Meta-Llama-3.1-8B-Instruct-abliterated', size: '8B', vision: false, tasks: ['roleplay', 'chat'], desc: 'Ролевая модель без цензурных срывов. Официально русский не поддерживает.', pros: ['Без фильтров', 'Сильна в англоязычном РП', 'Пишет стихи, сцены'], cons: ['На русском промпте соскакивает на английский', 'Слабее в кодинге и математике'], best_for: 'Англоязычное РП и творческие сценарии; для русского — не подходит' }, { name: 'MN-12B-Runeweaver-RP-RU', size: '12B', vision: false, tasks: ['roleplay'], desc: 'Специализированная русскоязычная RP-модель без цензуры.', pros: ['Без фильтров', 'Русский язык', 'Специально под РП'], cons: ['Заговаривается', 'Иногда переименовывает объекты', 'Тяжелее 4–8B'], best_for: 'РП без цензуры, требует точных промптов' }];// --- Render filters ---const filtersEl = document.getElementById('filters');const allBtn = document.createElement('button');allBtn.className = 'filter-btn active';allBtn.textContent = 'Все';allBtn.dataset.filter = 'all';filtersEl.appendChild(allBtn);for (const [key, info] of Object.entries(TASKS)) { const btn = document.createElement('button'); btn.className = 'filter-btn'; btn.textContent = info.label; btn.dataset.filter = key; btn.style.setProperty('--task-color', info.color); filtersEl.appendChild(btn);}// --- Render model cards ---const grid = document.getElementById('models-grid');MODELS.forEach(m => { const card = document.createElement('div'); card.className = 'card'; card.dataset.tasks = m.tasks.join(','); const taskTags = m.tasks.map(t => `<span class="task-tag" style="color:${TASKS[t].color}">${TASKS[t].label}</span>`).join(''); const pros = m.pros.map(p => `<li>${p}</li>`).join(''); const cons = m.cons.map(c => `<li>${c}</li>`).join(''); const visionBadge = m.vision ? '<span class="badge vision">vision</span>' : ''; card.innerHTML = ` <div class="card-header"> <div class="card-title">${m.name}</div> <div class="card-badges"> <span class="badge size">${m.size}</span> ${visionBadge} </div> </div> <div class="card-desc">${m.desc}</div> <div class="tasks-row">${taskTags}</div> <div class="section-label">Сильные стороны</div> <ul class="pros-list">${pros}</ul> <div class="section-label">Слабые стороны</div> <ul class="cons-list">${cons}</ul> <div class="best-for"><strong>Лучше всего для:</strong> ${m.best_for}</div> <div class="launch-row"> <span class="launch-cmd">-m ${m.name}</span> <button class="copy-btn" onclick="copyLaunch(this, '-m ${m.name}')">Копировать</button> </div> `; grid.appendChild(card);});// --- Filter logic ---filtersEl.addEventListener('click', e => { if (!e.target.classList.contains('filter-btn')) return; const filter = e.target.dataset.filter; filtersEl.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); e.target.classList.add('active'); grid.querySelectorAll('.card').forEach(card => { if (filter === 'all' || card.dataset.tasks.split(',').includes(filter)) { card.classList.remove('hidden'); } else { card.classList.add('hidden'); } });});// --- Copy button ---function copyLaunch(btn, text) { navigator.clipboard.writeText(text).then(() => { const orig = btn.textContent; btn.textContent = '✓'; btn.classList.add('copied'); setTimeout(() => { btn.textContent = orig; btn.classList.remove('copied'); }, 1200); });}</script></body></html>
Проверка после наполнения
1. Все модели видны в роутере:
./run_llama_mmap.sh
В логе должно быть: Router mode: каталог ./models (N шт.). Число N — количество .gguf без mmproj и без media/. Для текущего листинга — 10 (Blitzar, MN-12B, OxCoder, qwen2.5-coder, Qwen3-4B, RusMind, Gemma-E2B, Gemma-E4B, Qwen3.5-2B, Qwen3.5-4B, Qwen3.5-9B, Qwen3VL-4B).
2. Модель с mmproj видит картинки:
./run_llama_mmap.sh -m Qwen3VL-4B-Instruct-Q4_K_M
В логе — Найден mmproj: mmproj-Qwen3VL-4B-Instruct-F16.gguf и clip_model_load: .... В UI прикрепите картинку — модель должна её описать.
3. Шпаргалка открывается:
xdg-open web/models.html # или file:// в браузере
Проверьте: таблица сверху, фильтры работают, кнопка «Копировать» копирует -m <модель>.
4. Тест «какая модель для чего»:
-
Откройте шпаргалку, найдите «Кодинг (агентский)» ->
OxCoder-9B. Скопируйте-m OxCoder-9B.Q4_K_Mили любую другую модель. -
Запустите
./run_llama_mmap.sh-m OxCoder-9B.Q4_K_M. -
Отправте промпт для теста.
ссылка на оригинал статьи https://habr.com/ru/articles/1099492/