feat: 报销预审会话状态管理与工作台交互增强
- 新增差旅报销会话状态管理与对话模型重构 - 增强风险观测服务与运行时聊天上下文作用域 - 优化工作台图标资源、助理意图识别与摘要工具 - 完善报销创建视图样式与差旅详情页标准调整交互 - 补充风险观测、运行时聊天与报销端点测试覆盖
This commit is contained in:
78
server/src/app/api/v1/endpoints/steward.py
Normal file
78
server/src/app/api/v1/endpoints/steward.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from collections.abc import AsyncIterator
|
||||
from typing import Annotated, Any
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.responses import StreamingResponse
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_db
|
||||
from app.schemas.common import ErrorResponse
|
||||
from app.schemas.steward import StewardPlanRequest, StewardPlanResponse
|
||||
from app.services.runtime_chat import RuntimeChatService
|
||||
from app.services.steward_intent_agent import StewardIntentAgent
|
||||
from app.services.steward_planner import StewardPlannerService
|
||||
|
||||
router = APIRouter(prefix="/steward")
|
||||
DbSession = Annotated[Session, Depends(get_db)]
|
||||
|
||||
|
||||
@router.post(
|
||||
"/plans",
|
||||
response_model=StewardPlanResponse,
|
||||
summary="生成小财管家任务计划",
|
||||
description="把首页自然语言和附件元信息拆解为可确认、可追踪、可分派的财务任务计划。",
|
||||
responses={
|
||||
status.HTTP_400_BAD_REQUEST: {
|
||||
"model": ErrorResponse,
|
||||
"description": "请求缺少任务描述,无法生成小财管家计划。",
|
||||
}
|
||||
},
|
||||
)
|
||||
def create_steward_plan(payload: StewardPlanRequest, db: DbSession) -> StewardPlanResponse:
|
||||
try:
|
||||
return _build_steward_planner(db).build_plan(payload)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post(
|
||||
"/plans/stream",
|
||||
summary="流式生成小财管家任务计划",
|
||||
description="以 NDJSON 逐条返回小财管家的过程摘要事件,最后返回完整任务计划。",
|
||||
)
|
||||
async def stream_steward_plan(payload: StewardPlanRequest, db: DbSession) -> StreamingResponse:
|
||||
return StreamingResponse(
|
||||
_iter_steward_plan_events(payload, _build_steward_planner(db)),
|
||||
media_type="application/x-ndjson",
|
||||
)
|
||||
|
||||
|
||||
async def _iter_steward_plan_events(
|
||||
payload: StewardPlanRequest,
|
||||
planner: StewardPlannerService,
|
||||
) -> AsyncIterator[str]:
|
||||
try:
|
||||
plan = planner.build_plan(payload)
|
||||
except ValueError as exc:
|
||||
yield _encode_stream_event("error", {"message": str(exc)})
|
||||
return
|
||||
|
||||
for event in plan.thinking_events:
|
||||
yield _encode_stream_event("thinking", event.model_dump(mode="json"))
|
||||
await asyncio.sleep(0.18)
|
||||
|
||||
yield _encode_stream_event("plan", plan.model_dump(mode="json"))
|
||||
|
||||
|
||||
def _encode_stream_event(event: str, data: dict[str, Any]) -> str:
|
||||
return json.dumps({"event": event, "data": data}, ensure_ascii=False) + "\n"
|
||||
|
||||
|
||||
def _build_steward_planner(db: Session) -> StewardPlannerService:
|
||||
return StewardPlannerService(
|
||||
intent_agent=StewardIntentAgent(RuntimeChatService(db)),
|
||||
)
|
||||
Reference in New Issue
Block a user