mxivideo/docs/progress_system_usage.md

8.3 KiB
Raw Permalink Blame History

🚀 通用进度系统使用指南

一个完全重构的通用进度监听系统,从特定的模板导入功能抽离出来,现在可以用于任何需要进度监控的操作。

🎯 系统架构

Frontend (React)
├── useProgressCommand Hook     # React Hook for progress management
├── ProgressListener Class     # Generic progress listener utility
└── Service Classes            # Specialized service classes

Backend (Rust)
├── execute_python_action_with_progress  # Generic Python executor
├── PythonCommandBuilder                 # Command construction helper
└── Progress Callbacks                   # Flexible callback system

Python
└── JSON-RPC Protocol          # Standardized progress reporting

📚 使用方式

1. 使用React Hook推荐

import { useTemplateProgress } from '../hooks/useProgressCommand'

function MyComponent() {
  const {
    isExecuting,
    progress,
    result,
    error,
    logs,
    batchImport
  } = useTemplateProgress({
    onSuccess: (result) => {
      console.log('Import completed:', result)
    },
    onError: (error) => {
      console.error('Import failed:', error)
    }
  })

  const handleImport = async () => {
    try {
      await batchImport('/path/to/templates')
    } catch (error) {
      // Error is already handled by the hook
    }
  }

  return (
    <div>
      {isExecuting && (
        <div>
          <div>Progress: {progress?.progress}%</div>
          <div>Message: {progress?.message}</div>
        </div>
      )}
      
      <button onClick={handleImport} disabled={isExecuting}>
        {isExecuting ? 'Importing...' : 'Import Templates'}
      </button>
      
      {/* Real-time logs */}
      <div>
        {logs.map((log, index) => (
          <div key={index}>{log}</div>
        ))}
      </div>
    </div>
  )
}

2. 使用通用Hook

import { useProgressCommand } from '../hooks/useProgressCommand'

function DataProcessingComponent() {
  const { execute, isExecuting, progress, logs } = useProgressCommand()

  const processData = async () => {
    await execute(
      'process_data_with_progress',
      { 
        request: { 
          input_file: '/input.csv',
          output_file: '/output.json',
          processing_type: 'transform'
        }
      },
      'data-processing-progress'
    )
  }

  return (
    <div>
      <button onClick={processData} disabled={isExecuting}>
        Process Data
      </button>
      
      {progress && (
        <div>
          <div>Step: {progress.step}</div>
          <div>Progress: {progress.progress}%</div>
          <div>Message: {progress.message}</div>
        </div>
      )}
    </div>
  )
}

3. 使用Service类

import { AIVideoProgressService, DataProcessingService } from '../services/tauri'

// AI Video Generation
const generateVideo = async () => {
  const onProgress = (progress) => {
    console.log(`${progress.step}: ${progress.message}`)
    updateProgressBar(progress.progress)
  }

  try {
    const result = await AIVideoProgressService.generateVideoWithProgress(
      '/path/to/image.jpg',
      'A beautiful sunset',
      '/path/to/output.mp4',
      onProgress
    )
    console.log('Video generated:', result)
  } catch (error) {
    console.error('Generation failed:', error)
  }
}

// Data Processing
const processFiles = async () => {
  const result = await DataProcessingService.batchConvertFilesWithProgress(
    ['/file1.txt', '/file2.txt'],
    'pdf',
    (progress) => console.log(progress.message)
  )
}

4. 使用底层ProgressListener

import { ProgressListener } from '../services/tauri'

const customOperation = async () => {
  const listener = new ProgressListener()
  
  try {
    const result = await listener.execute(
      'my_custom_command',
      { param1: 'value1' },
      'my-progress-event',
      (progress) => {
        // Custom progress handling
        console.log(progress)
      }
    )
  } finally {
    listener.cleanup()
  }
}

🔧 添加新的进度命令

1. Rust端后端

