routes.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import base64
  2. from datetime import datetime
  3. from fastapi import APIRouter, HTTPException
  4. from utils.device_id import get_device_id
  5. from .models import ChatRequest, ChatResponse, OCRRequest, MessageCreateBill
  6. from core.chat_service import chat_service
  7. from core.agent_manager import agent_manager
  8. from utils.logger import chat_logger
  9. from tools.tool_factory import get_all_tools
  10. import time
  11. from utils.registration_manager import registration_manager
  12. from core.ocr_service import PaddleOCRService
  13. from core.document_processor.document_service import DocumentProcessingService
  14. # 初始化服务
  15. ocr_service = PaddleOCRService(
  16. api_url="https://a8l0g1qda8zd48nb.aistudio-app.com/ocr",
  17. token="f97d214abf87d5ea3c156e21257732a3b19661cb",
  18. )
  19. doc_service = DocumentProcessingService(ocr_service=ocr_service)
  20. router = APIRouter()
  21. @router.post("/chat", response_model=ChatResponse)
  22. async def chat_endpoint(request: ChatRequest):
  23. """聊天接口"""
  24. try:
  25. result = await chat_service.process_chat_request(request.model_dump())
  26. return ChatResponse(**result)
  27. except Exception as e:
  28. chat_logger.error(f"API处理失败: {str(e)}")
  29. raise HTTPException(status_code=500, detail=f"处理失败: {str(e)}")
  30. @router.post("/ocr")
  31. async def orc(request: OCRRequest):
  32. """OCR接口"""
  33. try:
  34. chat_logger.info(f"开始进行图片识别")
  35. # 1. 解码Base64图片
  36. try:
  37. if "," in request.image:
  38. # 去掉 data:image/xxx;base64, 前缀
  39. base64_str = request.image.split(",", 1)[1]
  40. else:
  41. base64_str = request.image
  42. image_bytes = base64.b64decode(base64_str)
  43. except Exception as e:
  44. chat_logger.error(f"图片解码失败: {e}")
  45. raise HTTPException(400, f"图片格式错误: {str(e)}")
  46. # 2. OCR识别
  47. result = await doc_service.pure_ocr(
  48. image_bytes=image_bytes, file_type=request.file_type
  49. )
  50. # 3. 返回结果
  51. return result
  52. except HTTPException:
  53. raise
  54. except Exception as e:
  55. chat_logger.error(f"处理失败: {e}")
  56. raise HTTPException(500, f"处理失败: {str(e)}")
  57. @router.post("/ocr_create_bill")
  58. async def ocr_create_bill_endpoint(request: OCRRequest):
  59. """
  60. 处理单张图片
  61. 请求格式:
  62. {
  63. "image": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
  64. "type": "invoice",
  65. }
  66. """
  67. try:
  68. chat_logger.info(f"开始处理 {request.type} 单据")
  69. # 1. 解码Base64图片
  70. try:
  71. if "," in request.image:
  72. # 去掉 data:image/xxx;base64, 前缀
  73. base64_str = request.image.split(",", 1)[1]
  74. else:
  75. base64_str = request.image
  76. image_bytes = base64.b64decode(base64_str)
  77. except Exception as e:
  78. chat_logger.error(f"图片解码失败: {e}")
  79. raise HTTPException(400, f"图片格式错误: {str(e)}")
  80. # 2. 处理单据
  81. result = await doc_service.ocr_create_bill(
  82. image_bytes=image_bytes, document_type=request.type
  83. )
  84. # 3. 返回结果
  85. return {
  86. "success": True,
  87. "type": request.type,
  88. "text": result.get("ocr_text", ""), # 识别出的文本
  89. "data": result.get("parsed_data", {}), # 结构化数据
  90. "timestamp": datetime.now().isoformat(),
  91. }
  92. except HTTPException:
  93. raise
  94. except Exception as e:
  95. chat_logger.error(f"处理失败: {e}")
  96. raise HTTPException(500, f"处理失败: {str(e)}")
  97. @router.post("/message_create_bill")
  98. async def message_create_bill_endpoint(request: MessageCreateBill):
  99. """
  100. 通过文本消息辅助建立单据
  101. 请求格式:
  102. {
  103. "message": "这是一条单据描述",
  104. "document_type": "invoice",
  105. }
  106. """
  107. try:
  108. result = await doc_service.message_create_bill(
  109. message=request.message, document_type=request.document_type
  110. )
  111. return result
  112. except Exception as e:
  113. chat_logger.error(f"处理失败: {e}")
  114. raise HTTPException(500, f"处理失败: {str(e)}")
  115. @router.get("/cache/status")
  116. async def cache_status():
  117. """查看缓存状态 - 修复版本"""
  118. try:
  119. cache_status = await agent_manager.get_cache_status()
  120. # ✅ 确保返回完整信息
  121. return {
  122. "success": True,
  123. "cache_size": cache_status.get("cache_size", 0),
  124. "cache_expiry_seconds": cache_status.get("cache_expiry_seconds", 3600),
  125. "cache_entries_count": len(cache_status.get("cache_entries", [])),
  126. "cache_entries": cache_status.get("cache_entries", []),
  127. "timestamp": time.time(),
  128. }
  129. except Exception as e:
  130. chat_logger.error(f"获取缓存状态失败: {str(e)}")
  131. return {
  132. "success": False,
  133. "error": str(e),
  134. "cache_size": 0,
  135. "cache_entries_count": 0,
  136. "cache_entries": [],
  137. }
  138. @router.delete("/cache/clear")
  139. async def clear_cache():
  140. """清空缓存"""
  141. try:
  142. # ✅ 使用异步版本
  143. cleared = await agent_manager.clear_cache()
  144. chat_logger.info(f"清空agent缓存, 清理数量={cleared}")
  145. return {
  146. "cleared_entries": cleared,
  147. "message": "缓存已清空",
  148. "status": "success",
  149. }
  150. except Exception as e:
  151. chat_logger.error(f"清空缓存失败: {str(e)}")
  152. raise HTTPException(status_code=500, detail=f"清空缓存失败: {str(e)}")
  153. @router.get("/health")
  154. async def health_check():
  155. """健康检查"""
  156. try:
  157. # ✅ 使用异步版本
  158. registration_status = await registration_manager.check_registration()
  159. return {
  160. "status": "healthy",
  161. "service": "龙嘉软件AI助手API",
  162. "registration_status": (
  163. "已注册" if registration_status else "未注册或注册过期"
  164. ),
  165. "device_id": get_device_id(),
  166. "timestamp": time.time(),
  167. }
  168. except Exception as e:
  169. return {
  170. "status": "unhealthy",
  171. "service": "龙嘉软件AI助手API",
  172. "error": str(e),
  173. "timestamp": time.time(),
  174. }
  175. @router.get("/tools/status")
  176. async def tools_status():
  177. """查看工具状态"""
  178. try:
  179. tools = get_all_tools()
  180. tool_info = []
  181. for i, tool in enumerate(tools):
  182. tool_info.append(
  183. {
  184. "index": i + 1,
  185. "name": getattr(tool, "name", "unknown"),
  186. "description": getattr(tool, "description", "unknown")[:100]
  187. + "...",
  188. }
  189. )
  190. return {"total_tools": len(tools), "tools": tool_info, "status": "success"}
  191. except Exception as e:
  192. chat_logger.error(f"获取工具状态失败: {str(e)}")
  193. raise HTTPException(status_code=500, detail=f"获取工具状态失败: {str(e)}")
  194. @router.post("/cache/initialize")
  195. async def initialize_cache():
  196. """初始化缓存系统"""
  197. try:
  198. # ✅ 使用异步版本
  199. await agent_manager.initialize()
  200. chat_logger.info("缓存系统初始化完成")
  201. return {"status": "success", "message": "缓存系统初始化完成"}
  202. except Exception as e:
  203. chat_logger.error(f"初始化缓存失败: {str(e)}")
  204. raise HTTPException(status_code=500, detail=f"初始化缓存失败: {str(e)}")
  205. @router.post("/cache/shutdown")
  206. async def shutdown_cache():
  207. """关闭缓存系统"""
  208. try:
  209. # ✅ 使用异步版本
  210. cleared = await agent_manager.shutdown()
  211. chat_logger.info(f"缓存系统已关闭,清理了 {cleared} 个实例")
  212. return {
  213. "cleared_entries": cleared,
  214. "message": "缓存系统已关闭",
  215. "status": "success",
  216. }
  217. except Exception as e:
  218. chat_logger.error(f"关闭缓存失败: {str(e)}")
  219. raise HTTPException(status_code=500, detail=f"关闭缓存失败: {str(e)}")
  220. @router.post("/admin/refresh-registration")
  221. async def refresh_registration():
  222. """手动刷新注册状态(管理员用)"""
  223. registration_manager.force_refresh()
  224. return {"status": "success", "message": "注册状态已刷新"}
  225. @router.get("/admin/registration-status")
  226. async def get_registration_status():
  227. """获取注册状态(管理员用)"""
  228. status = await registration_manager.check_registration()
  229. status_info = registration_manager.get_status()
  230. return {"is_registered": status, "status_info": status_info}
  231. @router.get("/")
  232. async def root():
  233. registration_status = await registration_manager.check_registration()
  234. base_info = {
  235. "service": "龙嘉软件AI助手API",
  236. "version": "1.0.0",
  237. "registration_status": "active" if registration_status else "expired",
  238. "device_id": get_device_id(),
  239. }
  240. if registration_status:
  241. base_info.update(
  242. {
  243. "endpoints": {
  244. "POST /chat": "聊天",
  245. "GET /health": "健康检查",
  246. "GET /cache/status": "查看agent缓存状态",
  247. "DELETE /cache/clear": "清空agent缓存",
  248. "GET /": "API信息",
  249. }
  250. }
  251. )
  252. else:
  253. base_info.update(
  254. {
  255. "message": "⚠️ 服务注册已过期,部分功能受限",
  256. "available_endpoints": {
  257. "GET /health": "健康检查",
  258. "GET /registration/status": "查看注册状态",
  259. "GET /service/info": "服务完整信息",
  260. "GET /": "API信息",
  261. },
  262. "restricted_endpoints": {"POST /chat": "AI聊天功能(需续费)"},
  263. "support_contact": "请联系管理员续费服务",
  264. }
  265. )
  266. return base_info