Fork of Priler/jarvis (CC BY-NC-SA 4.0) https://github.com/Priler/jarvis
Find a file
Bossiara13 633850d0f7
Some checks failed
Python CI / pytest (ubuntu-latest) (push) Failing after 5s
Python CI / ruff (push) Failing after 5s
Python CI / pytest (windows-latest) (push) Has been cancelled
feat: Python parity for wol / banter / conversation / ddg_answer + 11 tests
New `wave59_handlers.py` (~250 lines) mirroring four Rust-only packs:

- wol: pure-Python magic packet via socket + SO_BROADCAST. No PowerShell
  shellout (unlike the Rust pack). Reads MAC from memory_store under
  'wol_<alias>' or JARVIS_WOL_TARGET env. Same MAC format tolerance
  (colons / dashes / dots / bare) as the Rust normaliser.

- banter: pause/resume state + fire-one. Python edition doesn't run a
  background banter thread (the Rust daemon already does), so this is
  just the user-facing surface — same voice phrases work.

- conversation: do_conversation_summary calls Groq with last 12 turns
  from main.py's `message_log`. set_history_ref() injects the live list
  reference at startup so the handler reads up-to-date history without
  a circular import. Offline-safe: GROQ_TOKEN missing → speak the last
  user message instead. do_conversation_repeat re-speaks the last
  assistant turn.

- ddg_answer: urllib + DuckDuckGo Instant Answer JSON. Picks
  AbstractText → Answer → Definition → RelatedTopics[0]. Opens
  duckduckgo.com search fallback when nothing instant.

extensions.py / main.py / commands.yaml: 7 new dispatch entries +
proxy fns. commands.yaml now at 207 entries.

tests/test_wave59_handlers.py: 11 unit tests for MAC normalisation,
magic packet shape, WOL error paths, banter state machine, DDG trigger
stripping, conversation history handling. Network calls deliberately
NOT exercised here — they belong to integration tests.

