From b132a64de60d2a0fb8a1fb47b8826971c3e37553 Mon Sep 17 00:00:00 2001 From: DrSmoothl <1787882683@qq.com> Date: Sat, 2 May 2026 00:08:12 +0800 Subject: [PATCH 01/15] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91=EF=BC=8C=E5=A4=84?= =?UTF-8?q?=E7=90=86=E8=BF=94=E5=9B=9E=E7=9A=84=E6=A8=A1=E5=9E=8B=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E5=B9=B6=E6=B7=BB=E5=8A=A0=E9=89=B4=E6=9D=83=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard/src/lib/config-api.ts | 9 ++++++++- .../src/routes/config/modelProvider/ProviderForm.tsx | 6 +++++- src/webui/routers/model.py | 5 +++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dashboard/src/lib/config-api.ts b/dashboard/src/lib/config-api.ts index cfb51108..fa4ac5da 100644 --- a/dashboard/src/lib/config-api.ts +++ b/dashboard/src/lib/config-api.ts @@ -158,7 +158,14 @@ export async function fetchProviderModels( endpoint, }) const response = await fetchWithAuth(`/api/webui/models/list?${params}`) - return parseResponse(response) + // 后端返回 { success, models, provider, count },需要展开取出 models 数组 + const parsed = await parseResponse<{ models?: ModelListItem[] } | ModelListItem[]>(response) + if (!parsed.success) { + return parsed + } + const body = parsed.data + const models = Array.isArray(body) ? body : Array.isArray(body?.models) ? body.models : [] + return { success: true, data: models } } /** diff --git a/dashboard/src/routes/config/modelProvider/ProviderForm.tsx b/dashboard/src/routes/config/modelProvider/ProviderForm.tsx index 8095caa3..d7094ffa 100644 --- a/dashboard/src/routes/config/modelProvider/ProviderForm.tsx +++ b/dashboard/src/routes/config/modelProvider/ProviderForm.tsx @@ -138,7 +138,11 @@ export function ProviderForm({ -
{ e.preventDefault(); handleSaveEdit(); }} autoComplete="off"> + { e.preventDefault(); handleSaveEdit(); }} + autoComplete="off" + className="contents" + >
diff --git a/src/webui/routers/model.py b/src/webui/routers/model.py index fad701ba..27323835 100644 --- a/src/webui/routers/model.py +++ b/src/webui/routers/model.py @@ -146,6 +146,11 @@ async def _fetch_models_from_provider( client_config = build_openai_compatible_client_config(provider) headers.update(client_config.default_headers) params.update(client_config.default_query) + # build_openai_compatible_client_config 在“默认 Bearer”场景下, + # 会把 api_key 留在 client_config.api_key 中交给 OpenAI SDK 自行注入 Authorization 头, + # 而不会写入 default_headers。这里我们用 httpx 直接发请求,需要手动补上鉴权头/参数。 + if client_config.api_key and "Authorization" not in headers: + headers["Authorization"] = f"Bearer {client_config.api_key}" try: async with httpx.AsyncClient(timeout=30.0) as client: From be79d09a07d29426dfbb7c75acd9c9b7ef6e7405 Mon Sep 17 00:00:00 2001 From: DrSmoothl <1787882683@qq.com> Date: Sat, 2 May 2026 11:42:34 +0800 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0Sidebar?= =?UTF-8?q?=E5=92=8CDialog=E7=BB=84=E4=BB=B6=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E5=92=8C=E5=B8=83=E5=B1=80=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=BC=BAScrollArea=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot --- dashboard/src/components/layout/Sidebar.tsx | 8 +++++--- dashboard/src/components/ui/dialog.tsx | 12 ++++++++---- dashboard/src/components/ui/scroll-area.tsx | 5 ++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/dashboard/src/components/layout/Sidebar.tsx b/dashboard/src/components/layout/Sidebar.tsx index 55392b13..df28de66 100644 --- a/dashboard/src/components/layout/Sidebar.tsx +++ b/dashboard/src/components/layout/Sidebar.tsx @@ -29,7 +29,7 @@ export function Sidebar({ return (
diff --git a/dashboard/src/routes/plugins/MarketplaceTab.tsx b/dashboard/src/routes/plugins/MarketplaceTab.tsx index bcd4b8c2..e623530c 100644 --- a/dashboard/src/routes/plugins/MarketplaceTab.tsx +++ b/dashboard/src/routes/plugins/MarketplaceTab.tsx @@ -16,6 +16,7 @@ interface MarketplaceTabProps { checkPluginCompatibility: (plugin: PluginInfo) => boolean needsUpdate: (plugin: PluginInfo) => boolean getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null + getIncompatibleReason: (plugin: PluginInfo) => string | null } export function MarketplaceTab({ @@ -33,6 +34,7 @@ export function MarketplaceTab({ checkPluginCompatibility, needsUpdate, getStatusBadge, + getIncompatibleReason, }: MarketplaceTabProps) { // 过滤插件 const filteredPlugins = plugins.filter(plugin => { @@ -76,6 +78,7 @@ export function MarketplaceTab({ checkPluginCompatibility={checkPluginCompatibility} needsUpdate={needsUpdate} getStatusBadge={getStatusBadge} + getIncompatibleReason={getIncompatibleReason} /> ))}
diff --git a/dashboard/src/routes/plugins/PluginCard.tsx b/dashboard/src/routes/plugins/PluginCard.tsx index ad6d3f1e..93a0fdb1 100644 --- a/dashboard/src/routes/plugins/PluginCard.tsx +++ b/dashboard/src/routes/plugins/PluginCard.tsx @@ -20,6 +20,7 @@ interface PluginCardProps { checkPluginCompatibility: (plugin: PluginInfo) => boolean needsUpdate: (plugin: PluginInfo) => boolean getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null + getIncompatibleReason: (plugin: PluginInfo) => string | null } export function PluginCard({ @@ -34,6 +35,7 @@ export function PluginCard({ checkPluginCompatibility, needsUpdate, getStatusBadge, + getIncompatibleReason, }: PluginCardProps) { const navigate = useNavigate() @@ -114,8 +116,14 @@ export function PluginCard({ needsUpdate(plugin) ? (