ai-chatbot/lib/ai/model-classification.ts
Your Name ccc2e45b12
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
Add BFL image runtime provider
2026-03-21 01:36:53 +08:00

118 lines
2.8 KiB
TypeScript

const STATIC_VIDEO_PROVIDER_TYPES = new Set([
"doubao-video",
"volcano-video",
"qianwen-video",
"fal-video",
"ruxa-video",
]);
const STATIC_IMAGE_PROVIDER_TYPES = new Set([
"gemini",
"huanke-gemini",
"alibaba-image",
"bfl-image",
"ruxa-image",
"fal-image",
"openai-image",
"midjourney",
"volcano-vision",
]);
const RUNWAY_IMAGE_MODEL_IDS = new Set([
"gen4_image",
"gen4_image_turbo",
"gemini_2.5_flash",
]);
const RUNWAY_VIDEO_MODEL_PREFIXES = [
"gen4.5",
"gen4_turbo",
"gen4_aleph",
"gen3a_turbo",
"veo3.1_fast",
"veo3.1",
"veo3",
"act_two",
"upscale_v1",
];
const VIDEO_MODE_KEYS = new Set([
"text-to-video",
"first-frame",
"first-last-frame",
"reference-images",
]);
function normalizeText(value?: string | null) {
return String(value || "").trim().toLowerCase();
}
function hasVideoModes(capabilities: unknown) {
if (!capabilities || typeof capabilities !== "object") return false;
const supportedModes = (capabilities as { supportedModes?: unknown }).supportedModes;
if (!Array.isArray(supportedModes)) return false;
return supportedModes.some((mode) => VIDEO_MODE_KEYS.has(String(mode || "").trim()));
}
export function inferRunwayModelKind(modelId?: string | null): "image" | "video" | null {
const normalized = normalizeText(modelId);
if (!normalized) return null;
if (RUNWAY_IMAGE_MODEL_IDS.has(normalized)) return "image";
if (RUNWAY_VIDEO_MODEL_PREFIXES.some((prefix) => normalized === prefix || normalized.startsWith(`${prefix}_`))) {
return "video";
}
return null;
}
export function isStaticVideoProviderType(providerType?: string | null): boolean {
return STATIC_VIDEO_PROVIDER_TYPES.has(normalizeText(providerType));
}
export function isVideoModelDescriptor(params: {
providerType?: string | null;
modelId?: string | null;
capabilities?: unknown;
supportsImageGen?: boolean | null;
}): boolean {
const providerType = normalizeText(params.providerType);
if (isStaticVideoProviderType(providerType)) {
return true;
}
if (hasVideoModes(params.capabilities)) {
return true;
}
if (providerType === "runway") {
return inferRunwayModelKind(params.modelId) === "video";
}
return false;
}
export function isImageGenerationModelDescriptor(params: {
providerType?: string | null;
modelId?: string | null;
capabilities?: unknown;
supportsImageGen?: boolean | null;
}): boolean {
const providerType = normalizeText(params.providerType);
if (providerType === "runway") {
const runwayModelKind = inferRunwayModelKind(params.modelId);
if (runwayModelKind === "image") return true;
if (runwayModelKind === "video") return false;
}
if (isVideoModelDescriptor(params)) {
return false;
}
if (params.supportsImageGen === true) {
return true;
}
return STATIC_IMAGE_PROVIDER_TYPES.has(providerType);
}