diff --git a/apps/desktop/src-tauri/src/business/services/volcano_video_service.rs b/apps/desktop/src-tauri/src/business/services/volcano_video_service.rs index 8c38470..064c30d 100644 --- a/apps/desktop/src-tauri/src/business/services/volcano_video_service.rs +++ b/apps/desktop/src-tauri/src/business/services/volcano_video_service.rs @@ -92,6 +92,15 @@ pub struct RealmanAvatarPictureCreateRoleOmniRequest { pub image_url: String, } +/// OmniHuman 主体识别查询结果请求参数 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RealmanAvatarPictureCreateRoleOmniGetResultRequest { + /// 服务标识,固定值 + pub req_key: String, + /// 任务ID + pub task_id: String, +} + /// 火山云 API 响应元数据 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct VolcanoResponseMetadata { @@ -601,6 +610,62 @@ impl VolcanoVideoService { Ok(api_response) } + /// OmniHuman 主体识别 - 查询任务结果 + /// 用于查询已提交的主体识别任务的处理结果 + pub async fn realman_avatar_picture_create_role_omni_get_result( + &self, + task_id: String + ) -> Result { + info!("开始查询 OmniHuman 主体识别任务结果: {}", task_id); + + // 构建请求参数 + let request_body = RealmanAvatarPictureCreateRoleOmniGetResultRequest { + req_key: "realman_avatar_picture_create_role_omni".to_string(), + task_id, + }; + + // 火山云API调用 - OmniHuman 主体识别查询结果 + let api_url = "https://visual.volcengineapi.com?Action=RealmanAvatarPictureCreateRoleOmniGetResult&Version=2024-06-06"; + + // 构建认证头 + let now = Utc::now(); + let timestamp = now.format("%Y%m%dT%H%M%SZ").to_string(); + let date = now.format("%Y%m%d").to_string(); + let auth_header = self.build_auth_header("POST", api_url, ×tamp, &date, &request_body)?; + + info!("调用 OmniHuman 主体识别查询结果 API: {:?}", request_body); + + let response = self.http_client + .post(api_url) + .header("Authorization", auth_header) + .header("Content-Type", "application/json") + .header("X-Date", timestamp) + .json(&request_body) + .send() + .await?; + + if !response.status().is_success() { + let status = response.status(); + let error_text = response.text().await.unwrap_or_default(); + return Err(anyhow!("OmniHuman 主体识别查询结果 API 调用失败: {} - {}", status, error_text)); + } + + // 先获取响应文本进行调试 + let response_text = response.text().await?; + info!("OmniHuman 查询结果 API 原始响应: {}", response_text); + + // 尝试解析响应 + let api_response: RealmanAvatarPictureCreateRoleOmniResponse = serde_json::from_str(&response_text) + .map_err(|e| anyhow!("解析查询结果响应失败: {} - 响应内容: {}", e, response_text))?; + + if api_response.result.code != 10000 { + return Err(anyhow!("OmniHuman 主体识别查询结果 API 返回错误: {} - {}", api_response.result.code, api_response.result.message)); + } + + info!("OmniHuman 主体识别任务结果查询成功: {:?}", api_response); + Ok(api_response) + } + /// 批量删除视频生成记录 pub async fn batch_delete_video_generations(&self, ids: Vec) -> Result<()> { for id in ids { diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index 47e96cb..6abf77a 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -503,6 +503,7 @@ pub fn run() { commands::volcano_video_commands::batch_download_volcano_videos, commands::volcano_video_commands::get_video_stream_base64, commands::volcano_video_commands::realman_avatar_picture_create_role_omni_submit_task, + commands::volcano_video_commands::realman_avatar_picture_create_role_omni_get_result, // 图像编辑命令 commands::image_editing_commands::set_image_editing_config, commands::image_editing_commands::set_image_editing_api_key, diff --git a/apps/desktop/src-tauri/src/presentation/commands/volcano_video_commands.rs b/apps/desktop/src-tauri/src/presentation/commands/volcano_video_commands.rs index 6c73725..058f21f 100644 --- a/apps/desktop/src-tauri/src/presentation/commands/volcano_video_commands.rs +++ b/apps/desktop/src-tauri/src/presentation/commands/volcano_video_commands.rs @@ -480,3 +480,40 @@ pub async fn realman_avatar_picture_create_role_omni_submit_task( } } } + +/// OmniHuman 主体识别 - 查询任务结果 +/// 用于查询已提交的主体识别任务的处理结果 +#[tauri::command] +pub async fn realman_avatar_picture_create_role_omni_get_result( + state: State<'_, AppState>, + task_id: String, +) -> Result { + info!("开始查询 OmniHuman 主体识别任务结果: {}", task_id); + + // 获取数据库连接 + let database = { + let database_guard = state + .database + .lock() + .map_err(|e| format!("获取数据库失败: {}", e))?; + database_guard + .as_ref() + .ok_or("数据库未初始化")? + .clone() + }; + + // 创建服务实例 + let service = VolcanoVideoService::new(database); + + // 调用 OmniHuman 主体识别查询结果 + match service.realman_avatar_picture_create_role_omni_get_result(task_id).await { + Ok(response) => { + info!("OmniHuman 主体识别任务结果查询成功: {:?}", response); + Ok(response) + } + Err(e) => { + error!("OmniHuman 主体识别任务结果查询失败: {}", e); + Err(e.to_string()) + } + } +} diff --git a/apps/desktop/src/pages/tools/OmniHumanDetectionTool.tsx b/apps/desktop/src/pages/tools/OmniHumanDetectionTool.tsx index 9c2058c..593bf05 100644 --- a/apps/desktop/src/pages/tools/OmniHumanDetectionTool.tsx +++ b/apps/desktop/src/pages/tools/OmniHumanDetectionTool.tsx @@ -20,11 +20,46 @@ const OmniHumanDetectionTool: React.FC = () => { const [imagePreview, setImagePreview] = useState(''); const [isProcessing, setIsProcessing] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); + const [currentTaskId, setCurrentTaskId] = useState(''); const [result, setResult] = useState(null); const [errorMessage, setErrorMessage] = useState(''); const { addNotification, success, error } = useNotifications(); + // 轮询查询结果 + const pollForResult = useCallback(async (taskId: string): Promise => { + const maxAttempts = 30; // 最多轮询30次 + const pollInterval = 2000; // 每2秒轮询一次 + + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + try { + const result = await videoGenerationService.realmanAvatarPictureCreateRoleOmniGetResult(taskId); + + // 检查任务状态 + if (result.Result.data?.status === 'completed' || result.Result.data?.image_urls?.length) { + // 任务完成,返回结果 + return result; + } else if (result.Result.data?.status === 'failed') { + // 任务失败 + throw new Error('任务处理失败'); + } + + // 任务还在处理中,继续轮询 + setUploadProgress(80 + (attempt / maxAttempts) * 15); // 80-95% 的进度用于轮询 + await new Promise(resolve => setTimeout(resolve, pollInterval)); + + } catch (err) { + if (attempt === maxAttempts) { + throw err; + } + // 继续重试 + await new Promise(resolve => setTimeout(resolve, pollInterval)); + } + } + + throw new Error('任务处理超时,请稍后手动查询结果'); + }, []); + // 选择图片文件 const handleSelectImage = useCallback(async () => { try { @@ -85,16 +120,27 @@ const OmniHumanDetectionTool: React.FC = () => { setUploadProgress(70); // 2. 使用云端 URL 调用识别 API - const response = await videoGenerationService.realmanAvatarPictureCreateRoleOmniSubmitTask(uploadResult.url); + const submitResponse = await videoGenerationService.realmanAvatarPictureCreateRoleOmniSubmitTask(uploadResult.url); - setUploadProgress(100); - setResult(response); + setUploadProgress(80); - if (response.Result.code === 10000) { - success('主体识别任务提交成功'); + if (submitResponse.Result.code === 10000) { + const taskId = submitResponse.Result.data?.task_id; + if (taskId) { + setCurrentTaskId(taskId); + success('主体识别任务提交成功,正在处理中...'); + + // 3. 轮询查询结果 + const finalResult = await pollForResult(taskId); + setUploadProgress(100); + setResult(finalResult); + success('主体识别完成!'); + } else { + throw new Error('未获取到任务ID'); + } } else { - setErrorMessage(`识别失败: ${response.Result.message}`); - error(`识别失败: ${response.Result.message}`); + setErrorMessage(`识别失败: ${submitResponse.Result.message}`); + error(`识别失败: ${submitResponse.Result.message}`); } } catch (err) { const errMsg = err instanceof Error ? err.message : '未知错误'; @@ -111,6 +157,8 @@ const OmniHumanDetectionTool: React.FC = () => { setImagePreview(''); setResult(null); setErrorMessage(''); + setCurrentTaskId(''); + setUploadProgress(0); }, []); return ( @@ -221,7 +269,7 @@ const OmniHumanDetectionTool: React.FC = () => { 识别成功
-

任务ID: {result.Result.data?.task_id}

+

任务ID: {result.Result.data?.task_id || currentTaskId}

请求ID: {result.Result.request_id}

处理时间: {result.Result.time_elapsed}

diff --git a/apps/desktop/src/services/videoGenerationService.ts b/apps/desktop/src/services/videoGenerationService.ts index 0fb13d8..07ef914 100644 --- a/apps/desktop/src/services/videoGenerationService.ts +++ b/apps/desktop/src/services/videoGenerationService.ts @@ -282,6 +282,23 @@ class VideoGenerationService implements VideoGenerationAPI { throw new Error(`OmniHuman 主体识别任务失败: ${error}`); } } + + /** + * OmniHuman 主体识别 - 查询任务结果 + * 用于查询已提交的主体识别任务的处理结果 + */ + async realmanAvatarPictureCreateRoleOmniGetResult(taskId: string): Promise { + try { + const response = await invoke( + 'realman_avatar_picture_create_role_omni_get_result', + { taskId } + ); + return response; + } catch (error) { + console.error('OmniHuman 主体识别结果查询失败:', error); + throw new Error(`OmniHuman 主体识别结果查询失败: ${error}`); + } + } } // 导出单例实例