Fork of Priler/jarvis (CC BY-NC-SA 4.0) https://github.com/Priler/jarvis
Find a file
Bossiara13 16240609de fix(commands): repair weather set_city schema, retire broken AHK browser pack
set_city used a plain `phrases = [...]` array which fails the lang-map schema
in JCommand — the whole weather pack was being skipped at load. Normalized
to per-language phrases.

browser/command.toml pointed at Priler's bundled AutoHotKey exes that do not
ship in this fork, so the entries were dead. Renamed to .disabled (the loader
skips packs without command.toml) so we do not collide with the new Lua
apps pack while keeping the directory for reference.
2026-05-15 00:54:34 +03:00
crates chore(app): instrument init steps with eprintln + label app::close calls 2026-04-27 21:07:33 +03:00
frontend chore: build frontend assets so tauri context generates cleanly 2026-04-22 17:57:29 +03:00
lib library files required for the build added 2026-01-17 06:08:09 +05:00
resources fix(commands): repair weather set_city schema, retire broken AHK browser pack 2026-05-15 00:54:34 +03:00
.gitignore chore: gitignore tauri-generated schema files 2026-04-22 17:55:56 +03:00
Cargo.lock chore: add webrtc-vad workspace dep 2026-04-23 11:07:04 +03:00
Cargo.toml chore: add webrtc-vad workspace dep 2026-04-23 11:07:04 +03:00
LICENSE.txt Readme and License 2023-04-28 19:39:48 +05:00
post_build.py some fixes + gliner first implementation 2026-02-11 07:21:50 +05:00
poster.jpg Some funky stuff, bruh 2023-05-01 01:52:47 +05:00
README.md docs: README — VAD smart command end 2026-04-23 11:08:09 +03:00

J.A.R.V.I.S (Rust) — форк Bossiara13

Форк Rust-переписки голосового ассистента Priler/jarvis. Текущий репозиторий: https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-rust.

Что это

Голосовой ассистент, написанный на Rust, работающий локально (без облака). Текущий стек:

  • Vosk — Speech-to-Text (через vosk-rs).
  • fastembed + ort — локальные эмбеддинги для intent-классификации (MiniLM L6/L12 ONNX).
  • Picovoice Porcupine / Rustpotter / Vosk — три опциональных движка wake-word.
  • mlua (Lua 5.5, vendored) — скрипты пользовательских команд.
  • Tauri + Vite/Svelte — GUI-оболочка (фронтенд в отдельной папке frontend/).
  • nnnoiseless — подавление шума.
  • fluent / unic-langid — i18n (ru, ua, en).

LLM-клиент (Groq / OpenAI-совместимый) добавлен в jarvis-core::llm и подключён к голосовому циклу. Если фраза начинается с триггера («скажи», «ответь», «произнеси»), она уходит в Groq и ответ возвращается через IPC-событие LlmReply. Без триггера всё работает как раньше — wake-word + intent + Lua. Это следующий шаг после CLI-only LLM из v0.2.0.

Это форк

Оригинальный автор — Abraham Tugalov (Priler). Апстрим: https://github.com/Priler/jarvis. Лицензия сохранена: CC BY-NC-SA 4.0 (см. LICENSE.txt). Атрибуция в Cargo.toml и voice.toml пакетов озвучки не изменена.

Что отличается от апстрима

  • Обновлён список авторов в Cargo.toml (добавлен Bossiara13 (fork), оригинал сохранён).
  • README переписан и отражает фактическую архитектуру (апстримный README называет проект "Tauri+Svelte", что давно не соответствует действительности — это workspace из 4-х крейтов).
  • Отсутствующие в апстриме ONNX-модели (all-MiniLM-L6-v2, paraphrase-multilingual-MiniLM-L12-v2-onnx-Q) подтянуты через Git LFS из HuggingFace (Qdrant) и запушены в форк.

Структура репозитория

Cargo workspace из четырёх крейтов:

