- 新增模特详情页组件,支持照片上传和视频生成 - 实现视频生成数据模型和仓库层 - 集成Dify API进行视频生成 - 添加云存储上传功能,自动转换S3 URL为CDN地址 - 实现统一的删除确认弹框,替换window.confirm - 支持照片和视频生成任务的删除功能 - 优化UI/UX设计,符合前端开发规范 - 添加完整的错误处理和状态管理 核心功能: 模特照片上传到云端 多选照片进行视频生成 实时任务状态跟踪 视频生成历史记录 统一删除确认对话框 响应式设计和优雅动画
242 lines
6.6 KiB
TypeScript
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;
|