use reqwest::{header::{HeaderMap, HeaderValue}, Client};
use serde::{Deserialize, Serialize};
use crate::models::tools::*;
#[derive(Serialize)]
struct ChatCompletion {
model: String,
messages: Vec<Message>,
temperature: f32,
tools: Option<Vec<Tool>>,
}
#[derive(Deserialize)]
struct APIResponse {
choices: Vec<Choice>,
}
pub async fn generate(
base_url: String,
api_key: String,
model: String,
temperature: f32,
messages: Vec<Message>
) -> Result<String, reqwest::Error> {
generate_with_tools(base_url, api_key, model, temperature, messages, None).await
}
pub async fn generate_with_tools(
base_url: String,
api_key: String,
model: String,
temperature: f32,
messages: Vec<Message>,
tools: Option<Vec<Tool>>
) -> Result<String, reqwest::Error> {
let content_type: &str = "application/json";
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
HeaderValue::from_str(&format!("Bearer {}", api_key))
.expect("Failed to add api key to Bearer"),
);
headers.insert(
"content-type",
HeaderValue::from_str(content_type).expect("Failed to add content-type")
);
let client = Client::builder().default_headers(headers).build().expect("Can't build client");
let chat_completion = ChatCompletion {
model,
messages,
temperature,
tools,
};
let response = client
.post(base_url)
.json(&chat_completion)
.send()
.await?;
let res: APIResponse = response.json().await?;
if let Some(choice) = res.choices.first() {
if let Some(content) = &choice.message.content {
return Ok(content.clone());
}
}
Ok(String::new())
}
pub async fn generate_full_response(
base_url: String,
api_key: String,
model: String,
temperature: f32,
messages: Vec<Message>,
tools: Option<Vec<Tool>>
) -> Result<LLMResponse, String> {
let content_type: &str = "application/json";
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
HeaderValue::from_str(&format!("Bearer {}", api_key))
.map_err(|e| format!("Failed to create auth header: {}", e))?,
);
headers.insert(
"content-type",
HeaderValue::from_str(content_type)
.map_err(|e| format!("Failed to create content-type header: {}", e))?
);
let client = Client::builder()
.default_headers(headers)
.build()
.map_err(|e| format!("Failed to create HTTP client: {}", e))?;
let chat_completion = ChatCompletion {
model,
messages,
temperature,
tools,
};
let response = client
.post(base_url)
.json(&chat_completion)
.send()
.await
.map_err(|e| format!("HTTP request failed: {}", e))?;
if !response.status().is_success() {
let status_code = response.status();
let error_text = response.text().await.unwrap_or_else(|_| "No error details".to_string());
return Err(format!("API request failed with status {}: {}", status_code, error_text));
}
let res: LLMResponse = response.json()
.await
.map_err(|e| format!("Failed to parse JSON response: {}", e))?;
Ok(res)
}