style(api): 重构api架构

This commit is contained in:
2026-05-05 20:33:18 +08:00
parent d30c7e37a6
commit b3ea4cd8d9
3 changed files with 116 additions and 130 deletions
-129
View File
@@ -1,129 +0,0 @@
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from typing import Dict
from fastapi import FastAPI, WebSocket, Request
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse, JSONResponse
from pretor.api.platform.frontend import client_router
from pretor.api.auth import auth_router
from pretor.api.provider import provider_router
from pretor.api.resource import resource_router
from pretor.api.cluster import cluster_router
from pretor.api.agent import agent_router
from pretor.api.workflow import workflow_router
from pretor.utils.error import (
DemandError, ModelNotExistError, UserError,
UserNotExistError, UserPasswordError, ProviderError,
ProviderNotExistError, WorkflowError, WorkflowExit
)
from ray import serve
app = FastAPI()
app.include_router(client_router) # 客户端路径
app.include_router(auth_router) # 用户路径
app.include_router(provider_router) # 供应商路径
app.include_router(resource_router) # 资源路径
app.include_router(cluster_router) # 集群信息路径
app.include_router(agent_router) # agent路径
app.include_router(workflow_router) # workflow路径
@app.exception_handler(UserNotExistError)
async def user_not_exist_handler(request: Request, exc: UserNotExistError):
return JSONResponse(status_code=404, content={"message": "用户不存在"})
@app.exception_handler(UserPasswordError)
async def user_password_handler(request: Request, exc: UserPasswordError):
return JSONResponse(status_code=401, content={"message": "密码错误"})
@app.exception_handler(UserError)
async def user_error_handler(request: Request, exc: UserError):
return JSONResponse(status_code=400, content={"message": "用户相关错误"})
@app.exception_handler(ProviderNotExistError)
async def provider_not_exist_handler(request: Request, exc: ProviderNotExistError):
return JSONResponse(status_code=404, content={"message": "服务提供商不存在"})
@app.exception_handler(ProviderError)
async def provider_error_handler(request: Request, exc: ProviderError):
return JSONResponse(status_code=400, content={"message": "服务提供商错误"})
@app.exception_handler(ModelNotExistError)
async def model_not_exist_handler(request: Request, exc: ModelNotExistError):
return JSONResponse(status_code=404, content={"message": "模型不存在"})
@app.exception_handler(DemandError)
async def demand_error_handler(request: Request, exc: DemandError):
return JSONResponse(status_code=400, content={"message": "需求格式错误或不满足"})
@app.exception_handler(WorkflowExit)
async def workflow_exit_handler(request: Request, exc: WorkflowExit):
return JSONResponse(status_code=400, content={"message": "工作流已退出"})
@app.exception_handler(WorkflowError)
async def workflow_error_handler(request: Request, exc: WorkflowError):
return JSONResponse(status_code=500, content={"message": "工作流执行错误"})
base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
frontend_dir = os.path.join(base_dir, "frontend", "dist")
if os.path.exists(frontend_dir):
app.mount("/assets", StaticFiles(directory=os.path.join(frontend_dir, "assets")), name="assets")
@app.get("/favicon.svg", include_in_schema=False)
async def serve_favicon():
return FileResponse(os.path.join(frontend_dir, "favicon.svg"))
@app.get("/icons.svg", include_in_schema=False)
async def serve_icons():
return FileResponse(os.path.join(frontend_dir, "icons.svg"))
@app.get("/{full_path:path}", include_in_schema=False)
async def serve_frontend(full_path: str):
# 【重要安全修复】避免拦截不存在的 API 路由。如果是调用了不存在的 /api/ 接口,直接返回 404,不返回前端页面
if full_path.startswith("api/"):
return JSONResponse(status_code=404, content={"detail": "API endpoint not found"})
index_path = os.path.join(frontend_dir, "index.html")
if os.path.exists(index_path):
return FileResponse(index_path)
return JSONResponse(status_code=404, content={"detail": "Frontend build not found"})
else:
import logging
logging.getLogger("pretor").warning(f"Frontend dist folder not found at {frontend_dir}. Skipping frontend mount.")
@serve.deployment
@serve.ingress(app)
class PretorGateway:
gateway: Dict[str, WebSocket]
def __init__(self):
self.gateway = {}