Крейт Назначение
jarvis-core Библиотека: конфиг, intent, STT, wake-word, аудио, Lua-бэкенд, i18n.
jarvis-app Бинарь-«демон»: собирает всё вместе, tray, IPC.
jarvis-gui Tauri-приложение (использует frontend/dist/client).
jarvis-cli CLI для отладки: классификация intent, список команд, dump конфига.

Прочее:

  • frontend/ — Vite + Svelte UI для jarvis-gui. Собирается отдельно.
  • lib/windows/amd64/ — нативные DLL/LIB для Vosk, Porcupine, PvRecorder.
  • resources/ — голоса, модели, конфиги по умолчанию. ONNX-модели хранятся в Git LFS.
  • post_build.py — постпроцессинг артефактов сборки (Python 3).

Сборка

Требования:

  • Rust 1.93+ (собирается на stable MSVC).
  • Node 24+ и npm — для фронтенда.
  • Python 3 — для post_build.py.
  • MSVC build tools (Windows, x64).
  • Установленные libvosk.lib, libpv_porcupine.dll, libpv_recorder.dll в lib/windows/amd64/ (уже в репозитории).

Перед сборкой jarvis-gui нужно собрать фронтенд:

cd frontend
npm install
npm run build
cd ..

Затем workspace:

cargo build --workspace

Холодная сборка занимает около 10 минут (ONNX runtime, aws-lc-rs, tauri).

Статус сборки в этом форке

На моей машине (cargo build --workspace, stable MSVC) итог:

  • jarvis-core — собрался (1 warning, unused import).
  • jarvis-app — собрался, бинарник target/debug/jarvis-app.exe создан.
  • jarvis-cliпадает на линковке: LNK1181: cannot open input file "libvosk.lib". Причина: у jarvis-cli нет своего build.rs, а .cargo/config.toml с rustc-link-search лежит только внутри crates/jarvis-app/ и не подтягивается для jarvis-cli. Лечится либо добавлением такого же build.rs в crates/jarvis-cli/, либо вынесением config.toml в корень. Сознательно не трогал — фикс выходит за рамки рефакторинга (v0.0.1-import фиксирует поведение апстрима как есть).
  • jarvis-gui — падает в tauri::generate_context!(): frontendDist = "../../frontend/dist/client" не существует. Это ожидаемо, если не запустить npm run build в frontend/ заранее (см. секцию «Сборка»).

Запуск уже собранного:

./target/debug/jarvis-app.exe

Для CLI (jarvis-cli --help, команды classify, execute, list, phrases) нужно сначала починить линковку Vosk (см. выше).

LLM (Groq)

В jarvis-core есть модуль llm — блокирующий клиент для OpenAI-совместимого эндпоинта chat completions. По умолчанию настроен на Groq. Используется через фиче-флаг llm (включён в дефолтный набор jarvis_app, также подтянут в jarvis-cli).

Переменные окружения:

Переменная Обязательна Значение по умолчанию
GROQ_TOKEN да
GROQ_BASE_URL нет https://api.groq.com/openai/v1
GROQ_MODEL нет llama-3.3-70b-versatile

Быстрая проверка через CLI:

set GROQ_TOKEN=gsk_...
jarvis-cli ask "скажи привет одной фразой"

Ответ печатается в stdout. Без GROQ_TOKEN команда завершится с кодом 2 и сообщением об ошибке. При ошибке API — код 1 и тело ответа.

Программное использование из Rust:

use jarvis_core::llm::{LlmClient, ChatMessage};

let client = LlmClient::from_env()?;
let reply = client.complete(&[ChatMessage::user("привет")], 256)?;
println!("{}", reply);

Подключение к голосовому циклу

