Compare commits

...

3 Commits

Author SHA1 Message Date
CI Bot 3e3f7175d8 style: auto-format with black + isort + prettier [skip ci-format-check] 2026-07-28 08:30:41 +00:00
xiaoxia 4750e67c55 chore: retrigger CI
CI/CD Pipeline / Staging E2E Tests (pull_request) Blocked by required conditions
CI/CD Pipeline / Staging API Integration Tests (pull_request) Blocked by required conditions
CI/CD Pipeline / Deploy Production (pull_request) Blocked by required conditions
CI/CD Pipeline / Production Browser E2E (pull_request) Blocked by required conditions
CI/CD Pipeline / ACR Image Cleanup (pull_request) Blocked by required conditions
CI/CD Pipeline / Canary Release to Production (pull_request) Blocked by required conditions
Preview Cleanup / Cleanup Preview Environment (pull_request) Waiting to run
ACR Cleanup / ACR Image Cleanup (pull_request_target) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 39s
CI/CD Pipeline / Unit Tests (pull_request) Waiting to run
CI/CD Pipeline / Frontend Unit Tests (pull_request) Waiting to run
CI/CD Pipeline / Build Production API Image (pull_request) Waiting to run
CI/CD Pipeline / Build Production Web Image (pull_request) Waiting to run
CI/CD Pipeline / Build Production Worker Image (pull_request) Waiting to run
CI/CD Pipeline / CI Gate (pull_request) Blocked by required conditions
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 50s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m10s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Waiting to run
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m9s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 3m31s
CI/CD Pipeline / Integration Tests (pull_request) Waiting to run
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m57s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m18s
PR Automation / Auto Approve on CI Green (pull_request) Failing after 1m14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 59s
AI Code Review / AI Code Review (pull_request) Successful in 4m1s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 7m34s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 46m18s
2026-07-28 16:06:04 +08:00
xiaoxia aa36e7ae62 refactor(generate): 拆分useStep5Voice模式选择逻辑到子Hook(184→165行, -10%) 2026-07-28 16:06:04 +08:00
6 changed files with 94 additions and 47 deletions
@@ -0,0 +1,70 @@
import { useCallback } from "react"
import type { VoiceClone } from "@/api/voice-clone"
interface UseVoiceModeSelectionOptions {
selectedVoice: string
onSelectedVoiceChange: (voiceId: string) => void
voiceMode: "preset" | "custom" | "clone"
onVoiceModeChange: (mode: "preset" | "custom" | "clone") => void
selectedClonedVoice: string
onSelectedClonedVoiceChange: (voiceId: string) => void
addClone: (voice: VoiceClone) => void
cloneModalOpen: boolean
onCloneModalOpenChange: (open: boolean) => void
}
export function useVoiceModeSelection({
onSelectedVoiceChange,
onVoiceModeChange,
onSelectedClonedVoiceChange,
addClone,
onCloneModalOpenChange,
}: UseVoiceModeSelectionOptions) {
const handleSelectRecommendedVoice = useCallback(
(voiceId: string) => {
onVoiceModeChange("preset")
onSelectedVoiceChange(voiceId)
},
[onVoiceModeChange, onSelectedVoiceChange],
)
const handleSelectPresetVoice = useCallback(
(voiceId: string) => {
onVoiceModeChange("preset")
onSelectedVoiceChange(voiceId)
},
[onVoiceModeChange, onSelectedVoiceChange],
)
const handleSelectCloneVoice = useCallback(() => {
onVoiceModeChange("clone")
}, [onVoiceModeChange])
const handleSelectClonedVoice = useCallback(
(voiceId: string) => {
onSelectedClonedVoiceChange(voiceId)
},
[onSelectedClonedVoiceChange],
)
const handleOpenCloneModal = useCallback(() => {
onCloneModalOpenChange(true)
}, [onCloneModalOpenChange])
const handleCloneSuccess = useCallback(
(voice: VoiceClone) => {
addClone(voice)
onCloneModalOpenChange(false)
},
[addClone, onCloneModalOpenChange],
)
return {
handleSelectRecommendedVoice,
handleSelectPresetVoice,
handleSelectCloneVoice,
handleSelectClonedVoice,
handleOpenCloneModal,
handleCloneSuccess,
}
}
+24 -43
View File
@@ -2,15 +2,15 @@
* Step 5 配音选择 Hook
* 封装 AI 推荐、预设音色试听、TTS 自定义合成、存为素材等逻辑
*/
import { useCallback } from "react"
import type { VoiceClone } from "@/api/voice-clone"
import { message } from "antd"
import type { VoiceClone } from "@/api/voice-clone"
import { VOICE_GENDER_ICON, CLONE_STATUS_CONFIG } from "../constants"
import { formatDuration } from "../utils/formatDuration"
import { useVoiceAudio } from "./step5-voice/useVoiceAudio"
import { useVoiceRecommend } from "./step5-voice/useVoiceRecommend"
import { useTtsSynthesis } from "./step5-voice/useTtsSynthesis"
import { useSaveToLibrary } from "./step5-voice/useSaveToLibrary"
import { useVoiceModeSelection } from "./step5-voice/useVoiceModeSelection"
interface UseStep5VoiceProps {
selectedVoice: string
@@ -81,48 +81,29 @@ export function useStep5Voice({
handleAddTagInModal,
} = useSaveToLibrary(completedTtsJobId, resetTtsState)
/* ── 推荐音色选择 ── */
const handleSelectRecommendedVoice = useCallback(
(voiceId: string) => {
onVoiceModeChange("preset")
onSelectedVoiceChange(voiceId)
},
[onVoiceModeChange, onSelectedVoiceChange],
)
const {
handleSelectRecommendedVoice,
handleSelectPresetVoice,
handleSelectCloneVoice,
handleSelectClonedVoice,
handleOpenCloneModal,
handleCloneSuccess: rawCloneSuccess,
} = useVoiceModeSelection({
selectedVoice,
onSelectedVoiceChange,
voiceMode,
onVoiceModeChange,
selectedClonedVoice,
onSelectedClonedVoiceChange,
addClone,
cloneModalOpen,
onCloneModalOpenChange,
})
/* ── 克隆成功回调 ── */
const handleCloneSuccess = useCallback(
(voice: VoiceClone) => {
addClone(voice)
onCloneModalOpenChange(false)
message.success("音色克隆成功!")
},
[addClone, onCloneModalOpenChange],
)
/* ── 预设音色选择操作 ── */
const handleSelectPresetVoice = useCallback(
(voiceId: string) => {
onVoiceModeChange("preset")
onSelectedVoiceChange(voiceId)
},
[onVoiceModeChange, onSelectedVoiceChange],
)
const handleSelectCloneVoice = useCallback(() => {
onVoiceModeChange("clone")
}, [onVoiceModeChange])
const handleSelectClonedVoice = useCallback(
(voiceId: string) => {
onSelectedClonedVoiceChange(voiceId)
},
[onSelectedClonedVoiceChange],
)
const handleOpenCloneModal = useCallback(() => {
onCloneModalOpenChange(true)
}, [onCloneModalOpenChange])
const handleCloneSuccess = (voice: VoiceClone) => {
rawCloneSuccess(voice)
message.success("音色克隆成功!")
}
return {
// 数据
@@ -6,7 +6,6 @@
from __future__ import annotations
# ── 单轨时间计算 ──────────────────────────────────────────────────────────────
@@ -13,7 +13,6 @@
from __future__ import annotations
from packages.domain.speed_config import (
DEFAULT_SPEED,
SpeedConfig,
@@ -6,7 +6,6 @@ domain 层纯逻辑模块,0 FFmpeg 依赖,快速轻量。
from __future__ import annotations
import dataclasses
from unittest.mock import MagicMock
import pytest
-1
View File
@@ -4,7 +4,6 @@ from __future__ import annotations
import dataclasses
import pytest
from packages.domain.transition_presets import (