feat: 重构 IdentifyFace.vue 为 Hooks 架构
- 新增 hooks/ 目录,包含三个专用 Hook: * useVoiceGeneration - 语音生成和校验逻辑 * useDigitalHumanGeneration - 数字人视频生成逻辑 * useIdentifyFaceController - 协调两个子 Hook 的控制器 - 新增 types/identify-face.ts 完整类型定义 - 重构 IdentifyFace.vue 使用 hooks 架构: * 视图层与业务逻辑分离 * 状态管理清晰化 * 模块解耦,逻辑清晰 - 遵循单一职责原则,每个 Hook 只负责一个领域 - 提升代码可测试性和可维护性 - 支持两种视频素材来源:素材库选择和直接上传 - 实现语音生成优先校验的业务规则 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,15 @@ import { message } from "ant-design-vue"
|
||||
import { MaterialService } from './material'
|
||||
|
||||
/**
|
||||
* 人脸识别
|
||||
* 显示加载提示
|
||||
*/
|
||||
const showLoading = (text) => message.loading(text, 0)
|
||||
|
||||
/**
|
||||
* 销毁加载提示
|
||||
*/
|
||||
const hideLoading = () => message.destroy()
|
||||
|
||||
export function identifyFace(data) {
|
||||
return request({
|
||||
url: '/webApi/api/tik/kling/identify-face',
|
||||
@@ -16,9 +23,6 @@ export function identifyFace(data) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建口型同步任务
|
||||
*/
|
||||
export function createLipSyncTask(data) {
|
||||
return request({
|
||||
url: '/webApi/api/tik/kling/task/create',
|
||||
@@ -27,9 +31,6 @@ export function createLipSyncTask(data) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询口型同步任务
|
||||
*/
|
||||
export function getLipSyncTask(taskId) {
|
||||
return request({
|
||||
url: `/webApi/api/tik/kling/lip-sync/${taskId}`,
|
||||
@@ -37,13 +38,36 @@ export function getLipSyncTask(taskId) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建可灵任务并识别(推荐方式)
|
||||
*/
|
||||
export async function createKlingTaskAndIdentify(file) {
|
||||
export async function identifyUploadedVideo(videoFile) {
|
||||
try {
|
||||
// 1. 提取视频封面
|
||||
message.loading('正在提取视频封面...', 0)
|
||||
showLoading('正在识别视频中的人脸...')
|
||||
const identifyRes = await identifyFace({ video_url: videoFile.fileUrl })
|
||||
hideLoading()
|
||||
|
||||
if (identifyRes.code !== 0) {
|
||||
throw new Error(identifyRes.msg || '识别失败')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
fileId: videoFile.id,
|
||||
videoUrl: videoFile.fileUrl,
|
||||
sessionId: identifyRes.data.sessionId,
|
||||
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
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
hideLoading()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadAndIdentifyVideo(file) {
|
||||
try {
|
||||
showLoading('正在提取视频封面...')
|
||||
let coverBase64 = null
|
||||
try {
|
||||
const { extractVideoCover } = await import('@/utils/video-cover')
|
||||
@@ -52,46 +76,39 @@ export async function createKlingTaskAndIdentify(file) {
|
||||
quality: 0.8
|
||||
})
|
||||
coverBase64 = cover.base64
|
||||
console.log('视频封面提取成功')
|
||||
} catch (coverError) {
|
||||
console.warn('视频封面提取失败:', coverError)
|
||||
// 封面提取失败不影响主流程
|
||||
}
|
||||
message.destroy()
|
||||
hideLoading()
|
||||
|
||||
// 2. 上传视频到OSS(包含封面)
|
||||
message.loading('正在上传视频...', 0)
|
||||
showLoading('正在上传视频...')
|
||||
const uploadRes = await MaterialService.uploadFile(file, 'video', coverBase64)
|
||||
message.destroy()
|
||||
hideLoading()
|
||||
|
||||
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)
|
||||
showLoading('正在生成播放链接...')
|
||||
const urlRes = await MaterialService.getVideoPlayUrl(fileId)
|
||||
message.destroy()
|
||||
hideLoading()
|
||||
|
||||
if (urlRes.code !== 0) {
|
||||
throw new Error(urlRes.msg || '获取播放链接失败')
|
||||
}
|
||||
|
||||
const videoUrl = urlRes.data
|
||||
console.log('视频URL:', videoUrl)
|
||||
|
||||
// 4. 调用识别API
|
||||
message.loading('正在识别视频中的人脸...', 0)
|
||||
const videoUrl = urlRes.data
|
||||
|
||||
showLoading('正在识别视频中的人脸...')
|
||||
const identifyRes = await identifyFace({ video_url: videoUrl })
|
||||
message.destroy()
|
||||
|
||||
hideLoading()
|
||||
|
||||
if (identifyRes.code !== 0) {
|
||||
throw new Error(identifyRes.msg || '识别失败')
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
@@ -99,14 +116,12 @@ export async function createKlingTaskAndIdentify(file) {
|
||||
videoUrl,
|
||||
sessionId: identifyRes.data.sessionId,
|
||||
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
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
message.destroy()
|
||||
console.error('可灵任务失败:', error)
|
||||
hideLoading()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user