-- "Сколько будет 1000 долларов в рублях" / "переведи 50 евро в доллары" -- Uses cbr-xml-daily.ru (CBR daily rates, JSON, no key, mirrors RU central bank). local phrase = (jarvis.context.phrase or ""):lower() -- Strip trigger words local body = phrase:gsub("сколько будет", "") :gsub("переведи", "") :gsub("конвертируй", "") :gsub("convert", "") :gsub("how much is", "") :gsub("^[%s,:%.]+", "") :gsub("%s+$", "") -- Extract amount (digit or russian "сто", "тысяча" — keep simple, digits only) local amount_str = body:match("([%d%.,]+)") if not amount_str then jarvis.speak("Не понял сумму.") jarvis.audio.play_error() return { chain = false } end local amount = tonumber((amount_str:gsub(",", "."))) if not amount then jarvis.speak("Не понял сумму.") jarvis.audio.play_error() return { chain = false } end -- Detect source + target currencies via heuristic substring matches. local function detect(text) if text:find("доллар") or text:find("usd") or text:find("dollar") then return "USD" end if text:find("евро") or text:find("eur") or text:find("euro") then return "EUR" end if text:find("юан") or text:find("cny") or text:find("yuan") then return "CNY" end if text:find("фунт") or text:find("gbp") or text:find("pound") then return "GBP" end if text:find("иен") or text:find("jpy") or text:find("yen") then return "JPY" end if text:find("рубл") or text:find("rub") or text:find("ruble") then return "RUB" end return nil end -- Split on the conversion word "в"/"в"/"to"/"into" to detect from/to. local from_part, to_part local in_idx = body:find("%s+в%s+") or body:find("%s+to%s+") or body:find("%s+into%s+") if in_idx then from_part = body:sub(1, in_idx - 1) to_part = body:sub(in_idx + 1) else -- Heuristic: only one currency named → assume target RUB. from_part = body to_part = "рубли" end local from_ccy = detect(from_part) local to_ccy = detect(to_part) or "RUB" if not from_ccy then jarvis.speak("Не понял исходную валюту.") jarvis.audio.play_error() return { chain = false } end -- Fetch CBR rates (RUB-denominated). local body_json = jarvis.http.get("https://www.cbr-xml-daily.ru/daily_json.js") if not body_json or body_json == "" then jarvis.speak("Не получилось получить курсы.") jarvis.audio.play_error() return { chain = false } end -- We can't safely parse JSON without a Lua JSON lib. Use jarvis.http.json instead. local data = jarvis.http.json("https://www.cbr-xml-daily.ru/daily_json.js") if not data or not data.Valute then jarvis.speak("Не получилось разобрать ответ.") jarvis.audio.play_error() return { chain = false } end -- Each Valute entry: { Value=rub_per_unit, Nominal=N }. Effective rub_per_unit = Value/Nominal. local function rub_per(ccy) if ccy == "RUB" then return 1.0 end local v = data.Valute[ccy] if not v then return nil end return v.Value / v.Nominal end local rub_from = rub_per(from_ccy) local rub_to = rub_per(to_ccy) if not rub_from or not rub_to then jarvis.speak("Этой валюты нет в курсах ЦБ.") jarvis.audio.play_error() return { chain = false } end local result = amount * rub_from / rub_to -- Format pretty local function fmt(n) if n >= 1000 then return string.format("%d", math.floor(n + 0.5)) elseif n >= 10 then return string.format("%.1f", n) else return string.format("%.2f", n) end end local function unit(ccy, n) if ccy == "RUB" then return (n == 1 and "рубль" or (n < 5 and "рубля" or "рублей")) end if ccy == "USD" then return (n == 1 and "доллар" or (n < 5 and "доллара" or "долларов")) end if ccy == "EUR" then return "евро" end if ccy == "CNY" then return (n == 1 and "юань" or (n < 5 and "юаня" or "юаней")) end if ccy == "GBP" then return (n == 1 and "фунт" or (n < 5 and "фунта" or "фунтов")) end if ccy == "JPY" then return "иен" end return ccy end local result_int = math.floor(result + 0.5) local line = string.format("%s %s — это %s %s.", fmt(amount), unit(from_ccy, amount), fmt(result), unit(to_ccy, result_int)) jarvis.speak(line) jarvis.audio.play_ok() return { chain = false }