fix: 修复查询结果 API 响应格式解析问题
问题修复: - 修复查询结果响应中缺少 task_id 字段导致的解析失败 - 重构数据结构,区分提交任务和查询结果的不同响应格式 - 添加类型守卫确保类型安全的数据访问 - 优化轮询逻辑,正确检测任务完成状态 (status: 'done') 技术改进: - 分离提交和查询的数据结构: * RealmanAvatarPictureCreateRoleOmniSubmitData (包含 task_id) * RealmanAvatarPictureCreateRoleOmniResultData (包含 status, image_urls, resp_data) - 使用 TypeScript 联合类型和类型守卫确保类型安全 - 更新前端代码使用正确的数据访问路径 - 完善错误处理和状态检测逻辑 现在 OmniHuman 主体识别功能可以正确解析查询结果响应了!
This commit is contained in:
parent
1a97d54450
commit
365e2c4615
|
|
@ -136,21 +136,32 @@ pub struct RealmanAvatarPictureCreateRoleOmniResult {
|
||||||
pub time_elapsed: String,
|
pub time_elapsed: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OmniHuman 主体识别返回数据
|
/// OmniHuman 主体识别提交任务返回数据
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RealmanAvatarPictureCreateRoleOmniData {
|
pub struct RealmanAvatarPictureCreateRoleOmniSubmitData {
|
||||||
|
/// 任务ID
|
||||||
|
pub task_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// OmniHuman 主体识别查询结果返回数据
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct RealmanAvatarPictureCreateRoleOmniResultData {
|
||||||
/// 输出处理过的图片url数组(单张图)
|
/// 输出处理过的图片url数组(单张图)
|
||||||
pub image_urls: Option<Vec<String>>,
|
pub image_urls: Option<Vec<String>>,
|
||||||
/// 返回图base64数组
|
/// 返回图base64数组
|
||||||
pub binary_data_base64: Option<Vec<String>>,
|
pub binary_data_base64: Option<Vec<String>>,
|
||||||
/// 任务ID
|
|
||||||
pub task_id: String,
|
|
||||||
/// 算法返回数据
|
/// 算法返回数据
|
||||||
pub resp_data: Option<String>,
|
pub resp_data: Option<String>,
|
||||||
/// 任务状态
|
/// 任务状态
|
||||||
pub status: Option<String>,
|
pub status: Option<String>,
|
||||||
/// 算法返回信息
|
}
|
||||||
pub algorithm_base_resp: Option<serde_json::Value>,
|
|
||||||
|
/// OmniHuman 主体识别返回数据(兼容两种情况)
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum RealmanAvatarPictureCreateRoleOmniData {
|
||||||
|
Submit(RealmanAvatarPictureCreateRoleOmniSubmitData),
|
||||||
|
Result(RealmanAvatarPictureCreateRoleOmniResultData),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 火山云视频生成服务
|
/// 火山云视频生成服务
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,11 @@ import { open } from '@tauri-apps/plugin-dialog';
|
||||||
import { useNotifications } from '../../components/NotificationSystem';
|
import { useNotifications } from '../../components/NotificationSystem';
|
||||||
import videoGenerationService from '../../services/videoGenerationService';
|
import videoGenerationService from '../../services/videoGenerationService';
|
||||||
import fileUploadService from '../../services/fileUploadService';
|
import fileUploadService from '../../services/fileUploadService';
|
||||||
import { RealmanAvatarPictureCreateRoleOmniResponse } from '../../types/videoGeneration';
|
import {
|
||||||
|
RealmanAvatarPictureCreateRoleOmniResponse,
|
||||||
|
RealmanAvatarPictureCreateRoleOmniResultData,
|
||||||
|
RealmanAvatarPictureCreateRoleOmniSubmitData
|
||||||
|
} from '../../types/videoGeneration';
|
||||||
|
|
||||||
const OmniHumanDetectionTool: React.FC = () => {
|
const OmniHumanDetectionTool: React.FC = () => {
|
||||||
const [selectedImage, setSelectedImage] = useState<string>('');
|
const [selectedImage, setSelectedImage] = useState<string>('');
|
||||||
|
|
@ -26,6 +30,16 @@ const OmniHumanDetectionTool: React.FC = () => {
|
||||||
|
|
||||||
const { addNotification, success, error } = useNotifications();
|
const { addNotification, success, error } = useNotifications();
|
||||||
|
|
||||||
|
// 类型守卫:检查是否为查询结果数据
|
||||||
|
const isResultData = (data: any): data is RealmanAvatarPictureCreateRoleOmniResultData => {
|
||||||
|
return data && typeof data === 'object' && ('status' in data || 'image_urls' in data || 'resp_data' in data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 类型守卫:检查是否为提交任务数据
|
||||||
|
const isSubmitData = (data: any): data is RealmanAvatarPictureCreateRoleOmniSubmitData => {
|
||||||
|
return data && typeof data === 'object' && 'task_id' in data;
|
||||||
|
};
|
||||||
|
|
||||||
// 轮询查询结果
|
// 轮询查询结果
|
||||||
const pollForResult = useCallback(async (taskId: string): Promise<RealmanAvatarPictureCreateRoleOmniResponse> => {
|
const pollForResult = useCallback(async (taskId: string): Promise<RealmanAvatarPictureCreateRoleOmniResponse> => {
|
||||||
const maxAttempts = 30; // 最多轮询30次
|
const maxAttempts = 30; // 最多轮询30次
|
||||||
|
|
@ -36,13 +50,16 @@ const OmniHumanDetectionTool: React.FC = () => {
|
||||||
const result = await videoGenerationService.realmanAvatarPictureCreateRoleOmniGetResult(taskId);
|
const result = await videoGenerationService.realmanAvatarPictureCreateRoleOmniGetResult(taskId);
|
||||||
|
|
||||||
// 检查任务状态
|
// 检查任务状态
|
||||||
if (result.Result.data?.status === 'completed' || result.Result.data?.image_urls?.length) {
|
if (result.Result.data && isResultData(result.Result.data)) {
|
||||||
|
const resultData = result.Result.data;
|
||||||
|
if (resultData.status === 'done' || resultData.image_urls?.length) {
|
||||||
// 任务完成,返回结果
|
// 任务完成,返回结果
|
||||||
return result;
|
return result;
|
||||||
} else if (result.Result.data?.status === 'failed') {
|
} else if (resultData.status === 'failed') {
|
||||||
// 任务失败
|
// 任务失败
|
||||||
throw new Error('任务处理失败');
|
throw new Error('任务处理失败');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 任务还在处理中,继续轮询
|
// 任务还在处理中,继续轮询
|
||||||
setUploadProgress(80 + (attempt / maxAttempts) * 15); // 80-95% 的进度用于轮询
|
setUploadProgress(80 + (attempt / maxAttempts) * 15); // 80-95% 的进度用于轮询
|
||||||
|
|
@ -125,7 +142,8 @@ const OmniHumanDetectionTool: React.FC = () => {
|
||||||
setUploadProgress(80);
|
setUploadProgress(80);
|
||||||
|
|
||||||
if (submitResponse.Result.code === 10000) {
|
if (submitResponse.Result.code === 10000) {
|
||||||
const taskId = submitResponse.Result.data?.task_id;
|
const data = submitResponse.Result.data;
|
||||||
|
const taskId = data && isSubmitData(data) ? data.task_id : undefined;
|
||||||
if (taskId) {
|
if (taskId) {
|
||||||
setCurrentTaskId(taskId);
|
setCurrentTaskId(taskId);
|
||||||
success('主体识别任务提交成功,正在处理中...');
|
success('主体识别任务提交成功,正在处理中...');
|
||||||
|
|
@ -269,17 +287,17 @@ const OmniHumanDetectionTool: React.FC = () => {
|
||||||
<span className="text-green-800 font-medium">识别成功</span>
|
<span className="text-green-800 font-medium">识别成功</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-green-700">
|
<div className="text-sm text-green-700">
|
||||||
<p>任务ID: {result.Result.data?.task_id || currentTaskId}</p>
|
<p>任务ID: {currentTaskId || (result.Result.data && isSubmitData(result.Result.data) ? result.Result.data.task_id : '未知')}</p>
|
||||||
<p>请求ID: {result.Result.request_id}</p>
|
<p>请求ID: {result.Result.request_id}</p>
|
||||||
<p>处理时间: {result.Result.time_elapsed}</p>
|
<p>处理时间: {result.Result.time_elapsed}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{result.Result.data?.image_urls && result.Result.data.image_urls.length > 0 && (
|
{result.Result.data && isResultData(result.Result.data) && result.Result.data.image_urls && result.Result.data.image_urls.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium text-gray-900 mb-2">处理后的图片</h4>
|
<h4 className="font-medium text-gray-900 mb-2">处理后的图片</h4>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
{result.Result.data.image_urls.map((url, index) => (
|
{result.Result.data.image_urls.map((url: string, index: number) => (
|
||||||
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-gray-50">
|
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-gray-50">
|
||||||
<img
|
<img
|
||||||
src={url}
|
src={url}
|
||||||
|
|
@ -302,7 +320,7 @@ const OmniHumanDetectionTool: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{result.Result.data?.resp_data && (
|
{result.Result.data && isResultData(result.Result.data) && result.Result.data.resp_data && (
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium text-gray-900 mb-2">算法返回数据</h4>
|
<h4 className="font-medium text-gray-900 mb-2">算法返回数据</h4>
|
||||||
<div className="p-3 bg-gray-50 border border-gray-200 rounded text-sm font-mono">
|
<div className="p-3 bg-gray-50 border border-gray-200 rounded text-sm font-mono">
|
||||||
|
|
|
||||||
|
|
@ -397,21 +397,26 @@ export interface RealmanAvatarPictureCreateRoleOmniRequest {
|
||||||
image_url: string;
|
image_url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RealmanAvatarPictureCreateRoleOmniData {
|
export interface RealmanAvatarPictureCreateRoleOmniSubmitData {
|
||||||
|
/** 任务ID */
|
||||||
|
task_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RealmanAvatarPictureCreateRoleOmniResultData {
|
||||||
/** 输出处理过的图片url数组(单张图) */
|
/** 输出处理过的图片url数组(单张图) */
|
||||||
image_urls?: string[];
|
image_urls?: string[];
|
||||||
/** 返回图base64数组 */
|
/** 返回图base64数组 */
|
||||||
binary_data_base64?: string[];
|
binary_data_base64?: string[];
|
||||||
/** 任务ID */
|
|
||||||
task_id: string;
|
|
||||||
/** 算法返回数据 */
|
/** 算法返回数据 */
|
||||||
resp_data?: string;
|
resp_data?: string;
|
||||||
/** 任务状态 */
|
/** 任务状态 */
|
||||||
status?: string;
|
status?: string;
|
||||||
/** 算法返回信息 */
|
|
||||||
algorithm_base_resp?: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type RealmanAvatarPictureCreateRoleOmniData =
|
||||||
|
| RealmanAvatarPictureCreateRoleOmniSubmitData
|
||||||
|
| RealmanAvatarPictureCreateRoleOmniResultData;
|
||||||
|
|
||||||
export interface VolcanoResponseMetadata {
|
export interface VolcanoResponseMetadata {
|
||||||
Action: string;
|
Action: string;
|
||||||
Region: string;
|
Region: string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue