J.A.R.V.I.S-rust/resources/commands/math/math.lua
Bossiara13 100db82bd6 feat(commands): tier-1 — translate, math, theme toggle, project opener, sound panel
Five more portable Lua command packs. Bumps the total from 16 to 21
packs. cargo test -p jarvis-core --lib commands::tests still 3/3.

translate/ — translate.lua. Picks the target language from triggers
like "переведи на английский" / "translate to russian"; falls back to
English when only "переведи X" is heard. Sends to Groq with a strict
"translation only" system prompt at temp 0.3. Drops the result into
the clipboard, fires a notify, and speaks via PowerShell SAPI in the
matching ISO voice (ru-RU / uk-UA / en-US / de-DE etc.) so a German
translation actually sounds German.

math/ — math.lua. Strips the trigger ("посчитай" / "calculate" /
"сколько будет" / "what is" / ...), sends the remainder to Groq with
temp=0.0 and max_tokens=64, asking ONLY for the numeric result. If
the model replies "нет" (the system-prompt sentinel for non-math),
plays not_found instead of speaking nonsense. Otherwise speaks
"Получилось X" via SAPI.

theme/ — set.lua dispatched by command_id (theme_dark / theme_light).
Flips AppsUseLightTheme + SystemUsesLightTheme under
HKCU\...\Themes\Personalize via Set-ItemProperty. No reboot needed,
Windows shell re-themes immediately.

projects/ — open.lua + list.lua. Reads/creates
%USERPROFILE%\Documents\jarvis-projects.json (a flat
[{"name": ..., "path": ...}] list). open.lua strips the trigger,
exact-matches then substring-matches the project name, opens the path
in VS Code if `code.cmd` is on PATH, otherwise in Explorer. First
call creates a sample config with jarvis-rust / jarvis-python /
dietpi entries pointing under USERPROFILE so it works on any machine.
list.lua just notifies the configured project names.

sound_panel/ — open.lua. Two-liner: rundll32 mmsys.cpl,,1 (Recording
tab). Useful both as a standalone "открой настройки звука" and as
the place to fix the mic-disabled state that prevents jarvis-app
from starting.

Portability: USERPROFILE / SystemDrive / PATH lookup throughout.
2026-05-15 12:06:30 +03:00

87 lines
3.5 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local lang = jarvis.context.language
local phrase = (jarvis.context.phrase or ""):lower()
local triggers = {
"сколько будет", "сколько это", "посчитай", "вычисли", "реши",
"how much is", "calculate", "compute", "solve", "what is",
"скільки буде", "порахуй", "обчисли",
}
local query = phrase
for _, t in ipairs(triggers) do
local s, e = string.find(query, t, 1, true)
if s == 1 then
query = query:sub(e + 1)
break
end
end
query = query:gsub("^%s+", ""):gsub("%s+$", "")
if query == "" then
jarvis.system.notify("Math", lang == "ru" and "Что посчитать?" or "What to compute?")
jarvis.audio.play_error()
return { chain = false }
end
local token = jarvis.system.env("GROQ_TOKEN")
if not token or token == "" then
jarvis.system.notify("Math", "GROQ_TOKEN не задан")
jarvis.audio.play_error()
return { chain = false }
end
local base = jarvis.system.env("GROQ_BASE_URL"); if not base or base == "" then base = "https://api.groq.com/openai/v1" end
local model = jarvis.system.env("GROQ_MODEL"); if not model or model == "" then model = "llama-3.3-70b-versatile" end
local sys = "Ты калькулятор. Решай арифметику, простые уравнения, конверсии единиц, проценты. "
.. "Отвечай ТОЛЬКО результатом числом или короткой строкой (для уравнений — значения корней). "
.. "Если запрос — не математика, ответь одним словом «нет»."
local payload = {
model = model,
messages = {
{ role = "system", content = sys },
{ role = "user", content = query },
},
max_tokens = 64,
temperature = 0.0,
}
jarvis.log("info", "math query: " .. query)
local res = jarvis.http.post_json(base .. "/chat/completions", payload, { Authorization = "Bearer " .. token })
if not res.ok then
jarvis.log("error", "math api failed: " .. tostring(res.status))
jarvis.system.notify("Math", "Ошибка API")
jarvis.audio.play_error()
return { chain = false }
end
local body = res.body or ""
local content = body:match('"content"%s*:%s*"(.-[^\\])"')
if not content then
jarvis.system.notify("Math", "Не смог распарсить ответ")
jarvis.audio.play_error()
return { chain = false }
end
content = content:gsub('\\n', '\n'):gsub('\\"', '"'):gsub('\\\\', '\\'):gsub('\\t', '\t')
content = content:gsub("^%s+", ""):gsub("%s+$", "")
if content:lower() == "нет" or content == "" then
jarvis.system.notify("Math", lang == "ru" and "Это не математика" or "Not math")
jarvis.audio.play_not_found()
return { chain = false }
end
jarvis.system.notify(query, content)
jarvis.log("info", "math result: " .. content)
local sapi_text = ((lang == "ru" and "Получилось " or "Result: ") .. content):gsub("'", "''"):gsub("\r?\n", " ")
local ps = string.format(
[[Add-Type -AssemblyName System.Speech; $s = New-Object System.Speech.Synthesis.SpeechSynthesizer; foreach ($v in $s.GetInstalledVoices()) { if ($v.VoiceInfo.Culture.TwoLetterISOLanguageName -eq 'ru') { try { $s.SelectVoice($v.VoiceInfo.Name); break } catch {} } } $s.Speak('%s')]],
sapi_text
)
jarvis.system.exec(string.format('powershell -NoProfile -ExecutionPolicy Bypass -Command "%s"', ps:gsub('"', '\\"')))
jarvis.audio.play_ok()
return { chain = false }