168 lines
5.2 KiB
Python
168 lines
5.2 KiB
Python
|
|
"""
|
|||
|
|
Session monitoring and management endpoints.
|
|||
|
|
[AC-ASA-07, AC-ASA-09] Session list and detail monitoring.
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
from typing import Annotated, Optional
|
|||
|
|
from datetime import datetime
|
|||
|
|
|
|||
|
|
from fastapi import APIRouter, Depends, Query
|
|||
|
|
from fastapi.responses import JSONResponse
|
|||
|
|
|
|||
|
|
from app.core.tenant import get_tenant_id
|
|||
|
|
from app.models import ErrorResponse
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
router = APIRouter(prefix="/admin/sessions", tags=["Session Monitoring"])
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.get(
|
|||
|
|
"",
|
|||
|
|
operation_id="listSessions",
|
|||
|
|
summary="Query session list",
|
|||
|
|
description="[AC-ASA-09] Get list of sessions with pagination and filtering.",
|
|||
|
|
responses={
|
|||
|
|
200: {"description": "Session list with pagination"},
|
|||
|
|
401: {"description": "Unauthorized", "model": ErrorResponse},
|
|||
|
|
403: {"description": "Forbidden", "model": ErrorResponse},
|
|||
|
|
},
|
|||
|
|
)
|
|||
|
|
async def list_sessions(
|
|||
|
|
tenant_id: Annotated[str, Depends(get_tenant_id)],
|
|||
|
|
status: Annotated[Optional[str], Query()] = None,
|
|||
|
|
start_time: Annotated[Optional[str], Query(alias="startTime")] = None,
|
|||
|
|
end_time: Annotated[Optional[str], Query(alias="endTime")] = None,
|
|||
|
|
page: int = Query(1, ge=1),
|
|||
|
|
page_size: int = Query(20, ge=1, le=100),
|
|||
|
|
) -> JSONResponse:
|
|||
|
|
"""
|
|||
|
|
[AC-ASA-09] List sessions with filtering and pagination.
|
|||
|
|
"""
|
|||
|
|
logger.info(
|
|||
|
|
f"[AC-ASA-09] Listing sessions: tenant={tenant_id}, status={status}, "
|
|||
|
|
f"start_time={start_time}, end_time={end_time}, page={page}, page_size={page_size}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
mock_sessions = [
|
|||
|
|
{
|
|||
|
|
"sessionId": "kf_001_wx123456_1708765432000",
|
|||
|
|
"status": "active",
|
|||
|
|
"startTime": "2026-02-24T10:00:00Z",
|
|||
|
|
"endTime": None,
|
|||
|
|
"messageCount": 15,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"sessionId": "kf_002_wx789012_1708851832000",
|
|||
|
|
"status": "closed",
|
|||
|
|
"startTime": "2026-02-23T14:30:00Z",
|
|||
|
|
"endTime": "2026-02-23T15:45:00Z",
|
|||
|
|
"messageCount": 8,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"sessionId": "kf_003_wx345678_1708938232000",
|
|||
|
|
"status": "expired",
|
|||
|
|
"startTime": "2026-02-22T09:00:00Z",
|
|||
|
|
"endTime": "2026-02-23T09:00:00Z",
|
|||
|
|
"messageCount": 3,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"sessionId": "kf_004_wx901234_1709024632000",
|
|||
|
|
"status": "active",
|
|||
|
|
"startTime": "2026-02-21T16:00:00Z",
|
|||
|
|
"endTime": None,
|
|||
|
|
"messageCount": 22,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"sessionId": "kf_005_wx567890_1709111032000",
|
|||
|
|
"status": "closed",
|
|||
|
|
"startTime": "2026-02-20T11:00:00Z",
|
|||
|
|
"endTime": "2026-02-20T12:30:00Z",
|
|||
|
|
"messageCount": 12,
|
|||
|
|
},
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
filtered = mock_sessions
|
|||
|
|
if status:
|
|||
|
|
filtered = [s for s in filtered if s["status"] == status]
|
|||
|
|
|
|||
|
|
total = len(filtered)
|
|||
|
|
total_pages = (total + page_size - 1) // page_size
|
|||
|
|
|
|||
|
|
return JSONResponse(
|
|||
|
|
content={
|
|||
|
|
"data": filtered,
|
|||
|
|
"pagination": {
|
|||
|
|
"page": page,
|
|||
|
|
"pageSize": page_size,
|
|||
|
|
"total": total,
|
|||
|
|
"totalPages": total_pages,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.get(
|
|||
|
|
"/{session_id}",
|
|||
|
|
operation_id="getSessionDetail",
|
|||
|
|
summary="Get session details",
|
|||
|
|
description="[AC-ASA-07] Get full session details with messages and trace.",
|
|||
|
|
responses={
|
|||
|
|
200: {"description": "Full session details with messages and trace"},
|
|||
|
|
401: {"description": "Unauthorized", "model": ErrorResponse},
|
|||
|
|
403: {"description": "Forbidden", "model": ErrorResponse},
|
|||
|
|
},
|
|||
|
|
)
|
|||
|
|
async def get_session_detail(
|
|||
|
|
tenant_id: Annotated[str, Depends(get_tenant_id)],
|
|||
|
|
session_id: str,
|
|||
|
|
) -> JSONResponse:
|
|||
|
|
"""
|
|||
|
|
[AC-ASA-07] Get session detail with messages and trace information.
|
|||
|
|
"""
|
|||
|
|
logger.info(
|
|||
|
|
f"[AC-ASA-07] Getting session detail: tenant={tenant_id}, session_id={session_id}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
mock_session = {
|
|||
|
|
"sessionId": session_id,
|
|||
|
|
"messages": [
|
|||
|
|
{
|
|||
|
|
"role": "user",
|
|||
|
|
"content": "我想了解产品价格",
|
|||
|
|
"timestamp": "2026-02-24T10:00:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"role": "assistant",
|
|||
|
|
"content": "您好,我们的产品价格根据套餐不同有所差异。基础版每月99元,专业版每月299元。企业版提供定制化服务。",
|
|||
|
|
"timestamp": "2026-02-24T10:00:05Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"role": "user",
|
|||
|
|
"content": "专业版包含哪些功能?",
|
|||
|
|
"timestamp": "2026-02-24T10:00:30Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"role": "assistant",
|
|||
|
|
"content": "专业版包含:高级数据分析、API 接入、优先技术支持、自定义报表等功能。",
|
|||
|
|
"timestamp": "2026-02-24T10:00:35Z",
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
"trace": {
|
|||
|
|
"retrieval": [
|
|||
|
|
{
|
|||
|
|
"query": "产品价格",
|
|||
|
|
"kbIds": ["kb_products"],
|
|||
|
|
"results": [
|
|||
|
|
{"source": "pricing.pdf", "score": 0.92, "content": "..."}
|
|||
|
|
],
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"tools": [],
|
|||
|
|
"errors": [],
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return JSONResponse(content=mock_session)
|