expo-popcore-old/lib/utils/form-schema-transformer.ts

165 lines
4.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { FormFieldSchema, RunFormSchema } from '@/lib/types/template-run';
// 定义工作流节点的数据结构
interface WorkflowNode {
id: string;
type: 'image' | 'video' | 'text' | 'audio';
data: {
label: string;
description?: string;
flowType: 'start' | 'normal' | 'end';
actionData?: {
prompt?: string;
aspectRatio?: string;
selectedModel?: string;
duration?: string;
advancedParams?: Record<string, any>;
};
output?: {
images?: Array<{ url: string }>;
videos?: Array<{ url: string }>;
coverUrl?: string;
};
};
}
// 节点类型到表单字段类型的映射
const nodeTypeToFieldType = {
image: 'image',
video: 'video',
text: 'textarea',
audio: 'text', // 暂时用文本字段处理音频
};
// 生成字段名称
const generateFieldName = (node: WorkflowNode, index: number): string => {
const typePrefix = node.type;
const flowType = node.data.flowType;
return `${typePrefix}_${flowType}_${index}`;
};
// 生成字段标签
const generateFieldLabel = (node: WorkflowNode): string => {
const baseLabel = node.data.label || `节点 ${node.id.slice(-8)}`;
const flowTypeLabel = {
start: '(输入)',
normal: '(处理)',
end: '(输出)'
};
return baseLabel + (flowTypeLabel[node.data.flowType] || '');
};
// 转换单个节点为表单字段
const transformNodeToFormField = (node: WorkflowNode, index: number): FormFieldSchema | null => {
// 只为start节点生成表单字段因为用户只需要输入数据
if (node.data.flowType !== 'start') {
return null;
}
const fieldName = generateFieldName(node, index);
const fieldType = nodeTypeToFieldType[node.type] || 'text';
const fieldLabel = generateFieldLabel(node);
const field: FormFieldSchema = {
name: fieldName,
label: fieldLabel,
type: fieldType as any,
required: true,
description: node.data.description || `请上传${node.type === 'image' ? '图片' : node.type === 'video' ? '视频' : '内容'}`,
};
// 根据节点类型设置默认值和占位符
switch (node.type) {
case 'image':
field.placeholder = '点击上传图片';
if (node.data.output?.coverUrl) {
field.defaultValue = node.data.output.coverUrl;
}
break;
case 'video':
field.placeholder = '点击上传视频';
if (node.data.output?.videos?.[0]?.url) {
field.defaultValue = node.data.output.videos[0].url;
}
break;
case 'text':
field.placeholder = '请输入文本内容';
field.min = 1;
field.max = 1000;
break;
}
// 如果节点有预填的prompt作为提示信息
if (node.data.actionData?.prompt) {
field.description += `\n\n提示${node.data.actionData.prompt}`;
}
return field;
};
// 主要的转换函数
export function transformWorkflowToFormSchema(formSchemaData: unknown): RunFormSchema {
try {
// 类型守卫:检查数据格式
if (!formSchemaData || typeof formSchemaData !== 'object') {
console.warn('formSchema数据格式无效');
return { fields: [] };
}
const data = formSchemaData as any;
// 检查是否包含nodes数组新格式或startNodes/endNodes旧格式
let nodesToProcess: WorkflowNode[] = [];
if (Array.isArray(data.nodes)) {
// 新格式从nodes数组中筛选start节点
nodesToProcess = data.nodes.filter((node: any) =>
node.data?.flowType === 'start'
);
} else if (Array.isArray(data.startNodes)) {
// 旧格式使用startNodes
nodesToProcess = data.startNodes;
}
if (nodesToProcess.length === 0) {
return { fields: [] };
}
// 转换节点为表单字段
const fields: FormFieldSchema[] = [];
nodesToProcess.forEach((node: any, index: number) => {
const formField = transformNodeToFormField(node, index);
if (formField) {
fields.push(formField);
}
});
return {
fields,
validation: {}
};
} catch (error) {
console.error('转换formSchema失败:', error);
return { fields: [] };
}
}
// 验证转换后的表单配置
export function validateFormSchema(schema: RunFormSchema): boolean {
if (!schema || !Array.isArray(schema.fields)) {
return false;
}
return schema.fields.every(field => {
return (
field.name &&
field.label &&
field.type &&
['text', 'number', 'textarea', 'select', 'image', 'video', 'color'].includes(field.type)
);
});
}