local lang = jarvis.context.language local phrase = (jarvis.context.phrase or ""):lower() local triggers = { "поставь напоминание через", "установи таймер на", "напомни мне через", "напомни через", "напомни", "remind me in", "set reminder in", "set timer for", "timer for", "постав нагадування через", "нагадай через", "таймер на", } local rest = phrase for _, t in ipairs(triggers) do local s, e = string.find(rest, t, 1, true) if s == 1 then rest = rest:sub(e + 1) break end end rest = rest:gsub("^%s+", "") local unit_words = { ["секунд"] = 1, ["секунду"] = 1, ["секунды"] = 1, ["second"] = 1, ["seconds"] = 1, ["sec"] = 1, ["минут"] = 60, ["минуту"] = 60, ["минуты"] = 60, ["мин"] = 60, ["minute"] = 60, ["minutes"] = 60, ["min"] = 60, ["час"] = 3600, ["часа"] = 3600, ["часов"] = 3600, ["часик"] = 3600, ["hour"] = 3600, ["hours"] = 3600, ["hr"] = 3600, } local rus_numerals = { ["один"] = 1, ["одну"] = 1, ["одна"] = 1, ["полторы"] = 1, ["полтора"] = 1, ["два"] = 2, ["две"] = 2, ["три"] = 3, ["четыре"] = 4, ["пять"] = 5, ["шесть"] = 6, ["семь"] = 7, ["восемь"] = 8, ["девять"] = 9, ["десять"] = 10, ["пятнадцать"] = 15, ["двадцать"] = 20, ["тридцать"] = 30, ["сорок"] = 40, ["пятьдесят"] = 50, ["час"] = 60, -- "через час" without number } local number, unit, body = nil, nil, nil local num_str, rest_after_num = rest:match("^(%d+)%s+(.+)") if num_str then number = tonumber(num_str) rest = rest_after_num else local first_word, after = rest:match("^(%S+)%s*(.*)") if first_word and rus_numerals[first_word] then number = rus_numerals[first_word] rest = after or "" end end if rest and #rest > 0 then local first_word, after = rest:match("^(%S+)%s*(.*)") if first_word then for w, secs in pairs(unit_words) do if first_word:sub(1, #w) == w then unit = secs body = after or "" break end end end end if not number then number = 5 if not unit then unit = 60 end body = rest elseif not unit then unit = 60 body = rest end local total_seconds = number * unit if total_seconds < 1 then total_seconds = 1 end if total_seconds > 86400 then total_seconds = 86400 end body = (body or ""):gsub("^%s+", ""):gsub("%s+$", "") if body == "" then body = lang == "ru" and "Напоминание!" or "Reminder!" end local function human_time(sec) if sec < 60 then return sec .. " сек" end if sec < 3600 then return math.floor(sec/60) .. " мин" end return string.format("%d ч %d мин", math.floor(sec/3600), math.floor((sec%3600)/60)) end local title_esc = (lang == "ru" and "Напоминание J.A.R.V.I.S." or "J.A.R.V.I.S. reminder"):gsub("'", "''") local body_esc = body:gsub("'", "''") local sapi_text = ((lang == "ru" and "Сэр, напоминаю: " or "Reminder: ") .. body):gsub("'", "''"):gsub("\r?\n", " ") local ps = string.format( [[Start-Sleep -Seconds %d; ]] .. [[$null = New-Object -ComObject Shell.Application; ]] .. [[try { ]] .. [[ Import-Module BurntToast -ErrorAction SilentlyContinue; ]] .. [[ New-BurntToastNotification -Text '%s', '%s' -ErrorAction SilentlyContinue ]] .. [[} catch {}; ]] .. [[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'); ]] .. [[$wsh = New-Object -ComObject WScript.Shell; $wsh.Popup('%s', 30, '%s', 64) | Out-Null]], total_seconds, title_esc, body_esc, sapi_text, body_esc, title_esc ) local cmd = string.format( 'powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -Command "%s"', ps:gsub('"', '\\"') ) jarvis.system.exec("start /b " .. cmd) jarvis.system.notify( lang == "ru" and "Таймер установлен" or "Timer set", string.format(lang == "ru" and "Через %s: %s" or "In %s: %s", human_time(total_seconds), body) ) jarvis.log("info", string.format("reminder in %ds: %s", total_seconds, body)) jarvis.audio.play_ok() return { chain = false }