from typing import Any, Dict, List, Optional, Union from fastapi import Depends, Request, Response from fastapi.responses import HTMLResponse from app import schemas from app.api.response import ResponseAPIRouter from app.db.models import User from app.api.deps import get_current_active_superuser_async router = ResponseAPIRouter() def _get_llm_provider_manager_type() -> type: """在真实管理请求边界解析 provider 运行时。""" from app.agent.llm.provider import LLMProviderManager return LLMProviderManager @router.post( "/manage", summary="LLM提供商统一管理", # 各动作 data 形态不一:目录查询返回列表,其余动作返回映射, # 须用具体联合类型声明,而非单一开放映射 response_model=schemas.Response[Union[List[Dict[str, Any]], Dict[str, Any]]], ) async def manage_provider( request: Request, payload: schemas.ManageRequest, _: User = Depends(get_current_active_superuser_async), ): """ LLM 提供商统一管理入口:前端上送 target/action/params 原样透传, 端点不定义任何提供商特定的名称、参数或响应字段; OAuth 回跳地址由具名回调路由统一构造后注入动作参数 """ params = dict(payload.params) # 目录类查询动作的 target 可为空,此时无需回跳地址; # 且 url_for 的路径参数不允许空值,必须先行防护 if payload.target: params.setdefault( "callback_url", str(request.url_for("llm_provider_auth_callback", provider_id=payload.target)), ) result = await _get_llm_provider_manager_type()().provider_manage( payload.target, payload.action, **params ) return schemas.Response( success=bool(result.get("success")), message=result.get("message"), data=result.get("data"), ) @router.get( "/provider-auth/callback/{provider_id}", summary="LLM提供商OAuth回调", response_class=Response, name="llm_provider_auth_callback", response_model=None, responses={ 200: { "description": "OAuth 授权结果页面", "content": {"text/html": {"schema": {"type": "string"}}}, } }, ) async def llm_provider_auth_callback( provider_id: str, code: Optional[str] = None, state: Optional[str] = None, error: Optional[str] = None, error_description: Optional[str] = None, ): """ 处理需要浏览器回跳的 OAuth provider。 """ success, message = await _get_llm_provider_manager_type()().handle_chatgpt_callback( provider_id, code, state, error, error_description, ) from app.agent.llm.provider import render_auth_result_html return HTMLResponse(content=render_auth_result_html(success, message))