feat: 添加管理员模型配置页面与 config.yaml 模型管理 API
新增 /api/admin/models 路由(读写 config.yaml models 段、连接测试、写前备份),以及工作区「模型配置」管理页与侧栏入口。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
17a12bb7b6
commit
ba912acf72
10 files changed
+962
-6
No files matched your search
@@ -0,0 +1,107 @@
|
||||
import { apiFetch } from "@/core/api";
|
||||
import { getBackendBaseURL } from "@/core/config";
|
||||
|
||||
export interface ManagedModel {
|
||||
name: string;
|
||||
display_name: string | null;
|
||||
description: string | null;
|
||||
use: string;
|
||||
model: string;
|
||||
base_url: string | null;
|
||||
request_timeout: number | null;
|
||||
max_retries: number | null;
|
||||
max_tokens: number | null;
|
||||
temperature: number | null;
|
||||
stream_usage: boolean | null;
|
||||
supports_thinking: boolean;
|
||||
supports_reasoning_effort: boolean;
|
||||
supports_vision: boolean;
|
||||
when_thinking_enabled: Record<string, unknown> | null;
|
||||
when_thinking_disabled: Record<string, unknown> | null;
|
||||
thinking: Record<string, unknown> | null;
|
||||
use_responses_api: boolean | null;
|
||||
output_version: string | null;
|
||||
extra_settings: Record<string, unknown>;
|
||||
api_key_configured: boolean;
|
||||
api_key_source: string | null;
|
||||
source: "config.yaml";
|
||||
}
|
||||
|
||||
export interface ManagedModelsResponse {
|
||||
models: ManagedModel[];
|
||||
config_path: string;
|
||||
updated_at: string | null;
|
||||
}
|
||||
|
||||
export interface ModelSavePayload {
|
||||
name: string;
|
||||
display_name?: string | null;
|
||||
description?: string | null;
|
||||
use: string;
|
||||
model: string;
|
||||
api_key?: string;
|
||||
clear_api_key?: boolean;
|
||||
base_url?: string | null;
|
||||
request_timeout?: number | null;
|
||||
max_retries?: number | null;
|
||||
max_tokens?: number | null;
|
||||
temperature?: number | null;
|
||||
stream_usage?: boolean | null;
|
||||
supports_thinking: boolean;
|
||||
supports_reasoning_effort: boolean;
|
||||
supports_vision: boolean;
|
||||
when_thinking_enabled?: Record<string, unknown> | null;
|
||||
when_thinking_disabled?: Record<string, unknown> | null;
|
||||
thinking?: Record<string, unknown> | null;
|
||||
use_responses_api?: boolean | null;
|
||||
output_version?: string | null;
|
||||
extra_settings: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface ModelConnectionTestResult {
|
||||
success: boolean;
|
||||
latency_ms: number;
|
||||
message: string;
|
||||
preview?: string | null;
|
||||
}
|
||||
|
||||
async function readError(response: Response, fallback: string): Promise<never> {
|
||||
const payload = await response.json().catch(() => null) as { detail?: string } | null;
|
||||
throw new Error(payload?.detail || fallback);
|
||||
}
|
||||
|
||||
export async function loadManagedModels(): Promise<ManagedModelsResponse> {
|
||||
const response = await apiFetch(`${getBackendBaseURL()}/api/admin/models`);
|
||||
if (!response.ok) return readError(response, "加载模型配置失败");
|
||||
return response.json() as Promise<ManagedModelsResponse>;
|
||||
}
|
||||
|
||||
export async function createManagedModel(payload: ModelSavePayload): Promise<ManagedModel> {
|
||||
const response = await apiFetch(`${getBackendBaseURL()}/api/admin/models`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!response.ok) return readError(response, "创建模型失败");
|
||||
return response.json() as Promise<ManagedModel>;
|
||||
}
|
||||
|
||||
export async function updateManagedModel(name: string, payload: ModelSavePayload): Promise<ManagedModel> {
|
||||
const response = await apiFetch(`${getBackendBaseURL()}/api/admin/models/${encodeURIComponent(name)}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!response.ok) return readError(response, "保存模型配置失败");
|
||||
return response.json() as Promise<ManagedModel>;
|
||||
}
|
||||
|
||||
export async function testManagedModel(model: ModelSavePayload): Promise<ModelConnectionTestResult> {
|
||||
const response = await apiFetch(`${getBackendBaseURL()}/api/admin/models/test`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ model }),
|
||||
});
|
||||
if (!response.ok) return readError(response, "模型连接测试失败");
|
||||
return response.json() as Promise<ModelConnectionTestResult>;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import {
|
||||
createManagedModel,
|
||||
loadManagedModels,
|
||||
testManagedModel,
|
||||
updateManagedModel,
|
||||
type ModelSavePayload,
|
||||
} from "./api";
|
||||
|
||||
export const MANAGED_MODELS_QUERY_KEY = ["admin", "model-config"] as const;
|
||||
|
||||
export function useManagedModels() {
|
||||
return useQuery({
|
||||
queryKey: MANAGED_MODELS_QUERY_KEY,
|
||||
queryFn: loadManagedModels,
|
||||
staleTime: 10_000,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
|
||||
export function useSaveManagedModel() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ name, payload, isNew }: { name: string; payload: ModelSavePayload; isNew: boolean }) =>
|
||||
isNew ? createManagedModel(payload) : updateManagedModel(name, payload),
|
||||
onSuccess: async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: MANAGED_MODELS_QUERY_KEY }),
|
||||
queryClient.invalidateQueries({ queryKey: ["models"] }),
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useTestManagedModel() {
|
||||
return useMutation({ mutationFn: testManagedModel });
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./api";
|
||||
export * from "./hooks";
|
||||
Reference in new issue
Block a user