Files
mixvideo-v2/apps/desktop/src/services/videoGenerationService.ts
imeepos d5ef9851cd feat: 实现模特详情页视频生成功能
- 新增模特详情页组件,支持照片上传和视频生成
- 实现视频生成数据模型和仓库层
- 集成Dify API进行视频生成
- 添加云存储上传功能,自动转换S3 URL为CDN地址
- 实现统一的删除确认弹框,替换window.confirm
- 支持照片和视频生成任务的删除功能
- 优化UI/UX设计,符合前端开发规范
- 添加完整的错误处理和状态管理

核心功能:
 模特照片上传到云端
 多选照片进行视频生成
 实时任务状态跟踪
 视频生成历史记录
 统一删除确认对话框
 响应式设计和优雅动画
2025-07-16 19:39:44 +08:00

242 lines
6.6 KiB
TypeScript

import { invoke } from '@tauri-apps/api/core';
import {
VideoGenerationTask,
VideoGenerationQueryParams,
CreateVideoGenerationRequest,
VideoGenerationAPI,
} from '../types/videoGeneration';
import { Model, ModelPhoto, PhotoType } from '../types/model';
/**
* 视频生成服务
* 提供视频生成相关的API调用功能
*/
class VideoGenerationService implements VideoGenerationAPI {
/**
* 创建视频生成任务
*/
async createVideoGenerationTask(request: CreateVideoGenerationRequest): Promise<VideoGenerationTask> {
try {
const task = await invoke<VideoGenerationTask>('create_video_generation_task', {
request
});
return task;
} catch (error) {
console.error('创建视频生成任务失败:', error);
throw new Error(`创建视频生成任务失败: ${error}`);
}
}
/**
* 执行视频生成任务
*/
async executeVideoGenerationTask(taskId: string): Promise<VideoGenerationTask> {
try {
const task = await invoke<VideoGenerationTask>('execute_video_generation_task', {
taskId
});
return task;
} catch (error) {
console.error('执行视频生成任务失败:', error);
throw new Error(`执行视频生成任务失败: ${error}`);
}
}
/**
* 获取视频生成任务
*/
async getVideoGenerationTask(taskId: string): Promise<VideoGenerationTask | null> {
try {
const task = await invoke<VideoGenerationTask | null>('get_video_generation_task', {
taskId
});
return task;
} catch (error) {
console.error('获取视频生成任务失败:', error);
throw new Error(`获取视频生成任务失败: ${error}`);
}
}
/**
* 获取视频生成任务列表
*/
async getVideoGenerationTasks(params?: VideoGenerationQueryParams): Promise<VideoGenerationTask[]> {
try {
const tasks = await invoke<VideoGenerationTask[]>('get_video_generation_tasks', {
params: params || {}
});
return tasks;
} catch (error) {
console.error('获取视频生成任务列表失败:', error);
throw new Error(`获取视频生成任务列表失败: ${error}`);
}
}
/**
* 取消视频生成任务
*/
async cancelVideoGenerationTask(taskId: string): Promise<void> {
try {
await invoke('cancel_video_generation_task', {
taskId
});
} catch (error) {
console.error('取消视频生成任务失败:', error);
throw new Error(`取消视频生成任务失败: ${error}`);
}
}
/**
* 删除视频生成任务
*/
async deleteVideoGenerationTask(taskId: string): Promise<void> {
try {
await invoke('delete_video_generation_task', {
taskId
});
} catch (error) {
console.error('删除视频生成任务失败:', error);
throw new Error(`删除视频生成任务失败: ${error}`);
}
}
/**
* 重试视频生成任务
*/
async retryVideoGenerationTask(taskId: string): Promise<VideoGenerationTask> {
try {
const task = await invoke<VideoGenerationTask>('retry_video_generation_task', {
taskId
});
return task;
} catch (error) {
console.error('重试视频生成任务失败:', error);
throw new Error(`重试视频生成任务失败: ${error}`);
}
}
/**
* 获取模特详情(包含照片)
*/
async getModelDetailWithPhotos(modelId: string): Promise<Model | null> {
try {
const model = await invoke<Model | null>('get_model_detail_with_photos', {
modelId
});
return model;
} catch (error) {
console.error('获取模特详情失败:', error);
throw new Error(`获取模特详情失败: ${error}`);
}
}
/**
* 批量上传模特照片
*/
async batchUploadModelPhotos(
modelId: string,
filePaths: string[],
photoType: PhotoType,
description?: string,
tags?: string[]
): Promise<ModelPhoto[]> {
try {
const photos = await invoke<ModelPhoto[]>('batch_upload_model_photos', {
modelId,
filePaths,
photoType,
description,
tags
});
return photos;
} catch (error) {
console.error('批量上传模特照片失败:', error);
throw new Error(`批量上传模特照片失败: ${error}`);
}
}
/**
* 获取模特视频生成统计
*/
async getModelVideoGenerationStatistics(modelId: string) {
try {
const stats = await invoke('get_model_video_generation_statistics', {
modelId
});
return stats;
} catch (error) {
console.error('获取模特视频生成统计失败:', error);
throw new Error(`获取模特视频生成统计失败: ${error}`);
}
}
/**
* 创建并执行视频生成任务(一步完成)
*/
async createAndExecuteVideoGeneration(request: CreateVideoGenerationRequest): Promise<VideoGenerationTask> {
try {
// 1. 创建任务
const task = await this.createVideoGenerationTask(request);
// 2. 执行任务
const executedTask = await this.executeVideoGenerationTask(task.id);
return executedTask;
} catch (error) {
console.error('创建并执行视频生成任务失败:', error);
throw error;
}
}
/**
* 轮询任务状态直到完成
*/
async pollTaskUntilComplete(
taskId: string,
onProgress?: (task: VideoGenerationTask) => void,
maxAttempts: number = 60,
intervalMs: number = 2000
): Promise<VideoGenerationTask> {
let attempts = 0;
while (attempts < maxAttempts) {
try {
const task = await this.getVideoGenerationTask(taskId);
if (!task) {
throw new Error('任务不存在');
}
if (onProgress) {
onProgress(task);
}
// 检查任务是否完成
if (task.status === 'Completed' || task.status === 'Failed' || task.status === 'Cancelled') {
return task;
}
// 等待一段时间后继续轮询
await new Promise(resolve => setTimeout(resolve, intervalMs));
attempts++;
} catch (error) {
console.error('轮询任务状态失败:', error);
attempts++;
if (attempts >= maxAttempts) {
throw new Error(`轮询任务状态超时: ${error}`);
}
// 等待一段时间后重试
await new Promise(resolve => setTimeout(resolve, intervalMs));
}
}
throw new Error('轮询任务状态超时');
}
}
// 导出单例实例
export const videoGenerationService = new VideoGenerationService();
export default videoGenerationService;