use crate::entity::{SummarizeRow, TranslateRow}; use crate::error::AIError; use reqwest::{Method, RequestBuilder}; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::borrow::Cow; #[derive(Clone, Debug)] pub struct AppFlowyAIClient { client: reqwest::Client, url: String, } impl AppFlowyAIClient { pub fn new(url: &str) -> Self { let url = url.to_string(); let client = reqwest::Client::new(); Self { client, url } } pub async fn summarize_row(&self, json: Value) -> Result { let url = format!("{}/summarize_row", self.url); let resp = self .http_client(Method::POST, &url)? .json(&json) .send() .await?; AIResponse::::from_response(resp) .await? .into_data() } pub async fn translate_row(&self, json: Value) -> Result { let url = format!("{}/translate_row", self.url); let resp = self .http_client(Method::POST, &url)? .json(&json) .send() .await?; AIResponse::::from_response(resp) .await? .into_data() } fn http_client(&self, method: Method, url: &str) -> Result { let request_builder = self.client.request(method, url); Ok(request_builder) } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AIResponse { #[serde(skip_serializing_if = "Option::is_none")] pub data: Option, #[serde(default)] pub message: Cow<'static, str>, } impl AIResponse where T: serde::de::DeserializeOwned + 'static, { pub async fn from_response(resp: reqwest::Response) -> Result { let status_code = resp.status(); if !status_code.is_success() { let body = resp.text().await?; anyhow::bail!("got error code: {}, body: {}", status_code, body) } let bytes = resp.bytes().await?; let resp = serde_json::from_slice(&bytes)?; Ok(resp) } pub fn into_data(self) -> Result { match self.data { None => Err(AIError::InvalidRequest("Empty payload".to_string())), Some(data) => Ok(data), } } }