From 5fdf3c5a4b0108d914e98f7c93393305bd0bdb66 Mon Sep 17 00:00:00 2001 From: imeepos Date: Fri, 1 Aug 2025 11:21:12 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20Hedra=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=E6=96=B9=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=96=87=E4=BB=B6=E8=B7=AF=E5=BE=84=E8=80=8C?= =?UTF-8?q?=E9=9D=9E=E6=96=87=E4=BB=B6=E5=86=85=E5=AE=B9=E4=BC=A0=E8=BE=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 HedraFileUploadRequest 使用 file_path 而不是 file_data - 添加 HedraFileUploadApiRequest 用于后端到 API 的请求 - 更新后端服务读取文件并转换为 API 请求格式 - 重构前端文件选择,使用 @tauri-apps/api/dialog 直接选择文件路径 - 移除复杂的文件转换和临时文件创建逻辑 - 简化文件上传流程,避免大文件在前后端间传输 这种方式更适合 Tauri 架构,避免了大文件传输的性能问题 --- .../data/models/bowong_text_video_agent.rs | 11 +++++- .../bowong_text_video_agent_service.rs | 20 +++++++++- .../src/pages/tools/HedraLipSyncTool.tsx | 38 +++++++++++++------ .../services/bowongTextVideoAgentService.ts | 28 +------------- .../desktop/src/types/bowongTextVideoAgent.ts | 2 +- 5 files changed, 58 insertions(+), 41 deletions(-) diff --git a/apps/desktop/src-tauri/src/data/models/bowong_text_video_agent.rs b/apps/desktop/src-tauri/src/data/models/bowong_text_video_agent.rs index c470d68..c59dcd8 100644 --- a/apps/desktop/src-tauri/src/data/models/bowong_text_video_agent.rs +++ b/apps/desktop/src-tauri/src/data/models/bowong_text_video_agent.rs @@ -258,12 +258,19 @@ pub struct ComfyUISyncExecuteRequest { pub max_wait_time: Option, } -/// Hedra 文件上传请求 +/// Hedra 文件上传请求(前端到后端) #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HedraFileUploadRequest { + pub file_path: String, + pub purpose: Option, // 'image', 'audio', 'video', 'voice' +} + +/// Hedra 文件上传 API 请求(后端到 API) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct HedraFileUploadApiRequest { pub file_data: Vec, pub filename: String, - pub purpose: Option, // 'image', 'audio', 'video', 'voice' + pub purpose: Option, } /// Hedra 任务提交请求 diff --git a/apps/desktop/src-tauri/src/infrastructure/bowong_text_video_agent_service.rs b/apps/desktop/src-tauri/src/infrastructure/bowong_text_video_agent_service.rs index 10cf612..0610141 100644 --- a/apps/desktop/src-tauri/src/infrastructure/bowong_text_video_agent_service.rs +++ b/apps/desktop/src-tauri/src/infrastructure/bowong_text_video_agent_service.rs @@ -525,7 +525,25 @@ impl BowongTextVideoAgentService { /// Hedra 上传文件 pub async fn hedra_upload_file(&self, request: &HedraFileUploadRequest) -> Result { - self.execute_request("hedra_upload_file", Some(request)).await + // 读取文件内容 + let file_data = std::fs::read(&request.file_path) + .map_err(|e| anyhow!("Failed to read file {}: {}", request.file_path, e))?; + + // 获取文件名 + let filename = std::path::Path::new(&request.file_path) + .file_name() + .and_then(|name| name.to_str()) + .ok_or_else(|| anyhow!("Invalid file path: {}", request.file_path))? + .to_string(); + + // 构造 API 请求 + let api_request = HedraFileUploadApiRequest { + file_data, + filename, + purpose: request.purpose.clone(), + }; + + self.execute_request("hedra_upload_file", Some(&api_request)).await } /// Hedra 提交任务 diff --git a/apps/desktop/src/pages/tools/HedraLipSyncTool.tsx b/apps/desktop/src/pages/tools/HedraLipSyncTool.tsx index 23268ff..f01389f 100644 --- a/apps/desktop/src/pages/tools/HedraLipSyncTool.tsx +++ b/apps/desktop/src/pages/tools/HedraLipSyncTool.tsx @@ -14,6 +14,7 @@ import { FileImage, FileAudio } from 'lucide-react'; +import { open } from '@tauri-apps/api/dialog'; import { useNotifications } from '../../components/NotificationSystem'; import { createBowongTextVideoAgentService } from '../../services/bowongTextVideoAgentService'; import { @@ -104,14 +105,29 @@ const HedraLipSyncTool: React.FC = () => { } }, [addNotification]); - // 文件上传 - const uploadFile = useCallback(async (fileInfo: HedraFileInfo, purpose: 'image' | 'audio'): Promise => { - const request: HedraFileUploadRequest = { - local_file: fileInfo.file, - purpose - }; - + // 文件选择和上传 + const selectAndUploadFile = useCallback(async (purpose: 'image' | 'audio'): Promise => { try { + // 使用文件选择对话框 + const selected = await open({ + multiple: false, + filters: [{ + name: purpose === 'image' ? '图片文件' : '音频文件', + extensions: purpose === 'image' + ? ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'] + : ['mp3', 'wav', 'aac', 'flac', 'm4a', 'ogg'] + }] + }); + + if (!selected || typeof selected !== 'string') { + throw new Error('未选择文件'); + } + + const request: HedraFileUploadRequest = { + file_path: selected, + purpose + }; + const response = await bowongService.hedraUploadFile(request); if (response.status && response.data) { return response.data; @@ -119,7 +135,7 @@ const HedraLipSyncTool: React.FC = () => { throw new Error(response.msg || '文件上传失败'); } } catch (error) { - console.error('文件上传失败:', error); + console.error('文件选择和上传失败:', error); throw error; } }, []); @@ -144,7 +160,7 @@ const HedraLipSyncTool: React.FC = () => { imageFile: prev.imageFile ? { ...prev.imageFile, uploadStatus: 'uploading' } : null })); - const imageUrl = await uploadFile(state.imageFile, 'image'); + const imageUrl = await selectAndUploadFile('image'); setState(prev => ({ ...prev, @@ -157,7 +173,7 @@ const HedraLipSyncTool: React.FC = () => { audioFile: prev.audioFile ? { ...prev.audioFile, uploadStatus: 'uploading' } : null })); - const audioUrl = await uploadFile(state.audioFile, 'audio'); + const audioUrl = await selectAndUploadFile('audio'); setState(prev => ({ ...prev, @@ -217,7 +233,7 @@ const HedraLipSyncTool: React.FC = () => { message: error instanceof Error ? error.message : '口型合成任务失败' }); } - }, [state.imageFile, state.audioFile, uploadFile, addNotification]); + }, [selectAndUploadFile, addNotification]); // 轮询任务状态 const pollTaskStatus = useCallback(async (taskId: string) => { diff --git a/apps/desktop/src/services/bowongTextVideoAgentService.ts b/apps/desktop/src/services/bowongTextVideoAgentService.ts index 9e5f04f..c0783c2 100644 --- a/apps/desktop/src/services/bowongTextVideoAgentService.ts +++ b/apps/desktop/src/services/bowongTextVideoAgentService.ts @@ -606,15 +606,7 @@ export class BowongTextVideoAgentFastApiService implements BowongTextVideoAgentA // ============================================================================ async hedraUploadFile(request: HedraFileUploadRequest): Promise { - // 将 File 对象转换为后端期望的格式 - const fileData = await this.fileToBytes(request.local_file); - const backendRequest = { - file_data: Array.from(fileData), // 转换为数字数组 - filename: request.local_file.name, - purpose: request.purpose || 'image' - }; - - return this.invokeAPI('hedra_upload_file', backendRequest); + return this.invokeAPI('hedra_upload_file', request); } async hedraSubmitTask(request: HedraTaskSubmitRequest): Promise { @@ -641,23 +633,7 @@ export class BowongTextVideoAgentFastApiService implements BowongTextVideoAgentA // 工具方法 // ============================================================================ - /** - * 将 File 对象转换为字节数组 - */ - private async fileToBytes(file: File): Promise { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => { - if (reader.result instanceof ArrayBuffer) { - resolve(new Uint8Array(reader.result)); - } else { - reject(new Error('Failed to read file as ArrayBuffer')); - } - }; - reader.onerror = () => reject(reader.error); - reader.readAsArrayBuffer(file); - }); - } + /** * 获取服务配置 diff --git a/apps/desktop/src/types/bowongTextVideoAgent.ts b/apps/desktop/src/types/bowongTextVideoAgent.ts index 0e9c69e..39e7dd6 100644 --- a/apps/desktop/src/types/bowongTextVideoAgent.ts +++ b/apps/desktop/src/types/bowongTextVideoAgent.ts @@ -545,7 +545,7 @@ export interface ComfyUISyncExecuteRequest { * Hedra 文件上传请求 */ export interface HedraFileUploadRequest { - local_file: File; + file_path: string; purpose?: 'image' | 'audio' | 'video' | 'voice'; // 默认 'image' }