J.A.R.V.I.S-rust/resources/commands/ocr/read_screen.lua
Bossiara13 69a38b0d89 feat: LLM auto-fallback + codegen pack + OCR pack
LLM auto-fallback (jarvis-app/src/app.rs + jarvis-core/src/config.rs):
- When neither intent classifier nor levenshtein finds a command match,
  route the utterance straight to the LLM instead of just playing the
  "not found" sound. Triggers ("скажи X", "answer Y") still work and
  take precedence — they short-circuit before command lookup.
- Two new config knobs:
    LLM_AUTO_FALLBACK = true        — master toggle
    LLM_AUTO_FALLBACK_MIN_CHARS = 4 — suppress for very short utterances
                                       so background noise doesn't burn
                                       Groq quota
- Requires GROQ_TOKEN; if absent, behaviour is unchanged (play_not_found).

codegen/ command pack:
- Phrases: "напиши код X", "сгенерируй скрипт Y", "write code Z", etc.
- Strips the trigger from the recognized phrase, sends what remains to
  Groq with a strict system prompt ("return ONLY code, no fences, no
  commentary") at temperature 0.2.
- Parses the JSON content, unescapes \n / \" / \\ / \t, strips any
  remaining ```lang ... ``` fences, drops the result into the clipboard
  via jarvis.system.clipboard.set.
- Notifies a 120-char preview + plays ok-sound. Works for any language
  the model handles (Python by default if unspecified).
- GROQ_TOKEN / GROQ_MODEL / GROQ_BASE_URL read from env at call time —
  same envvars the voice-loop fallback already uses.

ocr/ command pack:
- Phrases: "прочитай экран", "что на экране", "read screen", etc.
- Captures the primary screen via System.Windows.Forms + System.Drawing
  to a temp PNG, then shells to tesseract.exe (-l rus+eng for ru/ua,
  -l eng for en).
- Resolves Tesseract by PATH first, then C:\Program Files\Tesseract-OCR
  and the x86 install dir; if none works the user gets a friendly
  "winget install UB-Mannheim.TesseractOCR" hint in a notification.
- Recognized text goes to clipboard + a 200-char preview notification.

All three features are portable (env-var resolution, no hardcoded user
paths). Command-pack total is now 11. cargo test -p jarvis-core --lib
commands::tests passes 3/3.
2026-05-15 01:39:21 +03:00

82 lines
3.2 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 temp = jarvis.system.env("TEMP") or jarvis.system.env("TMP") or "C:\\Windows\\Temp"
local ts = jarvis.context.time.year .. jarvis.context.time.month .. jarvis.context.time.day
.. "_" .. jarvis.context.time.hour .. jarvis.context.time.minute .. jarvis.context.time.second
local img = temp .. "\\jarvis_ocr_" .. ts .. ".png"
local capture_ps = string.format(
[[Add-Type -AssemblyName System.Windows.Forms,System.Drawing; $b=[System.Windows.Forms.Screen]::PrimaryScreen.Bounds; $bmp=New-Object Drawing.Bitmap $b.Width,$b.Height; $g=[Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($b.Location,[Drawing.Point]::Empty,$b.Size); $bmp.Save('%s'); $g.Dispose(); $bmp.Dispose()]],
img:gsub("\\", "\\\\")
)
local capture_cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -Command "%s"', capture_ps:gsub('"', '\\"'))
local cap = jarvis.system.exec(capture_cmd)
if not cap.success or not jarvis.fs.exists(img) then
jarvis.log("error", "screen capture failed: " .. tostring(cap.stderr))
jarvis.system.notify("OCR", lang == "ru" and "Не смог снять экран" or "Could not capture screen")
jarvis.audio.play_error()
return { chain = false }
end
local tesseract_paths = {
"tesseract.exe",
"C:\\Program Files\\Tesseract-OCR\\tesseract.exe",
"C:\\Program Files (x86)\\Tesseract-OCR\\tesseract.exe",
}
local tess = nil
for _, p in ipairs(tesseract_paths) do
local check
if p == "tesseract.exe" then
check = jarvis.system.exec("where tesseract.exe")
else
check = { success = jarvis.fs.exists(p), stdout = p }
end
if check.success and (check.stdout or ""):gsub("[\r\n]+$", "") ~= "" then
tess = p == "tesseract.exe" and "tesseract.exe" or '"' .. p .. '"'
break
end
end
if not tess then
jarvis.log("error", "tesseract not found")
jarvis.system.notify(
"OCR",
lang == "ru"
and "Tesseract не установлен. Установи: winget install UB-Mannheim.TesseractOCR"
or "Tesseract not installed. Install: winget install UB-Mannheim.TesseractOCR"
)
jarvis.audio.play_error()
return { chain = false }
end
local langs = lang == "en" and "eng" or "rus+eng"
local ocr_cmd = string.format('%s "%s" - -l %s', tess, img, langs)
local ocr = jarvis.system.exec(ocr_cmd)
if not ocr.success then
jarvis.log("error", "tesseract failed: " .. tostring(ocr.stderr):sub(1, 200))
jarvis.system.notify("OCR", lang == "ru" and "Tesseract упал" or "Tesseract failed")
jarvis.audio.play_error()
return { chain = false }
end
local text = (ocr.stdout or ""):gsub("^%s+", ""):gsub("%s+$", "")
if text == "" then
jarvis.system.notify("OCR", lang == "ru" and "Текста не найдено" or "No text found")
jarvis.audio.play_not_found()
return { chain = false }
end
jarvis.system.clipboard.set(text)
jarvis.log("info", "OCR result (" .. #text .. " bytes) copied to clipboard")
local preview = text:gsub("\r?\n", " "):sub(1, 200)
if #text > 200 then preview = preview .. "..." end
jarvis.system.notify(
lang == "ru" and "Текст с экрана" or "Screen text",
preview
)
jarvis.audio.play_ok()
return { chain = false }