Помимо CLI, LLM подключён напрямую в jarvis-app. Логика в crates/jarvis-app/src/llm_fallback.rs:

  • При старте jarvis-app пытается прочитать GROQ_TOKEN. Если переменной нет — фоллбэк отключается, в лог пишется warning, голосовые команды продолжают работать как раньше.
  • Распознанная фраза (как из микрофона, так и из текстовой панели GUI) проверяется на префиксы-триггеры из config::get_llm_trigger_phrases (для ru/ua: скажи, ответь, произнеси; для en: say, tell, answer).
  • Если триггер найден — остаток фразы уходит в LlmClient::complete(), ответ публикуется в IPC как IpcEvent::LlmReply { text } (UI/GUI слушает этот ивент и проговаривает текст уже на своей стороне), а звук-«ок» проигрывается из текущего голосового пресета.
  • История разговора хранится в ConversationHistory с потолком LLM_DEFAULT_MAX_HISTORY = 8 ходов; system-prompt всегда сохраняется при вытеснении старых ходов.
  • При сетевой/API-ошибке последний user-turn убирается из истории, в IPC уходит LlmReply с короткой русской фразой («Не могу связаться с сервером, сэр.»), играется звук-«error». Голосовой цикл не падает.

Системный промпт (русский) описывает J.A.R.V.I.S. как британского дворецкого Тони Старка — короткие реплики (13 предложения), обращение «сэр», без излишней цензуры. Меняется в config::LLM_SYSTEM_PROMPT_RU.

VAD: умное завершение команды по тишине

После срабатывания wake-word jarvis-app слушает команду. Раньше окно закрывалось либо по таймауту Vosk, либо по жёсткому пределу из config::CMS_WAIT_DELAY — короткие команды («стоп», «громче») всё равно ждали несколько секунд тишины.

Теперь окно закрывается, как только пользователь замолчал. Реализовано через webrtc-vad (чистый Rust, тот же алгоритм, что в Python-версии). Это паритет с Python v0.2.0, где использовался webrtcvad с теми же параметрами.

Логика (state-машина в crates/jarvis-core/src/audio_processing/vad/listen_window.rs):

  • Кадр VAD: 30 мс при 16 кГц = 480 сэмплов = 960 байт (mono i16). Кадры с микрофона (по 512 сэмплов от pv_recorder) аккумулируются и режутся на VAD-кадры адаптером WebRtcVad::push_samples.
  • Каждый VAD-кадр учитывается в счётчиках speech_ms / silence_ms.
  • Окно закрывается, когда silence_ms >= VAD_COMMAND_END_SILENCE_MS И speech_ms >= VAD_COMMAND_MIN_SPEECH_MS.
  • До истечения VAD_COMMAND_MIN_LISTEN_MS окно не закрывается — пользователю даётся время начать говорить.
  • При достижении VAD_COMMAND_MAX_LISTEN_MS срабатывает hard-cap и управление возвращается в режим ожидания wake-word.
  • На событии «закрыть окно» вызывается stt::finalize_speech() — Vosk форсированно отдаёт финальный результат, не дожидаясь собственного таймаута.

Параметры (crates/jarvis-core/src/config.rs):

Константа Значение Назначение
VAD_AGGRESSIVENESS 2 Уровень WebRTC VAD: 0 — Quality, 3 — VeryAggressive.
VAD_COMMAND_END_SILENCE_MS 1200 Сколько тишины подряд считать «команда закончилась».
VAD_COMMAND_MIN_SPEECH_MS 500 Минимум речи в окне — иначе закрытие игнорируется.
VAD_COMMAND_MIN_LISTEN_MS 1000 Минимальная длительность окна (страховка от ранних закрытий)
VAD_COMMAND_MAX_LISTEN_MS 15000 Жёсткий потолок окна.

На короткие команды отзыв стал заметно быстрее (мы выходим на распознавание сразу после паузы пользователя, а не по 5-секундному порогу Vosk).

Лицензия

Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0). Полный текст — в LICENSE.txt. Атрибуция оригинального автора (Abraham Tugalov) сохранена.

В Cargo.toml декларирован license = "GPL-3.0-only" — это несоответствие унаследовано от апстрима и не правилось, чтобы не расходиться с upstream-конфигом. Приоритет имеет LICENSE.txt.

Python-версия

Старая версия ассистента была на Python. Последний коммит с Python-кодом в апстриме — 943efbf.