Skip to content

Commit 51ee25c

Browse files
committed
chore: ai tag api endpoint
1 parent ee16f42 commit 51ee25c

File tree

9 files changed

+150
-28
lines changed

9 files changed

+150
-28
lines changed

libs/appflowy-ai-client/src/client.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::dto::{
22
ChatAnswer, ChatQuestion, CompleteTextResponse, CompletionType, Document, MessageData,
3-
RepeatedRelatedQuestion, SearchDocumentsRequest, SummarizeRowResponse, TranslateRowData,
4-
TranslateRowResponse,
3+
RepeatedRelatedQuestion, SearchDocumentsRequest, SummarizeRowResponse, TagRowData,
4+
TagRowResponse, TranslateRowData, TranslateRowResponse,
55
};
66
use crate::error::AIError;
77

@@ -97,6 +97,18 @@ impl AppFlowyAIClient {
9797
.into_data()
9898
}
9999

100+
pub async fn tag_row(&self, data: TagRowData) -> Result<TagRowResponse, AIError> {
101+
let url = format!("{}/tag_row", self.url);
102+
let resp = self
103+
.http_client(Method::POST, &url)?
104+
.json(&data)
105+
.send()
106+
.await?;
107+
AIResponse::<TagRowResponse>::from_response(resp)
108+
.await?
109+
.into_data()
110+
}
111+
100112
pub async fn index_documents(&self, documents: &[Document]) -> Result<(), AIError> {
101113
let url = format!("{}/index_documents", self.url);
102114
let resp = self

libs/appflowy-ai-client/src/dto.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ pub struct TranslateRowParams {
9797
pub data: TranslateRowData,
9898
}
9999

100+
#[derive(Clone, Debug, Serialize, Deserialize)]
101+
pub struct TagRowParams {
102+
pub workspace_id: String,
103+
pub data: TagRowData,
104+
}
105+
100106
/// Represents different types of content that can be used to summarize a database row.
101107
#[derive(Clone, Debug, Serialize, Deserialize)]
102108
pub struct TranslateRowData {
@@ -114,3 +120,21 @@ pub struct TranslateItem {
114120
pub struct TranslateRowResponse {
115121
pub items: Vec<HashMap<String, String>>,
116122
}
123+
124+
#[derive(Clone, Debug, Serialize, Deserialize)]
125+
pub struct TagRowData {
126+
pub existing_tags: Vec<String>,
127+
pub items: Vec<TagItem>,
128+
pub num_tags: i32,
129+
}
130+
131+
#[derive(Clone, Debug, Serialize, Deserialize)]
132+
pub struct TagItem {
133+
pub title: String,
134+
pub content: String,
135+
}
136+
137+
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
138+
pub struct TagRowResponse {
139+
pub tags: Vec<String>,
140+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
mod summarize_test;
2+
mod tag_test;
23
mod translate_test;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use crate::appflowy_ai_client;
2+
3+
use appflowy_ai_client::dto::{TagItem, TagRowData};
4+
5+
#[tokio::test]
6+
async fn translate_row_test() {
7+
let client = appflowy_ai_client();
8+
9+
let mut items = Vec::new();
10+
for (key, value) in [("book name", "Atomic Habits"), ("author", "James Clear")].iter() {
11+
items.push(TagItem {
12+
title: key.to_string(),
13+
content: value.to_string(),
14+
});
15+
}
16+
17+
let data = TagRowData {
18+
existing_tags: vec![],
19+
items,
20+
num_tags: 3,
21+
};
22+
23+
let result = client.tag_row(data).await.unwrap();
24+
assert_eq!(result.tags.len(), 3);
25+
}

libs/client-api/src/http_ai.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::http::log_request_id;
22
use crate::Client;
33
use reqwest::Method;
44
use shared_entity::dto::ai_dto::{
5-
CompleteTextParams, CompleteTextResponse, SummarizeRowParams, SummarizeRowResponse,
6-
TranslateRowParams, TranslateRowResponse,
5+
CompleteTextParams, CompleteTextResponse, SummarizeRowParams, SummarizeRowResponse, TagRowParams,
6+
TagRowResponse, TranslateRowParams, TranslateRowResponse,
77
};
88
use shared_entity::response::{AppResponse, AppResponseError};
99
use tracing::instrument;
@@ -55,6 +55,22 @@ impl Client {
5555
.into_data()
5656
}
5757

58+
#[instrument(level = "info", skip_all)]
59+
pub async fn tag_row(&self, params: TagRowParams) -> Result<TagRowResponse, AppResponseError> {
60+
let url = format!("{}/api/ai/{}/tag_row", self.base_url, params.workspace_id);
61+
62+
let resp = self
63+
.http_client_with_auth(Method::POST, &url)
64+
.await?
65+
.json(&params)
66+
.send()
67+
.await?;
68+
69+
log_request_id(&resp);
70+
AppResponse::<TagRowResponse>::from_response(resp)
71+
.await?
72+
.into_data()
73+
}
5874
#[instrument(level = "info", skip_all)]
5975
pub async fn completion_text(
6076
&self,

src/api/ai.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use crate::state::AppState;
22
use actix_web::web::{Data, Json};
33
use actix_web::{web, Scope};
44
use app_error::AppError;
5-
use appflowy_ai_client::dto::{CompleteTextResponse, TranslateRowParams, TranslateRowResponse};
5+
use appflowy_ai_client::dto::{
6+
CompleteTextResponse, TagRowParams, TagRowResponse, TranslateRowParams, TranslateRowResponse,
7+
};
68
use shared_entity::dto::ai_dto::{
79
CompleteTextParams, SummarizeRowData, SummarizeRowParams, SummarizeRowResponse,
810
};
@@ -14,6 +16,7 @@ pub fn ai_completion_scope() -> Scope {
1416
.service(web::resource("/complete_text").route(web::post().to(complete_text_handler)))
1517
.service(web::resource("/summarize_row").route(web::post().to(summarize_row_handler)))
1618
.service(web::resource("/translate_row").route(web::post().to(translate_row_handler)))
19+
.service(web::resource("/tag_row").route(web::post().to(tag_row_handler)))
1720
}
1821

1922
async fn complete_text_handler(
@@ -85,3 +88,23 @@ async fn translate_row_handler(
8588
},
8689
}
8790
}
91+
92+
#[instrument(level = "debug", skip(state, payload), err)]
93+
async fn tag_row_handler(
94+
state: web::Data<AppState>,
95+
payload: web::Json<TagRowParams>,
96+
) -> actix_web::Result<Json<AppResponse<TagRowResponse>>> {
97+
let params = payload.into_inner();
98+
99+
match state.ai_client.tag_row(params.data).await {
100+
Ok(resp) => Ok(AppResponse::Ok().with_data(resp).into()),
101+
Err(err) => {
102+
error!("Failed to tag row: {:?}", err);
103+
Ok(
104+
AppResponse::Ok()
105+
.with_data(TagRowResponse::default())
106+
.into(),
107+
)
108+
},
109+
}
110+
}

tests/ai_test/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
mod chat_test;
22
mod complete_text;
3-
mod summarize_row;
3+
mod tool_test;

tests/ai_test/summarize_row.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/ai_test/tool_test.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use appflowy_ai_client::dto::{TagItem, TagRowData, TagRowParams};
2+
use client_api_test::TestClient;
3+
use serde_json::json;
4+
use shared_entity::dto::ai_dto::{SummarizeRowData, SummarizeRowParams};
5+
6+
#[tokio::test]
7+
async fn summarize_row_test() {
8+
let test_client = TestClient::new_user().await;
9+
let workspace_id = test_client.workspace_id().await;
10+
11+
let params = SummarizeRowParams {
12+
workspace_id: workspace_id.clone(),
13+
data: SummarizeRowData::Content(
14+
json!({"name": "Jack", "age": 25, "city": "New York"})
15+
.as_object()
16+
.unwrap()
17+
.clone(),
18+
),
19+
};
20+
21+
let resp = test_client.api_client.summarize_row(params).await.unwrap();
22+
assert!(!resp.text.is_empty());
23+
}
24+
#[tokio::test]
25+
async fn tag_row_test() {
26+
let test_client = TestClient::new_user().await;
27+
let workspace_id = test_client.workspace_id().await;
28+
29+
let params = TagRowParams {
30+
workspace_id: workspace_id.clone(),
31+
data: TagRowData {
32+
existing_tags: vec![],
33+
items: vec![TagItem {
34+
title: "Atomic habits".to_string(),
35+
content: "Atomic Habits by James Clear discusses how small, consistent changes in habits can lead to significant improvements over time. The book provides strategies for building good habits and breaking bad ones, emphasizing the importance of making tiny adjustments that compound into remarkable results. Clear introduces the concepts of habit stacking, the two-minute rule, and the four laws of behavior change: making habits obvious, attractive, easy, and satisfying".to_string(),
36+
}],
37+
num_tags: 5,
38+
},
39+
};
40+
41+
let resp = test_client.api_client.tag_row(params).await.unwrap();
42+
assert_eq!(resp.tags.len(), 5);
43+
}

0 commit comments

Comments
 (0)