96 lines
3.2 KiB
TypeScript
96 lines
3.2 KiB
TypeScript
import { isOptionalApiRouteMissing } from "./apiErrorUtils";
|
|
import { isRecord, serverRequest } from "./serverConnection";
|
|
|
|
export interface ModelCapabilityOption {
|
|
value: string;
|
|
label: string;
|
|
description?: string;
|
|
badge?: string;
|
|
enabled?: boolean;
|
|
status?: "available" | "maintenance" | "disabled" | string;
|
|
}
|
|
|
|
export interface WebModelCapabilities {
|
|
source: "server" | "fallback";
|
|
imageModels: ModelCapabilityOption[];
|
|
videoModels: ModelCapabilityOption[];
|
|
chatModels: ModelCapabilityOption[];
|
|
updatedAt?: string;
|
|
}
|
|
|
|
function toStringValue(value: unknown, fallback = ""): string {
|
|
if (typeof value === "string") return value.trim() || fallback;
|
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
return fallback;
|
|
}
|
|
|
|
function normalizeModelOption(raw: unknown): ModelCapabilityOption | null {
|
|
if (typeof raw === "string") {
|
|
const value = raw.trim();
|
|
return value ? { value, label: value } : null;
|
|
}
|
|
if (!isRecord(raw)) return null;
|
|
|
|
const value = toStringValue(raw.value ?? raw.id ?? raw.model ?? raw.modelKey ?? raw.model_key);
|
|
if (!value) return null;
|
|
|
|
const status = toStringValue(raw.status);
|
|
const enabled = raw.enabled === undefined ? status !== "maintenance" && status !== "disabled" : Boolean(raw.enabled);
|
|
if (!enabled) return null;
|
|
|
|
return {
|
|
value,
|
|
label: toStringValue(raw.label ?? raw.displayName ?? raw.display_name ?? raw.name, value),
|
|
description: toStringValue(raw.description) || undefined,
|
|
badge: toStringValue(raw.badge) || undefined,
|
|
enabled,
|
|
status: status || "available",
|
|
};
|
|
}
|
|
|
|
function normalizeModelList(value: unknown): ModelCapabilityOption[] {
|
|
return Array.isArray(value)
|
|
? value.map(normalizeModelOption).filter((item): item is ModelCapabilityOption => Boolean(item))
|
|
: [];
|
|
}
|
|
|
|
function createFallbackCapabilities(): WebModelCapabilities {
|
|
return {
|
|
source: "fallback",
|
|
imageModels: [],
|
|
videoModels: [],
|
|
chatModels: [],
|
|
};
|
|
}
|
|
|
|
let modelCapabilitiesRouteMissing = false;
|
|
|
|
export const modelCapabilitiesClient = {
|
|
async get(name = "web-model-capabilities"): Promise<WebModelCapabilities> {
|
|
if (modelCapabilitiesRouteMissing) return createFallbackCapabilities();
|
|
|
|
let payload: unknown;
|
|
try {
|
|
payload = await serverRequest<unknown>(`config/profile?name=${encodeURIComponent(name)}`);
|
|
} catch (error) {
|
|
if (isOptionalApiRouteMissing(error)) {
|
|
modelCapabilitiesRouteMissing = true;
|
|
return createFallbackCapabilities();
|
|
}
|
|
throw error;
|
|
}
|
|
|
|
const raw = isRecord(payload) && isRecord(payload.config) ? payload.config : payload;
|
|
const config = isRecord(raw) ? raw : {};
|
|
const models = isRecord(config.models) ? config.models : {};
|
|
|
|
return {
|
|
source: "server",
|
|
imageModels: normalizeModelList(config.imageModels ?? config.image_models ?? models.image),
|
|
videoModels: normalizeModelList(config.videoModels ?? config.video_models ?? models.video),
|
|
chatModels: normalizeModelList(config.chatModels ?? config.chat_models ?? models.chat ?? models.agent ?? models.text),
|
|
updatedAt: toStringValue((payload as { updatedAt?: unknown; updated_at?: unknown })?.updatedAt ?? (payload as { updated_at?: unknown })?.updated_at),
|
|
};
|
|
},
|
|
};
|