Files
hunjing/backend/app/api/v1/endpoints/chat.py
T
2026-08-21 16:00:13 +08:00

138 lines
4.7 KiB
Python

"""聊天 API。"""
from fastapi import APIRouter, Depends, Header, Query, Request, Response, status
from app.api.v1.deps import get_current_user
from app.schemas.auth import CurrentUser
from app.schemas.chat import (
ChatMessageListResponse,
ChatMessageResponse,
ChatSessionListResponse,
ChatSessionResponse,
CreateSessionRequest,
SelectVersionRequest,
SendMessageRequest,
SendMessageResponse,
UpdateSessionRequest,
)
from app.services.chat import (
create_session,
delete_session,
get_session_response,
list_message_responses,
list_session_responses,
select_message_version,
send_message,
update_session_response,
)
from app.services.idempotency import run_idempotent
router = APIRouter(prefix="/chat", tags=["chat"])
@router.post("/sessions", response_model=ChatSessionResponse)
async def create_chat_session(
payload: CreateSessionRequest,
current_user: CurrentUser = Depends(get_current_user),
) -> ChatSessionResponse:
return await create_session(payload, owner_scope=current_user.owner_scope)
@router.get("/sessions", response_model=ChatSessionListResponse)
async def list_chat_sessions(
current_user: CurrentUser = Depends(get_current_user),
status: str | None = Query(default=None, description="按状态过滤:active / archived"),
limit: int = Query(default=50, ge=1, le=100),
offset: int = Query(default=0, ge=0),
) -> ChatSessionListResponse:
return await list_session_responses(
owner_scope=current_user.owner_scope, status=status, limit=limit, offset=offset
)
@router.get("/sessions/{session_id}", response_model=ChatSessionResponse)
async def get_chat_session(
session_id: str,
current_user: CurrentUser = Depends(get_current_user),
) -> ChatSessionResponse:
return await get_session_response(session_id, owner_scope=current_user.owner_scope)
@router.patch("/sessions/{session_id}", response_model=ChatSessionResponse)
async def update_chat_session(
session_id: str,
payload: UpdateSessionRequest,
current_user: CurrentUser = Depends(get_current_user),
) -> ChatSessionResponse:
return await update_session_response(session_id, payload, owner_scope=current_user.owner_scope)
@router.delete("/sessions/{session_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_chat_session(
session_id: str,
current_user: CurrentUser = Depends(get_current_user),
) -> Response:
await delete_session(session_id, owner_scope=current_user.owner_scope)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/sessions/{session_id}/messages", response_model=SendMessageResponse)
async def send_chat_message(
session_id: str,
payload: SendMessageRequest,
request: Request,
idempotency_key: str | None = Header(default=None, alias="Idempotency-Key"),
current_user: CurrentUser = Depends(get_current_user),
) -> SendMessageResponse:
return await run_idempotent(
key=idempotency_key,
method="POST",
path=str(request.url.path),
payload=payload,
response_type=SendMessageResponse,
resource_type="run",
handler=lambda session: send_message(
session,
session_id,
payload,
owner_scope=current_user.owner_scope,
tool_runtime=getattr(request.app.state, "tool_runtime", None),
confirmation_registry=getattr(request.app.state, "confirmation_registry", None),
confirmation_store=getattr(request.app.state, "confirmation_store", None),
event_store=getattr(request.app.state, "event_store", None),
agent_run_registry=getattr(request.app.state, "agent_run_registry", None),
python_skill_catalog=getattr(request.app.state, "python_skill_catalog", None),
),
)
@router.get("/sessions/{session_id}/messages", response_model=ChatMessageListResponse)
async def list_chat_messages(
session_id: str,
current_user: CurrentUser = Depends(get_current_user),
limit: int = Query(default=100, ge=1, le=200),
offset: int = Query(default=0, ge=0),
) -> ChatMessageListResponse:
return await list_message_responses(
session_id, owner_scope=current_user.owner_scope, limit=limit, offset=offset
)
@router.patch(
"/sessions/{session_id}/messages/{message_id}/version",
response_model=ChatMessageResponse,
)
async def select_message_version_endpoint(
session_id: str,
message_id: str,
payload: SelectVersionRequest,
current_user: CurrentUser = Depends(get_current_user),
) -> ChatMessageResponse:
"""选择/激活消息的某个历史版本。"""
return await select_message_version(
session_id,
message_id,
payload,
owner_scope=current_user.owner_scope,
)