Ship Assistent 0.12.1: training tab, dataset pipeline, and heard RAG.

Restructure UI with app-level tabs and chat history drawer; add dataset curation,
HF import, Modelfile/QLoRA hooks, and link approved samples to the agent immediately
via heard vector memory without waiting for fine-tuning.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-22 14:27:59 +03:00
co-authored by Cursor
parent e8bb012885
commit 1a03c3178f
21 changed files with 4919 additions and 638 deletions
+284 -144
View File
@@ -2,161 +2,290 @@
<div class="sa-gate" id="sa_gate" hidden>
<p>Swarm Assistent только для моделей <strong>Krea 2</strong>. Выбери checkpoint Krea 2, чтобы включить чат.</p>
</div>
<div class="sa-layout" id="sa_layout">
<aside class="sa-image-pane" id="sa_image_pane">
<div class="sa-board-head">
<span class="sa-board-title">Доска</span>
<div class="sa-board-tabs" role="tablist" aria-label="Доска">
<button type="button" class="sa-board-tab sa-board-tab-active" data-board="generate" id="sa_board_tab_gen" role="tab" aria-selected="true">Generate</button>
<button type="button" class="sa-board-tab" data-board="refs" id="sa_board_tab_refs" role="tab" aria-selected="false">
Refs
<span class="sa-board-badge" id="sa_refs_badge" hidden></span>
</button>
</div>
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_add_ref" title="Добавить окно референса">+ Ref</button>
</div>
<div class="sa-board" id="sa_board" tabindex="0" title="Перетащи изображение на окно или вставь (Ctrl+V). Кликни, чтобы выбрать."></div>
<div class="sa-live-params" id="sa_live_params" title="Текущие параметры Generate"></div>
<div class="sa-image-actions" id="sa_image_actions">
<button type="button" class="basic-button sa-primary" id="sa_btn_look_result" title="Прикрепить готовый кадр Generate и спросить мнение">Посмотри результат</button>
<button type="button" class="basic-button" id="sa_btn_use_current" title="Скопировать текущий Generate в Ref">Снимок gen</button>
<button type="button" class="basic-button" id="sa_btn_clear_image" title="Очистить выбранный Ref">Очистить слот</button>
<div class="sa-more-wrap" id="sa_board_more_wrap">
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_board_more" title="Init / Mask / Сброс" aria-expanded="false" aria-haspopup="true"></button>
<div class="sa-more-menu" id="sa_board_more_menu" hidden role="menu">
<button type="button" class="sa-more-item" id="sa_btn_as_init" role="menuitem">Как Init (img2img)</button>
<button type="button" class="sa-more-item" id="sa_btn_as_mask" role="menuitem">Как Mask (inpaint)</button>
<button type="button" class="sa-more-item" id="sa_btn_clear_init" role="menuitem">Сброс Init + Mask</button>
<header class="sa-appbar" id="sa_appbar">
<div class="sa-appbar-brand">
<span class="sa-appbar-title">Assistent</span>
<span class="sa-live-dot" id="sa_live_dot" hidden></span>
<span class="sa-health" id="sa_ollama_health" role="button" tabindex="0" title="Ollama: проверяю…" hidden>Ollama · …</span>
</div>
<div class="sa-app-tabs" role="tablist" aria-label="Разделы Assistent">
<button type="button" class="sa-app-tab sa-app-tab-active" data-view="chat" id="sa_tab_chat" role="tab" aria-selected="true">Чат</button>
<button type="button" class="sa-app-tab" data-view="cards" id="sa_tab_cards" role="tab" aria-selected="false">Карточки</button>
<button type="button" class="sa-app-tab" data-view="train" id="sa_tab_train" role="tab" aria-selected="false">Обучение</button>
<button type="button" class="sa-app-tab" data-view="settings" id="sa_tab_settings" role="tab" aria-selected="false">Настройки</button>
</div>
<div class="sa-train-banner" id="sa_train_banner" hidden role="status">
<span class="sa-spinner" aria-hidden="true"></span>
<span id="sa_train_banner_text">Идёт тренировка…</span>
</div>
</header>
<div class="sa-views" id="sa_views">
<div class="sa-view" id="sa_view_chat">
<div class="sa-layout" id="sa_layout">
<aside class="sa-image-pane" id="sa_image_pane">
<div class="sa-board-head">
<span class="sa-board-title">Доска</span>
<div class="sa-board-tabs" role="tablist" aria-label="Доска">
<button type="button" class="sa-board-tab sa-board-tab-active" data-board="generate" id="sa_board_tab_gen" role="tab" aria-selected="true">Generate</button>
<button type="button" class="sa-board-tab" data-board="refs" id="sa_board_tab_refs" role="tab" aria-selected="false">
Refs
<span class="sa-board-badge" id="sa_refs_badge" hidden></span>
</button>
</div>
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_add_ref" title="Добавить окно референса">+ Ref</button>
</div>
</div>
</div>
</aside>
<div class="sa-splitter" id="sa_splitter" role="separator" aria-orientation="vertical" title="Потяни, чтобы изменить ширину"></div>
<section class="sa-chat-pane">
<header class="sa-chat-header">
<div class="sa-chat-title">
Assistent
<span class="sa-live-dot" id="sa_live_dot" hidden></span>
<span class="sa-health" id="sa_ollama_health" role="button" tabindex="0" title="Ollama: проверяю…" hidden>Ollama · …</span>
<div class="sa-sessions-bar">
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_new_chat" title="Новый чат">+</button>
<button type="button" class="basic-button sa-sessions-toggle" id="sa_btn_chats" title="История чатов" aria-expanded="false">История</button>
<span class="sa-session-label" id="sa_session_label" title="Текущий чат — клик открывает Историю" role="button" tabindex="0">Новый чат</span>
</div>
<div class="sa-subtabs" role="tablist" aria-label="Разделы Assistent">
<button type="button" class="sa-subtab sa-subtab-active" data-view="chat" id="sa_tab_chat" role="tab" aria-selected="true">Чат</button>
<button type="button" class="sa-subtab" data-view="cards" id="sa_tab_cards" role="tab" aria-selected="false">Карточки</button>
<button type="button" class="sa-subtab" data-view="settings" id="sa_tab_settings" role="tab" aria-selected="false">Настройки</button>
</div>
</div>
<div class="sa-chats-panel" id="sa_chats_panel" hidden>
<div class="sa-chats-panel-head">Сохранённые чаты</div>
<input type="search" class="sa-chats-search" id="sa_chats_search" placeholder="Поиск по истории…" autocomplete="off" />
<div class="sa-chats-list" id="sa_chats_list"></div>
<div class="sa-chats-panel-hint">Старт = всегда новый чат. Клик по чату восстанавливает сообщения и параметры Generate.</div>
</div>
<div class="sa-header-right">
<div class="sa-persona-wrap">
<select id="sa_persona" class="sa-select" title="Характер / тон" aria-label="Характер">
<option value="neutral">Нейтральный</option>
</select>
<button type="button" class="basic-button sa-icon-btn" id="sa_persona_delete" title="Удалить overlay-личность" hidden aria-label="Удалить личность"></button>
</div>
<div class="sa-persona-controls" id="sa_persona_controls" hidden></div>
<select id="sa_pack" class="sa-select" title="Пакет промпта" aria-label="Пакет промпта">
<option value="ordinary">Обычный</option>
<option value="write_prompt">Написать промпт</option>
</select>
<span class="sa-mode-badge" id="sa_mode_badge" title="Активный pack">обычный</span>
<select id="sa_model" class="sa-select sa-model-select" title="Модель Ollama (чат)" aria-label="Модель Ollama">
<option value="">Загрузка моделей…</option>
</select>
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_settings" title="Настройки" aria-label="Настройки"></button>
</div>
</header>
<div class="sa-view" id="sa_view_chat">
<div class="sa-messages" id="sa_messages">
<div class="sa-chat-empty" id="sa_chat_empty">
<div class="sa-chat-empty-title">Совместная работа с Krea 2</div>
<div class="sa-chat-empty-hint">Напиши промпт, кинь refs, выбери персону или открой <em>Карточки</em> для LoRA.</div>
</div>
</div>
<div class="sa-livebar" id="sa_livebar" hidden>
<span class="sa-spinner" aria-hidden="true"></span>
<span class="sa-livebar-text" id="sa_livebar_text">Работаю…</span>
<span class="sa-elapsed" id="sa_elapsed"></span>
</div>
<div class="sa-composer" id="sa_composer">
<div class="sa-chips" id="sa_chips" role="toolbar" aria-label="Быстрые параметры"></div>
<div class="sa-lora-chips" id="sa_lora_chips" role="toolbar" aria-label="Активные LoRA"></div>
<div class="sa-slash-wrap">
<textarea id="sa_input" rows="3" placeholder="Промпт, img2img, критика… Enter = отправить · /help = команды" aria-label="Сообщение Assistent"></textarea>
<div class="sa-slash-menu" id="sa_slash_menu" hidden role="listbox"></div>
</div>
<div class="sa-composer-actions">
<button type="button" class="basic-button sa-primary" id="sa_btn_send">Отправить</button>
<button type="button" class="basic-button sa-btn-gen" id="sa_btn_build_gen" title="Нет патча — Generate с текущим промптом SwarmUI">Собрать + Gen</button>
<button type="button" class="basic-button" id="sa_btn_interrupt" title="Прервать генерацию / чат" hidden>Стоп</button>
<div class="sa-more-wrap" id="sa_clear_more_wrap">
<button type="button" class="basic-button" id="sa_btn_clear" title="Очистить чат">Очистить</button>
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_clear_more" title="Ещё варианты очистки" aria-expanded="false"></button>
<div class="sa-more-menu" id="sa_clear_more_menu" hidden role="menu">
<button type="button" class="sa-more-item" id="sa_btn_clear_confirm" role="menuitem">Очистить весь чат…</button>
<button type="button" class="sa-more-item" id="sa_btn_clear_patches" role="menuitem">Убрать только патчи</button>
<div class="sa-board" id="sa_board" tabindex="0" title="Перетащи изображение на окно или вставь (Ctrl+V). Кликни, чтобы выбрать."></div>
<div class="sa-live-params" id="sa_live_params" title="Текущие параметры Generate"></div>
<div class="sa-image-actions" id="sa_image_actions">
<button type="button" class="basic-button sa-primary" id="sa_btn_look_result" title="Прикрепить готовый кадр Generate и спросить мнение">Посмотри результат</button>
<button type="button" class="basic-button" id="sa_btn_use_current" title="Скопировать текущий Generate в Ref">Снимок gen</button>
<button type="button" class="basic-button" id="sa_btn_clear_image" title="Очистить выбранный Ref">Очистить слот</button>
<div class="sa-more-wrap" id="sa_board_more_wrap">
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_board_more" title="Init / Mask / Сброс" aria-expanded="false" aria-haspopup="true"></button>
<div class="sa-more-menu" id="sa_board_more_menu" hidden role="menu">
<button type="button" class="sa-more-item" id="sa_btn_as_init" role="menuitem">Как Init (img2img)</button>
<button type="button" class="sa-more-item" id="sa_btn_as_mask" role="menuitem">Как Mask (inpaint)</button>
<button type="button" class="sa-more-item" id="sa_btn_clear_init" role="menuitem">Сброс Init + Mask</button>
</div>
</div>
<span class="sa-status" id="sa_status" role="status" aria-live="polite"></span>
</div>
</aside>
<div class="sa-splitter" id="sa_splitter" role="separator" aria-orientation="vertical" title="Потяни, чтобы изменить ширину"></div>
<div class="sa-chat-workspace" id="sa_chat_workspace">
<section class="sa-chat-pane">
<header class="sa-chat-header">
<div class="sa-chat-title">
<div class="sa-sessions-bar">
<button type="button" class="basic-button sa-sessions-toggle" id="sa_btn_chats" title="История чатов" aria-expanded="false">История</button>
<span class="sa-session-label" id="sa_session_label" title="Текущий чат" role="button" tabindex="0">Новый чат</span>
</div>
</div>
<div class="sa-header-right">
<div class="sa-persona-wrap">
<select id="sa_persona" class="sa-select" title="Характер / тон" aria-label="Характер">
<option value="neutral">Нейтральный</option>
</select>
<button type="button" class="basic-button sa-icon-btn" id="sa_persona_delete" title="Удалить overlay-личность" hidden aria-label="Удалить личность"></button>
</div>
<div class="sa-persona-controls" id="sa_persona_controls" hidden></div>
<select id="sa_pack" class="sa-select" title="Пакет промпта" aria-label="Пакет промпта">
<option value="ordinary">Обычный</option>
<option value="write_prompt">Написать промпт</option>
</select>
<span class="sa-mode-badge" id="sa_mode_badge" title="Активный pack">обычный</span>
<select id="sa_model" class="sa-select sa-model-select" title="Модель Ollama (чат)" aria-label="Модель Ollama">
<option value="">Загрузка моделей…</option>
</select>
</div>
</header>
<div class="sa-chat-body">
<div class="sa-messages" id="sa_messages">
<div class="sa-chat-empty" id="sa_chat_empty">
<div class="sa-chat-empty-title">Совместная работа с Krea 2</div>
<div class="sa-chat-empty-hint">Напиши промпт, кинь refs, выбери персону или открой <em>Карточки</em> для LoRA.</div>
</div>
</div>
<div class="sa-livebar" id="sa_livebar" hidden>
<span class="sa-spinner" aria-hidden="true"></span>
<span class="sa-livebar-text" id="sa_livebar_text">Работаю…</span>
<span class="sa-elapsed" id="sa_elapsed"></span>
</div>
<div class="sa-composer" id="sa_composer">
<div class="sa-chips" id="sa_chips" role="toolbar" aria-label="Быстрые параметры"></div>
<div class="sa-lora-chips" id="sa_lora_chips" role="toolbar" aria-label="Активные LoRA"></div>
<div class="sa-slash-wrap">
<textarea id="sa_input" rows="3" placeholder="Промпт, img2img, критика… Enter = отправить · /help = команды" aria-label="Сообщение Assistent"></textarea>
<div class="sa-slash-menu" id="sa_slash_menu" hidden role="listbox"></div>
</div>
<div class="sa-composer-actions">
<button type="button" class="basic-button sa-primary" id="sa_btn_send">Отправить</button>
<button type="button" class="basic-button sa-btn-gen" id="sa_btn_build_gen" title="Нет патча — Generate с текущим промптом SwarmUI">Собрать + Gen</button>
<button type="button" class="basic-button" id="sa_btn_interrupt" title="Прервать генерацию / чат" hidden>Стоп</button>
<div class="sa-more-wrap" id="sa_clear_more_wrap">
<button type="button" class="basic-button" id="sa_btn_clear" title="Очистить чат">Очистить</button>
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_clear_more" title="Ещё варианты очистки" aria-expanded="false"></button>
<div class="sa-more-menu" id="sa_clear_more_menu" hidden role="menu">
<button type="button" class="sa-more-item" id="sa_btn_clear_confirm" role="menuitem">Очистить весь чат…</button>
<button type="button" class="sa-more-item" id="sa_btn_clear_patches" role="menuitem">Убрать только патчи</button>
</div>
</div>
<span class="sa-status" id="sa_status" role="status" aria-live="polite"></span>
</div>
</div>
</div>
</section>
<aside class="sa-chats-drawer" id="sa_chats_panel" aria-label="История чатов">
<div class="sa-chats-drawer-head">
<strong>Чаты</strong>
<div class="sa-chats-drawer-actions">
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_new_chat" title="Новый чат">+</button>
<button type="button" class="basic-button sa-icon-btn" id="sa_btn_chats_close" title="Скрыть панель" aria-label="Скрыть историю">×</button>
</div>
</div>
<input type="search" class="sa-chats-search" id="sa_chats_search" placeholder="Поиск по истории…" autocomplete="off" />
<div class="sa-chats-list" id="sa_chats_list"></div>
<div class="sa-chats-panel-hint">Клик по чату восстанавливает сообщения и параметры Generate.</div>
</aside>
</div>
</div>
</div>
<div class="sa-view" id="sa_view_cards" hidden>
<div class="sa-cards-layout">
<div class="sa-cards-list-pane">
<div class="sa-cards-filter">
<select id="sa_cards_kind" class="sa-select">
<option value="all">Все</option>
<option value="checkpoint">Checkpoints</option>
<option value="lora">LoRAs</option>
</select>
<button type="button" class="basic-button" id="sa_btn_cards_refresh">Обновить</button>
</div>
<div class="sa-cards-list" id="sa_cards_list"></div>
<div class="sa-view" id="sa_view_cards" hidden>
<div class="sa-cards-layout">
<div class="sa-cards-list-pane">
<div class="sa-cards-filter">
<select id="sa_cards_kind" class="sa-select">
<option value="all">Все</option>
<option value="checkpoint">Checkpoints</option>
<option value="lora">LoRAs</option>
</select>
<button type="button" class="basic-button" id="sa_btn_cards_refresh">Обновить</button>
</div>
<div class="sa-cards-editor-pane">
<div class="sa-cards-editor-head">
<strong id="sa_card_title">Выбери модель</strong>
<span class="sa-card-badge" id="sa_card_badge" hidden></span>
<div class="sa-cards-list" id="sa_cards_list"></div>
</div>
<div class="sa-cards-editor-pane">
<div class="sa-cards-editor-head">
<strong id="sa_card_title">Выбери модель</strong>
<span class="sa-card-badge" id="sa_card_badge" hidden></span>
</div>
<div class="sa-card-previews" id="sa_card_previews" hidden></div>
<div class="sa-card-form" id="sa_card_form">
<label>Triggers <input type="text" id="sa_card_triggers" placeholder="слово1, слово2" /></label>
<label>Weight <input type="number" id="sa_card_weight" step="0.05" min="0" max="2" value="0.8" /></label>
<label>When <textarea id="sa_card_when" rows="2" placeholder="Когда использовать"></textarea></label>
<label>Avoid <textarea id="sa_card_avoid" rows="2" placeholder="Чего избегать"></textarea></label>
<label>Prompt hint <textarea id="sa_card_hint" rows="2" placeholder="Подсказка для промпта"></textarea></label>
<label>Notes <textarea id="sa_card_notes" rows="2" placeholder="Заметки"></textarea></label>
<label>Civitai URL <input type="text" id="sa_card_url" placeholder="https://civitai…" /></label>
<label class="sa-card-json-toggle"><input type="checkbox" id="sa_card_show_json" /> Показать JSON</label>
<textarea id="sa_card_json" rows="8" hidden placeholder="Card JSON…" spellcheck="false"></textarea>
</div>
<div class="sa-cards-actions">
<button type="button" class="basic-button sa-primary" id="sa_btn_card_to_chat" title="В чат: используй эту модель/LoRA">В чат</button>
<button type="button" class="basic-button" id="sa_btn_card_meta">Загрузить Civitai meta</button>
<button type="button" class="basic-button" id="sa_btn_card_generate">Сгенерировать с Assistent</button>
<button type="button" class="basic-button" id="sa_btn_card_save">Сохранить карточку</button>
<button type="button" class="basic-button" id="sa_btn_card_wanted" title="В очередь на следующий up">В wanted</button>
<span class="sa-status" id="sa_card_status"></span>
</div>
</div>
</div>
</div>
<div class="sa-view" id="sa_view_train" hidden>
<div class="sa-training" id="sa_training">
<div class="sa-training-tabs" role="tablist" aria-label="Разделы обучения">
<button type="button" class="sa-ttab sa-ttab-active" data-ttab="dataset" role="tab" aria-selected="true">Датасет</button>
<button type="button" class="sa-ttab" data-ttab="train" role="tab" aria-selected="false">Тренировка</button>
<button type="button" class="sa-ttab" data-ttab="models" role="tab" aria-selected="false">Модели</button>
</div>
<div class="sa-training-panes">
<div class="sa-tpane" data-tpane="dataset">
<div class="sa-train-toolbar">
<span class="sa-train-stats" id="sa_train_stats">Одобрено: —</span>
<select id="sa_train_filter_status" class="sa-select" title="Статус">
<option value="all">Все статусы</option>
<option value="approved">Одобренные</option>
<option value="draft">Черновики</option>
<option value="rejected">Отклонённые</option>
</select>
<select id="sa_train_filter_persona" class="sa-select" title="Личность"><option value="all">Все личности</option></select>
<button type="button" class="basic-button" id="sa_btn_train_from_chats">Из чатов</button>
<button type="button" class="basic-button" id="sa_btn_train_import_file">Импорт файла…</button>
<input type="file" id="sa_train_import_file" accept=".jsonl,.json,.csv,text/csv,application/json" hidden />
<button type="button" class="basic-button" id="sa_btn_train_export">Экспорт JSONL</button>
</div>
<div class="sa-card-previews" id="sa_card_previews" hidden></div>
<div class="sa-card-form" id="sa_card_form">
<label>Triggers <input type="text" id="sa_card_triggers" placeholder="слово1, слово2" /></label>
<label>Weight <input type="number" id="sa_card_weight" step="0.05" min="0" max="2" value="0.8" /></label>
<label>When <textarea id="sa_card_when" rows="2" placeholder="Когда использовать"></textarea></label>
<label>Avoid <textarea id="sa_card_avoid" rows="2" placeholder="Чего избегать"></textarea></label>
<label>Prompt hint <textarea id="sa_card_hint" rows="2" placeholder="Подсказка для промпта"></textarea></label>
<label>Notes <textarea id="sa_card_notes" rows="2" placeholder="Заметки"></textarea></label>
<label>Civitai URL <input type="text" id="sa_card_url" placeholder="https://civitai…" /></label>
<label class="sa-card-json-toggle"><input type="checkbox" id="sa_card_show_json" /> Показать JSON</label>
<textarea id="sa_card_json" rows="8" hidden placeholder="Card JSON…" spellcheck="false"></textarea>
<div class="sa-agent-heard-panel" id="sa_agent_heard_panel">
<div class="sa-agent-heard-head">
<strong>Услышанное → агент</strong>
<span class="sa-agent-heard-stats" id="sa_agent_heard_stats">Подключено: —</span>
</div>
<p class="sa-agent-heard-hint">Одобренные примеры сразу попадают в RAG агента (без QLoRA). Агент видит их как <code>heard_examples</code> и может запросить через <code>heard_search</code>.</p>
<div class="sa-agent-heard-controls">
<label class="sa-check"><input type="checkbox" id="sa_agent_heard_enabled" checked /> Включено для чата</label>
<label class="sa-check"><input type="checkbox" id="sa_agent_auto_link" checked /> Авто-подключение при одобрении</label>
<label>Примеров в контексте <input type="number" id="sa_agent_heard_quota" min="0" max="8" value="3" /></label>
<button type="button" class="basic-button sa-primary" id="sa_btn_agent_sync">Подключить все одобренные</button>
</div>
</div>
<div class="sa-cards-actions">
<button type="button" class="basic-button sa-primary" id="sa_btn_card_to_chat" title="В чат: используй эту модель/LoRA">В чат</button>
<button type="button" class="basic-button" id="sa_btn_card_meta">Загрузить Civitai meta</button>
<button type="button" class="basic-button" id="sa_btn_card_generate">Сгенерировать с Assistent</button>
<button type="button" class="basic-button" id="sa_btn_card_save">Сохранить карточку</button>
<button type="button" class="basic-button" id="sa_btn_card_wanted" title="В очередь на следующий up">В wanted</button>
<span class="sa-status" id="sa_card_status"></span>
<div class="sa-hf-panel">
<div class="sa-hf-head"><strong>Hugging Face</strong></div>
<div class="sa-hf-search-row">
<input type="search" id="sa_hf_search" class="sa-hf-search" placeholder="Поиск датасетов…" autocomplete="off" />
<button type="button" class="basic-button" id="sa_btn_hf_search">Найти</button>
<label class="sa-check sa-hf-show-all"><input type="checkbox" id="sa_hf_show_all" /> Показать все</label>
</div>
<div class="sa-hf-link-row">
<input type="text" id="sa_hf_link" class="sa-hf-link" placeholder="owner/name или https://huggingface.co/datasets/…" />
<button type="button" class="basic-button" id="sa_btn_hf_check">Проверить</button>
</div>
<div class="sa-hf-status" id="sa_hf_status" role="status"></div>
<div class="sa-hf-list" id="sa_hf_list"></div>
<div class="sa-hf-preview" id="sa_hf_preview" hidden></div>
<div class="sa-hf-import-row" id="sa_hf_import_row" hidden>
<label>Лимит строк <input type="number" id="sa_hf_import_limit" min="1" max="5000" value="200" /></label>
<label>Соотношение внешних:своих <input type="number" id="sa_hf_mix_ratio" min="0" max="20" step="0.5" value="3" title="Сколько внешних примеров на один свой" /></label>
<button type="button" class="basic-button sa-primary" id="sa_btn_hf_import">Импортировать</button>
</div>
</div>
<div class="sa-train-samples" id="sa_train_samples"></div>
</div>
<div class="sa-tpane" data-tpane="train" hidden>
<div class="sa-train-modes">
<label class="sa-check"><input type="radio" name="sa_train_mode" value="modelfile" checked /> Быстро: Ollama Modelfile</label>
<label class="sa-check"><input type="radio" name="sa_train_mode" value="qlora" /> QLoRA (нужен python-раннер)</label>
</div>
<div class="sa-train-form" id="sa_train_form_modelfile">
<label>Базовая модель (Ollama)
<select id="sa_modelfile_base" class="sa-select"><option value=""></option></select>
</label>
<label>Имя результата <input type="text" id="sa_modelfile_name" placeholder="assistent-neutral:v1" /></label>
<label>Персона для SYSTEM
<select id="sa_modelfile_persona" class="sa-select"><option value="neutral">neutral</option></select>
</label>
<label>Few-shot примеров <input type="number" id="sa_modelfile_shots" min="0" max="32" value="8" /></label>
<label>SYSTEM (редактируемый) <textarea id="sa_modelfile_system" rows="8" spellcheck="false"></textarea></label>
<div class="sa-settings-row sa-knob-row">
<label>num_ctx <input type="number" id="sa_modelfile_num_ctx" min="2048" max="131072" step="1024" value="16384" /></label>
<label>temperature <input type="number" id="sa_modelfile_temp" min="0" max="2" step="0.05" value="0.7" /></label>
</div>
<button type="button" class="basic-button sa-primary" id="sa_btn_modelfile_create">Создать модель</button>
</div>
<div class="sa-train-form" id="sa_train_form_qlora" hidden>
<p class="sa-settings-hint">Base model — HF id (safetensors). Тренер скачает веса сам (нужен HF_TOKEN в User Settings).</p>
<label>HF base model <input type="text" id="sa_qlora_base" placeholder="meta-llama/Llama-3.2-3B-Instruct" /></label>
<label>Имя адаптера <input type="text" id="sa_qlora_name" placeholder="assistent-lora-v1" /></label>
<div class="sa-settings-row sa-knob-row">
<label>rank <input type="number" id="sa_qlora_rank" min="4" max="128" value="16" /></label>
<label>alpha <input type="number" id="sa_qlora_alpha" min="4" max="256" value="32" /></label>
<label>LR <input type="number" id="sa_qlora_lr" min="0.000001" max="0.01" step="0.00001" value="0.0002" /></label>
<label>epochs <input type="number" id="sa_qlora_epochs" min="1" max="20" value="3" /></label>
<label>seq_len <input type="number" id="sa_qlora_seq" min="512" max="8192" step="256" value="2048" /></label>
</div>
<label class="sa-check"><input type="checkbox" id="sa_qlora_4bit" checked /> 4-bit QLoRA</label>
<label>HF датасет (опционально) <input type="text" id="sa_qlora_hf_dataset" placeholder="owner/name — только для раннера" /></label>
<button type="button" class="basic-button sa-primary" id="sa_btn_qlora_start">Запустить QLoRA</button>
<button type="button" class="basic-button" id="sa_btn_qlora_cancel" hidden>Отменить</button>
</div>
<div class="sa-train-progress" id="sa_train_progress" hidden>
<div class="sa-train-progress-bar"><div class="sa-train-progress-fill" id="sa_train_progress_fill"></div></div>
<pre class="sa-train-log" id="sa_train_log"></pre>
</div>
<span class="sa-status" id="sa_train_status"></span>
</div>
<div class="sa-tpane" data-tpane="models" hidden>
<p class="sa-settings-hint">Обученные и созданные модели (Ollama tags).</p>
<div class="sa-train-models-list" id="sa_train_models_list"></div>
<div class="sa-settings-row">
<button type="button" class="basic-button" id="sa_btn_train_models_refresh">Обновить</button>
</div>
</div>
</div>
</div>
<div class="sa-view" id="sa_view_settings" hidden>
</div>
<div class="sa-view" id="sa_view_settings" hidden>
<div class="sa-settings" id="sa_settings">
<div class="sa-settings-head">
<strong>Настройки</strong>
<button type="button" class="basic-button" id="sa_settings_close" title="К чату">← Чат</button>
</div>
<div class="sa-settings-tabs" role="tablist" aria-label="Разделы настроек">
<button type="button" class="sa-stab sa-stab-active" data-stab="behavior" role="tab" aria-selected="true">Поведение</button>
<button type="button" class="sa-stab" data-stab="models" role="tab" aria-selected="false">Модели</button>
@@ -190,10 +319,24 @@
<option value="nomic-embed-text">nomic-embed-text</option>
</select>
</label>
<div class="sa-skills-label">QLoRA-раннер</div>
<label>Python <input type="text" id="sa_runner_python" placeholder="python или полный путь" /></label>
<label>Тип тренера
<select id="sa_runner_kind" class="sa-select">
<option value="">— не настроен —</option>
<option value="llama-factory">LLaMA-Factory</option>
<option value="unsloth">Unsloth</option>
<option value="custom">Custom command</option>
</select>
</label>
<label>Рабочая директория <input type="text" id="sa_runner_workdir" placeholder="Assistent/training/runner" /></label>
<label>Custom command <input type="text" id="sa_runner_cmd" placeholder="{python} train.py --config {config}" /></label>
<label>convert_lora_to_gguf.py <input type="text" id="sa_runner_gguf_script" placeholder="путь к convert_lora_to_gguf.py" /></label>
<div class="sa-settings-row">
<button type="button" class="basic-button" id="sa_btn_refresh_models">Обновить модели</button>
<button type="button" class="basic-button" id="sa_btn_refresh_inventory">Обновить inventory</button>
<button type="button" class="basic-button" id="sa_btn_settings_health">Проверить Ollama</button>
<button type="button" class="basic-button" id="sa_btn_save_runner">Сохранить раннер</button>
</div>
<div class="sa-settings-health" id="sa_settings_health_line">Ollama · …</div>
</div>
@@ -293,9 +436,6 @@
</div>
</div>
</div>
</div>
</section>
</div>
</div>
</div>