From 4f830628159bec8ac74f7b783698853094d36010 Mon Sep 17 00:00:00 2001 From: Bossiara13 <236771060+DmitryBykov-ISPO@users.noreply.github.com> Date: Fri, 15 May 2026 23:38:03 +0300 Subject: [PATCH] docs+feat: USAGE.md + interesting_fact + mailto packs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit USAGE.md (new, ~250 lines) - Complete voice command reference organised by 13 categories - Table-formatted for fast skim ("Команда → Что делает") - Sections: Управление ассистентом / LLM / Память+профили+macros / Расписание / Окна+апп / Аудио+медиа / Система / Файлы+буфер / Информация из интернета / Утилиты-калькуляторы / Разработка / Развлечения / Скриншоты - Bottom: "Как добавить свою команду" with Lua snippet template, "Голосовое vs GUI" mapping, troubleshooting checklist (mic / TTS / LLM / command-not-found / logs). - Covers all 67 packs visible in resources/commands/. interesting_fact pack (resources/commands/interesting_fact/, 2 cmds) - fact.about "удиви меня" / "интересный факт про космос" → LLM with "curious conversationalist" prompt, generic or topic-targeted (1-2 sentences, no fluff). - fact.history_today "что было в этот день" / "этот день в истории" → Wikipedia "On this day" API (RU first, EN fallback) → LLM picks top 2-3 events, narrates concisely. mailto pack (resources/commands/mailto/, 1 cmd) - mailto.compose "напиши письмо" / "напиши письмо маме" → opens default mail client via mailto: URI. Looks up recipient via jarvis.memory ("email_маме") if a name is given. - Pairs well with: jarvis.memory.remember("email_маме", "mom@example.com") Pack count: 67 → 70. Tests: 112/112. --- USAGE.md | 259 ++++++++++++++++++ .../commands/interesting_fact/command.toml | 38 +++ resources/commands/interesting_fact/fact.lua | 35 +++ .../interesting_fact/history_today.lua | 48 ++++ resources/commands/mailto/command.toml | 18 ++ resources/commands/mailto/compose.lua | 32 +++ 6 files changed, 430 insertions(+) create mode 100644 USAGE.md create mode 100644 resources/commands/interesting_fact/command.toml create mode 100644 resources/commands/interesting_fact/fact.lua create mode 100644 resources/commands/interesting_fact/history_today.lua create mode 100644 resources/commands/mailto/command.toml create mode 100644 resources/commands/mailto/compose.lua diff --git a/USAGE.md b/USAGE.md new file mode 100644 index 0000000..73c5f94 --- /dev/null +++ b/USAGE.md @@ -0,0 +1,259 @@ +# Voice command reference + +Все голосовые команды J.A.R.V.I.S. (текущее состояние, **67 паков**). +Каждая команда — это фраза, которую можно произнести после wake-word ("Джарвис"). + +Группы: + +- [Управление ассистентом](#управление-ассистентом) +- [LLM / мозг](#llm--мозг) +- [Память / профили / macros](#память--профили--macros) +- [Расписание / напоминания / привычки](#расписание--напоминания--привычки) +- [Окна / приложения / процессы](#окна--приложения--процессы) +- [Аудио / медиа](#аудио--медиа) +- [Система / устройство](#система--устройство) +- [Файлы / буфер / заметки](#файлы--буфер--заметки) +- [Информация из интернета](#информация-из-интернета) +- [Утилиты-калькуляторы](#утилиты-калькуляторы) +- [Разработка](#разработка) +- [Развлечения](#развлечения) +- [Скриншоты / экран](#скриншоты--экран) + +После каждой команды есть **30-секундное grace-окно** для follow-up без повторного "Джарвис". +Конфигурируется через `CONVERSATION_GRACE_MS`. + +--- + +## Управление ассистентом + +| Команда (RU) | Что делает | +|---|---| +| "Помощь" / "что ты умеешь" | Перечисляет категории возможностей | +| "Расскажи о себе" / "кто ты такой" | Краткое представление (LLM варьирует) | +| "Сколько команд знаешь" | Health snapshot — все активные бэкенды + счётчики | +| "Диагностика" / "доложи о себе" | Одной строкой: TTS, LLM, профиль, памяти/задач | +| "Повтори за мной X" | Эхо — для теста микрофона + TTS | +| "Что я сказал" | Что услышал из последней фразы | +| "Стоп" / "хватит" / "прекрати" | Прерывает текущую команду | +| "Сбрось контекст" / "забудь разговор" | Очищает историю LLM | +| "Повтори последнее" / "повтори ответ" | Озвучивает последний ответ LLM | + +## LLM / мозг + +| Команда | Что делает | +|---|---| +| "Переключись на локальный" / "перейди на оллама" | Hot-swap на Ollama (persistent в БД) | +| "Переключись на облако" / "используй грок" | Hot-swap на Groq | +| "Какой у тебя мозг" / "облако или локально" | Текущий backend | + +Любая фраза без распознанной команды → LLM router (если включён) → если нет матча → LLM chat fallback. + +## Память / профили / macros + +| Команда | Что делает | +|---|---| +| "Запомни что я люблю чай улун" | Сохраняет факт | +| "Что ты помнишь про чай" | Substring-поиск по памяти | +| "Что ты знаешь обо мне" | Все факты | +| "Забудь про X" | Удалить факт | +| "Режим работа" / "режим игра" / "режим сон" / "режим за рулём" / "обычный режим" | Профиль (5 встроенных) | +| "Какой сейчас режим" | Активный профиль | +| "Запиши макрос имя" | Начать запись макроса | +| "Сохрани макрос" | Завершить запись и сохранить | +| "Отмени макрос" | Отменить запись | +| "Запусти макрос имя" | Воспроизвести (с интервалом 800мс) | +| "Какие у меня макросы" / "удали макрос имя" | Управление списком | + +Также: GUI страницы `/memory` (добавить/забыть факты), `/macros` (запуск/удаление), `/scheduler` (отмена задач). + +## Расписание / напоминания / привычки + +| Команда | Что делает | +|---|---| +| "Напомни через 5 минут выключить кофеварку" | One-shot reminder | +| "Напомни в 18:00 забрать ребёнка" | Today at HH:MM | +| "Каждые 2 часа напоминай попить воды" | Interval | +| "Каждый день в 9:00 делай брифинг" | Daily | +| "Что у меня запланировано" / "очисти расписание" | Управление | +| "Отмени напоминание про воду" | Substring-match remove | +| "Запусти помодоро" / "стоп помодоро" | 25/5 циклы | +| "Напоминай мне пить воду" | Каждые 2 часа | +| "Напоминай размяться" | Каждые 50 минут | +| "Напоминай отдыхать глазам" | 20-20-20 (каждые 20 мин) | +| "Отключи все привычки" | Стоп всех habit_nudge задач | +| "Настрой утренний брифинг на 9:00" | Daily briefing в указанное время | +| "Утренний брифинг" | Запустить брифинг сейчас | +| "Отключи утренний брифинг" | Снять daily задачу | + +## Окна / приложения / процессы + +| Команда | Что делает | +|---|---| +| "Открой Telegram" / "запусти Steam" / "Spotify" | Через `apps/` пак (имя в config) | +| "Закрой Telegram" / "убей процесс X" | Process kill | +| "Сверни всё" / "разверни окно" / "переключи окно" | Window manager | +| "Какие открыты окна" | Список Z-order | +| "Сверни активное" / "максимизируй" | Action на foreground | +| "Открой папку загрузок" / "файлы" / "проводник" | Explorer | + +## Аудио / медиа + +| Команда | Что делает | +|---|---| +| "Громче" / "тише" / "громкость на 30" | Volume up/down/set | +| "Заглуши" / "сними заглушку" | Mute toggle | +| "Какая громкость" | Текущий уровень | +| "Открой панель звука" | Sound panel | +| "Включи Realtek" / "переключи звук на Headphones" | Output device swap | +| "Пауза" / "плей" / "следующий трек" / "предыдущий трек" / "стоп музыка" | Media keys — Spotify / YouTube / Foobar / Yandex Music | +| "Запиши голосовую заметку" | (см. notes/) | +| "Выключи музыку через 30 минут" | Sleep timer для медиа | + +## Система / устройство + +| Команда | Что делает | +|---|---| +| "Сколько процессор грузится" / "сколько RAM" / "температура" | Sysinfo | +| "Сколько заряда" / "заряд батареи" | Battery % | +| "Сколько свободно на диске" / "сколько на диске C" | PowerShell Get-PSDrive | +| "Какие у меня диски" | C: D: E: со свободным местом | +| "Какая сеть" / "какой WiFi" | Net SSID via netsh | +| "Мой IP" / "локальный IP" | Get-NetIPAddress | +| "Внешний IP" | api.ipify.org | +| "Прибавь яркость" / "тусклее" / "яркость 70" | Brightness via WMI | +| "Тёмная тема" / "светлая тема" | Windows theme | +| "Заблокируй компьютер" | LockWorkStation | +| "Выключи компьютер" / "перезагрузи" / "ребутни" / "сон" / "гибернация" / "выйди из системы" / "отмени выключение" | Power management | +| "Выключи компьютер через 30 минут" | Sleep timer для системы | +| "Отмени таймер выключения" | shutdown /a + scheduler clear | + +## Файлы / буфер / заметки + +| Команда | Что делает | +|---|---| +| "Найди файл report" / "поищи documents" | File search | +| "Запиши заметку купить хлеб" | Append в notes file | +| "Покажи заметки" / "что я записал" | Открывает notes | +| "Прочитай буфер" / "что в буфере" | Clipboard contents speak | +| "Переведи буфер на английский" | LLM перевод + replace clipboard | + +## Информация из интернета + +| Команда | Что делает | +|---|---| +| "Какая погода" / "погода завтра" / "что с погодой" | Weather pack | +| "Курс доллара" / "курс юаня" | CBR rates | +| "Сколько 1000 долларов в рублях" | Currency convert | +| "Сколько Сбер" / "сколько Газпром" | MOEX котировки (22 тикера) | +| "Сколько биткоин" / "сколько эфир" | Crypto | +| "Новости" / "что нового в мире" | News RSS | +| "Найди в гугле X" / "загугли X" | DuckDuckGo Instant + LLM | +| "Википедия X" / "что такое X" / "кто такой Y" | Wikipedia REST | +| "Открыть Google поиск X" | Websearch (open browser) | +| "Переведи на английский X" | Translate | + +## Утилиты-калькуляторы + +| Команда | Что делает | +|---|---| +| "Посчитай 2 плюс 2" / "сколько будет 10 в степени 3" | Math | +| "Переведи 100 метров в футы" | Length convert | +| "70 кг в фунты" | Weight convert | +| "100 цельсий в фаренгейт" | Temperature convert | +| "100 км в час в мили в час" | Speed convert | +| "Сколько дней до нового года" | Date math (8 марта, 9 мая, Рождество, Новый год + любая дата) | +| "Какой сегодня день недели" | Zeller's congruence | +| "Время" / "сколько времени" / "какое сегодня число" | Date query | +| "Подбрось монету" / "орёл или решка" | Coin flip | +| "Сгенерируй пароль 16 символов" | Secure password → clipboard | +| "Сгенерируй UUID" | v4 UUID → clipboard | +| "Брось кубик" / "брось два кубика" | Dice | +| "Выбери случайно из X или Y или Z" | Random choice | +| "Запусти секундомер" / "сколько прошло" / "стоп секундомер" | Stopwatch | +| "Прибавь счётчик" / "сколько на счётчике" / "сбрось счётчик" | Counter | +| "Как пишется X" | Spelling | + +## Разработка + +| Команда | Что делает | +|---|---| +| "Укажи проект C:\..." | Codebase Q&A: установить root | +| "Какой проект сейчас" | Текущий root | +| "Что делает функция X" / "найди в коде Y" / "объясни код" | Walks codebase → LLM | +| "Текущий репо owner/repo" | GitHub: установить repo | +| "Какие пиары" / "открытые пиары" | List PRs via gh CLI | +| "Разбери последний пиар" | LLM-ревью PR (gh pr view) | +| "Сгенерируй код для X" | Code generation pack | +| "Открой Cursor" / "VS Code" | apps/ | + +## Развлечения + +| Команда | Что делает | +|---|---| +| "Расскажи анекдот" / "пошути" / "скажи фразу" / "тостер" | Fun pack (jokes) | +| "Запиши настроение 7" / "сегодня мне грустно" | Mood log | +| "Как прошла неделя" / "сводка настроения" | Mood recap via LLM | +| "Запусти Steam игру X" / "поиграй в Y" | Games pack | + +## Скриншоты / экран + +| Команда | Что делает | +|---|---| +| "Что на экране" / "опиши экран" | Vision LLM описание | +| "Прочитай ошибку" | Vision LLM: ищет stack trace, объясняет | +| "Сделай скриншот" / "скрин в буфер" | Screenshot → clipboard | +| "Сохрани скриншот" | Screenshot → ~/Pictures/Screenshots/ | +| "OCR экрана" / "прочитай текст" | OCR (existing pack) | +| "Суммаризируй экран" | Summarize visible window | + +--- + +## Как добавить свою команду + +Скопируй `resources/commands/echo/` как шаблон, отредактируй `command.toml` +(id, phrases) и `*.lua` (логика). Рекомендуемая структура — см. +[ARCHITECTURE.md → Recommended pack structure](ARCHITECTURE.md#recommended-pack-structure). + +Минимум: + +```lua +-- thing.lua +local phrase = (jarvis.context.phrase or ""):lower() +local body = jarvis.text.strip_trigger(phrase, { "сделай штуку" }) +body = body:gsub("^[%s,:%.]+", ""):gsub("%s+$", "") + +if body == "" then + return jarvis.cmd.error("Что именно?") +end + +-- ... do work ... + +return jarvis.cmd.ok("Готово.") +``` + +Затем `cargo test -p jarvis-core --lib commands::tests` — он автоматически +проверит что TOML парсится и Lua-скрипт существует. + +## Голосовое vs GUI + +GUI страницы — для случаев когда голосом неудобно: + +- `/commands` — все 67 паков с поиском (для discovery) +- `/macros` — список с кнопкой "Запустить" +- `/scheduler` — задачи с auto-poll каждые 5 сек +- `/memory` — добавление/удаление фактов с фильтром +- `/settings → AI Backends` — переключение LLM/TTS через dropdown + +## Что-то не работает? + +1. **Голос не распознаётся** — проверь микрофон в Settings → Devices. Скажи + "повтори за мной привет" — если эхо проходит, проблема не в STT. +2. **Не слышу ответ** — проверь TTS backend в Settings → AI Backends. Скажи + "проверка эхо" — должен быть слышен голос. Если нет, проверь динамики + + попробуй `JARVIS_TTS=sapi`. +3. **"Не могу связаться с сервером"** — LLM unreachable. Если Groq — + проверь GROQ_TOKEN и интернет. Если Ollama — `ollama serve` запущен? +4. **Команда не найдена** — посмотри `/commands` в GUI, поищи фразу. Если + фразы похожи но не та — agentic router сделает попытку, или подскажет. +5. **Что-то странное в логах** — `/jarvis.log` (путь видно + в первых строках `jarvis-app` stdout). diff --git a/resources/commands/interesting_fact/command.toml b/resources/commands/interesting_fact/command.toml new file mode 100644 index 0000000..a2867c1 --- /dev/null +++ b/resources/commands/interesting_fact/command.toml @@ -0,0 +1,38 @@ +# Interesting fact about X via LLM. + +[[commands]] +id = "fact.about" +type = "lua" +script = "fact.lua" +sandbox = "full" +timeout = 15000 + +[commands.phrases] +ru = [ + "расскажи интересный факт", + "интересный факт о", + "интересный факт про", + "удиви меня", + "интересный факт", + "расскажи факт", +] +en = ["tell me an interesting fact", "fun fact about", "surprise me"] +ua = ["цікавий факт"] + + +[[commands]] +id = "fact.history_today" +type = "lua" +script = "history_today.lua" +sandbox = "full" +timeout = 15000 + +[commands.phrases] +ru = [ + "что было в этот день", + "что произошло в этот день", + "этот день в истории", + "что случилось", +] +en = ["this day in history", "what happened today"] +ua = ["що сталося в цей день"] diff --git a/resources/commands/interesting_fact/fact.lua b/resources/commands/interesting_fact/fact.lua new file mode 100644 index 0000000..b923d57 --- /dev/null +++ b/resources/commands/interesting_fact/fact.lua @@ -0,0 +1,35 @@ +-- "Интересный факт о космосе" / "удиви меня" +local phrase = (jarvis.context.phrase or ""):lower() +local topic = jarvis.text.strip_trigger(phrase, { + "расскажи интересный факт про", + "расскажи интересный факт о", + "интересный факт про", + "интересный факт о", + "расскажи интересный факт", + "интересный факт", + "расскажи факт", + "удиви меня", + "tell me an interesting fact", + "fun fact about", + "surprise me", + "цікавий факт", +}) +topic = topic:gsub("^[%s,:%.]+", ""):gsub("%s+$", "") + +local user_prompt +if topic == "" then + user_prompt = "Расскажи один реально неочевидный научно-проверенный факт. На русском, 1-2 предложения. Без вступлений типа 'знали ли вы'." +else + user_prompt = "Расскажи один интересный факт про " .. topic .. ". На русском, 1-2 предложения. Без вступлений." +end + +local reply = jarvis.llm({ + { role = "system", content = "Ты любопытный собеседник. Говоришь короткими, цепляющими фактами без воды." }, + { role = "user", content = user_prompt } +}, { max_tokens = 200, temperature = 0.8 }) + +if not reply or reply == "" then + return jarvis.cmd.error("Сегодня нет интересных фактов.") +end + +return jarvis.cmd.ok(reply) diff --git a/resources/commands/interesting_fact/history_today.lua b/resources/commands/interesting_fact/history_today.lua new file mode 100644 index 0000000..22a1420 --- /dev/null +++ b/resources/commands/interesting_fact/history_today.lua @@ -0,0 +1,48 @@ +-- "Что было в этот день в истории" — Wikipedia API + LLM сжатие. +local t = jarvis.context.time + +-- Wikipedia's "On this day" Featured Content API: +-- https://api.wikimedia.org/feed/v1/wikipedia/ru/onthisday/events/MM/DD +local url = string.format( + "https://api.wikimedia.org/feed/v1/wikipedia/ru/onthisday/events/%02d/%02d", + t.month, t.day +) + +local data = jarvis.http.json(url) +if not data or not data.events or #data.events == 0 then + -- fallback: EN + url = string.format( + "https://api.wikimedia.org/feed/v1/wikipedia/en/onthisday/events/%02d/%02d", + t.month, t.day + ) + data = jarvis.http.json(url) +end + +if not data or not data.events or #data.events == 0 then + return jarvis.cmd.not_found("На этот день в истории ничего интересного.") +end + +-- Pick first 5 events to feed into LLM for summarisation +local sample = {} +for i = 1, math.min(5, #data.events) do + local ev = data.events[i] + local year = ev.year or "?" + local text = ev.text or "" + if text ~= "" then + table.insert(sample, year .. ": " .. text) + end +end + +local context = table.concat(sample, "\n") + +local reply = jarvis.llm({ + { role = "system", content = "Ты — историк. Из списка событий выбери 2-3 самых интересных для русскоязычного слушателя, расскажи коротко на русском. Без преамбул." }, + { role = "user", content = "Сегодня " .. t.day .. " число месяца " .. t.month .. ". События в этот день:\n\n" .. context } +}, { max_tokens = 350, temperature = 0.4 }) + +if not reply or reply == "" then + -- Fallback: just speak first event + return jarvis.cmd.ok(sample[1] or "Не нашёл интересного.") +end + +return jarvis.cmd.ok(reply) diff --git a/resources/commands/mailto/command.toml b/resources/commands/mailto/command.toml new file mode 100644 index 0000000..cafe3fc --- /dev/null +++ b/resources/commands/mailto/command.toml @@ -0,0 +1,18 @@ +# Mailto: open default mail client to compose a new message. + +[[commands]] +id = "mailto.compose" +type = "lua" +script = "compose.lua" +sandbox = "full" +timeout = 5000 + +[commands.phrases] +ru = [ + "напиши письмо", + "новое письмо", + "открой почту", + "составить письмо", +] +en = ["compose email", "new email", "open mail"] +ua = ["напиши лист", "новий лист"] diff --git a/resources/commands/mailto/compose.lua b/resources/commands/mailto/compose.lua new file mode 100644 index 0000000..2143ee8 --- /dev/null +++ b/resources/commands/mailto/compose.lua @@ -0,0 +1,32 @@ +-- "Напиши письмо имя_контакта" → opens mailto: URI in default handler. +-- For now just opens a blank compose; could be extended to pull recipient +-- from memory ("маме", "коллеге") via lookups. +local phrase = (jarvis.context.phrase or ""):lower() +local target = jarvis.text.strip_trigger(phrase, { + "напиши письмо", + "новое письмо", + "открой почту", + "составить письмо", + "compose email", + "new email", + "open mail", +}) +target = target:gsub("^[%s,:%.]+", ""):gsub("%s+$", "") + +local recipient = "" +if target ~= "" then + -- Try memory lookup — "напиши письмо маме" → memory.recall("email_маме") + local key = "email_" .. target + local addr = jarvis.memory.recall(key) + if addr and addr ~= "" then + recipient = addr + end +end + +local uri = recipient ~= "" and ("mailto:" .. recipient) or "mailto:" +jarvis.system.open(uri) + +if recipient ~= "" then + return jarvis.cmd.ok("Открываю письмо для " .. target .. ".") +end +return jarvis.cmd.ok("Открываю почтовый клиент.")