AI_Painting_V2.0/src/utils/taskPolling.js
WangLeo 2d12c5a20b feat: 新增 Music 音乐生成平台,遵循 Platform Descriptor 模式
基于旧项目 ai_music_v2.0 迁移,与 Painting/Video 统一架构:HTTP 轮询 + suanli 后端、
API 驱动配置、mode 独立 ref 驱动控件显隐。新增 AudioPlayer/CustomSlider 通用组件,
dialogBox/set.vue/taskPolling/modelApi 完成集成适配。
2026-06-12 19:20:18 +08:00

191 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ElNotification } from 'element-plus'
import { h } from 'vue'
import { requestCreateTask, requestTaskStatus } from '@/apis/display'
import { useDisplayStore, useUserStore } from '@/stores'
import { userError } from '@/utils/tokenError'
export function getChargeType(chargeType) {
switch (chargeType) {
case 'Painting':
return 1
case 'Video':
return 4
case 'Music':
return 5
default:
return 2
}
}
export function websocketError(code, msg) {
let message
switch (code) {
case 1006:
message = '用户身份验证失败'
userError()
break
case 4401:
message = msg
break
case 4402:
message = JSON.parse(msg)
break
case 4403:
message = msg
break
default:
message = '连接异常,请稍后重试'
}
ElNotification({
title: '生成失败',
message: h('i', { style: 'color: teal' }, message),
type: 'error',
duration: 6000
})
}
export function websocketSuccess() {
ElNotification({
title: '生成成功',
message: h('div', [
h('div', { style: 'font-weight: bold; color: teal;' }, '生成成功!'),
h('br'),
h('div', { style: 'color: orange; margin-top: 5px;' }, '内测状态请及时下载生成的文件云端储存与历史记录保留24小时')
]),
type: 'success',
duration: 6000
})
}
// 当前活跃的轮询定时器集合,用于页面卸载时清理
const activePollIntervals = new Set()
export async function generate(data, generateData) {
const useDisplay = useDisplayStore()
let taskId = null
let pollInterval = null
if (!data.modelId) {
ElNotification({
title: '生成失败',
message: h('i', { style: 'color: teal' }, '未找到模型ID请联系管理员配置'),
type: 'error'
})
return
}
useDisplay.isSubGerenate = true
// 从登录态获取 sessionId
const sessionId = useUserStore().userInfo.sessionId
if (!sessionId) {
ElNotification({
title: '生成失败',
message: h('i', { style: 'color: teal' }, '用户身份已过期,请重新登录'),
type: 'error'
})
useDisplay.isSubGerenate = false
return
}
try {
const body = data.body
// 构造请求体
const requestBody = {
model_id: data.modelId,
body,
request: data.request
}
// POST 创建任务
const createResult = await requestCreateTask(requestBody, sessionId)
if (createResult.code !== 0) {
ElNotification({
title: '生成失败',
message: h('i', { style: 'color: teal' }, createResult.message || '任务创建失败'),
type: 'error'
})
useDisplay.isSubGerenate = false
return
}
taskId = createResult.data.task_id
// 在列表中插入"生成中"条目
useDisplay.addGeneratingItem({
taskId,
type: data.type,
generateData
})
setTimeout(() => {
useDisplay.scrollToBottom()
}, 100)
// 轮询任务状态
const pollTask = async () => {
try {
const pollResult = await requestTaskStatus(taskId)
if (pollResult.code !== 0) return
const taskData = pollResult.data
if (taskData.status === 'completed') {
clearInterval(pollInterval)
activePollIntervals.delete(pollInterval)
useDisplay.isSubGerenate = false
// 提取结果 URL
const urls = taskData.outputs?.map((img) => img.url) || []
if (urls.length > 0) {
useDisplay.updateItemToSuccess(taskId, urls)
websocketSuccess()
} else {
websocketError(4403, '未获取到生成结果')
}
} else if (taskData.status === 'failed') {
clearInterval(pollInterval)
activePollIntervals.delete(pollInterval)
useDisplay.isSubGerenate = false
websocketError(4403, taskData.vendor_error || '生成失败')
}
// queued / processing 状态继续轮询
} catch (error) {
console.error('轮询任务状态失败:', error)
}
}
// 每 20 秒轮询一次
pollInterval = setInterval(pollTask, 20000)
activePollIntervals.add(pollInterval)
// 5 秒后先做第一次轮询
setTimeout(pollTask, 5000)
} catch (error) {
console.error('创建任务失败:', error)
useDisplay.isSubGerenate = false
ElNotification({
title: '生成通知',
message: h('i', { style: 'color: teal' }, '生成失败,请检查参数后重新提交任务'),
type: 'error'
})
if (pollInterval) {
clearInterval(pollInterval)
activePollIntervals.delete(pollInterval)
}
}
}
// 页面卸载时清理所有轮询
if (typeof window !== 'undefined') {
window.addEventListener('beforeunload', () => {
for (const interval of activePollIntervals) {
clearInterval(interval)
}
activePollIntervals.clear()
})
}