gitdataai/libs/api/chat/handlers/conversation.rs

182 lines
5.2 KiB
Rust

use actix_web::{HttpResponse, Result, web};
use service::error::AppError;
use session::Session;
use uuid::Uuid;
use crate::ApiResponse;
use crate::error::ApiError;
use super::types::{ConversationListQuery, ConversationResponse, CreateConversationParams};
fn get_user_id(session: &Session) -> Result<Uuid, ApiError> {
session
.user()
.ok_or_else(|| ApiError::from(AppError::Unauthorized))
}
#[utoipa::path(
post,
path = "/api/ai/conversations",
operation_id = "ai_conversation_create",
request_body = CreateConversationParams,
responses(
(status = 200, description = "Conversation created", body = ApiResponse<ConversationResponse>),
(status = 401, description = "Unauthorized"),
),
tag = "AI Chat"
)]
pub async fn conversation_create(
service: web::Data<service::AppService>,
session: Session,
params: web::Json<CreateConversationParams>,
) -> Result<HttpResponse, ApiError> {
let user_id = get_user_id(&session)?;
let model = params.model.clone().unwrap_or_else(|| "gpt-4".to_string());
let conversation = service
.create_conversation(
user_id,
params.project_id,
params.title.clone(),
model,
params.model_config.clone(),
params.access_visibility.clone(),
params.can_ask.clone(),
params.model_uid,
params.model_name.clone(),
)
.await?;
let resp = ConversationResponse::from(conversation);
Ok(ApiResponse::ok(resp).to_response())
}
#[utoipa::path(
get,
path = "/api/ai/conversations",
operation_id = "ai_conversation_list",
params(
("project_id" = Option<Uuid>, Query, description = "Filter by project"),
("q" = Option<String>, Query, description = "Search query (title)"),
),
responses(
(status = 200, description = "List of conversations", body = ApiResponse<Vec<ConversationResponse>>),
(status = 401, description = "Unauthorized"),
),
tag = "AI Chat"
)]
pub async fn conversation_list(
service: web::Data<service::AppService>,
session: Session,
query: web::Query<ConversationListQuery>,
) -> Result<HttpResponse, ApiError> {
let user_id = get_user_id(&session)?;
let convs = service
.list_conversations(user_id, query.project_id, 50, query.q.clone())
.await?;
let resp: Vec<ConversationResponse> =
convs.into_iter().map(ConversationResponse::from).collect();
Ok(ApiResponse::ok(resp).to_response())
}
#[utoipa::path(
get,
path = "/api/ai/conversations/{conversation_id}",
operation_id = "ai_conversation_get",
params(
("conversation_id" = Uuid, Path, description = "Conversation ID"),
),
responses(
(status = 200, description = "Get conversation", body = ApiResponse<ConversationResponse>),
(status = 404, description = "Not found"),
),
tag = "AI Chat"
)]
pub async fn conversation_get(
service: web::Data<service::AppService>,
session: Session,
path: web::Path<Uuid>,
) -> Result<HttpResponse, ApiError> {
let user_id = get_user_id(&session)?;
let conversation_id = path.into_inner();
let c = service
.find_conversation_owned(conversation_id, user_id)
.await?;
let resp = ConversationResponse::from(c);
Ok(ApiResponse::ok(resp).to_response())
}
#[utoipa::path(
patch,
path = "/api/ai/conversations/{conversation_id}",
operation_id = "ai_conversation_update",
params(
("conversation_id" = Uuid, Path, description = "Conversation ID"),
),
request_body = super::types::UpdateConversationParams,
responses(
(status = 200, description = "Conversation updated"),
(status = 404, description = "Not found"),
),
tag = "AI Chat"
)]
pub async fn conversation_update(
service: web::Data<service::AppService>,
session: Session,
path: web::Path<Uuid>,
params: web::Json<super::types::UpdateConversationParams>,
) -> Result<HttpResponse, ApiError> {
let user_id = get_user_id(&session)?;
let conversation_id = path.into_inner();
service
.update_conversation(
conversation_id,
user_id,
params.title.clone(),
params.model.clone(),
params.model_config.clone(),
params.status.clone(),
params.access_visibility.clone(),
params.can_ask.clone(),
params.model_uid,
params.model_name.clone(),
)
.await?;
Ok(crate::api_success())
}
#[utoipa::path(
delete,
path = "/api/ai/conversations/{conversation_id}",
operation_id = "ai_conversation_delete",
params(
("conversation_id" = Uuid, Path, description = "Conversation ID"),
),
responses(
(status = 200, description = "Conversation deleted"),
(status = 404, description = "Not found"),
),
tag = "AI Chat"
)]
pub async fn conversation_delete(
service: web::Data<service::AppService>,
session: Session,
path: web::Path<Uuid>,
) -> Result<HttpResponse, ApiError> {
let user_id = get_user_id(&session)?;
let conversation_id = path.into_inner();
service
.delete_conversation(conversation_id, user_id)
.await?;
Ok(crate::api_success())
}