Mirrors the rust tier-3 batch. 90 → 100 commands (round number — feels
right for an "имба" milestone).
main.py:
+ do_brightness: WMI WmiMonitorBrightness read + WmiSetBrightness write,
±20% step or 100/10 absolute, "no_wmi" sentinel for desktops.
+ do_window_switch: same alias map as process_kill (xrom→chrome/...),
PS finds process by name OR window-title substring, picks newest
StartTime, AppActivate via WScript.Shell.
+ do_spell_out: split chars, join with ". ", _speak.
+ do_network_settings: action.section = wifi|bluetooth|network →
matching ms-settings:* URI via cmd /c start "".
+ do_my_ip: Get-NetIPAddress filtered to non-loopback non-APIPA IPv4,
WAN via Invoke-RestMethod ipify, speaks "Локальный X. Внешний Y".
+ do_summarize_selection: pyautogui.hotkey(ctrl, c) → 250ms wait →
Get-Clipboard → Groq @ temp 0.3 ("3-5 sentence retell") → speak +
clipboard.
commands.yaml +10 entries: brightness_up/down/max/min, switch_to_window,
spell_out, open_wifi_settings, open_bluetooth_settings, my_ip,
summarize_selection.
Backlog: closed all "Tier-3 still TODO" pure-Lua items. Remaining
TODOs (pomodoro, currency-math, stocks, translate-clipboard, daily
briefing, etc.) are even smaller LOC and can roll in the next batch.
Mirrors the rust analog-inspired tier-2 packs. yaml + ast smoke pass.
56 → 82 commands (+26 yaml entries; 14 of them are power/fun/wiki/
news/etc. permutations).
main.py — 7 new action handlers, all built on stdlib urllib.request
(no new dep). Helper _http_get() with User-Agent header so RSS feeds
that 403 default UAs go through.
+ do_news: pulls RSS (default Lenta.ru), extracts <title> via regex,
skips channel title (idx 0), takes 5, sends to Groq for a 2-3
sentence summary at temp 0.4. Falls back to reading first 3
headlines verbatim if no token.
+ do_currency_rate: cbr-xml-daily.ru daily_json.js. Recognises
USD/EUR/CNY/GBP/JPY/KZT in the phrase, computes value/nominal,
diffs against Previous, speaks Russian with direction.
+ do_crypto_price: CoinGecko simple/price for BTC/ETH/SOL/DOGE/TON
with 24h change, picked by phrase keywords.
+ do_fun_ask: joke / fact / quote / compliment via Groq at temp 1.0
with per-kind system prompts, random seed in user message.
+ do_wiki_lookup: ru.wikipedia opensearch → page summary, optional
Groq retell when extract > 350 chars.
+ do_power: dispatch table for shutdown / restart / sleep /
hibernate / logoff / cancel — runs shutdown.exe /s|/r|/h|/l|/a
or rundll32 powrprof,SetSuspendState. 30-second grace on shutdown
and restart with /c message so "отмени выключение" works.
+ do_help_commands: sorts VA_CMD_LIST.keys(), speaks first 12 + total,
full list to clipboard.
commands.yaml +26 entries:
news_headlines, currency_rate, crypto_price, joke / fact / quote /
compliment (action:fun_ask, kind: ...), wiki_lookup, shutdown_pc /
restart_pc / sleep_pc / hibernate_pc / logoff_user / cancel_shutdown
(action:power, op: ...), help.
Inspired by what mainstream voice assistants (Siri/Alexa/Алиса/
Cortana) ship by default + power-user utilities (shutdown,
window/process control).
main.py: prints a 3-line banner at startup with name, version, edition
label ("Python edition") and the command count from the loaded YAML.
Makes the console window self-identifying when both python and rust
forks run simultaneously.
run.bat at repo root: cd /d into repo, sets the cmd title to
"J.A.R.V.I.S. (Python edition)", picks the venv interpreter at
.venv\Scripts\python.exe if present (falls back to system python),
runs main.py, then pauses at exit so the user can read any traceback
instead of the console window vanishing on crash.
Desktop shortcut "Jarvis (Python).lnk" points at this batch file
with the project icon (the rust fork's icon.ico, since python has
no .ico of its own).
Mirrors the rust packs from the same iteration. yaml.safe_load + ast.parse
both pass.
main.py — six new action handlers + a _speak_in_lang helper:
+ do_translate: picks target language from "переведи на X" / "translate to X"
triggers, defaults to English, sends to Groq with strict "translation only"
prompt, drops to clipboard, speaks via SAPI in matching ISO voice
+ do_math_eval: strips trigger, Groq at temp=0.0 max_tokens=64,
short-circuits on "нет" sentinel for non-math
+ do_theme_set: writes AppsUseLightTheme + SystemUsesLightTheme via
Set-ItemProperty under HKCU\...\Themes\Personalize, action param
mode: dark|light
+ do_open_project / do_list_projects: reads/creates
%USERPROFILE%\Documents\jarvis-projects.json (a flat list of
{name, path}), exact-match → substring-match, opens in VS Code if
code.cmd on PATH else Explorer. First call writes a sample config
pointing under USERPROFILE so it works on any host.
+ do_open_sound_panel: rundll32 mmsys.cpl,,1 — Recording tab
commands.yaml — 8 new entries:
+ translate, math_eval
+ theme_dark, theme_light (action params mode:dark/light)
+ open_project, list_projects
+ open_sound_panel
SAPI voice selection iterates GetInstalledVoices() and picks first
matching TwoLetterISOLanguageName — Russian phrases sound Russian,
English/German/etc. sound right too, falls back to default if no
matching voice is installed.
Total commands: 56 (was 49).
Mirrors the new rust packs from the same iteration. Total commands in
commands.yaml is now 49 (was 33). yaml.safe_load + ast.parse both pass.
Window management (8 commands) — uses the existing `keys` action with
pyautogui hotkey strings: winleft+d (show_desktop), winleft+up/down
(maximize/minimize), winleft+left/right (snap left/right), alt+f4
(close_window), winleft+shift+m (restore_all), winleft+tab (task_view).
No new action type needed.
Clipboard read aloud — new clipboard_read action. Shells to
PowerShell Get-Clipboard, caps preview at 400 chars, speaks via the
existing tts.va_speak (which already handles recorder.stop/start).
Notes — new notes_add + notes_open actions. notes_add strips the
trigger phrase, appends "[YYYY-MM-DD HH:MM] body\n" to
%USERPROFILE%\Documents\jarvis-notes.txt, creates the dir if needed.
notes_open shells "cmd /c start" so .txt opens in the user-default
editor.
Process killer — new process_kill action. Strips the trigger ("убей
процесс"/"закрой программу"/etc.), looks up the remainder in the same
alias map as the rust version (хром→chrome, телега→telegram, спотифай
→spotify, едж/эдж/edge→msedge, дискорд→discord, стим→steam, обс→obs64,
проводник/блокнот/калькулятор/диспетчер задач, vs code→code, etc.),
appends .exe if needed, runs taskkill /F /IM, speaks success or
"не нашёл процесс N".
Web search — new websearch action with a `service` param. Bases:
google → https://www.google.com/search?q=
youtube → https://www.youtube.com/results?search_query=
wiki → https://ru.wikipedia.org/wiki/Special:Search?search=
yandex → https://yandex.ru/search/?text=
Strips trigger, urllib.parse.quote-s the rest, opens via webbrowser.open
(respects the user'\''s default browser; config.BROWSER_PATHS only kicks in
for the older url-action commands).
Portability: USERPROFILE used for notes path, no other hardcoded paths.
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.
Adds optional 'browser' field to url-action; runtime resolves it via
config.BROWSER_PATHS (subprocess.Popen with the chosen exe). When
omitted, falls back to webbrowser.open (system default). Constructor
GUI gains a browser dropdown on URL action and on multi-step URL.
Existing open_browser/youtube/google updated to use yandex by default
since user prefers Yandex Browser.
shell uses subprocess (with shell=True so user can write a normal
command line); url uses webbrowser.open; keys uses pyautogui.hotkey
for combinations or pyautogui.typewrite for raw text. pyautogui is
imported lazily so the bot still starts on machines without a GUI.
Replaces the 100-line elif chain with a small dispatcher. Each entry in
commands.yaml now carries both 'phrases' (existing trigger list) and
'action' describing how to run it. Action types: exe, play_sound,
system (volume_mute/unmute/exit), sleep, multi.
The data migration lives in the next commit; the dispatcher in this
commit assumes the new schema.
Replace the fixed 10s post-wake-word listen window with a VAD-driven
loop. Once at least 500ms of speech have been seen, 1.2s of silence
closes the window. Hard cap at 15s as a safety net.
Tunable in config.py via VAD_AGGRESSIVENESS, COMMAND_END_SILENCE_MS,
COMMAND_MIN_SPEECH_MS, COMMAND_MIN_LISTEN_MS, COMMAND_MAX_LISTEN_MS.
- Names the assistant as J.A.R.V.I.S. (acronym + MCU pre-Age-of-Ultron)
- British butler tone, addresses user as «сэр»
- Brief replies (1-3 sentences)
- No prudish censorship
uses a second KaldiRecognizer with a JSON grammar of WAKE_WORDS + [unk] for
the wake phase, then hands off to the full-vocab recognizer for the 10s
command window. drops the pvporcupine dependency entirely.