Procházet zdrojové kódy

feat: full consult workflow

未来全栈 před 5 dny
rodič
revize
250d46b652

+ 8 - 4
src/modules/flow/lib/flow-display/flow-display.component.ts

@@ -30,7 +30,8 @@ import { FlowExecutor } from '../flow.executor';
                 <p>进度: {{task.progress * 100 | number:'1.0-0'}}%</p>
                 <p>开始时间: {{taskTimers[i]?.start | date:'mediumTime'}}</p>
                 <p>持续时间: {{calculateDuration(i) | number:'1.1-1'}}秒</p>
-                <pre *ngIf="task.output">{{task.output | json}}</pre>
+                <pre *ngIf="task.output">输出参数{{task.output | json}}</pre>
+                <pre *ngIf="task.data">共享数据{{task.data | json}}</pre>
               </ion-text>
             </div>
           </ion-label>
@@ -40,6 +41,9 @@ import { FlowExecutor } from '../flow.executor';
           </ion-badge>
         </ion-item>
       </ion-list>
+      <ion-card>共享数据
+      {{executor?.sharedData|json}}
+      </ion-card>
 
       <ion-footer *ngIf="executor?.status === 'failed'">
         <ion-toolbar color="danger">
@@ -86,13 +90,13 @@ import { FlowExecutor } from '../flow.executor';
 export class FlowDisplayComponent {
   @Input() executor?: FlowExecutor;
   expandedTasks: boolean[] = [];
-  taskTimers: {start?: Date, end?: Date}[] = [];
+  taskTimers: { start?: Date, end?: Date }[] = [];
 
-  dismiss(){
+  dismiss() {
     this.modalCtrl.dismiss();
   }
   constructor(
-    private modalCtrl:ModalController
+    private modalCtrl: ModalController
   ) {
     // 监听任务状态变化
     this.executor?.taskStart$.subscribe((task) => {

+ 25 - 1
src/modules/flow/lib/flow.executor.ts

@@ -9,6 +9,9 @@ export class FlowExecutor {
   private _status: FlowStatus = 'idle';
   private retryCount = 0;
 
+  // 共享数据
+  public sharedData: Record<string, any> = {}; // 共享数据存储
+
   // 事件系统
   public taskStart$ = new Subject<FlowTask>();
   public taskSuccess$ = new Subject<FlowTask>();
@@ -23,9 +26,28 @@ export class FlowExecutor {
 
   setWorkflow(workflow: FlowWorkflow) {
     this.workflow = workflow;
+
+    // 初始化所有任务的共享数据
+    this.workflow.taskList.forEach(task => {
+      task.setSharedData(this.sharedData);
+    });
+
     this.reset();
   }
 
+  // 添加获取共享数据的方法
+  getSharedData(): Record<string, any> {
+    return this.sharedData;
+  }
+  // 添加更新共享数据的方法
+  updateSharedData(data: Record<string, any>): void {
+    this.sharedData = { ...this.sharedData, ...data };
+    // 更新所有任务的引用(以防有新增任务)
+    this.workflow?.taskList.forEach(task => {
+      task.data = this.sharedData;
+    });
+  }
+
   async start() {
     if (!this.workflow) throw new Error('工作流未设置');
     this._status = 'running';
@@ -58,10 +80,12 @@ export class FlowExecutor {
     }
 
     const task = this.workflow.taskList[this.currentTaskIndex];
+    task.data = this.sharedData;
     try {
       this.taskStart$.next(task);
       await task.execute();
-
+      console.log(task.title, task.data, this.sharedData)
+      this.sharedData = task.data;
       // 只有当任务状态是success时才继续
       if (task.status === 'success') {
         this.taskSuccess$.next(task);

+ 11 - 5
src/modules/flow/lib/flow.task.ts

@@ -17,9 +17,15 @@ export interface FlowTaskOptions {
 export class FlowTask {
   // 核心属性
   title: string;
-  protected data: Record<string, any> = {};
   _status: 'idle' | 'running' | 'success' | 'failed' = 'idle';
   _progress: number = 0;
+  public data: Record<string, any> = {};
+  // 添加设置共享数据的方法
+  setSharedData(data: Record<string, any>): this {
+    this.data = data;
+    return this;
+  }
+
 
   // 校验规则
   inputSchema: FieldSchema[];
@@ -91,7 +97,7 @@ export class FlowTask {
    *          数据校验系统              *
    ************************************/
 
-  private validateInput(): void {
+  validateInput(): void {
     const errors: string[] = [];
 
     this.inputSchema.forEach(field => {
@@ -114,7 +120,7 @@ export class FlowTask {
     }
   }
 
-  private validateOutput(): void {
+  validateOutput(): void {
     const missingFields = this.outputSchema
       .filter(f => f.required)
       .filter(f => !(f.name in this.data))
@@ -130,12 +136,12 @@ export class FlowTask {
    ************************************/
 
   // 类型检查
-  private checkType(value: any, expected: FieldType): boolean {
+  checkType(value: any, expected: FieldType): boolean {
     const actualType = this.getType(value);
     return expected === 'any' || actualType === expected;
   }
 
-  private getType(value: any): FieldType {
+  getType(value: any): FieldType {
     if (Array.isArray(value)) return 'array';
     if (value === null) return 'object';
     return typeof value as FieldType;

+ 30 - 0
src/modules/flow/lib/tasks/task-completion-json/README.md

@@ -0,0 +1,30 @@
+# 任务:大模型生成JSON结果 TaskCompletionJson
+
+# 使用示例
+``` ts
+const triageTask = new TaskCompletionJson({
+  title: '智能分诊',
+  promptTemplate: `您是一名专业的分诊护士,根据患者描述推荐最合适的科室。严格按照以下JSON格式返回:
+  {
+    "department": "科室名称",
+    "reason": "分诊理由(50字以内)"
+  }
+  患者主诉:{{userDesc}}`,
+  input: [
+    { name: 'userDesc', type: 'string', required: true }
+  ],
+  output: [
+    { name: 'department', type: 'string', required: true },
+    { name: 'reason', type: 'string' }
+  ]
+});
+
+// Set input data
+triageTask.updateData('userDesc', '患者描述的症状...');
+
+// Execute the task
+await triageTask.execute();
+
+// Get results
+console.log(triageTask.output); // { department: '内科', reason: '根据症状描述判断...' }
+```

+ 219 - 0
src/modules/flow/lib/tasks/task-completion-json/task-completion-json.ts

@@ -0,0 +1,219 @@
+import { FmodeChatCompletion } from 'fmode-ng';
+import { FlowTask, FieldSchema, FlowTaskOptions } from '../../flow.task';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+
+export interface JsonCompletionOptions extends FlowTaskOptions {
+    promptTemplate: string;
+    modelOptions?: Record<string, any>;
+    strictPromptValidation?: boolean;
+}
+
+export class TaskCompletionJson extends FlowTask {
+    promptTemplate: string;
+    modelOptions: Record<string, any>;
+    strictPromptValidation: boolean;
+    destroy$ = new Subject<void>();
+
+    constructor(options: JsonCompletionOptions) {
+        super({
+            title: options.title || 'JSON Completion Task',
+            output: options.output, // Only output schema is needed
+            initialData: options.initialData
+        });
+
+        this.promptTemplate = options.promptTemplate;
+        this.modelOptions = options.modelOptions || {};
+        this.strictPromptValidation = options.strictPromptValidation ?? true;
+    }
+
+    override async handle(): Promise<void> {
+        // 1. Validate all required prompt variables exist in task.data
+        this.validatePromptVariables();
+
+        // 2. Prepare the prompt with variable substitution
+        const fullPrompt = this.renderPromptTemplate();
+
+        // 3. Call the LLM for completion
+        await this.callModelCompletion(fullPrompt);
+    }
+
+    validatePromptVariables(): void {
+        const requiredVariables = this.extractPromptVariables();
+        const missingVariables: string[] = [];
+        const undefinedVariables: string[] = [];
+
+        requiredVariables.forEach(variable => {
+            if (!(variable in this.data)) {
+                missingVariables.push(variable);
+            } else if (this.data[variable] === undefined) {
+                undefinedVariables.push(variable);
+            }
+        });
+
+        const errors: string[] = [];
+
+        if (missingVariables.length > 0) {
+            errors.push(`Missing required variables in task.data: ${missingVariables.join(', ')}`);
+        }
+
+        if (undefinedVariables.length > 0) {
+            errors.push(`Variables with undefined values: ${undefinedVariables.join(', ')}`);
+        }
+
+        if (errors.length > 0 && this.strictPromptValidation) {
+            throw new Error(`Prompt variable validation failed:\n${errors.join('\n')}`);
+        } else if (errors.length > 0) {
+            console.warn(`Prompt variable warnings:\n${errors.join('\n')}`);
+        }
+    }
+
+    extractPromptVariables(): string[] {
+        const matches = this.promptTemplate.match(/\{\{\w+\}\}/g) || [];
+        const uniqueVariables = new Set<string>();
+
+        matches.forEach(match => {
+            const key = match.replace(/\{\{|\}\}/g, '');
+            uniqueVariables.add(key);
+        });
+
+        return Array.from(uniqueVariables);
+    }
+
+    renderPromptTemplate(): string {
+        let result = this.promptTemplate;
+        const variables = this.extractPromptVariables();
+
+        variables.forEach(variable => {
+            if (this.data[variable] !== undefined) {
+                result = result.replace(new RegExp(`\\{\\{${variable}\\}\\}`, 'g'), this.data[variable]);
+            }
+        });
+
+        return result;
+    }
+
+    async callModelCompletion(prompt: string): Promise<void> {
+        return new Promise((resolve, reject) => {
+            const messages = [{
+                role: "user",
+                content: prompt
+            }];
+
+            const completion = new FmodeChatCompletion(messages);
+
+            let accumulatedContent = '';
+
+            completion.sendCompletion({
+                ...this.modelOptions,
+                onComplete: (message: any) => {
+                    console.log("onComplete", message);
+                }
+            })
+                .pipe(takeUntil(this.destroy$))
+                .subscribe({
+                    next: (message: any) => {
+                        if (message.content && typeof message.content === 'string') {
+                            accumulatedContent = message.content;
+                            this.setProgress(0.3 + (accumulatedContent.length / 1000) * 0.7);
+                        }
+
+                        if (message.complete) {
+                            try {
+                                const parsed = this.parseAndValidateResponse(accumulatedContent);
+                                this.updateOutputData(parsed);
+                                this.setProgress(1);
+                                resolve();
+                            } catch (error) {
+                                this.handleError(error as Error);
+                                reject(error);
+                            }
+                        }
+                    },
+                    error: (error) => {
+                        this.handleError(error);
+                        reject(error);
+                    }
+                });
+        });
+    }
+
+    parseAndValidateResponse(response: string): Record<string, any> {
+        const jsonStart = response.indexOf('{');
+        const jsonEnd = response.lastIndexOf('}') + 1;
+
+        if (jsonStart === -1 || jsonEnd === -1) {
+            throw new Error('Invalid JSON response format');
+        }
+
+        const jsonStr = response.slice(jsonStart, jsonEnd);
+        let parsedData: Record<string, any>;
+
+        try {
+            parsedData = JSON.parse(jsonStr);
+        } catch (e) {
+            throw new Error(`Failed to parse JSON response: ${(e as Error).message}`);
+        }
+
+        // Validate against output schema
+        this.validateOutputData(parsedData);
+
+        return parsedData;
+    }
+
+    validateOutputData(data: Record<string, any>): void {
+        if (!this.outputSchema || this.outputSchema.length === 0) {
+            return; // No validation needed if no output schema defined
+        }
+
+        const errors: string[] = [];
+
+        this.outputSchema.forEach(field => {
+            const value = data[field.name];
+
+            if (field.required && value === undefined) {
+                errors.push(`Missing required field in response: ${field.name}`);
+                return;
+            }
+
+            if (value !== undefined && !this.checkType(value, field.type)) {
+                errors.push(`${field.name} has wrong type, expected ${field.type}, got ${this.getType(value)}`);
+            }
+        });
+
+        if (errors.length > 0) {
+            throw new Error(`Output validation failed:\n${errors.join('\n')}`);
+        }
+    }
+
+    updateOutputData(parsedData: Record<string, any>): void {
+        Object.entries(parsedData).forEach(([key, value]) => {
+            this.updateData(key, value);
+        });
+    }
+
+    handleError(error: Error): void {
+        this.updateData('error', {
+            message: error.message,
+            stack: error.stack,
+            timestamp: new Date().toISOString()
+        });
+        this._status = 'failed';
+    }
+
+    override checkType(value: any, expected: any): boolean {
+        const actualType = this.getType(value);
+        return expected === 'any' || actualType === expected;
+    }
+
+    override getType(value: any): any {
+        if (Array.isArray(value)) return 'array';
+        if (value === null) return 'object';
+        return typeof value as any;
+    }
+
+    onDestroy(): void {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+}

+ 43 - 0
src/modules/flow/lib/tasks/task-completion-text/README.md

@@ -0,0 +1,43 @@
+
+# 使用示例
+```ts
+// 1. Initialize the task with required parameters
+const textGenerator = new TaskCompletionText({
+    promptTemplate: "Write a product description for {{productName}} that highlights these features: {{features}}. Target audience: {{audience}}.",
+    outputProperty: "productDescription", // Where to store the result
+    inputVariables: ["productName", "features", "audience"], // Explicitly declare required variables
+    modelOptions: {
+        temperature: 0.7,
+        maxTokens: 500
+    },
+    strictValidation: true // Fail if variables are missing
+});
+
+// 2. Prepare input data (variables referenced in the prompt)
+textGenerator.updateData('productName', 'Smart Coffee Maker');
+textGenerator.updateData('features', [
+    'Voice control',
+    'Custom brew strength',
+    'Scheduled brewing'
+].join(', '));
+textGenerator.updateData('audience', 'tech-savvy home users');
+
+// 3. Execute the task
+try {
+    await textGenerator.handle();
+    
+    // 4. Get the generated text from the specified property
+    const generatedText = textGenerator.getData('productDescription');
+    console.log('Generated Description:', generatedText);
+    
+    // Example output might be:
+    // "Introducing our Smart Coffee Maker, perfect for tech-savvy home users..."
+} catch (error) {
+    console.error('Generation failed:', error);
+    const errorDetails = textGenerator.getData('error');
+    // Handle error...
+}
+
+// 5. Clean up when done
+textGenerator.onDestroy();
+```

+ 165 - 0
src/modules/flow/lib/tasks/task-completion-text/task-completion-text.ts

@@ -0,0 +1,165 @@
+import { FmodeChatCompletion } from 'fmode-ng';
+import { FlowTask, FlowTaskOptions } from '../../flow.task';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+
+export interface TextCompletionOptions extends FlowTaskOptions {
+    promptTemplate: string;          // Required: Your prompt template with {{variables}}
+    outputProperty: string;          // Required: Where to store the result in task.data
+    inputVariables?: string[];       // Optional: List of required variables (for validation)
+    modelOptions?: Record<string, any>; // Optional: Model configuration
+    strictValidation?: boolean;      // Optional: Whether to fail on missing variables
+}
+
+export class TaskCompletionText extends FlowTask {
+    promptTemplate: string;
+    outputProperty: string;
+    inputVariables: string[];
+    strictPromptValidation: boolean = false;
+    modelOptions: Record<string, any>;
+    strictValidation: boolean;
+    destroy$ = new Subject<void>();
+
+    constructor(options: TextCompletionOptions) {
+        super({
+            title: options.title || 'Text Generation Task',
+            output: options.output,
+            initialData: options.initialData
+        });
+
+        if (!options.promptTemplate) throw new Error('promptTemplate is required');
+        if (!options.outputProperty) throw new Error('outputProperty is required');
+
+        this.promptTemplate = options.promptTemplate;
+        this.outputProperty = options.outputProperty;
+        this.inputVariables = options.inputVariables || this.extractPromptVariables();
+        this.modelOptions = options.modelOptions || {};
+        this.strictValidation = options.strictValidation ?? true;
+    }
+
+
+    override async handle(): Promise<void> {
+        // 1. Validate all required prompt variables exist in task.data
+        this.validatePromptVariables();
+
+        // 2. Prepare the prompt with variable substitution
+        const fullPrompt = this.renderPromptTemplate();
+
+        // 3. Call the LLM for text completion
+        await this.callModelCompletion(fullPrompt);
+    }
+
+    validatePromptVariables(): void {
+        const requiredVariables = this.extractPromptVariables();
+        const missingVariables: string[] = [];
+        const undefinedVariables: string[] = [];
+
+        requiredVariables.forEach(variable => {
+            if (!(variable in this.data)) {
+                missingVariables.push(variable);
+            } else if (this.data[variable] === undefined) {
+                undefinedVariables.push(variable);
+            }
+        });
+
+        const errors: string[] = [];
+
+        if (missingVariables.length > 0) {
+            errors.push(`Missing required variables in task.data: ${missingVariables.join(', ')}`);
+        }
+
+        if (undefinedVariables.length > 0) {
+            errors.push(`Variables with undefined values: ${undefinedVariables.join(', ')}`);
+        }
+
+        if (errors.length > 0 && this.strictPromptValidation) {
+            throw new Error(`Prompt variable validation failed:\n${errors.join('\n')}`);
+        } else if (errors.length > 0) {
+            console.warn(`Prompt variable warnings:\n${errors.join('\n')}`);
+        }
+    }
+
+    extractPromptVariables(): string[] {
+        const matches = this.promptTemplate.match(/\{\{\w+\}\}/g) || [];
+        const uniqueVariables = new Set<string>();
+
+        matches.forEach(match => {
+            const key = match.replace(/\{\{|\}\}/g, '');
+            uniqueVariables.add(key);
+        });
+
+        return Array.from(uniqueVariables);
+    }
+
+    renderPromptTemplate(): string {
+        let result = this.promptTemplate;
+        const variables = this.extractPromptVariables();
+
+        variables.forEach(variable => {
+            if (this.data[variable] !== undefined) {
+                result = result.replace(new RegExp(`\\{\\{${variable}\\}\\}`, 'g'), this.data[variable]);
+            }
+        });
+
+        return result;
+    }
+
+    async callModelCompletion(prompt: string): Promise<void> {
+        return new Promise((resolve, reject) => {
+            const messages = [{
+                role: "user",
+                content: prompt
+            }];
+
+            const completion = new FmodeChatCompletion(messages);
+
+            let accumulatedContent = '';
+
+            completion.sendCompletion({
+                ...this.modelOptions,
+                onComplete: (message: any) => {
+                    console.log("onComplete", message);
+                }
+            })
+                .pipe(takeUntil(this.destroy$))
+                .subscribe({
+                    next: (message: any) => {
+                        if (message.content && typeof message.content === 'string') {
+                            accumulatedContent = message.content;
+                            this.setProgress(0.3 + (accumulatedContent.length / 1000) * 0.7);
+                        }
+
+                        if (message.complete) {
+                            try {
+                                // Store the complete generated text in the specified property
+                                this.updateData(this.outputProperty, accumulatedContent);
+                                this.setProgress(1);
+                                resolve();
+                            } catch (error) {
+                                this.handleError(error as Error);
+                                reject(error);
+                            }
+                        }
+                    },
+                    error: (error) => {
+                        this.handleError(error);
+                        reject(error);
+                    }
+                });
+        });
+    }
+
+    handleError(error: Error): void {
+        this.updateData('error', {
+            message: error.message,
+            stack: error.stack,
+            timestamp: new Date().toISOString()
+        });
+        this._status = 'failed';
+    }
+
+    onDestroy(): void {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+}

+ 1 - 1
src/modules/flow/lib/tasks/task-user-form/form-collector/form-collector.component.html

@@ -121,7 +121,7 @@
                 </ion-item>
 
                 <!-- 文本域 -->
-                <ion-item *ngIf="field.type === 'Textarea'" lines="full">
+                <ion-item *ngIf="field.type === 'Textarea'||field.type === 'TextArea'" lines="full">
                     <ion-label position="stacked">
                         {{field.name}}
                         <span *ngIf="field.required" class="required">*</span>

+ 1 - 0
src/modules/flow/lib/tasks/task-user-form/form-collector/form-collector.component.ts

@@ -13,6 +13,7 @@ export interface FormField {
     max?: number;
     pattern?: string;
     placeholder?: string;
+    default?: any;
 }
 
 @Component({

+ 1 - 0
src/modules/flow/lib/tasks/task-user-form/get-user-form.ts

@@ -11,6 +11,7 @@ export interface FormField {
     pattern?: string;
     placeholder?: string;
     validator?: any;
+    default?: any;
 }
 
 /**

+ 9 - 9
src/modules/flow/lib/tasks/task-user-form/task-user-form.ts

@@ -53,20 +53,20 @@ export class TaskUserForm extends FlowTask {
     }
 
     private mapFieldType(type: string): any {
-        switch (type) {
-            case 'String':
+        switch (type.toLowerCase()) {
+            case 'string':
                 return 'string';
-            case 'Number':
+            case 'number':
                 return 'number';
-            case 'Boolean':
+            case 'boolean':
                 return 'boolean';
-            case 'Date':
+            case 'date':
                 return 'object'; // 日期类型通常处理为对象
-            case 'Radio':
-            case 'Select':
-            case 'Checkbox':
+            case 'radio':
+            case 'select':
+            case 'checkbox':
                 return 'array'; // 多选和单选可以处理为数组
-            case 'Textarea':
+            case 'textarea':
                 return 'string'; // 多行文本处理为字符串
             default:
                 throw new Error(`不支持的字段类型: ${type}`);

+ 11 - 0
src/modules/flow/page-flow-test/page-flow-test.component.html

@@ -9,6 +9,17 @@
         <ion-card-content>
             <ion-grid>
                 <ion-row>
+                    <ion-col size="12" size-md="6">
+                        <ion-card class="workflow-card" button (click)="consultWorkflow()">
+                            <ion-icon name="medkit" color="primary" class="workflow-icon"></ion-icon>
+                            <ion-card-header>
+                                <ion-card-title>门诊咨询</ion-card-title>
+                            </ion-card-header>
+                            <ion-card-content>
+                                完整工作流
+                            </ion-card-content>
+                        </ion-card>
+                    </ion-col>
                     <ion-col size="12" size-md="6">
                         <ion-card class="workflow-card" button (click)="startTriage()">
                             <ion-icon name="medkit" color="primary" class="workflow-icon"></ion-icon>

+ 198 - 1
src/modules/flow/page-flow-test/page-flow-test.component.ts

@@ -9,6 +9,9 @@ import { TriageTask } from './consult-tasks/consult-tasks';
 import { SymptomInputModalComponent } from './consult-tasks/symptom-input/symptom-input.modal';
 import { getUserForm } from '../lib/tasks/task-user-form/get-user-form';
 import { JobIntentionTask, UserBasicInfoTask, UserInterestsTask } from './job-workflow/task.job';
+import { TaskUserForm } from '../lib/tasks/task-user-form/task-user-form';
+import { TaskCompletionJson } from '../lib/tasks/task-completion-json/task-completion-json';
+import { TaskCompletionText } from '../lib/tasks/task-completion-text/task-completion-text';
 
 @Component({
   selector: 'app-page-flow-test',
@@ -54,6 +57,200 @@ export class PageFlowTestComponent {
     }
   }
 
+  async consultWorkflow() {
+    const tasks = [
+      // 描述病情任务(用户信息采集)
+      new TaskUserForm({
+        title: '病情描述',
+        modalCtrl: this.modalCtrl,
+        fieldList: [
+          {
+            type: "String",
+            key: "userDesc",
+            name: "病情描述",
+            required: true,
+            placeholder: "请详细描述您的症状、持续时间和不适感"
+          },
+          {
+            type: "String",
+            key: "duration",
+            name: "持续时间",
+            required: false,
+            placeholder: "例如:3天、2周等"
+          },
+          {
+            type: "Radio",
+            key: "painLevel",
+            name: "疼痛程度",
+            required: false,
+            options: [
+              { label: "无疼痛", value: "none" },
+              { label: "轻度", value: "mild" },
+              { label: "中度", value: "moderate" },
+              { label: "重度", value: "severe" }
+            ]
+          }
+        ],
+        initialData: {}
+      }),
+
+      // 智能分诊任务(AI分析)
+      new TaskCompletionJson({
+        title: '智能分诊',
+        promptTemplate: `您是一名专业的分诊护士,根据患者描述推荐最合适的科室。严格按照以下JSON格式返回:
+        {
+          "department": "科室名称",
+          "reason": "分诊理由(50字以内)"
+        }
+        患者主诉:{{userDesc}}
+        持续时间:{{duration}}
+        疼痛程度:{{painLevel}}`,
+        input: [
+          { name: 'userDesc', type: 'string', required: true },
+          { name: 'duration', type: 'string', required: false },
+          { name: 'painLevel', type: 'string', required: false }
+        ],
+        output: [
+          { name: 'department', type: 'string', required: true },
+          { name: 'reason', type: 'string' }
+        ]
+      }),
+      // 2. 问诊信息收集
+      new TaskUserForm({
+        title: '详细问诊',
+        modalCtrl: this.modalCtrl,
+        fieldList: [
+          {
+            type: "TextArea", key: "symptoms", name: "详细症状", required: true,
+            placeholder: "请详细描述您的症状、部位、性质和变化情况"
+          },
+          { type: "String", key: "medicalHistory", name: "既往病史", required: false },
+          { type: "String", key: "allergies", name: "过敏史", required: false },
+          { type: "String", key: "medications", name: "当前用药", required: false },
+          {
+            type: "Radio", key: "needTests", name: "是否需要检查", required: true,
+            options: [
+              { label: "需要", value: true },
+              { label: "不需要", value: false }
+            ]
+          }
+        ],
+        initialData: {}
+      }),
+
+      // 3. 检查建议生成(条件性任务)
+      new TaskCompletionText({
+        title: '检查建议',
+        promptTemplate: `作为专业医生,根据以下问诊信息为患者推荐适当的检查项目:
+    症状描述:{{symptoms}}
+    既往病史:{{medicalHistory || '无'}}
+    过敏史:{{allergies || '无'}}
+    当前用药:{{medications || '无'}}
+    
+    请列出建议的检查项目,说明每项检查的目的,并用通俗语言解释检查过程。`,
+        outputProperty: "testRecommendations",
+        inputVariables: ["symptoms", "medicalHistory", "allergies", "medications"],
+        modelOptions: {
+          temperature: 0.3,
+          maxTokens: 300
+        }
+      }),
+
+      new TaskUserForm({
+        title: '检查结果录入',
+        modalCtrl: this.modalCtrl,
+        fieldList: [
+          {
+            type: "TextArea",
+            key: "testResults",
+            name: "检查结果",
+            required: true,
+            placeholder: "请粘贴或输入您的检查报告结果(包括各项指标和参考值)"
+          },
+          {
+            type: "DatePicker",
+            key: "testDate",
+            name: "检查日期",
+            required: true,
+            default: new Date()
+          }
+        ]
+      }),
+      // 4. 诊断与处方生成
+      new TaskCompletionJson({
+        title: '诊断与处方',
+        promptTemplate: `作为主治医生,请根据以下信息给出诊断结果和治疗方案:
+        ## 患者信息
+        主诉:{{userDesc}}
+        详细症状:{{symptoms}}
+        {{#if medicalHistory}}既往病史:{{medicalHistory}}{{/if}}
+        {{#if allergies}}过敏史:{{allergies}}{{/if}}
+        {{#if medications}}当前用药:{{medications}}{{/if}}
+        ## 检查信息
+        检查日期:{{testDate}}
+        检查结果:{{testResults}}
+        
+        请按照以下JSON格式返回...`, // 保持原有JSON格式要求
+        input: [
+          { name: 'userDesc', type: 'string', required: true },
+          { name: 'symptoms', type: 'string', required: true },
+          { name: 'medicalHistory', type: 'string', required: false },
+          { name: 'allergies', type: 'string', required: false },
+          { name: 'medications', type: 'string', required: false },
+          { name: 'testResults', type: 'string', required: false }
+        ],
+        output: [
+          { name: 'diagnosis', type: 'string', required: true },
+          { name: 'treatmentPlan', type: 'string', required: true },
+          { name: 'medications', type: 'array', required: false },
+          { name: 'followUp', type: 'string', required: false },
+          { name: 'notes', type: 'string', required: false }
+        ],
+        modelOptions: {
+          temperature: 0.1, // 低随机性确保医疗准确性
+          maxTokens: 500
+        }
+      }),
+
+      // 5. 患者教育材料生成(可选任务)
+      new TaskCompletionText({
+        title: '患者教育',
+        promptTemplate: `根据以下诊断和治疗方案,生成患者友好的教育材料:
+    诊断:{{diagnosis}}
+    治疗方案:{{treatmentPlan}}
+    用药指导:{{#each medications}}- {{this.name}}: {{this.dosage}}, 用药{{this.duration}}{{/each}}
+    
+    请用通俗易懂的语言解释:
+    1. 疾病的基本知识
+    2. 为什么需要这个治疗方案
+    3. 用药注意事项
+    4. 日常生活建议
+    5. 何时需要紧急就医`,
+        outputProperty: "patientEducation",
+        inputVariables: ["diagnosis", "treatmentPlan", "medications"],
+        modelOptions: {
+          temperature: 0.5, // 中等随机性使语言更自然
+          maxTokens: 600
+        }
+      })
+    ];
+
+    // 创建工作流
+    const workflow = {
+      title: '门诊问诊工作流',
+      desc: '1.导诊',
+      taskList: tasks
+    };
+
+    this.executor.setWorkflow(workflow);
+    const modal = await this.modalCtrl.create({
+      component: FlowDisplayComponent,
+      componentProps: { executor: this.executor }
+    });
+
+    await modal.present();
+    await this.executor.start();
+  }
   async jobWorkflow() {
     // 创建工作流
     const workflow = {
@@ -62,7 +259,7 @@ export class PageFlowTestComponent {
       taskList: [
         new UserBasicInfoTask(this.modalCtrl),
         new JobIntentionTask(this.modalCtrl),
-        new UserInterestsTask(this.modalCtrl)
+        // new UserInterestsTask(this.modalCtrl)
       ]
     };