Files
ailine/app/backend.py
root ebbd73ddf0
Some checks failed
构建并部署 AI Agent 服务 / deploy (push) Failing after 1m17s
```
docs(quickstart): 更新快速开始文档以支持Nginx反向代理配置

- 修改环境变量配置方式,从直接创建.env文件改为复制模板文件
- 添加必需和可选配置项的详细说明
- 更新Docker Compose启动命令以使用正确的路径
- 增加Nginx反向代理访问方式的说明
- 为本地开发模式添加额外的数据库配置说明

fix(readme): 修正部署说明中的环境变量配置方法

- 将硬编码的环境变量配置改为使用模板文件复制方式
- 更新Docker Compose启动命令路径
- 补充Nginx反向代理访问说明
- 修正数据库配置注意事项

feat(backend): 支持从环境变量读取数据库连接配置

- 添加os模块导入
- 修改DB_URI配置逻辑,优先从环境变量读取
- 适配Docker和本地开发环境的不同数据库连接地址

refactor(docker): 优化Docker Compose配置支持Nginx代理

- 限制后端端口仅本机访问
- 修改前端API URL为相对路径,通过Nginx代理访问
- 限制前端端口仅本机访问

refactor(frontend): 适配Nginx反向代理后端API调用

- 将硬编码的后端API地址改为相对路径
- 支持通过Nginx代理转发请求到后端服务

chore(scripts): 更新启动脚本中的访问地址提示信息

- 修改前端启动成功后的访问地址提示
- 添加Nginx代理访问方式的说明
```
2026-04-14 01:44:55 +08:00

119 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
FastAPI 后端 - 支持动态模型切换,使用 PostgreSQL 持久化记忆
采用依赖注入模式,优雅管理资源生命周期
"""
import os
import uuid
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Depends, Request
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
from app.agent import AIAgentService
# PostgreSQL 连接字符串(优先从环境变量读取,适配 Docker 和本地开发)
DB_URI = os.getenv(
"DB_URI",
"postgresql://postgres:mysecretpassword@postgres:5432/langgraph_db?sslmode=disable"
)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理:创建并注入全局服务"""
# 1. 创建数据库连接池并初始化表
async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
await checkpointer.setup()
# 2. 构建 AI Agent 服务
agent_service = AIAgentService(checkpointer)
await agent_service.initialize()
# 3. 将服务实例存入 app.state
app.state.agent_service = agent_service
# 应用运行中...
yield
# 4. 关闭时自动清理数据库连接async with 负责)
print("🛑 应用关闭,数据库连接池已释放")
app = FastAPI(lifespan=lifespan)
# CORS 中间件(允许前端跨域)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ========== Pydantic 模型 ==========
class ChatRequest(BaseModel):
message: str
thread_id: str | None = None
model: str = "zhipu"
class ChatResponse(BaseModel):
reply: str
thread_id: str
model_used: str
# ========== 依赖注入函数 ==========
def get_agent_service(request: Request) -> AIAgentService:
"""从 app.state 中获取全局 AIAgentService 实例"""
return request.app.state.agent_service
# ========== HTTP 端点 ==========
@app.post("/chat", response_model=ChatResponse)
async def chat_endpoint(
request: ChatRequest,
agent_service: AIAgentService = Depends(get_agent_service)
):
"""同步对话接口,支持模型选择"""
if not request.message:
raise HTTPException(status_code=400, detail="message required")
thread_id = request.thread_id or str(uuid.uuid4())
reply = await agent_service.process_message(
request.message, thread_id, request.model
)
actual_model = request.model if request.model in agent_service.graphs else next(iter(agent_service.graphs.keys()))
return ChatResponse(reply=reply, thread_id=thread_id, model_used=actual_model)
# ========== WebSocket 端点(可选) ==========
@app.websocket("/ws")
async def websocket_endpoint(
websocket: WebSocket,
agent_service: AIAgentService = Depends(get_agent_service)
):
await websocket.accept()
try:
while True:
data = await websocket.receive_json()
message = data.get("message")
thread_id = data.get("thread_id", str(uuid.uuid4()))
model = data.get("model", "zhipu")
if not message:
await websocket.send_json({"error": "missing message"})
continue
reply = await agent_service.process_message(message, thread_id, model)
actual_model = model if model in agent_service.graphs else next(iter(agent_service.graphs.keys()))
await websocket.send_json({"reply": reply, "thread_id": thread_id, "model_used": actual_model})
except WebSocketDisconnect:
pass
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8001)