mxivideo/src/hooks/useProgressCommand.ts

262 lines
6.0 KiB
TypeScript

import { useState, useCallback, useRef } from 'react'
import { executeCommandWithProgress, ProgressListener } from '../services/tauri'
export interface ProgressState {
step: string
progress: number // -1 for indeterminate, 0-100 for percentage
message: string
details?: any
timestamp: number
}
export interface UseProgressCommandOptions {
onProgress?: (progress: ProgressState) => void
onSuccess?: (result: any) => void
onError?: (error: Error) => void
autoReset?: boolean // Auto reset state after completion
}
export interface UseProgressCommandReturn<T> {
// State
isExecuting: boolean
progress: ProgressState | null
result: T
error: Error | null
logs: string[]
// Actions
execute: (command: string, params: any, eventName: string) => Promise<any>
reset: () => void
addLog: (message: string) => void
clearLogs: () => void
}
/**
* React Hook for executing Tauri commands with progress monitoring
*
* @param options - Configuration options
* @returns Hook state and actions
*/
export function useProgressCommand<T>(options: UseProgressCommandOptions = {}): UseProgressCommandReturn<T> {
const [isExecuting, setIsExecuting] = useState(false)
const [progress, setProgress] = useState<ProgressState | null>(null)
const [result, setResult] = useState<any>(null)
const [error, setError] = useState<Error | null>(null)
const [logs, setLogs] = useState<string[]>([])
const listenerRef = useRef<ProgressListener | null>(null)
const addLog = useCallback((message: string) => {
const timestamp = new Date().toLocaleTimeString()
setLogs(prev => [...prev, `[${timestamp}] ${message}`])
}, [])
const clearLogs = useCallback(() => {
setLogs([])
}, [])
const reset = useCallback(() => {
setIsExecuting(false)
setProgress(null)
setResult(null)
setError(null)
if (options.autoReset !== false) {
setLogs([])
}
}, [options.autoReset])
const execute = useCallback(async (
command: string,
params: any,
eventName: string
): Promise<any> => {
try {
setIsExecuting(true)
setError(null)
setResult(null)
if (options.autoReset !== false) {
setProgress(null)
setLogs([])
}
addLog(`开始执行命令: ${command}`)
const onProgress = (progressData: ProgressState) => {
setProgress(progressData)
addLog(progressData.message)
options.onProgress?.(progressData)
}
const commandResult = await executeCommandWithProgress(
command,
params,
eventName,
onProgress
)
setResult(commandResult)
addLog('命令执行成功')
options.onSuccess?.(commandResult)
return commandResult
} catch (err) {
const error = err instanceof Error ? err : new Error(String(err))
setError(error)
addLog(`命令执行失败: ${error.message}`)
options.onError?.(error)
throw error
} finally {
setIsExecuting(false)
}
}, [options, addLog])
return {
// State
isExecuting,
progress,
result,
error,
logs,
// Actions
execute,
reset,
addLog,
clearLogs,
}
}
/**
* Specialized hook for template operations
*/
export interface TemplateInfo {
id: string
name: string
description: string
thumbnail_path: string
draft_content_path: string
resources_path: string
created_at: string
updated_at: string
canvas_config: any
duration: number
material_count: number
track_count: number
tags: string[]
}
export interface ImportResult {
status: boolean
msg: string
imported_count: number
failed_count: number
imported_templates: TemplateInfo[]
failed_templates: Array<{
name: string
error: string
}>
}
export function useTemplateProgress(options: UseProgressCommandOptions = {}) {
const hook = useProgressCommand<ImportResult>(options)
const batchImport = useCallback(async (sourceFolder: string) => {
return hook.execute(
'batch_import_templates_with_progress',
{ request: { source_folder: sourceFolder } },
'template-import-progress'
)
}, [hook])
return {
...hook,
batchImport,
}
}
/**
* Specialized hook for AI video operations
*/
export function useVideoProgress(options: UseProgressCommandOptions = {}) {
const hook = useProgressCommand(options)
const generateVideo = useCallback(async (
imagePath: string,
prompt: string,
outputPath: string
) => {
return hook.execute(
'generate_video_with_progress',
{ imagePath, prompt, outputPath },
'video-generation-progress'
)
}, [hook])
return {
...hook,
generateVideo,
}
}
/**
* Specialized hook for data processing operations
*/
export function useDataProcessingProgress(options: UseProgressCommandOptions = {}) {
const hook = useProgressCommand(options)
const processData = useCallback(async (
inputFile: string,
outputFile: string,
processingType: string
) => {
return hook.execute(
'process_data_with_progress',
{ request: { input_file: inputFile, output_file: outputFile, processing_type: processingType } },
'data-processing-progress'
)
}, [hook])
const batchConvertFiles = useCallback(async (
filePaths: string[],
outputFormat: string
) => {
return hook.execute(
'batch_convert_files_with_progress',
{ filePaths, outputFormat },
'file-conversion-progress'
)
}, [hook])
return {
...hook,
processData,
batchConvertFiles,
}
}
/**
* Specialized hook for machine learning operations
*/
export function useMLProgress(options: UseProgressCommandOptions = {}) {
const hook = useProgressCommand(options)
const trainModel = useCallback(async (
datasetPath: string,
modelType: string,
epochs: number,
learningRate: number
) => {
return hook.execute(
'train_model_with_progress',
{ request: { dataset_path: datasetPath, model_type: modelType, epochs, learning_rate: learningRate } },
'model-training-progress'
)
}, [hook])
return {
...hook,
trainModel,
}
}