130 lines
3.7 KiB
TypeScript

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<ReturnType<typeof getAiProvidersByType>>[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<WorldLabsProviderConfig> {
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,
});
}