106 lines
3.6 KiB
Lua
106 lines
3.6 KiB
Lua
|
|
-- "Википедия Эйнштейн" → fetch ru.wikipedia.org/api/rest_v1/page/summary/<topic>
|
|||
|
|
-- Falls back to LLM if Wikipedia doesn't have the article.
|
|||
|
|
local phrase = (jarvis.context.phrase or "")
|
|||
|
|
|
|||
|
|
local query = jarvis.text.strip_trigger(phrase:lower(), {
|
|||
|
|
"найди в википедии про",
|
|||
|
|
"найди в википедии",
|
|||
|
|
"что говорит википедия",
|
|||
|
|
"поищи в википедии",
|
|||
|
|
"статья из википедии",
|
|||
|
|
"википедия про",
|
|||
|
|
"википедия о",
|
|||
|
|
"википедия",
|
|||
|
|
"расскажи про",
|
|||
|
|
"что такое",
|
|||
|
|
"кто такая",
|
|||
|
|
"кто такой",
|
|||
|
|
"look up in wikipedia",
|
|||
|
|
"wikipedia article on",
|
|||
|
|
"wikipedia about",
|
|||
|
|
"wikipedia",
|
|||
|
|
"tell me about",
|
|||
|
|
"what is",
|
|||
|
|
"who is",
|
|||
|
|
"знайди у вікіпедії",
|
|||
|
|
"вікіпедія",
|
|||
|
|
"що таке",
|
|||
|
|
"хто такий",
|
|||
|
|
"розкажи про",
|
|||
|
|
})
|
|||
|
|
query = query:gsub("^[%s,:%.]+", ""):gsub("%s+$", "")
|
|||
|
|
|
|||
|
|
if query == "" then
|
|||
|
|
return jarvis.cmd.error("Какая статья?")
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
-- Wikipedia title needs underscores for spaces. Capitalize first letter of each word
|
|||
|
|
-- to match canonical titles (good enough heuristic).
|
|||
|
|
local title = query:gsub("(%S+)", function(w)
|
|||
|
|
-- Capitalize first byte (works for ASCII; for cyrillic, leave alone).
|
|||
|
|
local first = w:sub(1, 1)
|
|||
|
|
if first:match("[%a]") then
|
|||
|
|
return first:upper() .. w:sub(2)
|
|||
|
|
end
|
|||
|
|
return w
|
|||
|
|
end):gsub(" ", "_")
|
|||
|
|
|
|||
|
|
local function urlencode(s)
|
|||
|
|
return (s:gsub("[^A-Za-z0-9%-_%.~]", function(c)
|
|||
|
|
return string.format("%%%02X", string.byte(c))
|
|||
|
|
end))
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
-- Try Russian first, fall back to English.
|
|||
|
|
local lang_chain = { "ru", "en" }
|
|||
|
|
local data, source_lang
|
|||
|
|
|
|||
|
|
for _, lang in ipairs(lang_chain) do
|
|||
|
|
local url = string.format("https://%s.wikipedia.org/api/rest_v1/page/summary/%s",
|
|||
|
|
lang, urlencode(title))
|
|||
|
|
local d = jarvis.http.json(url)
|
|||
|
|
if d and d.extract and d.extract ~= "" then
|
|||
|
|
data = d
|
|||
|
|
source_lang = lang
|
|||
|
|
break
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
if not data then
|
|||
|
|
-- last resort: ask LLM directly
|
|||
|
|
local llm_answer = jarvis.llm({
|
|||
|
|
{ role = "system", content = "Кратко (2-3 предложения) на русском объясни тему. Если не знаешь — скажи." },
|
|||
|
|
{ role = "user", content = "Расскажи про: " .. query }
|
|||
|
|
}, { max_tokens = 200, temperature = 0.3 })
|
|||
|
|
if llm_answer and llm_answer ~= "" then
|
|||
|
|
return jarvis.cmd.ok(llm_answer)
|
|||
|
|
end
|
|||
|
|
return jarvis.cmd.not_found("В Википедии нет статьи про " .. query .. ".")
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
local extract = data.extract
|
|||
|
|
local title_actual = data.title or query
|
|||
|
|
|
|||
|
|
-- Truncate extract to ~3 sentences for spoken output
|
|||
|
|
local sentences = {}
|
|||
|
|
for sentence in extract:gmatch("[^%.%!%?]+[%.%!%?]") do
|
|||
|
|
table.insert(sentences, sentence)
|
|||
|
|
if #sentences >= 3 then break end
|
|||
|
|
end
|
|||
|
|
local spoken = #sentences > 0 and table.concat(sentences) or extract:sub(1, 400)
|
|||
|
|
|
|||
|
|
if source_lang == "en" then
|
|||
|
|
-- Translate English extract to Russian via LLM (no point in speaking English
|
|||
|
|
-- through a Russian voice).
|
|||
|
|
local translated = jarvis.llm({
|
|||
|
|
{ role = "system", content = "Переведи английский текст на русский, без вводных и комментариев." },
|
|||
|
|
{ role = "user", content = spoken }
|
|||
|
|
}, { max_tokens = 300, temperature = 0.0 })
|
|||
|
|
if translated and translated ~= "" then
|
|||
|
|
spoken = translated
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
jarvis.system.notify("Wikipedia: " .. title_actual, spoken:sub(1, 200))
|
|||
|
|
return jarvis.cmd.ok(spoken)
|