This commit is contained in:
2026-02-24 21:41:05 +08:00
parent c1d1b0ed70
commit 9388f7d75b
7 changed files with 108 additions and 178 deletions

View File

@@ -113,8 +113,17 @@ export function useSimplePipeline(options: PipelineOptions) {
* 运行完整流程(到 ready 状态)
*/
async function run(params: PipelineParams): Promise<void> {
// 重置状态
reset()
// 重置上下文数据,但保持状态在即将开始工作的状态
context.value = { ...INITIAL_CONTEXT }
error.value = null
history.value = ['idle']
// 立即设置忙碌状态,让 UI 显示 loading
// 根据是否有上传文件决定初始状态
const initialState: PipelineState = params.videoFile && !params.selectedVideo
? 'uploading'
: 'recognizing'
setState(initialState)
try {
// 保存参数到上下文
@@ -126,20 +135,28 @@ export function useSimplePipeline(options: PipelineOptions) {
// 步骤1: 上传视频(如果是上传模式)
if (params.videoFile && !params.selectedVideo) {
const fileId = await executeStep('uploading', () =>
options.uploadVideo(params.videoFile!)
)
context.value.videoFileId = fileId
try {
const fileId = await options.uploadVideo(params.videoFile!)
context.value.videoFileId = fileId
} catch (err) {
setError(err as Error)
throw err
}
} else if (params.selectedVideo) {
context.value.videoFileId = params.selectedVideo.fileId
}
// 步骤2: 识别人脸
const recognizeData = params.selectedVideo
? await options.recognizeFromLibrary(params.selectedVideo)
: await options.recognizeUploaded(context.value.videoFileId!)
await executeStep('recognizing', async () => recognizeData)
setState('recognizing')
let recognizeData
try {
recognizeData = params.selectedVideo
? await options.recognizeFromLibrary(params.selectedVideo)
: await options.recognizeUploaded(context.value.videoFileId!)
} catch (err) {
setError(err as Error)
throw err
}
context.value.sessionId = recognizeData.sessionId
context.value.faceId = recognizeData.faceId
@@ -148,9 +165,14 @@ export function useSimplePipeline(options: PipelineOptions) {
context.value.videoDurationMs = recognizeData.duration || 0
// 步骤3: 生成音频
const audioData = await executeStep('generating', () =>
options.generateAudio(params.text, params.voice, params.speechRate)
)
setState('generating')
let audioData
try {
audioData = await options.generateAudio(params.text, params.voice, params.speechRate)
} catch (err) {
setError(err as Error)
throw err
}
context.value.audioBase64 = audioData.audioBase64
context.value.audioFormat = audioData.format || 'mp3'
@@ -160,17 +182,17 @@ export function useSimplePipeline(options: PipelineOptions) {
setState('validating')
const videoDurationMs = context.value.videoDurationMs ?? 0
if (context.value.audioDurationMs > videoDurationMs) {
throw new Error(
`校验失败:音频时长(${(context.value.audioDurationMs / 1000).toFixed(1)}秒) 超过人脸时长(${(videoDurationMs / 1000).toFixed(1)}秒)`
)
const errorMsg = `校验失败:音频时长(${(context.value.audioDurationMs / 1000).toFixed(1)}秒) 超过人脸时长(${(videoDurationMs / 1000).toFixed(1)}秒)`
setError(new Error(errorMsg))
return
}
context.value.validationPassed = true
// 到达 ready 状态
setState('ready')
} catch (err) {
// 错误已在 executeStep 中处理
} catch {
// 错误已在各步骤中处理
}
}

View File

@@ -12,7 +12,7 @@ import type {
IdentifyResult,
Video,
} from '../types/identify-face'
import { identifyUploadedVideo } from '@/api/kling'
import { identifyUploadedVideo, uploadAndIdentifyVideo } from '@/api/kling'
import { useUpload } from '@/composables/useUpload'
export function useDigitalHumanGeneration() {
@@ -90,6 +90,7 @@ export function useDigitalHumanGeneration() {
}
if (hasSelectedVideo) {
// 从素材库选择:调用识别接口
const res = await identifyUploadedVideo(hasSelectedVideo) as {
success: boolean;
data: { sessionId: string; faceId: string | null; startTime: number; endTime: number }
@@ -100,35 +101,18 @@ export function useDigitalHumanGeneration() {
identifyResult.value.faceStartTime = res.data.startTime || 0
identifyResult.value.faceEndTime = res.data.endTime || 0
} else {
// 上传新视频:使用 uploadAndIdentifyVideo 完成上传+识别
const file = hasUploadFile!
let coverBase64 = null
try {
const { extractVideoCover } = await import('@/utils/video-cover')
const cover = await extractVideoCover(file, { maxWidth: 800, quality: 0.8 })
coverBase64 = cover.base64
} catch {
// 封面提取失败不影响主流程
const res = await uploadAndIdentifyVideo(file) as {
success: boolean;
data: { fileId: string; sessionId: string; faceId: string | null; startTime: number; endTime: number }
}
const fileId = await upload(file, {
fileCategory: 'video',
groupId: null,
coverBase64,
onStart: function() {},
onProgress: function() {},
onSuccess: function() {},
onError: function(err: Error) {
message.error(err.message || '上传失败')
}
})
identifyResult.value.videoFileId = fileId
// 上传后需要再调用识别接口获取人脸信息
// 暂时清空,等待后续识别
identifyResult.value.sessionId = ''
identifyResult.value.faceId = ''
identifyResult.value.faceStartTime = 0
identifyResult.value.faceEndTime = 0
identifyResult.value.videoFileId = res.data.fileId
identifyResult.value.sessionId = res.data.sessionId
identifyResult.value.faceId = res.data.faceId || ''
identifyResult.value.faceStartTime = res.data.startTime || 0
identifyResult.value.faceEndTime = res.data.endTime || 0
}
return { ...identifyResult.value }

View File

@@ -71,7 +71,6 @@ export function useVoiceGeneration(): UseVoiceGeneration {
audioState.value.generated = audioData
audioState.value.durationMs = await parseAudioDuration(audioData.audioBase64)
message.success('配音生成成功!')
} else {
throw new Error(res.msg || '配音生成失败')
}