#[tauri::command]
pub async fn my_new_command_with_progress(
    app: AppHandle,
    my_param: String
) -> Result<String, String> {
    let params = &[("--my_param", my_param.as_str())];
    
    execute_python_action_with_progress(
        app,
        "python_core.my_module",
        "my_action",
        params,
        "my-command-progress",
        None,
    ).await
}

2. Python端

from python_core.utils.jsonrpc import create_response_handler, create_progress_reporter

def my_action():
    rpc = create_response_handler("my_action")
    progress = create_progress_reporter()
    
    try:
        progress.step("start", "开始处理...")
        # ... processing ...
        
        progress.report("process", 50.0, "处理中...", {"detail": "info"})
        # ... more processing ...
        
        progress.complete("处理完成!")
        
        result = {"status": True, "data": "result"}
        rpc.success(result)
        
    except Exception as e:
        progress.error(f"处理失败: {str(e)}")
        rpc.error(-32603, "处理失败", str(e))

3. 前端Service

export class MyService {
  static async myOperationWithProgress(
    param: string,
    onProgress?: (progress: any) => void
  ): Promise<any> {
    return executeCommandWithProgress(
      'my_new_command_with_progress',
      { myParam: param },
      'my-command-progress',
      onProgress
    )
  }
}

4. 专用Hook

export function useMyOperationProgress(options = {}) {
  const hook = useProgressCommand(options)

  const executeOperation = useCallback(async (param: string) => {
    return hook.execute(
      'my_new_command_with_progress',
      { myParam: param },
      'my-command-progress'
    )
  }, [hook])

  return {
    ...hook,
    executeOperation,
  }
}

🎨 UI组件示例

进度模态框

function ProgressModal({ isOpen, onClose, progress, logs, isExecuting }) {
  return (
    <Modal isOpen={isOpen} onClose={!isExecuting ? onClose : undefined}>
      <div className="p-6">
        <h2 className="text-xl font-bold mb-4">操作进度</h2>
        
        {/* Progress Bar */}
        {progress && (
          <div className="mb-4">
            <div className="flex justify-between mb-2">
              <span>{progress.step}</span>
              <span>{progress.progress >= 0 ? `${progress.progress}%` : '处理中...'}</span>
            </div>
            <div className="w-full bg-gray-200 rounded-full h-2">
              <div
                className="bg-blue-600 h-2 rounded-full transition-all"
                style={{ width: `${Math.max(0, progress.progress)}%` }}
              />
            </div>
            <p className="text-sm text-gray-600 mt-2">{progress.message}</p>
          </div>
        )}
        
        {/* Logs */}
        <div className="bg-gray-50 rounded p-4 h-64 overflow-y-auto">
          {logs.map((log, index) => (
            <div key={index} className="text-xs text-gray-600 font-mono">
              {log}
            </div>
          ))}
        </div>
        
        {/* Actions */}
        <div className="flex justify-end mt-4">
          {!isExecuting && (
            <button onClick={onClose} className="px-4 py-2 bg-gray-200 rounded">
              关闭
            </button>
          )}
        </div>
      </div>
    </Modal>
  )
}

🔄 迁移指南

从旧的模板导入方式迁移

旧方式

const [importing, setImporting] = useState(false)
const [progress, setProgress] = useState(null)
const [logs, setLogs] = useState([])

const handleImport = async () => {
  setImporting(true)
  // ... manual progress handling
}

新方式

const { isExecuting, progress, logs, batchImport } = useTemplateProgress()

const handleImport = async () => {
  await batchImport(folderPath)
}

🎯 最佳实践

  1. 优先使用HookReact Hook提供最佳的状态管理和生命周期处理
  2. 合理的进度粒度:不要过于频繁地报告进度,影响性能
  3. 错误处理:始终处理可能的错误情况
  4. 用户反馈:提供清晰的进度信息和状态反馈
  5. 资源清理:确保在组件卸载时清理监听器

这个通用进度系统现在可以轻松扩展到任何需要进度监控的操作!🚀