diff --git a/app/(admin)/settings/_components/local-ai-sections/model3d-sections.tsx b/app/(admin)/settings/_components/local-ai-sections/model3d-sections.tsx
index 754910fa9..9d4ed9987 100644
--- a/app/(admin)/settings/_components/local-ai-sections/model3d-sections.tsx
+++ b/app/(admin)/settings/_components/local-ai-sections/model3d-sections.tsx
@@ -372,9 +372,10 @@ export function LocalAiModel3dSections({
- setWorldlabsKeyPoolConfig({
+ setWorldlabsKeyPoolConfig((prev) => ({
+ ...prev,
importToken: e.target.value,
- })
+ }))
}
placeholder="供 /api/worldlabs/key-pool/import 调用的 Bearer Token"
type="password"
diff --git a/app/(admin)/settings/_lib/types.ts b/app/(admin)/settings/_lib/types.ts
index a4ee95841..20e8cebab 100644
--- a/app/(admin)/settings/_lib/types.ts
+++ b/app/(admin)/settings/_lib/types.ts
@@ -167,6 +167,9 @@ export type AiProviderSettingsConfig = {
export type WorldLabsKeyPoolConfig = {
importToken: string;
+ providerName: string;
+ baseUrl: string;
+ isEnabled: boolean;
};
export type LocalAiModel3dSectionsProps = LocalAiSectionControlProps & {
diff --git a/app/(admin)/settings/admin-settings-client.tsx b/app/(admin)/settings/admin-settings-client.tsx
index cb4b45db9..38cca481d 100644
--- a/app/(admin)/settings/admin-settings-client.tsx
+++ b/app/(admin)/settings/admin-settings-client.tsx
@@ -3120,15 +3120,19 @@ export function AdminSettingsClient() {
}, [providersData?.providers]);
useEffect(() => {
+ const savedWorldlabsConfig = normalizeWorldLabsKeyPoolConfig(
+ worldlabsKeyPoolConfigData?.setting?.value
+ );
const worldlabsProvider = (providersData?.providers || []).find(
(provider) => provider.type === "worldlabs-3d"
);
if (worldlabsProvider) {
setWorldlabs3dConfig({
providerId: worldlabsProvider.id,
- name: worldlabsProvider.name || "World Labs",
+ name: worldlabsProvider.name || savedWorldlabsConfig.providerName,
baseUrl:
worldlabsProvider.baseUrl ||
+ savedWorldlabsConfig.baseUrl ||
getProviderDefaultBaseUrl("worldlabs-3d"),
apiKey: "",
isEnabled: worldlabsProvider.isEnabled,
@@ -3136,14 +3140,15 @@ export function AdminSettingsClient() {
return;
}
- setWorldlabs3dConfig({
+ setWorldlabs3dConfig((prev) => ({
providerId: "",
- name: "World Labs",
- baseUrl: getProviderDefaultBaseUrl("worldlabs-3d"),
- apiKey: "",
- isEnabled: true,
- });
- }, [providersData?.providers]);
+ name: savedWorldlabsConfig.providerName || "World Labs",
+ baseUrl:
+ savedWorldlabsConfig.baseUrl || getProviderDefaultBaseUrl("worldlabs-3d"),
+ apiKey: prev.providerId ? "" : prev.apiKey,
+ isEnabled: savedWorldlabsConfig.isEnabled,
+ }));
+ }, [providersData?.providers, worldlabsKeyPoolConfigData?.setting?.value]);
useEffect(() => {
setWorldlabsKeyPoolConfig(
@@ -6407,9 +6412,37 @@ export function AdminSettingsClient() {
worldlabs3dConfig.baseUrl.trim() ||
getProviderDefaultBaseUrl("worldlabs-3d");
const hasProvider = Boolean(worldlabs3dConfig.providerId);
+ const normalizedKeyPoolConfig = normalizeWorldLabsKeyPoolConfig({
+ ...worldlabsKeyPoolConfig,
+ providerName: trimmedName,
+ baseUrl: trimmedBaseUrl,
+ isEnabled: worldlabs3dConfig.isEnabled,
+ });
if (!hasProvider && !worldlabs3dConfig.apiKey.trim()) {
- toast.error("请填写 World Labs API Key");
+ const keyPoolResponse = await fetch("/api/admin/settings", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ key: WORLDLABS_KEY_POOL_CONFIG_KEY,
+ value: normalizedKeyPoolConfig,
+ }),
+ });
+
+ if (!keyPoolResponse.ok) {
+ const payload = await keyPoolResponse.json().catch(() => ({}));
+ throw new Error(
+ String(
+ payload?.message ||
+ payload?.error ||
+ "保存 World Labs 基础配置失败"
+ )
+ );
+ }
+
+ setWorldlabsKeyPoolConfig(normalizedKeyPoolConfig);
+ mutateWorldlabsKeyPoolConfig();
+ toast.success("World Labs 基础配置已保存,添加 API Key 后即可生成");
return;
}
@@ -6448,7 +6481,7 @@ export function AdminSettingsClient() {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
key: WORLDLABS_KEY_POOL_CONFIG_KEY,
- value: normalizeWorldLabsKeyPoolConfig(worldlabsKeyPoolConfig),
+ value: normalizedKeyPoolConfig,
}),
});
@@ -6465,6 +6498,7 @@ export function AdminSettingsClient() {
toast.success("World Labs 配置保存成功");
setWorldlabs3dConfig((prev) => ({ ...prev, apiKey: "" }));
+ setWorldlabsKeyPoolConfig(normalizedKeyPoolConfig);
mutateProviders();
mutateWorldlabsKeyPoolConfig();
} catch (error) {
diff --git a/app/api/worldlabs/key-pool/import/route.ts b/app/api/worldlabs/key-pool/import/route.ts
index 8e8835032..11c74a603 100644
--- a/app/api/worldlabs/key-pool/import/route.ts
+++ b/app/api/worldlabs/key-pool/import/route.ts
@@ -9,13 +9,14 @@ import {
sanitizeWorldLabsApiKey,
sanitizeWorldLabsBaseUrl,
} from "@/lib/worldlabs/server";
-import { getWorldLabsKeyPoolConfig } from "@/lib/worldlabs/key-pool-config";
+import {
+ DEFAULT_WORLDLABS_BASE_URL,
+ getWorldLabsKeyPoolConfig,
+} from "@/lib/worldlabs/key-pool-config";
export const runtime = "nodejs";
export const maxDuration = 60;
-const DEFAULT_WORLDLABS_BASE_URL = "https://api.worldlabs.ai";
-
const importPayloadSchema = z.object({
keys: z
.array(
@@ -161,7 +162,7 @@ export async function POST(request: Request) {
);
const defaultBaseUrl =
- sanitizeWorldLabsBaseUrl(payload.baseUrl || "") ||
+ sanitizeWorldLabsBaseUrl(payload.baseUrl || dbConfig.baseUrl || "") ||
DEFAULT_WORLDLABS_BASE_URL;
const defaultIsEnabled = payload.isEnabled !== false;
const namePrefix = String(payload.namePrefix || "WorldLabsKey").trim();
diff --git a/lib/worldlabs/key-pool-config-shared.ts b/lib/worldlabs/key-pool-config-shared.ts
index f80a4da3c..494072ef2 100644
--- a/lib/worldlabs/key-pool-config-shared.ts
+++ b/lib/worldlabs/key-pool-config-shared.ts
@@ -1,11 +1,18 @@
export const WORLDLABS_KEY_POOL_CONFIG_KEY = "worldlabs_key_pool_config";
+export const DEFAULT_WORLDLABS_BASE_URL = "https://api.worldlabs.ai";
export type WorldLabsKeyPoolConfig = {
importToken: string;
+ providerName: string;
+ baseUrl: string;
+ isEnabled: boolean;
};
export const defaultWorldLabsKeyPoolConfig: WorldLabsKeyPoolConfig = {
importToken: "",
+ providerName: "World Labs",
+ baseUrl: DEFAULT_WORLDLABS_BASE_URL,
+ isEnabled: true,
};
function normalizeImportToken(value: unknown) {
@@ -25,5 +32,11 @@ export function normalizeWorldLabsKeyPoolConfig(
const raw = value as Partial;
return {
importToken: normalizeImportToken(raw.importToken),
+ providerName:
+ String(raw.providerName || "World Labs").trim() || "World Labs",
+ baseUrl:
+ String(raw.baseUrl || DEFAULT_WORLDLABS_BASE_URL).trim() ||
+ DEFAULT_WORLDLABS_BASE_URL,
+ isEnabled: raw.isEnabled !== false,
};
}
diff --git a/lib/worldlabs/key-pool-config.ts b/lib/worldlabs/key-pool-config.ts
index d0c1ef46b..5bca9c4a1 100644
--- a/lib/worldlabs/key-pool-config.ts
+++ b/lib/worldlabs/key-pool-config.ts
@@ -2,6 +2,7 @@ import "server-only";
import { getSystemSetting } from "@/lib/db/queries";
import {
+ DEFAULT_WORLDLABS_BASE_URL,
defaultWorldLabsKeyPoolConfig,
normalizeWorldLabsKeyPoolConfig,
WORLDLABS_KEY_POOL_CONFIG_KEY,
@@ -9,6 +10,7 @@ import {
} from "@/lib/worldlabs/key-pool-config-shared";
export {
+ DEFAULT_WORLDLABS_BASE_URL,
defaultWorldLabsKeyPoolConfig,
normalizeWorldLabsKeyPoolConfig,
WORLDLABS_KEY_POOL_CONFIG_KEY,