batuta/serve/banco/
handlers_conversations.rs1use axum::{extract::State, http::StatusCode, response::Json};
4
5use super::conversations::Conversation;
6use super::state::BancoState;
7use super::types::{
8 ConversationCreatedResponse, ConversationResponse, ConversationsListResponse,
9 CreateConversationRequest, ErrorResponse,
10};
11
12pub async fn create_conversation_handler(
13 State(state): State<BancoState>,
14 Json(request): Json<CreateConversationRequest>,
15) -> Json<ConversationCreatedResponse> {
16 let model = request.model.unwrap_or_else(|| "banco-echo".to_string());
17 let id = state.conversations.create(&model);
18
19 if let Some(title) = request.title {
20 if let Some(mut conv) = state.conversations.get(&id) {
21 conv.meta.title = title;
22 }
23 }
24
25 let conv = state.conversations.get(&id);
26 let title = conv.map(|c| c.meta.title).unwrap_or_else(|| "New conversation".to_string());
27 Json(ConversationCreatedResponse { id, title })
28}
29
30pub async fn list_conversations_handler(
31 State(state): State<BancoState>,
32) -> Json<ConversationsListResponse> {
33 Json(ConversationsListResponse { conversations: state.conversations.list() })
34}
35
36pub async fn get_conversation_handler(
37 State(state): State<BancoState>,
38 axum::extract::Path(id): axum::extract::Path<String>,
39) -> Result<Json<ConversationResponse>, (StatusCode, Json<ErrorResponse>)> {
40 state.conversations.get(&id).map(|c| Json(ConversationResponse { conversation: c })).ok_or((
41 StatusCode::NOT_FOUND,
42 Json(ErrorResponse::new(format!("Conversation {id} not found"), "not_found", 404)),
43 ))
44}
45
46pub async fn delete_conversation_handler(
47 State(state): State<BancoState>,
48 axum::extract::Path(id): axum::extract::Path<String>,
49) -> Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
50 state.conversations.delete(&id).map(|()| StatusCode::NO_CONTENT).map_err(|_| {
51 (
52 StatusCode::NOT_FOUND,
53 Json(ErrorResponse::new(format!("Conversation {id} not found"), "not_found", 404)),
54 )
55 })
56}
57
58pub async fn rename_conversation_handler(
60 State(state): State<BancoState>,
61 axum::extract::Path(id): axum::extract::Path<String>,
62 Json(request): Json<RenameRequest>,
63) -> Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
64 state.conversations.rename(&id, &request.title).map(|()| StatusCode::OK).map_err(|_| {
65 (
66 StatusCode::NOT_FOUND,
67 Json(ErrorResponse::new(format!("Conversation {id} not found"), "not_found", 404)),
68 )
69 })
70}
71
72#[derive(Debug, serde::Deserialize)]
73pub struct RenameRequest {
74 pub title: String,
75}
76
77pub async fn search_conversations_handler(
79 State(state): State<BancoState>,
80 axum::extract::Query(params): axum::extract::Query<SearchParams>,
81) -> Json<ConversationsListResponse> {
82 let results = state.conversations.search(¶ms.q.unwrap_or_default());
83 Json(ConversationsListResponse { conversations: results })
84}
85
86#[derive(Debug, serde::Deserialize)]
87pub struct SearchParams {
88 pub q: Option<String>,
89}
90
91pub async fn export_conversations_handler(
93 State(state): State<BancoState>,
94) -> Json<Vec<Conversation>> {
95 Json(state.conversations.export_all())
96}
97
98pub async fn import_conversations_handler(
100 State(state): State<BancoState>,
101 Json(conversations): Json<Vec<Conversation>>,
102) -> Json<serde_json::Value> {
103 let count = state.conversations.import_all(conversations);
104 Json(serde_json::json!({ "imported": count }))
105}