Tests: 104 → 115 (+11).
2026-05-24 23:12:04 +03:00
.github/workflows chore: GitHub Actions CI workflow 2026-05-16 13:38:22 +03:00
.idea some reformat 2023-04-16 16:59:18 +05:00
custom-commands Revert "Поменял архитектуру, сильно уменьшил кол-во зависимостей, убрал pyaduio, porcupine" 2023-04-16 15:56:20 +05:00
gui feat: Wave 3 — plugin loader + Flet GUI (parity with Rust fork) 2026-05-16 13:27:04 +03:00
model_small some reformat 2023-04-16 16:59:18 +05:00
models/all-MiniLM-L6-v2 chore: vendor MiniLM-L6-v2 onnx model from Qdrant 2026-04-23 10:51:53 +03:00
sound Revert "Поменял архитектуру, сильно уменьшил кол-во зависимостей, убрал pyaduio, porcupine" 2023-04-16 15:56:20 +05:00
tests feat: Python parity for wol / banter / conversation / ddg_answer + 11 tests 2026-05-24 23:12:04 +03:00
tools/command_builder feat(url): optional browser field (yandex/chrome/firefox/edge) 2026-04-27 20:06:26 +03:00
utils chore: add utils/preview_effects.py for A/B comparison 2026-04-22 19:59:45 +03:00
.gitattributes chore: enable git lfs for .onnx files 2026-04-23 10:51:29 +03:00
.gitignore feat: expense tracker Python parity (Wave 10) 2026-05-16 15:02:07 +03:00
commands.yaml feat: Python parity for wol / banter / conversation / ddg_answer + 11 tests 2026-05-24 23:12:04 +03:00
config.py feat: parity with rust fork — LLM auto-fallback + 6 new action types + 20+ commands 2026-05-15 01:48:34 +03:00
dev.env.example chore: drop pvporcupine dep and PICOVOICE_TOKEN from env template 2026-04-22 17:47:22 +03:00
dev_handlers.py feat: LLM hot-swap voice command + Ollama backend (148 → 151 commands) 2026-05-16 00:44:42 +03:00
effects.py feat: add tts effects module (bandpass + reverb + optional pitch) 2026-04-22 19:58:20 +03:00
expenses_handlers.py feat: expense tracker Python parity (Wave 10) 2026-05-16 15:02:07 +03:00
extensions.py feat: Python parity for wol / banter / conversation / ddg_answer + 11 tests 2026-05-24 23:12:04 +03:00
gui.bat feat: Wave 3 — plugin loader + Flet GUI (parity with Rust fork) 2026-05-16 13:27:04 +03:00
intent.py feat: onnx intent classifier replacing fuzzy match 2026-04-23 10:53:18 +03:00
LICENSE.txt license added 2023-04-22 02:17:06 +05:00
llm_backend.py feat: LLM hot-swap voice command + Ollama backend (148 → 151 commands) 2026-05-16 00:44:42 +03:00
macros_store.py feat: vision + macros + scheduler in Python (129 → 142 commands) 2026-05-16 00:00:22 +03:00
main.py feat: Python parity for wol / banter / conversation / ddg_answer + 11 tests 2026-05-24 23:12:04 +03:00
memory_store.py feat: Python parity for Wave 6-8 — memory admin / cooking / leftoff / trivia / routines 2026-05-16 14:55:47 +03:00
outlook_handlers.py feat: Wave 5 Python parity — outlook COM + time tracker 2026-05-16 14:34:44 +03:00
personality_handlers.py feat: personality pack — Python parity 2026-05-16 13:53:44 +03:00
plugins_store.py feat: Wave 3 — plugin loader + Flet GUI (parity with Rust fork) 2026-05-16 13:27:04 +03:00
profiles_store.py feat: memory_store + profiles_store + 10 new yaml entries (119 → 129) 2026-05-15 23:54:33 +03:00
README.md feat: Wave 3 — plugin loader + Flet GUI (parity with Rust fork) 2026-05-16 13:27:04 +03:00
requirements.txt feat: Wave 5 Python parity — outlook COM + time tracker 2026-05-16 14:34:44 +03:00
run.bat feat: "Python edition" startup banner + one-click run.bat launcher 2026-05-15 12:12:21 +03:00
run_builder.bat docs: command builder README + user-facing README section + run_builder.bat 2026-04-23 02:13:47 +03:00
scheduler_store.py feat: vision + macros + scheduler in Python (129 → 142 commands) 2026-05-16 00:00:22 +03:00
time_tracker_handlers.py feat: Wave 5 Python parity — outlook COM + time tracker 2026-05-16 14:34:44 +03:00
tts.py fix: Python startup no longer silent on first run 2026-05-24 22:12:24 +03:00
vision_handler.py feat: LLM hot-swap voice command + Ollama backend (148 → 151 commands) 2026-05-16 00:44:42 +03:00
wave1_handlers.py feat: Wave 1 python parity — 20 new commands (154 → 174) 2026-05-16 01:08:17 +03:00
wave59_handlers.py feat: Python parity for wol / banter / conversation / ddg_answer + 11 tests 2026-05-24 23:12:04 +03:00
wave68_handlers.py feat: Python parity for Wave 6-8 — memory admin / cooking / leftoff / trivia / routines 2026-05-16 14:55:47 +03:00

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 и заполните ключ:

Vosk-модель для русского языка лежит в model_small/ (уже в репозитории). Запуск:

python main.py

GUI (Flet)

Опциональная графическая панель — те же 7 страниц, что и в Rust-форке (Главная / Команды / Макросы / Расписание / Память / Плагины / Настройки).

pip install flet>=0.85   # одноразово, уже в requirements.txt
python -m gui            # или просто gui.bat

GUI не запускает ассистент сам — это панель управления. Кнопка «Запустить J.A.R.V.I.S.» на главной запускает main.py отдельным процессом.

Плагины

Голосовые команды, которые лежат вне репозитория. Добавляются без правки проекта: создайте папку в

%APPDATA%\com.priler.jarvis\plugins\<имя_плагина>\
    commands.yaml      (тот же формат, что и корневой commands.yaml)
    disabled           (опционально — пустой файл, отключает плагин)

Плагины подхватываются при следующем запуске main.py. ID встроенных команд выигрывают конфликты (плагин не может переопределить, например, open_browser). GUI-страница «Плагины» показывает список, флажки enable/disable и кнопку «Открыть папку».

Конфигурация

  • 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-скрипты под конкретный сетап автора оригинала (переключение мониторов, управление Яндекс.Музыкой и т.п.). На вашей машине большая часть из них работать не будет, но ассистент запустится в любом случае.

Использование

  1. Скажите «Джарвис» (или «jarvis») — ассистент даст звуковой сигнал готовности.
  2. Произнесите команду — окно записи закрывается само, как только вы замолчите (см. ниже про 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 = FalseFalse для меняющегося шума (рекомендуется), 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 — полоса пропускания (по умолчанию 2007000 Гц). Сужение полосы даёт ощущение «голоса по радио».
  • 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.