routes.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import json
  2. import os
  3. from fastapi import APIRouter, UploadFile, File, Form, HTTPException
  4. from fastapi.responses import StreamingResponse
  5. import utils.util
  6. from api.handler_registry import HANDLER_REGISTRY
  7. from api.schema import ChatRequest
  8. from config.settings import JSON_CACHE_DIR, REPORT_OUTPUT_DIR, SERVER_HOST, PDF_SAVE_DIR
  9. from service.stream_service import format_sse_event, stream_calculation_sync, detect_intent, stream_review_sync
  10. from service.history_manager import fetch_all_sessions, fetch_session_detail, remove_session_file
  11. from service.pdf_parse_service import parse_pdf, get_latest_file
  12. router = APIRouter()
  13. @router.post("/api/vent/review/pdf")
  14. async def api_review(
  15. file: UploadFile = File(),
  16. session_id: str | None = Form(default=None),
  17. message : str | None = Form(default=None)
  18. ):
  19. if not file.filename.endswith(".pdf"):
  20. raise HTTPException(status_code=400, detail="仅支持PDF")
  21. return StreamingResponse(
  22. stream_review_sync(file,message,session_id),
  23. media_type="text/event-stream",
  24. headers={
  25. "Cache-Control": "no-cache",
  26. "Connection": "keep-alive",
  27. "X-Accel-Buffering": "no"
  28. }
  29. )
  30. @router.post("/api/vent/chat")
  31. async def vent_chat(req: ChatRequest):
  32. return StreamingResponse(
  33. stream_calculation_sync(req.message, req.session_id),
  34. media_type="text/event-stream",
  35. headers={
  36. "Cache-Control": "no-cache",
  37. "Connection": "keep-alive"
  38. }
  39. )
  40. @router.get("/health")
  41. async def health():
  42. return {"status": "ok", "agent": "create_agent(LangGraph)"}
  43. @router.get("/api/history/session_list")
  44. async def list_sessions():
  45. return {"code":200,"data":fetch_all_sessions()}
  46. @router.get("/api/history/detail/{session_id}")
  47. async def get_session_history(session_id:str):
  48. data = fetch_session_detail(session_id)
  49. return {"code":200,"data":data}
  50. @router.delete("/api/history/delete/{session_id}")
  51. async def remove_session(session_id: str):
  52. success = remove_session_file(session_id)
  53. if not success:
  54. raise HTTPException(
  55. status_code=404,
  56. detail=f"会话 {session_id} 不存在或删除失败"
  57. )
  58. return {"code": 200, "message": "会话删除成功", "data": None}
  59. @router.get("/api/latest-json", summary="")
  60. async def get_latest_json():
  61. """
  62. 获取指定文件夹中修改时间最新的JSON文件并返回内容
  63. """
  64. hash_id = utils.util.get_user_setting("last_upload_file")
  65. latest_file_path = f"{JSON_CACHE_DIR}/{hash_id}.json"
  66. try:
  67. with open(latest_file_path, "r", encoding="utf-8") as f:
  68. data = json.load(f)
  69. except json.JSONDecodeError:
  70. raise HTTPException(status_code=500, detail="JSON文件格式错误")
  71. except Exception as e:
  72. raise HTTPException(status_code=500, detail=f"读取文件失败: {str(e)}")
  73. return {"code": 200, "message": "一切ok", "data": data}
  74. @router.get("/api/latest-pdf", summary="")
  75. async def get_latest_pdf():
  76. hash_id = utils.util.get_user_setting("last_upload_file")
  77. pdf_filename = f"{hash_id}.pdf"
  78. url = f"{SERVER_HOST}/static/save_pdf/{pdf_filename}"
  79. return {"code": 200, "message": "一切ok", "data": url}
  80. @router.post("/api/vent/unified")
  81. async def unified_vent_api(
  82. # 表单参数
  83. message: str = Form(...),
  84. session_id: str | None = Form(default=None),
  85. # 文件参数(可选)
  86. file: UploadFile | None = File(default=None)
  87. ):
  88. """
  89. 配风管理统一入口:意图识别 + 自动分发业务
  90. 支持:纯文本对话 / PDF文件+文本审查
  91. """
  92. # 1. 基础参数校验
  93. if not message.strip():
  94. raise HTTPException(status_code=400, detail="指令内容不能为空")
  95. # 2. 意图识别
  96. has_file = bool(file)
  97. intent_type = await detect_intent(session_id,message,has_file)
  98. # 3. 未知意图:使用stream_calculation_sync进行流式处理
  99. if intent_type not in HANDLER_REGISTRY:
  100. headers = {"Cache-Control": "no-cache", "Connection": "keep-alive"}
  101. return StreamingResponse(
  102. stream_calculation_sync(message, session_id),
  103. media_type="text/event-stream",
  104. headers=headers
  105. )
  106. # 4. 从注册表获取对应处理器
  107. handler = HANDLER_REGISTRY[intent_type]
  108. # 5. 执行当前业务的专属参数校验
  109. handler.validate(file)
  110. # 6. 生成流式响应(分两种场景调用)
  111. if handler.need_file:
  112. # 带文件:审查场景
  113. stream_iter = handler.stream_func(file,message, session_id)
  114. headers = {"Cache-Control": "no-cache", "Connection": "keep-alive", "X-Accel-Buffering": "no"}
  115. else:
  116. # 无文件:计算场景
  117. stream_iter = handler.stream_func(message, session_id)
  118. headers = {"Cache-Control": "no-cache", "Connection": "keep-alive"}
  119. return StreamingResponse(stream_iter, media_type="text/event-stream", headers=headers)