2026-01-19 00:09:36 +08:00
|
|
|
|
"""
|
|
|
|
|
|
低代码智能体平台 - FastAPI 主应用
|
|
|
|
|
|
"""
|
2026-05-02 16:17:49 +08:00
|
|
|
|
import asyncio
|
2026-01-19 00:09:36 +08:00
|
|
|
|
import logging
|
|
|
|
|
|
from fastapi import FastAPI, Request
|
|
|
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
|
|
from fastapi.exceptions import RequestValidationError
|
|
|
|
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
|
|
from app.core.config import settings
|
|
|
|
|
|
from app.core.error_handler import (
|
|
|
|
|
|
validation_exception_handler,
|
|
|
|
|
|
api_exception_handler,
|
|
|
|
|
|
sqlalchemy_exception_handler,
|
|
|
|
|
|
general_exception_handler
|
|
|
|
|
|
)
|
|
|
|
|
|
from app.core.exceptions import BaseAPIException
|
|
|
|
|
|
from app.core.database import init_db
|
|
|
|
|
|
|
|
|
|
|
|
# 配置日志
|
|
|
|
|
|
logging.basicConfig(
|
|
|
|
|
|
level=logging.INFO,
|
|
|
|
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
|
|
|
|
)
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
app = FastAPI(
|
|
|
|
|
|
title=settings.APP_NAME,
|
|
|
|
|
|
version=settings.APP_VERSION,
|
|
|
|
|
|
description="""
|
|
|
|
|
|
## 低代码智能体平台 API
|
|
|
|
|
|
|
|
|
|
|
|
一个支持可视化工作流设计和智能Agent配置的低代码平台。
|
|
|
|
|
|
|
|
|
|
|
|
### 主要功能
|
|
|
|
|
|
|
|
|
|
|
|
* **用户认证** - 用户注册、登录、JWT认证
|
|
|
|
|
|
* **工作流管理** - 工作流的创建、读取、更新、删除、执行
|
|
|
|
|
|
* **工作流版本管理** - 版本保存、版本列表、版本回滚
|
|
|
|
|
|
* **执行管理** - 工作流执行、执行记录查询、执行状态监控
|
|
|
|
|
|
* **执行日志** - 详细的执行日志记录和查询
|
|
|
|
|
|
* **数据源管理** - 多种数据源的连接和管理
|
|
|
|
|
|
* **WebSocket实时推送** - 执行状态实时更新
|
|
|
|
|
|
|
|
|
|
|
|
### 认证方式
|
|
|
|
|
|
|
|
|
|
|
|
大部分API需要JWT认证。请先通过 `/api/v1/auth/login` 获取token,然后在请求头中添加:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Authorization: Bearer <your_token>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### API版本
|
|
|
|
|
|
|
|
|
|
|
|
当前API版本:v1
|
|
|
|
|
|
|
|
|
|
|
|
### 文档
|
|
|
|
|
|
|
|
|
|
|
|
* **Swagger UI**: `/docs` - 交互式API文档
|
|
|
|
|
|
* **ReDoc**: `/redoc` - 可读性更好的API文档
|
|
|
|
|
|
""",
|
|
|
|
|
|
docs_url="/docs",
|
|
|
|
|
|
redoc_url="/redoc",
|
|
|
|
|
|
openapi_tags=[
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "auth",
|
|
|
|
|
|
"description": "用户认证相关API,包括注册、登录、获取用户信息等。"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "workflows",
|
|
|
|
|
|
"description": "工作流管理API,包括工作流的CRUD操作、执行、版本管理等。"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "executions",
|
|
|
|
|
|
"description": "执行管理API,包括执行记录的创建、查询、状态获取等。"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "execution-logs",
|
|
|
|
|
|
"description": "执行日志API,包括日志查询、日志统计等。"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "data-sources",
|
|
|
|
|
|
"description": "数据源管理API,包括数据源的CRUD操作、连接测试、数据查询等。"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "websocket",
|
|
|
|
|
|
"description": "WebSocket API,用于实时推送执行状态。"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# CORS 配置
|
|
|
|
|
|
cors_origins = [origin.strip() for origin in settings.CORS_ORIGINS.split(",")]
|
2026-01-23 09:49:45 +08:00
|
|
|
|
# 添加调试日志
|
|
|
|
|
|
logger.info(f"CORS允许的源: {cors_origins}")
|
2026-01-19 00:09:36 +08:00
|
|
|
|
app.add_middleware(
|
|
|
|
|
|
CORSMiddleware,
|
|
|
|
|
|
allow_origins=cors_origins,
|
|
|
|
|
|
allow_credentials=True,
|
|
|
|
|
|
allow_methods=["*"],
|
|
|
|
|
|
allow_headers=["*"],
|
2026-01-23 09:49:45 +08:00
|
|
|
|
expose_headers=["*"],
|
2026-01-19 00:09:36 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 注册全局异常处理器
|
|
|
|
|
|
app.add_exception_handler(RequestValidationError, validation_exception_handler)
|
|
|
|
|
|
app.add_exception_handler(BaseAPIException, api_exception_handler)
|
|
|
|
|
|
app.add_exception_handler(SQLAlchemyError, sqlalchemy_exception_handler)
|
|
|
|
|
|
app.add_exception_handler(Exception, general_exception_handler)
|
|
|
|
|
|
|
|
|
|
|
|
# 请求日志中间件
|
|
|
|
|
|
@app.middleware("http")
|
|
|
|
|
|
async def log_requests(request: Request, call_next):
|
|
|
|
|
|
"""记录请求日志"""
|
|
|
|
|
|
import time
|
|
|
|
|
|
start_time = time.time()
|
|
|
|
|
|
|
|
|
|
|
|
# 记录请求
|
|
|
|
|
|
logger.info(f"{request.method} {request.url.path} - 客户端: {request.client.host if request.client else 'unknown'}")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
response = await call_next(request)
|
|
|
|
|
|
process_time = time.time() - start_time
|
|
|
|
|
|
|
|
|
|
|
|
# 记录响应
|
|
|
|
|
|
logger.info(
|
|
|
|
|
|
f"{request.method} {request.url.path} - "
|
|
|
|
|
|
f"状态码: {response.status_code} - "
|
|
|
|
|
|
f"耗时: {process_time:.3f}s"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
process_time = time.time() - start_time
|
|
|
|
|
|
logger.error(
|
|
|
|
|
|
f"{request.method} {request.url.path} - "
|
|
|
|
|
|
f"异常: {str(e)} - "
|
|
|
|
|
|
f"耗时: {process_time:.3f}s"
|
|
|
|
|
|
)
|
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/")
|
|
|
|
|
|
async def root():
|
|
|
|
|
|
"""根路径"""
|
|
|
|
|
|
return {
|
|
|
|
|
|
"message": "欢迎使用低代码智能体平台 API",
|
|
|
|
|
|
"version": settings.APP_VERSION,
|
|
|
|
|
|
"docs": "/docs"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/health")
|
|
|
|
|
|
async def health_check():
|
2026-04-08 11:44:24 +08:00
|
|
|
|
"""健康检查(含内置工具是否已注册,便于排查「可动手 Agent」)。"""
|
|
|
|
|
|
from app.services.tool_registry import tool_registry
|
|
|
|
|
|
|
|
|
|
|
|
names = tool_registry.builtin_tool_names()
|
|
|
|
|
|
count = tool_registry.builtin_tool_count()
|
|
|
|
|
|
file_agent_core = {"file_write", "file_read", "system_info"}
|
|
|
|
|
|
subset_ok = file_agent_core.issubset(set(names))
|
|
|
|
|
|
expected_ok = count >= 10
|
|
|
|
|
|
tools_ready = expected_ok and subset_ok
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
"status": "healthy",
|
|
|
|
|
|
"checks": {
|
|
|
|
|
|
"builtin_tools_ready": tools_ready,
|
|
|
|
|
|
"builtin_tools_count_ok": expected_ok,
|
|
|
|
|
|
"file_agent_core_ready": subset_ok,
|
|
|
|
|
|
},
|
|
|
|
|
|
"builtin_tools": {
|
|
|
|
|
|
"count": count,
|
|
|
|
|
|
"names": names,
|
|
|
|
|
|
"expected_min_count": 10,
|
|
|
|
|
|
},
|
|
|
|
|
|
"notes": {
|
|
|
|
|
|
"celery": "工作流/Agent 执行通常在 Celery Worker 中跑;Worker 日志中也应出现「内置工具就绪」且 count 应与 API 一致。若仅 API 有工具而 Worker 无,会出现 LLM 无法真正调用 file_write。",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
2026-01-19 00:09:36 +08:00
|
|
|
|
|
2026-01-23 09:49:45 +08:00
|
|
|
|
# 应用启动时初始化数据库和工具
|
2026-01-19 00:09:36 +08:00
|
|
|
|
@app.on_event("startup")
|
|
|
|
|
|
async def startup_event():
|
|
|
|
|
|
"""应用启动事件"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
logger.info("正在初始化数据库...")
|
|
|
|
|
|
init_db()
|
|
|
|
|
|
logger.info("数据库初始化完成")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"数据库初始化失败: {e}")
|
|
|
|
|
|
# 不抛出异常,允许应用继续启动
|
2026-01-23 09:49:45 +08:00
|
|
|
|
|
2026-04-08 11:44:24 +08:00
|
|
|
|
# 注册内置工具(与 Celery Worker 共用 app.core.tools_bootstrap)
|
2026-01-23 09:49:45 +08:00
|
|
|
|
try:
|
2026-04-08 11:44:24 +08:00
|
|
|
|
from app.core.tools_bootstrap import ensure_builtin_tools_registered
|
|
|
|
|
|
|
|
|
|
|
|
ensure_builtin_tools_registered()
|
2026-01-23 09:49:45 +08:00
|
|
|
|
from app.services.tool_registry import tool_registry
|
2026-04-08 11:44:24 +08:00
|
|
|
|
|
|
|
|
|
|
logger.info("内置工具注册完成(count=%s)", tool_registry.builtin_tool_count())
|
2026-01-23 09:49:45 +08:00
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"内置工具注册失败: {e}")
|
|
|
|
|
|
# 不抛出异常,允许应用继续启动
|
2026-01-19 00:09:36 +08:00
|
|
|
|
|
2026-05-02 00:38:41 +08:00
|
|
|
|
# 加载自定义工具(从数据库同步到注册表)
|
|
|
|
|
|
try:
|
|
|
|
|
|
from app.core.database import SessionLocal
|
|
|
|
|
|
db = SessionLocal()
|
|
|
|
|
|
try:
|
|
|
|
|
|
tool_registry.load_tools_from_db(db)
|
|
|
|
|
|
logger.info("自定义工具加载完成(count=%s)", len(tool_registry._tool_schemas) - tool_registry.builtin_tool_count())
|
|
|
|
|
|
finally:
|
|
|
|
|
|
db.close()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"自定义工具加载失败: {e}")
|
|
|
|
|
|
|
2026-05-02 16:17:49 +08:00
|
|
|
|
# 启动飞书长连接(在主事件循环中运行)
|
|
|
|
|
|
try:
|
|
|
|
|
|
from app.services.feishu_ws_handler import start_ws_client
|
|
|
|
|
|
asyncio.ensure_future(start_ws_client())
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"飞书长连接启动失败: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
# 启动橙子飞书长连接
|
|
|
|
|
|
try:
|
|
|
|
|
|
from app.services.orange_ws_handler import start_ws_client as start_orange_ws
|
|
|
|
|
|
asyncio.ensure_future(start_orange_ws())
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"橙子长连接启动失败: {e}")
|
|
|
|
|
|
|
2026-05-02 21:44:47 +08:00
|
|
|
|
# 启动苏瑶飞书长连接
|
|
|
|
|
|
try:
|
|
|
|
|
|
from app.services.suyao_ws_handler import start_ws_client as start_suyao_ws
|
|
|
|
|
|
asyncio.ensure_future(start_suyao_ws())
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"苏瑶长连接启动失败: {e}")
|
|
|
|
|
|
|
2026-05-02 21:53:36 +08:00
|
|
|
|
# 启动甜甜飞书长连接(苏瑶3号)
|
|
|
|
|
|
try:
|
|
|
|
|
|
from app.services.tiantian_ws_handler import start_ws_client as start_tiantian_ws
|
|
|
|
|
|
asyncio.ensure_future(start_tiantian_ws())
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"甜甜长连接启动失败: {e}")
|
|
|
|
|
|
|
2026-05-03 00:20:29 +08:00
|
|
|
|
# 启动灵犀飞书长连接(学习助手)
|
|
|
|
|
|
try:
|
|
|
|
|
|
from app.services.lingxi_ws_handler import start_ws_client as start_lingxi_ws
|
|
|
|
|
|
asyncio.ensure_future(start_lingxi_ws())
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"灵犀长连接启动失败: {e}")
|
|
|
|
|
|
|
2026-01-19 00:09:36 +08:00
|
|
|
|
# 注册路由
|
2026-05-02 16:17:49 +08:00
|
|
|
|
from app.api import auth, uploads, workflows, executions, websocket, execution_logs, data_sources, agents, platform_templates, model_configs, webhooks, template_market, batch_operations, collaboration, permissions, monitoring, alert_rules, node_test, node_templates, tools, agent_chat, agent_monitoring, knowledge_base, agent_schedules, notifications, feishu_bind
|
2026-01-19 00:09:36 +08:00
|
|
|
|
|
|
|
|
|
|
app.include_router(auth.router)
|
2026-04-13 20:17:18 +08:00
|
|
|
|
app.include_router(uploads.router)
|
2026-01-19 00:09:36 +08:00
|
|
|
|
app.include_router(workflows.router)
|
|
|
|
|
|
app.include_router(executions.router)
|
|
|
|
|
|
app.include_router(websocket.router)
|
|
|
|
|
|
app.include_router(execution_logs.router)
|
|
|
|
|
|
app.include_router(data_sources.router)
|
|
|
|
|
|
app.include_router(agents.router)
|
2026-04-09 21:58:53 +08:00
|
|
|
|
app.include_router(platform_templates.router)
|
2026-01-19 00:09:36 +08:00
|
|
|
|
app.include_router(model_configs.router)
|
|
|
|
|
|
app.include_router(webhooks.router)
|
|
|
|
|
|
app.include_router(template_market.router)
|
|
|
|
|
|
app.include_router(batch_operations.router)
|
|
|
|
|
|
app.include_router(collaboration.router)
|
|
|
|
|
|
app.include_router(permissions.router)
|
|
|
|
|
|
app.include_router(monitoring.router)
|
|
|
|
|
|
app.include_router(alert_rules.router)
|
|
|
|
|
|
app.include_router(node_test.router)
|
|
|
|
|
|
app.include_router(node_templates.router)
|
2026-01-23 09:49:45 +08:00
|
|
|
|
app.include_router(tools.router)
|
2026-05-01 11:31:48 +08:00
|
|
|
|
app.include_router(agent_chat.router)
|
2026-05-01 19:32:59 +08:00
|
|
|
|
app.include_router(agent_monitoring.router)
|
2026-05-01 22:30:46 +08:00
|
|
|
|
app.include_router(knowledge_base.router)
|
2026-05-02 12:14:37 +08:00
|
|
|
|
app.include_router(agent_schedules.router)
|
2026-05-02 16:17:49 +08:00
|
|
|
|
app.include_router(notifications.router)
|
|
|
|
|
|
app.include_router(feishu_bind.router)
|
2026-01-19 00:09:36 +08:00
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
import uvicorn
|
|
|
|
|
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|