mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 07:56:52 +08:00
fix(api): 修复LLM manage端点目录查询返回列表无法透过Dict响应模型校验导致设置页500
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, List, Optional, Union
|
||||||
|
|
||||||
from fastapi import Depends, Request, Response
|
from fastapi import Depends, Request, Response
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
@@ -15,7 +15,9 @@ router = ResponseAPIRouter()
|
|||||||
@router.post(
|
@router.post(
|
||||||
"/manage",
|
"/manage",
|
||||||
summary="LLM提供商统一管理",
|
summary="LLM提供商统一管理",
|
||||||
response_model=schemas.Response[Dict[str, Any]],
|
# 各动作 data 形态不一:目录查询返回列表,其余动作返回映射,
|
||||||
|
# 须用具体联合类型声明,而非单一开放映射
|
||||||
|
response_model=schemas.Response[Union[List[Dict[str, Any]], Dict[str, Any]]],
|
||||||
)
|
)
|
||||||
async def manage_provider(
|
async def manage_provider(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
@@ -637,6 +637,8 @@ def test_openapi_success_models_have_no_implicit_empty_nested_schemas():
|
|||||||
"ManageRequest",
|
"ManageRequest",
|
||||||
# 通用管理响应的 data 为模块自定义结构,按设计不固定字段。
|
# 通用管理响应的 data 为模块自定义结构,按设计不固定字段。
|
||||||
"Response_Dict_str__Any__",
|
"Response_Dict_str__Any__",
|
||||||
|
# LLM 提供商管理响应的 data 目录查询为列表、其余动作为映射。
|
||||||
|
"Response_Union_List_Dict_str__Any____Dict_str__Any___",
|
||||||
}
|
}
|
||||||
allowed_empty_components = {"McpJsonRpcEmptyResult"}
|
allowed_empty_components = {"McpJsonRpcEmptyResult"}
|
||||||
violations = []
|
violations = []
|
||||||
|
|||||||
@@ -279,3 +279,32 @@ def test_llm_manage_endpoint_accepts_empty_target(monkeypatch):
|
|||||||
assert resp.success is True
|
assert resp.success is True
|
||||||
assert captured["provider"] == ""
|
assert captured["provider"] == ""
|
||||||
assert "callback_url" not in captured["params"]
|
assert "callback_url" not in captured["params"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_llm_manage_endpoint_response_model_accepts_list_data():
|
||||||
|
"""目录查询动作 data 为列表,响应模型须同时覆盖列表与映射形态。
|
||||||
|
|
||||||
|
回归守护:list_providers 返回 list[dict],
|
||||||
|
若响应模型声明为 Dict[str, Any] 会在序列化校验时直接 500;
|
||||||
|
同时受响应模型守护测试约束,不得使用 Any/JsonData 弱类型。
|
||||||
|
"""
|
||||||
|
from typing import Any, Dict, List, Union
|
||||||
|
|
||||||
|
from app.api.endpoints import llm as llm_endpoint
|
||||||
|
|
||||||
|
route = next(
|
||||||
|
r for r in llm_endpoint.router.routes if getattr(r, "path", "").endswith("/manage")
|
||||||
|
)
|
||||||
|
assert route.response_model is schemas.Response[
|
||||||
|
Union[List[Dict[str, Any]], Dict[str, Any]]
|
||||||
|
]
|
||||||
|
|
||||||
|
list_resp = schemas.Response[Union[List[Dict[str, Any]], Dict[str, Any]]](
|
||||||
|
success=True, message="", data=[{"id": "openai", "name": "OpenAI 兼容"}]
|
||||||
|
)
|
||||||
|
assert list_resp.data == [{"id": "openai", "name": "OpenAI 兼容"}]
|
||||||
|
|
||||||
|
dict_resp = schemas.Response[Union[List[Dict[str, Any]], Dict[str, Any]]](
|
||||||
|
success=True, message="", data={"models": ["gpt-4o"]}
|
||||||
|
)
|
||||||
|
assert dict_resp.data == {"models": ["gpt-4o"]}
|
||||||
|
|||||||
Reference in New Issue
Block a user