import "server-only"; import { getAiProviderById, getAiProvidersByType, } from "@/lib/db/queries"; import { DEFAULT_WORLDLABS_BASE_URL } from "./client"; import type { WorldLabsProviderConfig } from "./types"; let worldLabsProviderCursor = 0; export function sanitizeWorldLabsApiKey(value: string): string { return String(value || "") .replace(/[\u2028\u2029]/g, "") .replace(/[\u0000-\u001F\u007F]/g, "") .replace(/\s+/g, "") .trim(); } export function sanitizeWorldLabsBaseUrl(value: string): string { return String(value || "") .replace(/[\u2028\u2029]/g, "") .replace(/[\u0000-\u001F\u007F]/g, "") .trim(); } function providerToWorldLabsConfig( provider: Awaited>[number] | undefined ): WorldLabsProviderConfig | null { if (!provider) return null; const providerApiKey = sanitizeWorldLabsApiKey(String(provider.apiKey || "")); if (!providerApiKey) return null; return { apiKey: providerApiKey, baseUrl: sanitizeWorldLabsBaseUrl(String(provider.baseUrl || "")) || DEFAULT_WORLDLABS_BASE_URL, providerId: provider.id, providerName: provider.name, } satisfies WorldLabsProviderConfig; } export async function getWorldLabsProviderConfigs(): Promise< WorldLabsProviderConfig[] > { const legacyProviders = await getAiProvidersByType({ type: "worldlabs-3d", enabledOnly: true, }); const providers = legacyProviders.length > 0 ? legacyProviders : await getAiProvidersByType({ type: "vip98k", enabledOnly: true, }); const normalizedProviders = providers .map((provider) => providerToWorldLabsConfig(provider)) .filter((item): item is WorldLabsProviderConfig => Boolean(item)); if (normalizedProviders.length > 0) { return normalizedProviders; } const envApiKey = sanitizeWorldLabsApiKey(String(process.env.WORLDLABS_API_KEY || "")); if (!envApiKey) { return []; } return [ { apiKey: envApiKey, baseUrl: sanitizeWorldLabsBaseUrl(String(process.env.WORLDLABS_BASE_URL || "")) || DEFAULT_WORLDLABS_BASE_URL, providerName: "WORLDLABS_API_KEY", }, ]; } export async function getWorldLabsProviderConfig( preferredProviderId?: string | null, options?: { includeDisabledPreferred?: boolean } ): Promise { const providers = await getWorldLabsProviderConfigs(); const preferredId = String(preferredProviderId || "").trim(); if (preferredId) { const matchedProvider = providers.find((item) => item.providerId === preferredId) || null; if (matchedProvider) { return matchedProvider; } if (options?.includeDisabledPreferred) { const disabledOrEnabledProvider = providerToWorldLabsConfig( await getAiProviderById({ id: preferredId }) ); if (disabledOrEnabledProvider) { return disabledOrEnabledProvider; } } } const worldLabsProvider = providers.length > 0 ? providers[worldLabsProviderCursor % providers.length] : null; if (providers.length > 0) { worldLabsProviderCursor = (worldLabsProviderCursor + 1) % providers.length; } if (worldLabsProvider) { return worldLabsProvider; } throw new Error("未配置 3D 世界服务,请启用 VIP98K 服务商并同步 world-generation 模型"); } export async function reportWorldLabsProviderRuntimeFailure( providerId?: string | null, reason?: string ) { const normalizedProviderId = String(providerId || "").trim(); if (!normalizedProviderId) return; console.warn("[WorldLabsPool] Provider reported a runtime failure; keeping enabled", { providerId: normalizedProviderId, reason, }); }