| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- """
- 系统音色初始化脚本
- 初始化系统预置音色数据到数据库。
- 注意:此脚本用于初始化数据库,系统运行时所有音色数据均从数据库获取,不包含硬编码。
- 数据来源说明:
- - 当前版本:基于阿里云百炼平台CosyVoice模型的官方音色文档手动整理
- - 未来版本:如果DashScope SDK提供获取系统音色的API,可改为从SDK同步
- 需求: 4.1
- """
- import sys
- from pathlib import Path
- # 添加项目根目录到路径
- sys.path.insert(0, str(Path(__file__).parent.parent))
- from app.database import SessionLocal
- from app.models.audio import SystemVoice
- # 系统预置音色数据
- # 注意:此数据仅用于初始化数据库,系统运行时所有音色均从数据库获取
- # 基于阿里云百炼平台CosyVoice模型的官方音色文档整理
- # 如果DashScope SDK未来提供获取系统音色的API,可改为从SDK动态获取
- SYSTEM_VOICES = [
- # ==================== 社交陪伴类 ====================
- {
- "voice_id": "longanyang",
- "name": "龙安洋",
- "trait": "阳光大男孩",
- "age": "20~30岁",
- "category": "社交陪伴",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longanhuan",
- "name": "龙安欢",
- "trait": "欢脱元气女",
- "age": "20~30岁",
- "category": "社交陪伴",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longanjing",
- "name": "龙安静",
- "trait": "温柔知性女",
- "age": "20~30岁",
- "category": "社交陪伴",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longanshu",
- "name": "龙安舒",
- "trait": "成熟稳重男",
- "age": "30~40岁",
- "category": "社交陪伴",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- # ==================== 客服类 ====================
- {
- "voice_id": "longxiaoxia",
- "name": "龙小夏",
- "trait": "甜美客服女声",
- "age": "20~30岁",
- "category": "客服",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longlaotie",
- "name": "龙老铁",
- "trait": "亲切客服男声",
- "age": "30~40岁",
- "category": "客服",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
-
- # ==================== 新闻播报类 ====================
- {
- "voice_id": "longshuo",
- "name": "龙硕",
- "trait": "专业新闻男声",
- "age": "30~40岁",
- "category": "新闻播报",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longwan",
- "name": "龙婉",
- "trait": "专业新闻女声",
- "age": "30~40岁",
- "category": "新闻播报",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
-
- # ==================== 有声书类 ====================
- {
- "voice_id": "longyue",
- "name": "龙悦",
- "trait": "温暖讲述女声",
- "age": "30~40岁",
- "category": "有声书",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longcheng",
- "name": "龙城",
- "trait": "磁性讲述男声",
- "age": "30~40岁",
- "category": "有声书",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longshu",
- "name": "龙书",
- "trait": "儿童故事女声",
- "age": "20~30岁",
- "category": "有声书",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- # ==================== 短视频配音类 ====================
- {
- "voice_id": "longxiaochun",
- "name": "龙小淳",
- "trait": "活泼解说女声",
- "age": "20~30岁",
- "category": "短视频配音",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longxiaobai",
- "name": "龙小白",
- "trait": "幽默解说男声",
- "age": "20~30岁",
- "category": "短视频配音",
- "languages": ["中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
-
- # ==================== 多语言类 ====================
- {
- "voice_id": "longjielidou",
- "name": "龙杰力豆",
- "trait": "英语男声",
- "age": "30~40岁",
- "category": "多语言",
- "languages": ["英文", "中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longmeimei",
- "name": "龙美美",
- "trait": "英语女声",
- "age": "20~30岁",
- "category": "多语言",
- "languages": ["英文", "中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longyuuko",
- "name": "龙优子",
- "trait": "日语女声",
- "age": "20~30岁",
- "category": "多语言",
- "languages": ["日文", "中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longtaro",
- "name": "龙太郎",
- "trait": "日语男声",
- "age": "30~40岁",
- "category": "多语言",
- "languages": ["日文", "中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longmina",
- "name": "龙美娜",
- "trait": "韩语女声",
- "age": "20~30岁",
- "category": "多语言",
- "languages": ["韩文", "中文(普通话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- # ==================== 方言类 ====================
- {
- "voice_id": "longdongbei",
- "name": "龙东北",
- "trait": "东北话男声",
- "age": "30~40岁",
- "category": "方言",
- "languages": ["中文(东北话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longsichuan",
- "name": "龙四川",
- "trait": "四川话男声",
- "age": "30~40岁",
- "category": "方言",
- "languages": ["中文(四川话)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longminnan",
- "name": "龙闽南",
- "trait": "闽南语女声",
- "age": "30~40岁",
- "category": "方言",
- "languages": ["中文(闽南语)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
- {
- "voice_id": "longyueyu",
- "name": "龙粤语",
- "trait": "粤语男声",
- "age": "30~40岁",
- "category": "方言",
- "languages": ["中文(粤语)"],
- "models": ["cosyvoice-v3-flash", "cosyvoice-v3-plus"],
- "ssml_support": True,
- "instruct_support": True,
- "timestamp_support": True
- },
-
- # ==================== CosyVoice-v2 专用音色 ====================
- {
- "voice_id": "longxiaochun_v2",
- "name": "龙小淳V2",
- "trait": "活泼解说女声",
- "age": "20~30岁",
- "category": "通用",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v2"],
- "ssml_support": True,
- "instruct_support": False,
- "timestamp_support": True
- },
- {
- "voice_id": "longxiaoxia_v2",
- "name": "龙小夏V2",
- "trait": "甜美客服女声",
- "age": "20~30岁",
- "category": "通用",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v2"],
- "ssml_support": True,
- "instruct_support": False,
- "timestamp_support": True
- },
- {
- "voice_id": "longlaotie_v2",
- "name": "龙老铁V2",
- "trait": "亲切客服男声",
- "age": "30~40岁",
- "category": "通用",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v2"],
- "ssml_support": True,
- "instruct_support": False,
- "timestamp_support": True
- },
- {
- "voice_id": "longshuo_v2",
- "name": "龙硕V2",
- "trait": "专业新闻男声",
- "age": "30~40岁",
- "category": "通用",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v2"],
- "ssml_support": True,
- "instruct_support": False,
- "timestamp_support": True
- },
- {
- "voice_id": "longwan_v2",
- "name": "龙婉V2",
- "trait": "专业新闻女声",
- "age": "30~40岁",
- "category": "通用",
- "languages": ["中文(普通话)", "英文"],
- "models": ["cosyvoice-v2"],
- "ssml_support": True,
- "instruct_support": False,
- "timestamp_support": True
- },
- ]
- def init_system_voices():
- """初始化系统音色数据"""
- db = SessionLocal()
- inserted = 0
- updated = 0
-
- try:
- for voice_data in SYSTEM_VOICES:
- # 检查是否已存在
- existing = db.query(SystemVoice).filter(
- SystemVoice.voice_id == voice_data["voice_id"]
- ).first()
-
- if existing:
- # 更新现有记录
- existing.name = voice_data["name"]
- existing.trait = voice_data["trait"]
- existing.age = voice_data["age"]
- existing.category = voice_data["category"]
- existing.languages = voice_data["languages"]
- existing.models = voice_data["models"]
- existing.ssml_support = voice_data["ssml_support"]
- existing.instruct_support = voice_data["instruct_support"]
- existing.timestamp_support = voice_data.get("timestamp_support", False)
- existing.is_active = True
- updated += 1
- else:
- # 创建新记录
- voice = SystemVoice(
- voice_id=voice_data["voice_id"],
- name=voice_data["name"],
- trait=voice_data["trait"],
- age=voice_data["age"],
- category=voice_data["category"],
- languages=voice_data["languages"],
- models=voice_data["models"],
- ssml_support=voice_data["ssml_support"],
- instruct_support=voice_data["instruct_support"],
- timestamp_support=voice_data.get("timestamp_support", False),
- is_active=True
- )
- db.add(voice)
- inserted += 1
-
- db.commit()
- print(f"系统音色初始化完成: 新增 {inserted} 条, 更新 {updated} 条, 共 {inserted + updated} 条")
-
- except Exception as e:
- db.rollback()
- print(f"系统音色初始化失败: {e}")
- raise
- finally:
- db.close()
- def list_system_voices():
- """列出所有系统音色"""
- db = SessionLocal()
- try:
- voices = db.query(SystemVoice).filter(SystemVoice.is_active == True).all()
- print(f"\n当前系统音色列表 (共 {len(voices)} 个):")
- print("-" * 80)
-
- # 按分类分组显示
- categories = {}
- for voice in voices:
- cat = voice.category or "未分类"
- if cat not in categories:
- categories[cat] = []
- categories[cat].append(voice)
-
- for category, voice_list in sorted(categories.items()):
- print(f"\n【{category}】")
- for voice in voice_list:
- models_str = ", ".join(voice.models) if voice.models else "无"
- print(f" - {voice.voice_id}: {voice.name} ({voice.trait}) - 模型: {models_str}")
-
- print("-" * 80)
- finally:
- db.close()
- def clear_system_voices():
- """清空所有系统音色(谨慎使用)"""
- db = SessionLocal()
- try:
- count = db.query(SystemVoice).delete()
- db.commit()
- print(f"已清空 {count} 条系统音色记录")
- except Exception as e:
- db.rollback()
- print(f"清空失败: {e}")
- raise
- finally:
- db.close()
- if __name__ == "__main__":
- import argparse
-
- parser = argparse.ArgumentParser(description="系统音色管理脚本")
- parser.add_argument(
- "action",
- choices=["init", "list", "clear"],
- nargs="?",
- default="init",
- help="操作类型: init(初始化), list(列表), clear(清空)"
- )
-
- args = parser.parse_args()
-
- if args.action == "init":
- init_system_voices()
- elif args.action == "list":
- list_system_voices()
- elif args.action == "clear":
- confirm = input("确定要清空所有系统音色吗?(yes/no): ")
- if confirm.lower() == "yes":
- clear_system_voices()
- else:
- print("操作已取消")
|