| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- import sys
- from pathlib import Path
- from dotenv import load_dotenv
- load_dotenv()
- from fastapi import FastAPI
- from fastapi.middleware.cors import CORSMiddleware
- from fastapi.staticfiles import StaticFiles
- from fastapi.responses import RedirectResponse
- from contextlib import asynccontextmanager
- from api import router
- # ============================================================
- # 应用生命周期
- # ============================================================
- @asynccontextmanager
- async def lifespan(app: FastAPI):
- """应用启动/关闭时的生命周期管理"""
- import threading
- print("=" * 60)
- print(" 煤矿通风数据智能解读系统 启动中...")
- print("=" * 60)
- # === 关键优化:在后台线程预热 Agent,不阻塞 uvicorn 启动 ===
- # 原因:create_deep_agent 需要导入 langchain/langgraph 并编译状态图,
- # 首次执行耗时可达数分钟,阻塞 uvicorn 等待 lifespan 完成后才接受请求。
- # 改为后台预热后,服务可以在几秒内就绪,Agent 在后台慢慢初始化。
- #
- # 首次请求如果 Agent 还没预热完,routes.py 中的 get_xxx_agent() 会触发懒加载,
- # 第一个请求会稍慢(等待编译完成),后续请求就是热实例直接用了。
- agent_ready = threading.Event()
- def _warmup_agents():
- """后台线程:预热 Agent 实例"""
- try:
- from agents.vent_agent import get_click_agent, get_dialog_agent
- print("[启动] 后台预热点选解读 Agent...(不阻塞服务就绪)")
- get_click_agent()
- print("[启动] 后台预热对话解读 Agent...(不阻塞服务就绪)")
- get_dialog_agent()
- # ── 预热配风计划审查 Agent(消除首次请求的图编译开销)──
- from agents.review_agent import (
- get_form_review_agent,
- get_data_consistency_agent,
- get_calc_verification_agent,
- get_summary_agent,
- )
- print("[启动] 后台预热形式审查 Agent...")
- get_form_review_agent()
- print("[启动] 后台预热数据一致性审查 Agent...")
- get_data_consistency_agent()
- print("[启动] 后台预热计算核验审查 Agent...")
- get_calc_verification_agent()
- print("[启动] 后台预热汇总审查 Agent...")
- get_summary_agent()
- print("[启动] Agent 预热完成,服务已完全就绪")
- except Exception as e:
- print(f"[警告] Agent 预初始化失败(将在首次请求时懒加载): {e}")
- finally:
- agent_ready.set()
- threading.Thread(target=_warmup_agents, daemon=True, name="agent-warmup").start()
- print("[启动] 服务已就绪(Agent 后台预热中),监听 http://0.0.0.0:8000")
- print("[启动] API 文档: http://localhost:8000/docs")
- print("=" * 60)
- yield
- # 关闭时清理
- print("[关闭] 服务停止")
- # ============================================================
- # 创建 FastAPI 应用
- # ============================================================
- app = FastAPI(
- title="煤矿通风数据智能解读系统",
- description="""
- 基于 DeepAgents 框架的煤矿通风监测数据智能解读服务。
- ## 功能
- - **点选数据解读**: 对单条巷道监测数据进行深度合规分析
- - **对话式数据解读**: 通过自然语言对话查询和分析通风数据
- - **聊天历史**: 查询和管理对话历史记录
- ## 技术栈
- - DeepAgents (LangChain) - Agent 编排
- - FastAPI - Web 框架
- - SQLite - 聊天历史存储
- - SSE - 流式响应
- """,
- version="1.0.0",
- lifespan=lifespan,
- )
- # CORS 配置(允许前端跨域访问)
- app.add_middleware(
- CORSMiddleware,
- allow_origins=["*"],
- allow_credentials=True,
- allow_methods=["*"],
- allow_headers=["*"],
- )
- # 注册路由
- app.include_router(router)
- # 静态文件服务(审查报告 .docx 下载)
- _static_dir = Path(__file__).parent / "static"
- _static_dir.mkdir(parents=True, exist_ok=True)
- (_static_dir / "reports").mkdir(exist_ok=True)
- app.mount("/static", StaticFiles(directory=str(_static_dir)), name="static")
- # ============================================================
- # 根路由 → Chat UI
- # ============================================================
- @app.get("/")
- async def root():
- """根路径重定向到聊天界面"""
- return RedirectResponse(url="/static/index.html")
- # ============================================================
- # 健康检查
- # ============================================================
- @app.get("/health")
- async def health_check():
- """健康检查接口"""
- return {
- "status": "ok",
- "service": "煤矿通风数据智能解读系统",
- "version": "1.0.0",
- }
- # ============================================================
- # 直接运行入口
- # ============================================================
- if __name__ == "__main__":
- import uvicorn
- uvicorn.run(
- "main:app",
- host="0.0.0.0",
- port=8070,
- reload=True,
- log_level="info",
- )
|