44dc89360a
Deploy / Build Production Runtime Images (push) Has been skipped
Deploy / Deploy Production (push) Has been skipped
Deploy / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 170h24m47s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 170h24m52s
Deploy / Deploy Staging (push) Failing after 170h27m34s
CI/CD Pipeline / Frontend Lint (push) Failing after 170h28m8s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 170h28m14s
- 新增预置音色配置(8 个 CosyVoice 真实音色) - 增强 GET /api/v1/voices 接口,支持 type 查询参数(preset/clone/all) - 新增 GET /api/v1/voices/presets 端点 - 统一响应格式,包含 preset_count 和 clone_count - 保留原有 CRUD 端点向后兼容 - 添加 18 个预置音色单元测试(全部通过) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
134 lines
3.6 KiB
Python
134 lines
3.6 KiB
Python
"""预置音色配置 — Phase 3 CosyVoice 集成.
|
||
|
||
定义系统预置的 CosyVoice 音色列表,不存数据库,以配置方式提供。
|
||
音色 ID 对应阿里云 CosyVoice 模型中的真实音色名。
|
||
|
||
参考: https://help.aliyun.com/zh/model-studio/cosyvoice-voice-list
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class PresetVoice:
|
||
"""预置音色定义。
|
||
|
||
Attributes:
|
||
voice_id: CosyVoice 模型音色名(如 longxiaochun)
|
||
name: 中文展示名
|
||
description: 音色描述
|
||
gender: 性别(male/female)
|
||
language: 语言代码(如 zh-CN)
|
||
preview_url: 预览音频 URL(可选)
|
||
tags: 标签列表
|
||
"""
|
||
|
||
voice_id: str
|
||
name: str
|
||
description: str
|
||
gender: str
|
||
language: str = "zh-CN"
|
||
preview_url: str = ""
|
||
tags: list[str] | None = None
|
||
|
||
def to_dict(self) -> dict:
|
||
"""序列化为字典。"""
|
||
return {
|
||
"voice_id": self.voice_id,
|
||
"name": self.name,
|
||
"description": self.description,
|
||
"gender": self.gender,
|
||
"language": self.language,
|
||
"preview_url": self.preview_url,
|
||
"tags": self.tags or [],
|
||
}
|
||
|
||
|
||
# 预置音色列表(阿里云 CosyVoice 真实可用音色)
|
||
PRESET_VOICES: list[PresetVoice] = [
|
||
PresetVoice(
|
||
voice_id="longxiaochun",
|
||
name="龙小淳",
|
||
description="温柔女声,适合情感类内容",
|
||
gender="female",
|
||
language="zh-CN",
|
||
tags=["温柔", "女声", "情感"],
|
||
),
|
||
PresetVoice(
|
||
voice_id="longxiaoxia",
|
||
name="龙小夏",
|
||
description="知性女声,适合新闻播报",
|
||
gender="female",
|
||
language="zh-CN",
|
||
tags=["知性", "女声", "播报"],
|
||
),
|
||
PresetVoice(
|
||
voice_id="longxiaochen",
|
||
name="龙小晨",
|
||
description="磁性男声,适合有声书",
|
||
gender="male",
|
||
language="zh-CN",
|
||
tags=["磁性", "男声", "有声书"],
|
||
),
|
||
PresetVoice(
|
||
voice_id="longyue",
|
||
name="龙悦",
|
||
description="甜美女声,适合广告配音",
|
||
gender="female",
|
||
language="zh-CN",
|
||
tags=["甜美", "女声", "广告"],
|
||
),
|
||
PresetVoice(
|
||
voice_id="longshu",
|
||
name="龙书",
|
||
description="沉稳男声,适合教育讲解",
|
||
gender="male",
|
||
language="zh-CN",
|
||
tags=["沉稳", "男声", "教育"],
|
||
),
|
||
PresetVoice(
|
||
voice_id="longjing",
|
||
name="龙静",
|
||
description="优雅女声,适合纪录片解说",
|
||
gender="female",
|
||
language="zh-CN",
|
||
tags=["优雅", "女声", "纪录片"],
|
||
),
|
||
PresetVoice(
|
||
voice_id="longbo",
|
||
name="龙博",
|
||
description="浑厚男声,适合科技类内容",
|
||
gender="male",
|
||
language="zh-CN",
|
||
tags=["浑厚", "男声", "科技"],
|
||
),
|
||
PresetVoice(
|
||
voice_id="longtian",
|
||
name="龙甜",
|
||
description="活泼女声,适合短视频配音",
|
||
gender="female",
|
||
language="zh-CN",
|
||
tags=["活泼", "女声", "短视频"],
|
||
),
|
||
]
|
||
|
||
|
||
def get_preset_voices() -> list[PresetVoice]:
|
||
"""获取所有预置音色。"""
|
||
return PRESET_VOICES
|
||
|
||
|
||
def get_preset_voice_by_id(voice_id: str) -> PresetVoice | None:
|
||
"""根据 voice_id 获取预置音色。"""
|
||
for voice in PRESET_VOICES:
|
||
if voice.voice_id == voice_id:
|
||
return voice
|
||
return None
|
||
|
||
|
||
def is_preset_voice(voice_id: str) -> bool:
|
||
"""判断是否为预置音色。"""
|
||
return get_preset_voice_by_id(voice_id) is not None
|