2025-12-01 22:27:50 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 可灵数字人 API
|
|
|
|
|
|
*/
|
|
|
|
|
|
import request from './http'
|
|
|
|
|
|
import { message } from "ant-design-vue"
|
|
|
|
|
|
import { MaterialService } from './material'
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 人脸识别
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function identifyFace(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/webApi/api/tik/kling/identify-face',
|
|
|
|
|
|
method: 'post',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 创建口型同步任务
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function createLipSyncTask(data) {
|
|
|
|
|
|
return request({
|
2025-12-02 01:55:57 +08:00
|
|
|
|
url: '/webApi/api/tik/kling/task/create',
|
2025-12-01 22:27:50 +08:00
|
|
|
|
method: 'post',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 查询口型同步任务
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getLipSyncTask(taskId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/webApi/api/tik/kling/lip-sync/${taskId}`,
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 创建可灵任务并识别(推荐方式)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function createKlingTaskAndIdentify(file) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 1. 提取视频封面
|
|
|
|
|
|
message.loading('正在提取视频封面...', 0)
|
|
|
|
|
|
let coverBase64 = null
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { extractVideoCover } = await import('@/utils/video-cover')
|
|
|
|
|
|
const cover = await extractVideoCover(file, {
|
|
|
|
|
|
maxWidth: 800,
|
|
|
|
|
|
quality: 0.8
|
|
|
|
|
|
})
|
|
|
|
|
|
coverBase64 = cover.base64
|
|
|
|
|
|
console.log('视频封面提取成功')
|
|
|
|
|
|
} catch (coverError) {
|
|
|
|
|
|
console.warn('视频封面提取失败:', coverError)
|
|
|
|
|
|
// 封面提取失败不影响主流程
|
|
|
|
|
|
}
|
|
|
|
|
|
message.destroy()
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 上传视频到OSS(包含封面)
|
|
|
|
|
|
message.loading('正在上传视频...', 0)
|
|
|
|
|
|
const uploadRes = await MaterialService.uploadFile(file, 'video', coverBase64)
|
|
|
|
|
|
message.destroy()
|
|
|
|
|
|
|
|
|
|
|
|
if (uploadRes.code !== 0) {
|
|
|
|
|
|
throw new Error(uploadRes.msg || '上传失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const fileId = uploadRes.data
|
|
|
|
|
|
console.log('文件上传成功,ID:', fileId, '封面长度:', coverBase64?.length || 0)
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 获取公网播放URL
|
|
|
|
|
|
message.loading('正在生成播放链接...', 0)
|
|
|
|
|
|
const urlRes = await MaterialService.getVideoPlayUrl(fileId)
|
|
|
|
|
|
message.destroy()
|
|
|
|
|
|
|
|
|
|
|
|
if (urlRes.code !== 0) {
|
|
|
|
|
|
throw new Error(urlRes.msg || '获取播放链接失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const videoUrl = urlRes.data
|
|
|
|
|
|
console.log('视频URL:', videoUrl)
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 调用识别API
|
|
|
|
|
|
message.loading('正在识别视频中的人脸...', 0)
|
|
|
|
|
|
const identifyRes = await identifyFace({ video_url: videoUrl })
|
|
|
|
|
|
message.destroy()
|
|
|
|
|
|
|
|
|
|
|
|
if (identifyRes.code !== 0) {
|
|
|
|
|
|
throw new Error(identifyRes.msg || '识别失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: {
|
|
|
|
|
|
fileId,
|
|
|
|
|
|
videoUrl,
|
|
|
|
|
|
sessionId: identifyRes.data.sessionId,
|
2025-12-02 01:55:57 +08:00
|
|
|
|
faceId: identifyRes.data.data.face_data[0].face_id || null,
|
|
|
|
|
|
// 人脸时间信息,用于音频插入时间
|
|
|
|
|
|
startTime: identifyRes.data.data.face_data[0].start_time || 0,
|
|
|
|
|
|
endTime: identifyRes.data.data.face_data[0].end_time || 0
|
2025-12-01 22:27:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
message.destroy()
|
|
|
|
|
|
console.error('可灵任务失败:', error)
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|