root a0c2586487 feat(backend): B3 Task 3.1 - 对话与消息基础 API
- 添加 Conversation CRUD 端点(创建/列表/获取/删除)
- 添加 Message 操作端点(发送/列表)
- 注册 conversations 路由到 API v1
- 修复测试 fixture 的 API 路径前缀
- 添加 async_client fixture alias

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 02:24:06 +08:00

70 lines
2.6 KiB
Python

from fastapi import APIRouter, Depends, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import get_db
from app.schemas.conversation import (
ConversationCreate,
ConversationResponse,
ConversationUpdate,
MessageCreate,
MessageResponse,
)
from app.services import conversation_service
router = APIRouter(prefix="/conversations", tags=["conversations"])
@router.post("", response_model=ConversationResponse, status_code=status.HTTP_201_CREATED)
async def create_conversation(
data: ConversationCreate, session: AsyncSession = Depends(get_db)
) -> ConversationResponse:
conv = await conversation_service.create_conversation(
session, data.tenant_id, data.employee_id, data.user_id, data.title
)
return ConversationResponse.from_model(conv)
@router.get("", response_model=list[ConversationResponse])
async def list_conversations(
tenant_id: str, session: AsyncSession = Depends(get_db)
) -> list[ConversationResponse]:
convs = await conversation_service.list_conversations(session, tenant_id)
return [ConversationResponse.from_model(c) for c in convs]
@router.get("/{conversation_id}", response_model=ConversationResponse)
async def get_conversation(
conversation_id: str, session: AsyncSession = Depends(get_db)
) -> ConversationResponse:
conv = await conversation_service.get_conversation(session, conversation_id)
return ConversationResponse.from_model(conv)
@router.delete("/{conversation_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_conversation(
conversation_id: str, session: AsyncSession = Depends(get_db)
) -> None:
await conversation_service.delete_conversation(session, conversation_id)
@router.post("/{conversation_id}/messages", response_model=MessageResponse)
async def send_message(
conversation_id: str,
data: MessageCreate,
session: AsyncSession = Depends(get_db),
) -> MessageResponse:
# For now, just create a user message (LLM response will come in Task 3.2)
await conversation_service.get_conversation(session, conversation_id)
msg = await conversation_service.create_message(
session, conversation_id, role="user", content=data.content
)
return MessageResponse.from_model(msg)
@router.get("/{conversation_id}/messages", response_model=list[MessageResponse])
async def list_messages(
conversation_id: str, session: AsyncSession = Depends(get_db)
) -> list[MessageResponse]:
await conversation_service.get_conversation(session, conversation_id)
messages = await conversation_service.list_messages(session, conversation_id)
return [MessageResponse.from_model(m) for m in messages]