- TypeScript 66.1%
- HTML 14.3%
- JavaScript 4.9%
- Python 4.7%
- CSS 4.6%
- Other 5.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| aec | ||
| ct | ||
| src | ||
| stt-test | ||
| tests | ||
| tn-test | ||
| tts-test | ||
| vm | ||
| web | ||
| whisper | ||
| .dockerignore | ||
| .gitignore | ||
| .prettierrc.json | ||
| AGENTS.md | ||
| build_engine.cmd | ||
| build_llama.cmd | ||
| build_whisper.cmd | ||
| DEPLOY.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.js | ||
| KILO-LLM.md | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| start.cmd | ||
| tsconfig.assistant.json | ||
| tsconfig.client.json | ||
| tsconfig.json | ||
| tsconfig.server.json | ||
| vite.assistant.config.ts | ||
| vite.config.ts | ||
| vitest.config.ts | ||
| whisper_run.cmd | ||
Qwen3-TTS Local Web UI
Локальный веб-интерфейс к Qwen3-TTS-GGUF на AMD GPU (RDNA2: RX 6600 XT / 6700 XT / 6900 XT) через Vulkan-бэкенд движка qwentts.cpp. Полный голосовой стек для Home Assistant: TTS (Qwen3-TTS) + STT (Whisper.cpp) + агент диалога (LLM на llama.cpp) — всё на одной видеокарте, без ROCm.
Возможности
- Три режима синтеза: готовые голоса (customvoice), клонирование (base), дизайн голоса по текстовому описанию (voicedesign).
- Клонирование по 3 схемам: ICL (1 файл + транскрипт), усреднённый x-vector (N файлов без транскриптов), длинный ICL (N файлов с транскриптами).
- Автоимпорт реплик с Fandom: парсер страницы реплик через MediaWiki API + прокси аудио с CDN.
- Управление моделями: полная матрица talker-файлов на диске, докачка с HuggingFace с прогрессом и отменой, удаление.
- Ленивый старт и idle-стоп: движки поднимаются по первому запросу и гаснут после простоя — VRAM освобождается автоматически.
- Home Assistant: Wyoming TTS (:10200), Whisper STT (:10300), LLM-агент с function calling (через прокси
/llm/*). - Идентификация говорящего: CAM++-отпечатки голосов домочадцев, подпись «кто сказал» в ленте Live поверх STT-потока (в HA не уходит).
- TypeScript + сборка: оркестратор на TS (ESM, tsc), SPA на TS (Vite). Рантайм-код оркестратора — zero-deps (только нативные модули Node);
node_modulesнужны лишь для сборки/тестов.
Как это устроено
Браузер (SPA, dist/client/)
│ /api/*
▼
Node-оркестратор (dist/server/index.js, :3002) ── спавнит и проксирует всё
├── tts-server (qwentts.cpp, Vulkan) движки :8101..8124, ленивый старт
├── Wyoming TTS для HA (src/server/wyoming) TCP :10200
├── Whisper STT (Wyoming) публичный :10300 → внутренний :10400
└── llama-server (LLM-агент) :8130, прокси /llm/* на :3002
▼
Vulkan0 = AMD GPU (RDNA2, RADV)
Home Assistant подключается ко всем трём сервисам через оркестратор — он держит ленивый старт, idle-таймеры и логи.
Требования
- AMD GPU с архитектурой RDNA2 (проверено на RX 6900 XT 16 ГБ и RX 6600 XT 8 ГБ), драйвер
amdgpu/ Vulkan-драйвер RADV. - Node.js 20+ (для сборки:
npm installставит только dev-зависимости; рантайм — без зависимостей). - ~7 ГБ VRAM на TTS 1.7B Q8_0 (три движка сразу), ~3–4 ГБ на Whisper, ~2–3 ГБ на LLM 3B Q4 — см. бюджет VRAM.
Быстрый старт (Windows)
1. Тулчейн
winget install Kitware.CMake Ninja-build.Ninja KhronosGroup.VulkanSDK
winget install Microsoft.VisualStudio.2022.BuildTools --override "--quiet --wait --norestart --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"
2. Движок
git clone --recurse-submodules https://github.com/ServeurpersoCom/qwentts.cpp.git
build_engine.cmd # ждёт пути VS/Vulkan в начале файла, поправь под свою версию
Артефакты: qwentts.cpp/build/Release/{tts-server,qwen-tts,qwen-codec}.exe + ggml-*.dll.
3. Модели
Базовый набор (Q8_0, 1.7B) — положить в models/:
qwen-talker-1.7b-base-Q8_0.ggufqwen-talker-1.7b-customvoice-Q8_0.ggufqwen-talker-1.7b-voicedesign-Q8_0.ggufqwen-tokenizer-12hz-Q8_0.gguf
Можно ничего не скачивать вручную — на вкладке «Модели» все отсутствующие файлы качаются кнопкой ⬇ скачать прямо из UI.
4. Сборка и запуск
npm install # dev-зависимости (typescript, vite, vitest, eslint)
npm run build # tsc → dist/server, vite → dist/client
start.cmd # или: npm start (node dist/server/index.js)
Для разработки: npm run dev — оркестратор на tsx-watch (:3002) + Vite HMR (:5173, проксирует /api и /llm).
UI откроется на http://localhost:3002. Whisper STT и LLM-агент не стартуют вместе с веб-интерфейсом — подними их кнопками из соответствующих вкладок (или они поднимутся лениво по первому запросу HA).
Деплой на Linux (Proxmox / Docker)
Основной путь — привилегированный LXC-хелпер ct/qwen3-tts.sh (Docker + bind /dev/dri + Mesa RADV). Запасной — VM с GPU-passthrough (vm/qwen3-tts-vm.sh). Полная инструкция, GPU-чеклист и troubleshooting — в DEPLOY.md.
Интерфейс
Синтез (три вкладки режима)
- Готовые голоса — спикеры модели (serena, uncle_fu и др.) + зарегистрированные клоны.
- Клонирование — загрузка эталонного аудио (или импорт с Fandom), регистрация клона.
- Дизайн голоса — описание голоса свободным текстом (пол/возраст/тон/тембр/эмоция/темп/стиль, есть чипы-шпаргалки; лучше на английском).
На каждой вкладке: селекторы «Модель»/«Квантизация», гейт 🚀 запустить / ■ остановить движка, параметры (seed, temperature, top-k/p, repetition penalty). Выбор сохраняется в localStorage.
Модели
Полная матрица вариантов репо Serveurperso/Qwen3-TTS-GGUF: talker 1.7b/0.6b × квантизации Q8_0/Q4_K_M/BF16/F32 × три режима, плюс кодек в четырёх квантизациях. Что есть на диске, сколько весит, суммарный объём; докачка с прогрессом/отменой; удаление (гасит движки, держащие файл).
Wyoming · HA
Статус и лог Wyoming TTS-сервиса, конфиг (голос по умолчанию, разрешённые клиенты).
Whisper (STT)
Вкладки Сервис / Модели / Кто говорит / Тест и лог: запуск-остановка сервиса, смена модели/языка/порта, скачивание GGUF-моделей whisper.cpp, тест «синтез → транскрибация» с RTF, VRAM, логи.
Кто говорит (идентификация говорящего)
Вкладка Кто говорит в разделе STT: регистрация домочадцев по записи с микрофона (или загрузке WAV) и определение, кто произнёс реплику, по голосовому отпечатку. Движок — CAM++ (sherpa-onnx, ONNX, CPU, ~28 МБ), матчинг — косинусная близость 192-мерных эмбеддингов с настраиваемым порогом. Работает поверх входящего STT-потока: каждое обращение Home Assistant подписывается в ленте Live (👤 имя · близость). Результат не уходит в HA — только виден в интерфейсе, для отладки и калибровки порога на реальных голосах. Выкл: SPEAKER_ID=0.
Агент диалога (LLM)
Вкладки Сервис / Модели / Тест чата: запуск llama-server, полный конфиг (модель, ctx, слои на GPU, temperature, системный промпт, idle-стоп, thinking), курированный каталог GGUF с докачкой, стриминговый тест чата с метриками TTFT и ток/с.
Голосовой ассистент (веб-сателлит)
Отдельная страница на /assistant (собирается своим Vite-entry в dist/assistant). Это софтовый голосовой сателлит прямо в браузере: зажми кнопку → говори → распознавание (Whisper) → разговорный агент Home Assistant → озвучка. Мозг и все сущности остаются в HA — оркестратор лишь мост с long-lived токеном, браузер токена не видит.
- Триггер: сейчас push-to-talk (удержание кнопки). Программный wake word (WASM-модель) — задел: интерфейс
VoiceTriggerпозволяет подключить его, не переписывая цикл. - Эхоподавление: браузерный
echoCancellationгасит собственное воспроизведение TTS — ассистент не слушает сам себя. - Настройка: шестерёнка на странице (URL HA, токен, conversation agent, голос/язык озвучки) или env
HA_URL/HA_TOKEN/HA_AGENT_ID. - Запуск в dev:
npm run dev:assistant(Vite на:5174, проксирует/apiи/llmна оркестратор:3002); в проде —npm run buildи страница доступна наhttp://<хост>:3002/assistant.
Подключение к Home Assistant
TTS (Wyoming)
Настройки → Интеграции → Wyoming → host <хост>, порт 10200. Голоса: встроенные спикеры + все клоны из UI (появляются в HA в течение ~30 с без перезапуска).
STT (Whisper)
Настройки → Интеграции → Wyoming → host <хост>, порт 10300. На Windows оркестратор проксирует на внутренний порт Whisper и поднимает его лениво по первому коннекту.
LLM-агент (llama.cpp)
HA ≥ 2026.8: Настройки → Устройства и службы → Интеграции → llama.cpp → URL http://<хост>:3002/llm/v1 (через оркестратор — ленивый старт и продление idle-таймера по трафику HA), API key пусто (или LLM_API_KEY), выбор модели из /v1/models. Системный промпт задаётся в поле Instructions интеграции. Интеграция «OpenAI» не подходит — у неё нет поля base URL.
Пайплайн Assist
stt.whisper (ru) + llama.cpp + tts.qwen3-tts.
Конфигурация (переменные окружения)
| Переменная | Дефолт | Назначение |
|---|---|---|
PORT |
3002 |
Порт веб-UI/оркестратора |
BIND_HOST |
127.0.0.1 |
Хост привязки UI |
TTS_DEVICE |
Vulkan0 |
Vulkan-устройство движка |
TTS_IDLE_MIN |
20 |
Минут простоя до остановки движков |
TTS_SIZE / TTS_QUANT |
1.7b / Q8_0 |
Дефолтный вариант синтеза |
TTS_BIN |
— | Путь к tts-server (Linux/Docker) |
TTS_MODELS_DIR |
models/ |
Каталог GGUF-весов |
TTS_STATE_DIR |
web/ |
Каталог состояния (клоны, конфиги, кэши) |
TTS_TN |
1 |
Русская текстовая нормализация (TN) перед синтезом: числа/даты/время прописью через rutextnorm + согласование рода числительных через pymorphy3 («1 минуту» → «одну минуту») (0 — выкл). Настраивается и из UI (вкладка Wyoming), значение в tn_enabled.json имеет приоритет над env. Нормализуется только русский/auto язык |
TN_PYTHON |
py -3.13 (Win) / python3 (Linux) |
Интерпретатор Python для TN-sidecar. Требуется pip install rutextnorm pymorphy3 pymorphy3-dicts-ru. Пинится явно: на PATH python может стоять другой мажор без модулей. Формат — команда с аргументами одной строкой |
WYOMING_PORT |
10200 |
Wyoming TTS для HA (0 — выключить) |
WYOMING_HOST |
0.0.0.0 |
Привязка Wyoming |
WYOMING_MODE |
customvoice |
Режим спикеров по умолчанию |
WYOMING_SIZE / WYOMING_QUANT |
— | Фолбэк-вариант Wyoming |
WYOMING_FOLLOW |
yes |
Wyoming берёт вариант с текущего запущенного движка |
WYOMING_VOICE |
— | Голос по умолчанию |
WYOMING_MAX_LEAD_SEC |
0.5 |
Лид троттлинга Wyoming-стрима, с (0 — выкл). Сателлиты с маленьким буфером (ESP32) переполняются burst'ом быстрой генерации — лид ограничивает «запас» аудио вперёд. Настраивается из UI (вкладка Wyoming), значение в wyoming_lead.json имеет приоритет над env |
ASR_PORT |
10300 |
Публичный порт Whisper STT |
ASR_MODEL |
large-v3-turbo-q5_0 |
Дефолт модели whisper.cpp |
ASR_LANG |
ru |
Дефолтный язык STT |
ASR_STREAM |
yes |
VAD-стриминг STT: инкрементальные partial-ы и финал по концу речи (no = прежний батч: один decode на AudioStop) |
LLM_PORT |
8130 |
Порт llama-server |
LLM_MODEL |
qwen2.5-3b-instruct-q4_k_m |
Дефолт LLM |
LLM_CTX |
16384 |
Контекст (HA кладёт ~9–12k токенов tool-схем) |
LLM_GPU_LAYERS |
-1 |
Слоёв на GPU (-ngl) |
LLM_THREADS |
0 |
Потоки CPU (0 = авто) |
LLM_TEMPERATURE |
0.6 |
Температура генерации |
LLM_MAX_TOKENS |
1024 |
Максимум токенов ответа |
LLM_REPEAT_PENALTY |
1.05 |
Анти-повтор llama-server (--repeat-penalty, 1 = выкл). Без него малые кванты зацикливаются на одинаковых tool_call |
LLM_DRY_MULTIPLIER |
0.8 |
DRY-сэмплер (--dry-multiplier, 0 = выкл) — сильнее давит повторяющиеся последовательности |
LLM_SIMPLIFY_TOOLS |
1 |
Упрощать tool-схемы для слабого движка: вырезать anyOf/oneOf (HA кладёт их в intent-тулзы, Qwen3.5-4B Q4 не тянет → пустые аргументы). 0 = выкл |
LLM_DUMP_REQ |
1 |
Дампить последний chat-запрос HA в llm_last_request.json для отладки. 0 = выкл |
LLM_SYSTEM_PROMPT |
— | Системный промпт |
LLM_API_KEY |
— | Пусто = без авторизации |
LLM_IDLE_MIN |
30 |
Idle-стоп агента (мин) |
LLM_REASONING |
off |
Thinking (off — ответ сразу в content) |
LLM_FLASH_ATTN |
off |
Flash attention. Замерено на RDNA2 (6900 XT, AMD proprietary Vulkan 26.8.1, llama.cpp b1-c0ab6e5): on РЕГРЕССИРУЕТ префилл (12k: ~450-580 ток/с vs ~700-1000 у off), резолвер гасит fused KV-rows FA («not supported»). На старом Mesa (LXC) FA вообще сливает attention на CPU. Дефолт off — обычный матмул на GPU быстрее; включать только после своих замеров |
LLM_WARM_PREFIX |
1 |
Префикс-прогрев LLM: при старте агента проигрывать реальный [tools + system-без-времени] из llm_last_request.json (max_tokens=1), чтобы первый запрос HA переиспользовал ~10k токенов prefix-KV-кэша. 0 = синтетический ping |
LLM_BIN / LLM_MODELS_DIR |
— | Путь к бинарю / каталог models/llm/ |
HA_URL |
— | Базовый URL Home Assistant для веб-ассистента (напр. http://homeassistant.local:8123) |
HA_TOKEN |
— | Long-lived access token HA (создать: профиль → Безопасность → Long-lived access token) |
HA_AGENT_ID |
— | Conversation agent в HA (пусто = дефолтный). Рабочий конфиг — ha_config.json (STATE_DIR), редактируется из шестерёнки на /assistant |
Env-переменные ASR/LLM — только дефолты для первой записи; рабочий конфиг редактируется из UI и лежит в asr_config.json / agent_config.json (STATE_DIR).
Бюджет VRAM
| Компонент | 16 ГБ (6900 XT) | 8 ГБ (6600 XT) |
|---|---|---|
| TTS 1.7B Q8_0 (3 движка) | ~7 ГБ | не влезает с остальными → 0.6B |
| Whisper large-v3-turbo q5_0 | ~3–4 ГБ | small/medium |
| LLM 3B Q4_K_M | ~2–3 ГБ | 1.5B/3B + idle-стоп остальных |
| Итого | ~12–14 ГБ — помещается | туго: полагайся на idle-стоп или снижай LLM_GPU_LAYERS |
API
Все эндпоинты — на оркестраторе (:3002), JSON, без авторизации (BIND_HOST по умолчанию localhost).
| Метод | Путь | Что делает |
|---|---|---|
POST |
/api/speech |
Синтез: {mode,size,quant,input,voice,language,instructions,response_format:"wav",seed,temperature,top_k,top_p,repetition_penalty} → WAV 24 кГц моно |
GET |
/api/status |
Статус движков |
GET |
/api/voices?mode=&size=&quant= |
Список голосов (спикеры + клоны) |
POST |
/api/voices |
Регистрация клона {mode,size,quant,name,ref_text,wav_b64} (только base) |
POST |
/api/voices/multi |
Усреднённый x-vector {name, wavs:[b64...]} |
DELETE |
/api/voices/{name}?mode=base&size=&quant= |
Удаление клона |
GET |
/api/models |
Матрица моделей: наличие/размер/статусы |
POST |
/api/codec |
Смена квантизации кодека {quant} (останавливает все движки) |
POST / GET / DELETE |
/api/download?file= |
Стриминг-загрузка с HF: прогресс / отмена |
DELETE |
/api/model?file= |
Удаление файла модели с диска |
POST |
/api/engine/start {mode,size,quant} |
Запуск движка |
POST |
/api/engine/stop {mode,size,quant} |
Остановка движка |
GET |
/api/engine/logs?key= |
Лог движка |
GET |
/api/fandom/parse?url=&count= |
Топ-N реплик со страницы Fandom |
GET |
/api/fandom/audio?url=&referer= |
Прокси аудио с Fandom CDN |
GET |
/api/stt |
Статус ASR: running/модель/VRAM/лог/config |
POST |
/api/stt/start|stop|restart |
Управление STT-движком (Whisper/Parakeet) |
POST |
/api/stt/config |
{model, lang, port} + авторестарт |
POST |
/api/stt/test |
Тест: синтез → транскрибация (или {wav_b64} — только транскрибация) |
GET |
/api/stt/models |
Список GGUF-моделей whisper.cpp |
POST / GET / DELETE |
/api/stt/download?model= |
Загрузка моделей STT |
GET |
/api/agent |
Статус LLM: running/pid/config/VRAM/baseUrl |
POST |
/api/agent/start|stop|restart |
Управление агентом |
POST |
/api/agent/config |
{model,port,ctx,gpuLayers,threads,temperature,maxTokens,systemPrompt,apiKey,idleMin,reasoning} |
GET |
/api/agent/models |
Каталог LLM GGUF |
POST / GET / DELETE |
/api/agent/download?model= |
Загрузка LLM-моделей |
POST |
/api/agent/chat |
Стриминг-SSE прокси /v1/chat/completions |
* |
/llm/* |
Прокси на llama-server для HA |
GET |
/api/ha |
Статус привязки HA: configured/reachable/url/маска-токен/agent |
POST |
/api/ha/config |
{url, token, agentId} — рантайм-привязка (токен-маска не перезаписывает настоящий) |
POST |
/api/ha/converse |
{text, conversation_id} → прокси в HA /api/conversation/process → {ok, speech, conversation_id, intent} |
GET |
/assistant |
Веб-страница голосового ассистента (отдельный Vite-entry) |
Лицензии
UI-код — как есть. Движок qwentts.cpp — MIT. Модель Qwen3-TTS и кодек — Apache 2.0.