use async_trait::async_trait;
use reqwest::Client;
use std::sync::Arc;
use tracing::{debug, error, info, trace};
use crate::{Chat, Message, ModelInfo, Result, provider::HTTPProvider};
#[async_trait]
pub trait LLMService<M: ModelInfo> {
async fn generate_next_message(&self, chat: &Chat) -> Result<Message>;
}
pub struct HTTPLlmService<M: ModelInfo> {
model: M,
provider: Arc<dyn HTTPProvider<M>>,
}
impl<M: ModelInfo> HTTPLlmService<M> {
pub fn new(model: M, provider: Arc<dyn HTTPProvider<M>>) -> Self {
HTTPLlmService { model, provider }
}
}
#[async_trait]
impl<M: ModelInfo> LLMService<M> for HTTPLlmService<M> {
async fn generate_next_message(&self, chat: &Chat) -> Result<Message> {
let client = Client::new();
let request = match self.provider.accept(self.model, chat) {
Ok(req) => {
debug!(
"Request created successfully: {} {}",
req.method(),
req.url()
);
trace!("Request headers: {:#?}", req.headers());
req
}
Err(e) => {
error!("Failed to create request: {}", e);
return Err(e);
}
};
debug!("Sending HTTP request");
let response = match client.execute(request).await {
Ok(resp) => {
info!("Received response with status: {}", resp.status());
trace!("Response headers: {:#?}", resp.headers());
resp
}
Err(e) => {
error!("HTTP request failed: {}", e);
return Err(e.into());
}
};
debug!("Reading response body");
let response_text = match response.text().await {
Ok(text) => {
trace!("Response body: {}", text);
text
}
Err(e) => {
error!("Failed to read response body: {}", e);
return Err(e.into());
}
};
debug!("Parsing response");
let message = match self.provider.parse(response_text) {
Ok(msg) => {
info!("Successfully parsed response into message");
debug!("Message role: {}", msg.role_str());
msg
}
Err(e) => {
error!("Failed to parse response: {}", e);
return Err(e);
}
};
Ok(message)
}
}