Brings the python fork in line with the new feature/pc-tools work that
landed in rust. Same UX, same trigger phrases, same env vars.
config.py:
+ LLM_AUTO_FALLBACK = True
+ LLM_AUTO_FALLBACK_MIN_CHARS = 4
Mirrors the rust config knobs. The old "скажи X" trigger still works
(VA_TBR strips it before intent matching, so what remains hits this
fallback anyway) — but now ANY unrecognized query goes to Groq, not
just "скажи" ones.
main.py:
va_respond: replaced the fuzz-on-"скажи" gate with a unified auto-
fallback that fires whenever no command matches, GROQ_TOKEN is set,
and the utterance is at least LLM_AUTO_FALLBACK_MIN_CHARS long.
+ _speak(text): recorder.stop() → tts.va_speak → start, used by the
new action handlers so the mic doesn't pick up the assistant.
+ _set_clipboard(text): subprocess to PowerShell Set-Clipboard, no
new python deps.
+ _strip_trigger(voice, triggers): shared helper for codegen/file_search
where we need the text AFTER the trigger phrase.
New action handlers (registered in run_action dispatch):
+ groq_codegen — extracts query, calls Groq with strict "code only"
system prompt at temp 0.2, strips ```lang ... ``` fences, puts the
result in the clipboard, speaks "Код в буфере, сэр. Строк: N".
+ ocr_screen — PowerShell System.Drawing screenshot to a temp PNG,
shells to tesseract.exe (-l rus+eng), speaks a 120-char preview,
clipboard. Looks for tesseract on PATH first then standard install
dirs; gives a clear "Tesseract не установлен" if missing.
+ sysinfo — CIM-based battery/cpu/ram/disk via PS one-liners, time
via python datetime (gets us localized weekday for free). Topics:
time / battery / cpu / ram / disk / all.
+ file_search — strips trigger, recursive Get-ChildItem in Desktop/
Documents/Downloads (depth 3, top 5), opens explorer /select on
the first hit, speaks count and basename.
+ audio_devices_panel — opens mmsys.cpl. Proper COM-based device
switching (like the rust IPolicyConfig version) is deferred — TODO
in backlog.
commands.yaml:
Total 33 commands (was 19). New:
+ open_notepad / open_calculator / open_explorer / open_terminal
/ open_settings / open_task_manager / lock_screen / screenshot
— all via shell action (no AHK exes needed).
+ volume_up / volume_down — five chained keys=volumeup/volumedown
presses each, like rust's _volume_helper.ps1 with Times=5.
+ media_stop — keys=stop.
+ sysinfo_time / sysinfo_battery / sysinfo_cpu / sysinfo_ram /
sysinfo_disk / sysinfo_all — sysinfo action.
+ file_search, codegen, read_screen, switch_audio_device.
Replaced (were AHK exes that Priler ships and we don't have):
~ music → keys playpause
~ music_off → keys playpause (toggle)
~ music_next → keys nexttrack
~ music_prev → keys prevtrack
Removed (Priler hardware/setup specific, can't sensibly port):
- gaming_mode_on / gaming_mode_off (display config switch)
- music_save (depends on the specific player AHK was driving)
- switch_to_headphones / switch_to_dynamics (replaced with the
generic switch_audio_device that opens mmsys.cpl)
Kept as-is (worked already, no AHK dependency):
open_browser / open_youtube / open_google (url action)
sound_off / sound_on (pycaw via system.volume_mute/unmute)
thanks / stupid / off
Smoke-tested: yaml.safe_load → 33 commands, ast.parse main.py → OK.
Portability: USERPROFILE for screenshot path, $env:SystemDrive for disk,
PATH lookup for tesseract before falling back to standard install dirs.
No hardcoded user-specific paths.
|
||
|---|---|---|
| .idea | ||
| custom-commands | ||
| model_small | ||
| models/all-MiniLM-L6-v2 | ||
| sound | ||
| tools/command_builder | ||
| utils | ||
| .gitattributes | ||
| .gitignore | ||
| commands.yaml | ||
| config.py | ||
| dev.env.example | ||
| effects.py | ||
| intent.py | ||
| LICENSE.txt | ||
| main.py | ||
| README.md | ||
| requirements.txt | ||
| run_builder.bat | ||
| tts.py | ||
J.A.R.V.I.S (Python) — Bossiara13's fork
Голосовой ассистент для Windows с wake-word «jarvis». Распознаёт речь локально через Vosk (русская модель), отвечает голосом через Silero TTS, а свободные вопросы (фразы, начинающиеся со слова «скажи …») отправляет в LLM на Groq и зачитывает ответ.
Это форк
Форк репозитория Priler/jarvis (автор оригинала — Abraham Tugalov, 2022). Лицензия наследуется: CC BY-NC-SA 4.0 (см. LICENSE.txt).
Что отличается от оригинала
- Из истории удалены случайно закоммиченные секреты.
- Бэкенд LLM переключён с OpenAI на Groq (бесплатный тариф) через openai-совместимый API.
- Код обновлён под новую версию SDK
openai(>=1.0); старый pre-1.0 интерфейс был сломан. - Убрана зависимость от Picovoice Porcupine — wake-word распознаётся напрямую через Vosk с grammar-constraint (второй
KaldiRecognizerсо словарём изWAKE_WORDS). Ключ Picovoice больше не нужен. - Обновлена ветка/тэги (
dev,v0.0.1-import), причёсан README иrequirements.txt.
Установка
Требуется Python 3.11 (на 3.13 ряд зависимостей пока ставится с бубном).
git clone https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-py.git
cd J.A.R.V.I.S-py
py -3.11 -m venv .venv
.venv\Scripts\activate
pip install --upgrade pip
pip install -r requirements.txt
Скопируйте dev.env.example в dev.env и заполните ключ:
GROQ_TOKEN— бесплатно на console.groq.com.
Vosk-модель для русского языка лежит в model_small/ (уже в репозитории). Запуск:
python main.py
Конфигурация
config.py:MICROPHONE_INDEX = -1— индекс микрофона (-1означает устройство по умолчанию). Если микрофонов несколько и берётся не тот, поменяйте число.WAKE_WORDS = ('jarvis', 'джарвис')— варианты транскрипции wake-word, которые принимает Vosk. Если ваш голос/акцент стабильно расшифровывается как, например,жарвис— добавьте этот вариант сюда (всё в нижнем регистре).GROQ_MODEL— имя модели Groq (по умолчаниюllama-3.3-70b-versatile).INTENT_SIMILARITY_THRESHOLD = 0.45— минимальная косинусная близость для срабатывания команды (см. ниже).DENOISE_ENABLED = False— шумоподавление перед Vosk (см. ниже).
commands.yaml— набор голосовых команд и их вариантов; матчится семантически по эмбеддингам.custom-commands/— скомпилированные AHK-скрипты под конкретный сетап автора оригинала (переключение мониторов, управление Яндекс.Музыкой и т.п.). На вашей машине большая часть из них работать не будет, но ассистент запустится в любом случае.
Использование
- Скажите «Джарвис» (или «jarvis») — ассистент даст звуковой сигнал готовности.
- Произнесите команду — окно записи закрывается само, как только вы замолчите (см. ниже про VAD):
- либо одну из фраз из
commands.yaml(открыть браузер, выключить звук и т.д.); - либо начните со слова «скажи …» — остаток фразы уйдёт в Groq, ответ будет зачитан вслух.
- либо одну из фраз из
VAD (определение конца команды)
Окно записи команды закрывается по голосовой активности (webrtcvad), а не по таймеру. Параметры в config.py:
VAD_AGGRESSIVENESS(0..3) — насколько агрессивно VAD режет шум; по умолчанию 2.COMMAND_END_SILENCE_MS— длительность тишины, после которой окно закрывается (по умолчанию 1200 мс).COMMAND_MIN_SPEECH_MS— минимальная длительность речи, иначе тишина не считается концом (500 мс).COMMAND_MIN_LISTEN_MS— минимальное время записи, чтобы не закрыться мгновенно (1000 мс).COMMAND_MAX_LISTEN_MS— жёсткий потолок (15000 мс).
Семантический матчинг команд
Раньше распознанная фраза сравнивалась с фразами из commands.yaml через fuzzywuzzy.fuzz.ratio — это срабатывало только на формальное совпадение букв. Теперь используется sentence-transformer all-MiniLM-L6-v2 (ONNX, CPU) — фраза кодируется в 384-мерный вектор, считается косинусная близость с фразами всех команд, побеждает самая близкая.
Это означает, что фраза «запусти браузер» сматчится с командой open_browser, даже если в YAML записано только «открой браузер» — у них близкий смысл.
- Модель лежит в
models/all-MiniLM-L6-v2/(87 МБ, хранится через Git LFS —git lfs pullпосле клонирования). - Порог
INTENT_SIMILARITY_THRESHOLD = 0.45(косинус, диапазон [-1; 1], для близких смыслов обычно 0.7+). Ниже порога — «команда не распознана», сработаетnot_found.wav(или ветка«скажи …»для LLM). - Все фразы из
commands.yamlэмбеддятся один раз при старте; на каждой команде эмбеддится только распознанная пользователем фраза (~1-5 мс на CPU).
Шумоподавление перед STT
Опциональный пре-процессинг аудио командного буфера через noisereduce (спектральное гейтирование). Помогает в шумных помещениях (кулер, кондиционер, фоновая музыка). К wake-word фазе не применяется — там важна отзывчивость.
В config.py:
DENOISE_ENABLED = False— главный тумблер.DENOISE_PROP = 0.85— доля подавления (0..1).DENOISE_STATIONARY = False—Falseдля меняющегося шума (рекомендуется),Trueдля стабильного фона.
Эффекты под AI-ассистента
Silero звучит естественно, но иногда хочется лёгкой «AI-окраски» в духе J.A.R.V.I.S. — узкую полосу, еле заметную реверберацию, при желании небольшой сдвиг высоты. Это тонкий постпроцессинг, голос и sample rate не меняются.
По умолчанию эффекты выключены. Включаются в config.py:
TTS_EFFECTS_ENABLED— главный тумблер (Falseпо умолчанию).TTS_BANDPASS_LOW_HZ/TTS_BANDPASS_HIGH_HZ— полоса пропускания (по умолчанию 200–7000 Гц). Сужение полосы даёт ощущение «голоса по радио».TTS_REVERB_WET(0..1) иTTS_REVERB_DECAY_MS— доля мокрого сигнала и длительность хвоста короткой реверберации (по умолчанию 0.20 и 100 мс).TTS_PITCH_SEMITONES— сдвиг высоты в полутонах (по умолчанию 0, разумный диапазон ±2).
Фильтры реализованы на scipy.signal (IIR, sosfiltfilt — нулевая фазовая задержка), реверберация — несколько затухающих задержанных копий, pitch — ресэмплинг по линейной интерполяции. Всё in-process, без временных файлов и лишних зависимостей.
Быстрое A/B сравнение перед тем как переключать тумблер:
.venv\Scripts\python.exe utils\preview_effects.py
Скрипт сгенерирует sound/_preview_silero_raw.wav и sound/_preview_silero_fx.wav — откройте оба в плеере и решите, нравится ли эффект. Параметры fx-версии берутся из текущего config.py (независимо от TTS_EFFECTS_ENABLED).
Схема commands.yaml
Каждая команда — это пара phrases + action:
open_browser:
phrases:
- открой браузер
- запусти браузер
action: {type: exe, file: "Run browser.exe"}
Типы действий:
exe— запустить.exeизcustom-commands/. Поля:file(имя файла), необязательныеwait: true(ждать завершения),delay_ms(пауза после запуска). По умолчанию послеexeпроигрывается звук подтвержденияok— отключается черезconfirm_sound: null.play_sound— проиграть WAV изsound/. Полеname(без расширения). Именаgreetиokпроигрываются с рандомным выбором из вариантовgreet1/2/3.wav,ok1/2/3.wav.system— встроенные операции.op: volume_mute,volume_unmute,exit.multi— последовательность шагов:steps: [...].
Шаги внутри multi — тех же типов. Пример:
sound_off:
phrases: [выключи звук, отключи звук]
action:
type: multi
steps:
- {type: play_sound, name: ok}
- {type: system, op: volume_mute}
Конструктор команд
GUI для добавления команд в commands.yaml без ручной правки YAML.
Запуск:
python -m tools.command_builder
Или из корня репо run_builder.bat (под Windows). Открывается окно pywebview с пошаговым мастером: фразы → тип действия → параметры → предпросмотр YAML и сохранение. На шаге «Действие» доступна вкладка «Подсказать (LLM)» — модель Groq предложит готовый блок по описанию на русском.
После сохранения команды Jarvis нужно перезапустить, чтобы она подхватилась.
Требования:
- Windows 10/11 с установленным WebView2 Runtime (обычно уже стоит вместе с Edge — иначе скачать у Microsoft).
- Зависимости из
requirements.txt(включаяpywebview,ruamel.yaml,pyautogui).
Подробности для разработчиков — tools/command_builder/README.md. TODO: добавить скриншот окна.
Лицензия
CC BY-NC-SA 4.0 — см. LICENSE.txt. Авторство оригинала — Abraham Tugalov / Priler. Изменения в этом форке — Bossiara13 (Dmitry Bykov), 2026.