Files
xiaoxia-saas/packages/domain/tts_config.py
T
xiaoxia 09d2b12ea8
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 57s
CI/CD Pipeline / Validate Code Quality And Tests (push) Successful in 3m7s
CI/CD Pipeline / Unit Tests (push) Successful in 3m13s
CI/CD Pipeline / Integration Tests (push) Successful in 1m22s
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m32s
CI Build & Deploy Pipeline / Build Staging API Image (push) Successful in 18m38s
CI Build & Deploy Pipeline / Build Staging Web Image (push) Successful in 19s
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Successful in 8m7s
CI Build & Deploy Pipeline / Build Production API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (push) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (push) Has been skipped
CI Build & Deploy Pipeline / Staging E2E Tests (push) Successful in 2m16s
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Successful in 4m35s
feat(ci): P1-1 Phase2 后端启用F401+F841并修复存量 (#470)
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-07-17 14:06:50 +08:00

103 lines
2.8 KiB
Python
Executable File

"""TTS 配音配置模型."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Optional
@dataclass(slots=True)
class TtsConfig:
"""TTS 配音配置.
Attributes:
enabled: 是否启用配音
voice_id: 音色 ID
speed: 语速 (0.5 ~ 2.0)
pitch: 语调 (-12 ~ 12 半音)
volume: 音量 (0.0 ~ 1.0)
text: 配音文本(整段配音时使用)
align_mode: 对齐模式 - "subtitle"=按字幕对齐 / "full"=整段配音
overlap_mode: 与原音的叠加模式 - "replace"=替换 / "mix"=混音
"""
enabled: bool = False
voice_id: str = ""
speed: float = 1.0
pitch: float = 0.0
volume: float = 0.8
text: str = ""
align_mode: str = "full" # subtitle / full
overlap_mode: str = "replace" # replace / mix
@classmethod
def parse(cls, data: Optional[dict[str, Any]]) -> "TtsConfig":
"""从 dict 解析配置,无效值回退到默认."""
if not data or not isinstance(data, dict):
return cls()
enabled = data.get("enabled", False)
if not isinstance(enabled, bool):
enabled = False
if not enabled:
return cls(enabled=False)
voice_id = data.get("voice_id", "")
if not isinstance(voice_id, str):
voice_id = ""
speed = data.get("speed", 1.0)
if not isinstance(speed, (int, float)):
speed = 1.0
pitch = data.get("pitch", 0.0)
if not isinstance(pitch, (int, float)):
pitch = 0.0
volume = data.get("volume", 0.8)
if not isinstance(volume, (int, float)):
volume = 0.8
text = data.get("text", "")
if not isinstance(text, str):
text = ""
align_mode = data.get("align_mode", "full")
if align_mode not in ("subtitle", "full"):
align_mode = "full"
overlap_mode = data.get("overlap_mode", "replace")
if overlap_mode not in ("replace", "mix"):
overlap_mode = "replace"
config = cls(
enabled=enabled,
voice_id=voice_id,
speed=float(speed),
pitch=float(pitch),
volume=float(volume),
text=text,
align_mode=align_mode,
overlap_mode=overlap_mode,
)
config._clamp()
return config
def _clamp(self) -> None:
"""边界钳制."""
if self.speed < 0.5:
self.speed = 0.5
elif self.speed > 2.0:
self.speed = 2.0
if self.pitch < -12:
self.pitch = -12
elif self.pitch > 12:
self.pitch = 12
if self.volume < 0.0:
self.volume = 0.0
elif self.volume > 1.0:
self.volume = 1.0