From ff4384fbd07a4b7394a9af8c9159cd65715d3471 Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:37:11 +0800 Subject: [PATCH] feat: translate api endpoint (#612) * chore: support translate * chore: support translate * chore: update endpoint structs --- libs/appflowy-ai-client/src/client.rs | 11 ++++--- libs/appflowy-ai-client/src/dto.rs | 30 +++++++++++++++---- libs/appflowy-ai-client/tests/row_test/mod.rs | 1 + .../tests/row_test/translate_test.rs | 25 ++++++++++++++++ libs/client-api/src/http_ai.rs | 24 +++++++++++++++ src/api/ai.rs | 23 +++++++++++++- 6 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 libs/appflowy-ai-client/tests/row_test/translate_test.rs diff --git a/libs/appflowy-ai-client/src/client.rs b/libs/appflowy-ai-client/src/client.rs index e9231c52..73aff13e 100644 --- a/libs/appflowy-ai-client/src/client.rs +++ b/libs/appflowy-ai-client/src/client.rs @@ -1,6 +1,7 @@ use crate::dto::{ ChatAnswer, ChatQuestion, CompleteTextResponse, CompletionType, Document, MessageData, - RepeatedRelatedQuestion, SearchDocumentsRequest, SummarizeRowResponse, TranslateRowResponse, + RepeatedRelatedQuestion, SearchDocumentsRequest, SummarizeRowResponse, TranslateRowData, + TranslateRowResponse, }; use crate::error::AIError; @@ -81,12 +82,14 @@ impl AppFlowyAIClient { .into_data() } - pub async fn translate_row(&self, json: Value) -> Result { + pub async fn translate_row( + &self, + data: TranslateRowData, + ) -> Result { let url = format!("{}/translate_row", self.url); - trace!("translate_row url: {}", url); let resp = self .http_client(Method::POST, &url)? - .json(&json) + .json(&data) .send() .await?; AIResponse::::from_response(resp) diff --git a/libs/appflowy-ai-client/src/dto.rs b/libs/appflowy-ai-client/src/dto.rs index 26b13467..6d2fa482 100644 --- a/libs/appflowy-ai-client/src/dto.rs +++ b/libs/appflowy-ai-client/src/dto.rs @@ -1,16 +1,12 @@ use serde::{Deserialize, Serialize, Serializer}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use std::collections::HashMap; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SummarizeRowResponse { pub text: String, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct TranslateRowResponse { - text: String, -} - #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ChatQuestion { pub chat_id: String, @@ -94,3 +90,27 @@ pub enum CollabType { UserAwareness = 5, Unknown = 6, } + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TranslateRowParams { + pub workspace_id: String, + pub data: TranslateRowData, +} + +/// Represents different types of content that can be used to summarize a database row. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TranslateRowData { + pub cells: Vec, + pub language: String, + pub include_header: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TranslateItem { + pub title: String, + pub content: String, +} +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct TranslateRowResponse { + pub items: Vec>, +} diff --git a/libs/appflowy-ai-client/tests/row_test/mod.rs b/libs/appflowy-ai-client/tests/row_test/mod.rs index d9fd84d6..26c481a7 100644 --- a/libs/appflowy-ai-client/tests/row_test/mod.rs +++ b/libs/appflowy-ai-client/tests/row_test/mod.rs @@ -1 +1,2 @@ mod summarize_test; +mod translate_test; diff --git a/libs/appflowy-ai-client/tests/row_test/translate_test.rs b/libs/appflowy-ai-client/tests/row_test/translate_test.rs new file mode 100644 index 00000000..075a51a8 --- /dev/null +++ b/libs/appflowy-ai-client/tests/row_test/translate_test.rs @@ -0,0 +1,25 @@ +use crate::appflowy_ai_client; + +use appflowy_ai_client::dto::{TranslateItem, TranslateRowData}; + +#[tokio::test] +async fn translate_row_test() { + let client = appflowy_ai_client(); + + let mut cells = Vec::new(); + for (key, value) in [("book name", "Atomic Habits"), ("author", "James Clear")].iter() { + cells.push(TranslateItem { + title: key.to_string(), + content: value.to_string(), + }); + } + + let data = TranslateRowData { + cells, + language: "Chinese".to_string(), + include_header: false, + }; + + let result = client.translate_row(data).await.unwrap(); + assert_eq!(result.items.len(), 2); +} diff --git a/libs/client-api/src/http_ai.rs b/libs/client-api/src/http_ai.rs index 6f78d0a3..44426c42 100644 --- a/libs/client-api/src/http_ai.rs +++ b/libs/client-api/src/http_ai.rs @@ -3,6 +3,7 @@ use crate::Client; use reqwest::Method; use shared_entity::dto::ai_dto::{ CompleteTextParams, CompleteTextResponse, SummarizeRowParams, SummarizeRowResponse, + TranslateRowParams, TranslateRowResponse, }; use shared_entity::response::{AppResponse, AppResponseError}; use tracing::instrument; @@ -31,6 +32,29 @@ impl Client { .into_data() } + #[instrument(level = "info", skip_all)] + pub async fn translate_row( + &self, + params: TranslateRowParams, + ) -> Result { + let url = format!( + "{}/api/ai/{}/translate_row", + self.base_url, params.workspace_id + ); + + let resp = self + .http_client_with_auth(Method::POST, &url) + .await? + .json(¶ms) + .send() + .await?; + + log_request_id(&resp); + AppResponse::::from_response(resp) + .await? + .into_data() + } + #[instrument(level = "info", skip_all)] pub async fn completion_text( &self, diff --git a/src/api/ai.rs b/src/api/ai.rs index ae0becac..ff42bb55 100644 --- a/src/api/ai.rs +++ b/src/api/ai.rs @@ -2,7 +2,7 @@ use crate::state::AppState; use actix_web::web::{Data, Json}; use actix_web::{web, Scope}; use app_error::AppError; -use appflowy_ai_client::dto::CompleteTextResponse; +use appflowy_ai_client::dto::{CompleteTextResponse, TranslateRowParams, TranslateRowResponse}; use shared_entity::dto::ai_dto::{ CompleteTextParams, SummarizeRowData, SummarizeRowParams, SummarizeRowResponse, }; @@ -13,6 +13,7 @@ pub fn ai_completion_scope() -> Scope { web::scope("/api/ai/{workspace_id}") .service(web::resource("/complete_text").route(web::post().to(complete_text_handler))) .service(web::resource("/summarize_row").route(web::post().to(summarize_row_handler))) + .service(web::resource("/translate_row").route(web::post().to(translate_row_handler))) } async fn complete_text_handler( @@ -64,3 +65,23 @@ async fn summarize_row_handler( }, } } + +#[instrument(level = "debug", skip(state, payload), err)] +async fn translate_row_handler( + state: web::Data, + payload: web::Json, +) -> actix_web::Result>> { + let params = payload.into_inner(); + + match state.ai_client.translate_row(params.data).await { + Ok(resp) => Ok(AppResponse::Ok().with_data(resp).into()), + Err(err) => { + error!("Failed to translate row: {:?}", err); + Ok( + AppResponse::Ok() + .with_data(TranslateRowResponse::default()) + .into(), + ) + }, + } +}