Files
sionrui/openspec/changes/refactor-identify-face-hooks/specs/identify-face-controller/spec.md
sion123 36195ea55a 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>
2025-12-28 00:19:17 +08:00

111 lines
4.4 KiB
Markdown
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.
## ADDED Requirements
### Requirement: useVoiceGeneration Hook
系统 SHALL 提供 `useVoiceGeneration` Hook封装所有语音生成相关逻辑。
#### Scenario: 初始化语音生成状态
- **GIVEN** 组件挂载时调用 useVoiceGeneration
- **THEN** 返回响应式状态ttsText(空字符串)、speechRate(1.0)、selectedVoiceMeta(null)、audioState(初始状态)
#### Scenario: 生成配音
- **GIVEN** 用户点击生成配音按钮且 canGenerateAudio 为 true
- **WHEN** 调用 generateAudio 方法
- **THEN** 执行以下流程:
1. 调用 VoiceService.synthesize 生成音频
2. 解析音频时长
3. 验证音频与人脸区间重合度
4. 更新 audioState.generated 和 audioState.durationMs
5. 返回成功或失败结果
#### Scenario: 音频时长校验
- **GIVEN** 音频生成完成且有人脸识别数据
- **WHEN** 调用 validateAudioDuration
- **THEN** 计算音频与人脸区间的重合时长
- **AND** 如果重合时长 >= 2000ms设置 audioState.validationPassed = true
- **ELSE** 设置 audioState.validationPassed = false 并显示警告消息
### Requirement: useDigitalHumanGeneration Hook
系统 SHALL 提供 `useDigitalHumanGeneration` Hook封装所有数字人生成相关逻辑。
#### Scenario: 处理视频文件上传
- **GIVEN** 用户上传视频文件MP4或MOV格式
- **WHEN** 调用 handleFileUpload 方法
- **THEN** 执行以下流程:
1. 验证文件格式
2. 创建视频预览 URL
3. 重置识别状态
4. 调用 performFaceRecognition 进行人脸识别
5. 更新 videoState 和 identifyState
#### Scenario: 从素材库选择视频
- **GIVEN** 用户点击"从素材库选择"选项
- **WHEN** 选择视频并调用 handleVideoSelect
- **THEN** 执行以下流程:
1. 设置 selectedVideo 到 videoState
2. 重置识别状态
3. 设置 videoFileId
4. 更新 materialValidation.videoDuration
5. 触发人脸识别
#### Scenario: 人脸识别
- **GIVEN** 有视频文件或已选择视频
- **WHEN** 调用 performFaceRecognition
- **THEN** 根据视频来源调用对应API
- 如果是上传文件:调用 uploadAndIdentifyVideo
- 如果是素材库:调用 identifyUploadedVideo
- **AND** 更新 identifyStatesessionId、faceId、faceStartTime、faceEndTime
- **AND** 设置 identifyState.identified = true
#### Scenario: 素材时长校验
- **GIVEN** 有视频时长和音频时长数据
- **WHEN** 调用 validateMaterialDuration(videoDurationMs, audioDurationMs)
- **THEN** 检查 videoDurationMs > audioDurationMs
- **AND** 更新 materialValidationvideoDuration、audioDuration、isValid
### Requirement: useIdentifyFaceController Hook
系统 SHALL 提供 `useIdentifyFaceController` Hook协调语音生成和数字人生成逻辑。
#### Scenario: 生成数字人视频
- **GIVEN** 所有必需数据已准备(文案、音色、视频、配音校验通过)
- **WHEN** 调用 generateDigitalHuman 方法
- **THEN** 执行以下流程:
1. 检查 canGenerate 为 true
2. 如果未识别,先执行人脸识别
3. 构建任务数据taskName、videoFileId、文本、语音参数等
4. 如果有预生成音频,添加到 pre_generated_audio 字段
5. 调用 createLipSyncTask 提交任务
6. 返回成功或失败结果
#### Scenario: 确保配音校验顺序
- **GIVEN** 用户尝试生成数字人视频
- **WHEN** 还未生成配音或校验未通过
- **THEN** 阻止生成并提示用户先完成配音生成和校验
#### Scenario: 更换视频
- **GIVEN** 用户点击更换视频按钮
- **WHEN** 调用 replaceVideo 方法
- **THEN** 重置所有相关状态:
- videoState清空上传文件和选中视频
- identifyState重置识别结果
- materialValidation重置校验结果
- audioState重置音频状态
## MODIFIED Requirements
### Requirement: IdentifyFace.vue 组件重构
原始的 monolithic 组件 MUST 被重构为使用 hooks 的轻量级视图层。
#### Scenario: 视图层职责
- **WHEN** IdentifyFace.vue 渲染时
- **THEN** 只负责:
1. UI 模板渲染(接收 hooks 返回的数据和状态)
2. 事件绑定(将用户操作转发给 hooks 的方法)
3. 计算属性显示(使用 hooks 提供的 computed 值)
- **AND** 不直接包含业务逻辑(全部委托给 hooks
#### Scenario: 响应式数据绑定
- **GIVEN** hooks 提供的响应式状态
- **WHEN** 组件渲染时
- **THEN** 通过 v-model 和响应式引用直接绑定到 UI 控件
- **AND** 状态变化自动触发 UI 更新