export type JsonValue = any; export type JsonRecord = Record; export interface VideoPromptSchemaFieldConfig { key: string; label: string; type?: string; enabled: boolean; editable: boolean; maxLength?: number; } export interface VideoPromptSchemaSectionConfig extends VideoPromptSchemaFieldConfig { contentKey?: string; itemFields: VideoPromptSchemaFieldConfig[]; children: VideoPromptSchemaFieldConfig[]; } function isRecord(value: unknown): value is JsonRecord { return !!value && typeof value === 'object' && !Array.isArray(value); } function readString(source: JsonRecord, ...keys: string[]): string { for (const key of keys) { const value = source[key]; if (value !== undefined && value !== null && String(value).trim() !== '') return String(value); } return ''; } function readBool(source: JsonRecord, defaultValue: boolean, ...keys: string[]): boolean { for (const key of keys) { const value = source[key]; if (value === true || value === false) return value; if (value === 'true') return true; if (value === 'false') return false; } return defaultValue; } function readNumber(source: JsonRecord, ...keys: string[]): number | undefined { for (const key of keys) { const value = source[key]; if (typeof value === 'number' && Number.isFinite(value) && value > 0) return value; if (typeof value === 'string' && value.trim()) { const parsed = Number(value); if (Number.isFinite(parsed) && parsed > 0) return parsed; } } return undefined; } function normalizeField(raw: unknown): VideoPromptSchemaFieldConfig | null { if (!isRecord(raw)) return null; const key = readString(raw, 'key'); if (!key) return null; return { key, label: readString(raw, 'label') || key, type: readString(raw, 'type') || undefined, enabled: readBool(raw, true, 'enabled'), editable: readBool(raw, true, 'editable'), maxLength: readNumber(raw, 'maxLength', 'max_length'), }; } export function getSchemaConfigData(snapshot: unknown): JsonRecord | null { if (!isRecord(snapshot)) return null; const data = snapshot.data; if (isRecord(data)) return data; if (Array.isArray(snapshot.sections)) return snapshot; return null; } export function hasSchemaConfigSnapshot(snapshot: unknown): boolean { return !!getSchemaConfigData(snapshot); } export function normalizeSchemaSections(snapshot: unknown): VideoPromptSchemaSectionConfig[] { const data = getSchemaConfigData(snapshot); const rawSections = Array.isArray(data?.sections) ? data.sections : []; return rawSections .map((raw): VideoPromptSchemaSectionConfig | null => { const base = normalizeField(raw); if (!base || !isRecord(raw)) return null; const children = Array.isArray(raw.children) ? raw.children.map(normalizeField).filter(Boolean) as VideoPromptSchemaFieldConfig[] : []; const itemFields = Array.isArray(raw.itemFields) ? raw.itemFields.map(normalizeField).filter(Boolean) as VideoPromptSchemaFieldConfig[] : Array.isArray(raw.item_fields) ? raw.item_fields.map(normalizeField).filter(Boolean) as VideoPromptSchemaFieldConfig[] : []; return { ...base, contentKey: readString(raw, 'contentKey', 'content_key') || undefined, children, itemFields, }; }) .filter((section): section is VideoPromptSchemaSectionConfig => !!section && section.enabled); } export function inferSchemaSections(schema: unknown): VideoPromptSchemaSectionConfig[] { if (!isRecord(schema)) return []; return Object.entries(schema) .filter(([key]) => !['schemaVersion', 'schemaUsage', 'schema_version', 'schema_usage'].includes(key)) .map(([key, value]) => { if (Array.isArray(value) && value.every(isRecord)) { const fields = Array.from(new Set(value.flatMap((item) => Object.keys(item)))); return { key, label: key, type: 'flow', enabled: true, editable: false, itemFields: fields.filter((field) => field !== '时间段').map((field) => ({ key: field, label: field, enabled: true, editable: false })), children: [], } as VideoPromptSchemaSectionConfig; } if (isRecord(value)) { return { key, label: key, type: 'object', enabled: true, editable: false, children: Object.keys(value).map((field) => ({ key: field, label: field, enabled: true, editable: false })), itemFields: [], } as VideoPromptSchemaSectionConfig; } return { key, label: key, type: 'text', enabled: true, editable: false, children: [], itemFields: [], } as VideoPromptSchemaSectionConfig; }); } export function stringifySchemaValue(value: JsonValue): string { if (value === null || value === undefined) return ''; if (typeof value === 'object') { try { return JSON.stringify(value, null, 2); } catch { return String(value); } } return String(value); }