use foukoapi::genai::{ChatMessage, GenClient};
use foukoapi::{Bot, Embed, Platform, Reply, Result};
use std::sync::{Arc, Mutex};
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "info,foukoapi=debug".into()),
)
.init();
let url = std::env::var("GENAI_URL").unwrap_or_else(|_| "http://127.0.0.1:11434".into());
let key = std::env::var("GENAI_KEY").ok();
let model = std::env::var("GENAI_MODEL").unwrap_or_else(|_| "llama3.2".into());
let mut bot = Bot::new();
if let Ok(token) = std::env::var("TG_TOKEN") {
bot = bot.add_platform(Platform::telegram(token));
}
bot.command("/ask", move |ctx| {
let (url, key, model) = (url.clone(), key.clone(), model.clone());
async move {
let question = ctx.args().trim().to_owned();
if question.is_empty() {
return ctx.reply("usage: /ask <question>").await;
}
ctx.typing().await;
let text = Arc::new(Mutex::new(String::new()));
let editor = {
let (ctx, text) = (ctx.clone(), text.clone());
tokio::spawn(async move {
let mut shown = String::new();
loop {
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
let now = text.lock().unwrap().clone();
if !now.is_empty() && now != shown {
let _ = ctx.edit_reply(Reply::text(format!("{now} ..."))).await;
shown = now;
}
}
})
};
let client = GenClient::new(url, key);
let result = client
.chat_stream(&model, &[ChatMessage::user(question.as_str())], |so_far| {
*text.lock().unwrap() = so_far.to_owned();
})
.await;
editor.abort();
match result {
Ok(answer) => {
let embed = Embed::new()
.title("Answer")
.description(answer)
.footer(model);
ctx.edit_reply(Reply::embed(embed)).await
}
Err(e) => ctx.reply(format!("genai error: {e}")).await,
}
}
})
.run()
.await
}