105 lines
3.5 KiB
Python
105 lines
3.5 KiB
Python
"""
|
||
智能体唯一 HTTP 入口(合并原 8810/8809/8811)。
|
||
|
||
本文件职责:组装 FastAPI、挂载通道、启动 inbox/outbox 线程、暴露 /health。
|
||
禁止:在请求处理里同步 LibreOffice / 等完整 LLM / invoke 整图。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
from contextlib import asynccontextmanager
|
||
|
||
import uvicorn
|
||
from fastapi import FastAPI
|
||
|
||
from agent.channel.aibot import router as aibot_router
|
||
from agent.channel.bridge import router as bridge_router
|
||
from agent.channel.h5 import router as h5_router
|
||
from agent.channel.quote_template_parse import router as quote_template_parse_router
|
||
from agent.channel.runtime import start_channel_runtime
|
||
from agent.channel.wecom.callback import router as wecom_router
|
||
from agent.config import get_settings
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
@asynccontextmanager
|
||
async def lifespan(app: FastAPI):
|
||
"""
|
||
进程生命周期:启动企微 inbox/outbox 消费线程。
|
||
|
||
为何放在 HTTP 进程:回调快回后需同机消费;与 LibreOffice 无关的快路径。
|
||
"""
|
||
settings = get_settings()
|
||
runtime = start_channel_runtime(settings)
|
||
app.state.channel_runtime = runtime
|
||
logger.info(
|
||
"通道运行时就绪 ytd_env=%s wecom_agent_id=%s corp_configured=%s",
|
||
settings.ytd_env,
|
||
settings.wecom_agent_id,
|
||
bool(settings.wecom_corp_id and settings.wecom_secret),
|
||
)
|
||
yield
|
||
runtime.stop()
|
||
|
||
|
||
def create_app() -> FastAPI:
|
||
"""构建 FastAPI 应用(可供测试 import)。"""
|
||
settings = get_settings()
|
||
app = FastAPI(
|
||
title="YTD Inquiry Agent HTTP",
|
||
version="0.2.0",
|
||
description="询价智能体 HTTP:企微回调入队 + echo 出站联调",
|
||
lifespan=lifespan,
|
||
)
|
||
|
||
@app.get("/health")
|
||
def health() -> dict[str, object]:
|
||
"""存活探测:不访问 PG/Redis;附带通道配置是否齐全(不含密钥)。"""
|
||
return {
|
||
"status": "UP",
|
||
"service": "agent-http",
|
||
"ytd_env": settings.ytd_env,
|
||
"port": settings.agent_http_port,
|
||
"wecom_crypto_ready": bool(
|
||
settings.wecom_callback_token
|
||
and settings.wecom_encoding_aes_key
|
||
and settings.wecom_corp_id
|
||
),
|
||
"wecom_send_ready": bool(settings.wecom_corp_id and settings.wecom_secret),
|
||
}
|
||
|
||
app.include_router(wecom_router)
|
||
app.include_router(h5_router)
|
||
app.include_router(bridge_router)
|
||
app.include_router(aibot_router)
|
||
app.include_router(quote_template_parse_router)
|
||
return app
|
||
|
||
|
||
def main() -> None:
|
||
"""进程入口:默认端口 8910。"""
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
|
||
)
|
||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||
settings = get_settings()
|
||
# test 环境默认允许本机注入,便于并存期联调
|
||
if settings.ytd_env == "test" and not settings.dev_inject_enabled:
|
||
# pydantic 冻结后不能改;通过环境变量在启动前设置更干净。此处仅打日志提示。
|
||
logger.info("提示:test 下可用 POST /internal/dev/inject-text 联调(无需改 Nginx)")
|
||
|
||
app = create_app()
|
||
logger.info(
|
||
"启动智能体 HTTP ytd_env=%s port=%s",
|
||
settings.ytd_env,
|
||
settings.agent_http_port,
|
||
)
|
||
uvicorn.run(app, host="0.0.0.0", port=settings.agent_http_port, log_level="info")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|