import request from './request' /** * 图生视频API服务 */ export const imageToVideoApi = { /** * 创建图生视频任务 * @param {Object} params - 任务参数 * @param {File} params.firstFrame - 首帧图片 * @param {File} params.lastFrame - 尾帧图片(可选) * @param {string} params.prompt - 描述文字 * @param {string} params.aspectRatio - 视频比例 * @param {number} params.duration - 视频时长 * @param {boolean} params.hdMode - 是否高清模式 * @returns {Promise} API响应 */ createTask(params) { // 参数验证 if (!params) { throw new Error('参数不能为空') } if (!params.firstFrame) { throw new Error('首帧图片不能为空') } if (!params.prompt || params.prompt.trim() === '') { throw new Error('描述文字不能为空') } if (!params.aspectRatio) { throw new Error('视频比例不能为空') } if (!params.duration || params.duration < 1 || params.duration > 60) { throw new Error('视频时长必须在1-60秒之间') } const formData = new FormData() // 添加必填参数 formData.append('firstFrame', params.firstFrame) formData.append('prompt', params.prompt.trim()) formData.append('aspectRatio', params.aspectRatio) formData.append('duration', params.duration.toString()) formData.append('hdMode', params.hdMode.toString()) // 添加可选参数 if (params.lastFrame) { formData.append('lastFrame', params.lastFrame) } return request({ url: '/image-to-video/create', method: 'POST', data: formData, headers: { 'Content-Type': 'multipart/form-data' } }) }, /** * 获取用户任务列表 * @param {number} page - 页码 * @param {number} size - 每页数量 * @returns {Promise} API响应 */ getTasks(page = 0, size = 10) { return request({ url: '/image-to-video/tasks', method: 'GET', params: { page, size } }) }, /** * 获取任务详情 * @param {string} taskId - 任务ID * @returns {Promise} API响应 */ getTaskDetail(taskId) { return request({ url: `/image-to-video/tasks/${taskId}`, method: 'GET' }) }, /** * 获取任务状态 * @param {string} taskId - 任务ID * @returns {Promise} API响应 */ getTaskStatus(taskId) { return request({ url: `/image-to-video/tasks/${taskId}/status`, method: 'GET' }) }, /** * 轮询任务状态 * @param {string} taskId - 任务ID * @param {Function} onProgress - 进度回调 * @param {Function} onComplete - 完成回调 * @param {Function} onError - 错误回调 * @returns {Function} 停止轮询的函数 */ pollTaskStatus(taskId, onProgress, onComplete, onError) { let isPolling = true let pollCount = 0 const maxPolls = 30 // 最大轮询次数(1小时,每2分钟一次) const poll = async () => { if (!isPolling || pollCount >= maxPolls) { if (pollCount >= maxPolls) { onError && onError(new Error('任务超时')) } return } try { const response = await request({ url: `/image-to-video/tasks/${taskId}/status`, method: 'GET' }) // 检查响应是否有效 if (!response || !response.data || !response.data.success) { onError && onError(new Error('获取任务状态失败')) isPolling = false return } const taskData = response.data.data // 检查taskData是否有效 if (!taskData || !taskData.status) { onError && onError(new Error('无效的任务数据')) isPolling = false return } if (taskData.status === 'COMPLETED') { onComplete && onComplete(taskData) isPolling = false return } if (taskData.status === 'FAILED' || taskData.status === 'CANCELLED') { console.error('任务失败:', { taskId: taskId, status: taskData.status, errorMessage: taskData.errorMessage, pollCount: pollCount }) onError && onError(new Error(taskData.errorMessage || '任务失败')) isPolling = false return } // 调用进度回调 onProgress && onProgress({ status: taskData.status, progress: taskData.progress || 0, resultUrl: taskData.resultUrl }) pollCount++ // 继续轮询 setTimeout(poll, 120000) // 每2分钟轮询一次 } catch (error) { console.error('轮询任务状态失败:', error) onError && onError(error) isPolling = false } } // 开始轮询 poll() // 返回停止轮询的函数 return () => { isPolling = false } } } export default imageToVideoApi