From cd8ed8bc5793985df2c1692072a932ceee517b95 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 8 Jul 2026 02:13:35 +0200 Subject: OPEN THE RUST GATES Signed-off-by: salmonik --- src/openrouter/mod.rs | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/openrouter/mod.rs (limited to 'src/openrouter/mod.rs') diff --git a/src/openrouter/mod.rs b/src/openrouter/mod.rs new file mode 100644 index 0000000..31cee85 --- /dev/null +++ b/src/openrouter/mod.rs @@ -0,0 +1,134 @@ +use reqwest::Client; +use serde::{Deserialize, Serialize}; + +use crate::error::Result; +use crate::lang; + +pub struct OpenRouterClient { + api_key: String, + model: String, + client: Client, +} + +#[derive(Serialize)] +struct ChatRequest { + model: String, + messages: Vec, + max_tokens: u32, +} + +#[derive(Serialize)] +struct Message { + role: String, + content: String, +} + +#[derive(Deserialize)] +struct ChatResponse { + choices: Vec, +} + +#[derive(Deserialize)] +struct Choice { + message: MessageContent, +} + +#[derive(Deserialize)] +struct MessageContent { + content: String, +} + +impl OpenRouterClient { + pub fn new(api_key: String, model: String) -> Self { + Self { + api_key, + model, + client: Client::new(), + } + } + + pub async fn chat(&self, system_prompt: &str, user_message: &str) -> Result { + let body = ChatRequest { + model: self.model.clone(), + messages: vec![ + Message { + role: "system".into(), + content: system_prompt.to_string(), + }, + Message { + role: "user".into(), + content: user_message.to_string(), + }, + ], + max_tokens: 500, + }; + + let resp = self + .client + .post("https://openrouter.ai/api/v1/chat/completions") + .header("Authorization", format!("Bearer {}", self.api_key)) + .json(&body) + .send() + .await?; + + if !resp.status().is_success() { + let status = resp.status(); + let text = resp.text().await.unwrap_or_default(); + return Err(crate::error::Error::Custom(lang::fmt_openrouter_err( + &status, &text, + ))); + } + + let chat_resp: ChatResponse = resp.json().await?; + Ok(chat_resp + .choices + .into_iter() + .next() + .map(|c| c.message.content) + .unwrap_or_default()) + } + + pub async fn chat_with_history( + &self, + system_prompt: &str, + messages: Vec<(String, String)>, // (role, content) pairs + ) -> Result { + let mut msg_vec = vec![Message { + role: "system".into(), + content: system_prompt.to_string(), + }]; + for (role, content) in messages { + msg_vec.push(Message { role, content }); + } + + let body = ChatRequest { + model: self.model.clone(), + messages: msg_vec, + max_tokens: 500, + }; + + let resp = self + .client + .post("https://openrouter.ai/api/v1/chat/completions") + .header("Authorization", format!("Bearer {}", self.api_key)) + .json(&body) + .send() + .await?; + + if !resp.status().is_success() { + let status = resp.status(); + let text = resp.text().await.unwrap_or_default(); + return Err(crate::error::Error::Custom(lang::fmt_openrouter_err( + &status, &text, + ))); + } + + let chat_resp: ChatResponse = resp.json().await?; + Ok(chat_resp + .choices + .into_iter() + .next() + .map(|c| c.message.content) + .unwrap_or_default()) + } +} -- cgit v1.2.3