Initial commit: Expo app with Better Auth integration

- Complete Expo React Native app setup with TypeScript
- Better Auth authentication system integration
- Secure storage implementation for session tokens
- Authentication flow with login/logout functionality
- API client configuration for backend communication
- Responsive UI components with themed styling
- Expo Router navigation setup
- Development configuration and scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
imeepos
2025-10-14 10:32:52 +08:00
commit 7e3f94bae3
71 changed files with 20800 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
import { RunFormSchema, FormFieldSchema } 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;
};
};
}
interface FormSchemaData {
startNodes: WorkflowNode[];
endNodes: WorkflowNode[];
}
// 节点类型到表单字段类型的映射
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) {
console.log('未找到需要用户输入的节点');
return { fields: [] };
}
// 转换节点为表单字段
const fields: FormFieldSchema[] = [];
nodesToProcess.forEach((node: any, index: number) => {
const formField = transformNodeToFormField(node, index);
if (formField) {
fields.push(formField);
}
});
console.log(`成功转换 ${fields.length} 个表单字段`);
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)
);
});
}