Files
AIGC/demo/frontend/src/api/imageToVideo.js

190 lines
5.0 KiB
JavaScript
Raw Normal View History

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