Files
moss-ai/app/backend-python/api/conversation.py
雷雨 8635b84b2d init
2025-12-15 22:05:56 +08:00

286 lines
8.2 KiB
Python

"""
对话列表管理 API 路由
"""
import logging
from uuid import uuid4
from fastapi import APIRouter, HTTPException, status, Query
from typing import Optional
from pydantic import BaseModel, Field
from services.conversation_service import conversation_service
from services.chat_history_service import chat_history_service
logger = logging.getLogger(__name__)
router = APIRouter()
# ==================== 请求/响应模型 ====================
class CreateConversationRequest(BaseModel):
system_user_id: int = Field(..., description="系统用户ID")
title: str = Field(default="新对话", description="对话标题")
description: Optional[str] = Field(None, description="对话描述")
class Config:
json_schema_extra = {
"example": {
"system_user_id": 1000000001,
"title": "智能家居控制",
"description": "关于空调和灯光的对话"
}
}
class UpdateConversationRequest(BaseModel):
context_id: str = Field(..., description="会话上下文ID")
title: Optional[str] = Field(None, description="新标题")
class Config:
json_schema_extra = {
"example": {
"context_id": "session-abc123",
"title": "空调温度调节"
}
}
class DeleteConversationRequest(BaseModel):
context_id: str = Field(..., description="会话上下文ID")
system_user_id: int = Field(..., description="系统用户ID")
class Config:
json_schema_extra = {
"example": {
"context_id": "session-abc123",
"system_user_id": 1000000001
}
}
# ==================== API 端点 ====================
@router.post("/conversations/create")
async def create_conversation(request: CreateConversationRequest):
"""
创建新对话
"""
try:
# 生成新的 context_id
context_id = f"session-{uuid4().hex[:16]}"
logger.info(f"📝 创建新对话: user={request.system_user_id}, title={request.title}")
conversation = await conversation_service.create_conversation(
system_user_id=request.system_user_id,
context_id=context_id,
title=request.title,
description=request.description
)
logger.info(f"✅ 创建对话成功: context={context_id}")
return {
"success": True,
"message": "创建对话成功",
"data": conversation
}
except Exception as e:
logger.error(f"❌ 创建对话失败: {e}", exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={
"error": "CreateConversationError",
"message": str(e)
}
)
@router.get("/conversations/list")
async def get_conversations(
system_user_id: int = Query(..., description="系统用户ID"),
limit: int = Query(50, description="返回数量限制"),
only_active: bool = Query(True, description="是否只返回活跃对话")
):
"""
获取用户的对话列表
"""
try:
logger.info(f"📋 获取对话列表: user={system_user_id}, limit={limit}")
conversations = await conversation_service.get_user_conversations(
system_user_id=system_user_id,
limit=limit,
only_active=only_active
)
return {
"success": True,
"message": "获取对话列表成功",
"data": conversations,
"total": len(conversations)
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={
"error": "GetConversationsError",
"message": str(e)
}
)
@router.get("/conversations/{context_id}")
async def get_conversation(context_id: str):
"""
获取指定对话的详细信息
"""
try:
logger.info(f"🔍 获取对话详情: context={context_id}")
conversation = await conversation_service.get_conversation_by_context(context_id)
if not conversation:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail={
"error": "ConversationNotFound",
"message": f"对话不存在: {context_id}"
}
)
return {
"success": True,
"message": "获取对话详情成功",
"data": conversation
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={
"error": "GetConversationError",
"message": str(e)
}
)
@router.put("/conversations/update")
async def update_conversation(request: UpdateConversationRequest):
"""
更新对话信息(如标题)
"""
try:
success = await conversation_service.update_conversation(
context_id=request.context_id,
title=request.title
)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail={
"error": "ConversationNotFound",
"message": f"对话不存在: {request.context_id}"
}
)
return {
"success": True,
"message": "更新对话成功"
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={
"error": "UpdateConversationError",
"message": str(e)
}
)
@router.delete("/conversations/delete")
async def delete_conversation(request: DeleteConversationRequest):
"""
删除对话(软删除)
"""
try:
success = await conversation_service.delete_conversation(
context_id=request.context_id,
system_user_id=request.system_user_id,
soft_delete=True
)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail={
"error": "ConversationNotFound",
"message": f"对话不存在或无权限: {request.context_id}"
}
)
return {
"success": True,
"message": "删除对话成功"
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={
"error": "DeleteConversationError",
"message": str(e)
}
)
@router.get("/conversations/{context_id}/history")
async def get_conversation_history(
context_id: str,
system_user_id: int = Query(..., description="系统用户ID"),
limit: int = Query(50, description="返回消息数量限制")
):
"""
获取指定对话的历史消息
"""
try:
logger.info(f"📜 获取对话历史: context={context_id}, limit={limit}")
messages = await chat_history_service.get_conversation_history(
system_user_id=system_user_id,
context_id=context_id,
limit=limit
)
# 确保是列表,然后反转顺序,使得最旧的消息在前
messages = list(messages) if not isinstance(messages, list) else messages
messages.reverse()
return {
"success": True,
"message": "获取对话历史成功",
"data": messages,
"total": len(messages)
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={
"error": "GetConversationHistoryError",
"message": str(e)
}
)