别再只用默认语音了!Python edge-tts库隐藏玩法:用代码批量试听并导出所有声音模型
·
解锁edge-tts隐藏技能:Python自动化批量试听与声音模型管理指南
当面对edge-tts提供的上百种声音模型时,手动一个个试听和记录效果无疑是效率极低的做法。本文将介绍如何用Python编写自动化脚本,快速遍历所有语音模型,生成音频样本并智能分类存储,帮助开发者高效找到最适合项目的声音。
1. 环境准备与基础配置
在开始之前,我们需要确保开发环境已经正确配置。edge-tts是微软Edge浏览器文本转语音服务的Python接口,支持多种语言和声音模型。
首先安装必要的库:
pip install edge-tts
pip install pydub # 用于音频处理
创建一个新的Python文件,导入所需模块:
import asyncio
import os
from edge_tts import VoicesManager, Communicate
from pydub import AudioSegment
设置基础配置参数:
SAMPLE_TEXT = "欢迎使用edge-tts语音合成服务,这是一段测试文本。" # 用于生成语音样本的文本
OUTPUT_DIR = "voice_samples" # 输出目录
os.makedirs(OUTPUT_DIR, exist_ok=True) # 确保输出目录存在
2. 获取并分析可用声音模型
edge-tts提供了丰富的语音模型,我们需要先获取完整的列表并进行分析。
async def get_voice_list():
voices = await VoicesManager.create()
return voices.voices
def analyze_voices(voice_list):
languages = set()
genders = set()
for voice in voice_list:
languages.add(voice['Locale'])
genders.add(voice['Gender'])
print(f"发现 {len(voice_list)} 种声音模型")
print(f"支持语言: {len(languages)} 种")
print(f"性别分布: {', '.join(genders)}")
运行分析:
async def main():
voice_list = await get_voice_list()
analyze_voices(voice_list)
if __name__ == "__main__":
asyncio.run(main())
这段代码会输出类似以下信息:
发现 328 种声音模型
支持语言: 50 种
性别分布: Male, Female
3. 批量生成语音样本
现在我们来编写核心功能:批量生成所有声音模型的语音样本。
async def generate_sample(voice, text, output_dir):
try:
output_path = os.path.join(
output_dir,
f"{voice['Locale']}_{voice['ShortName']}.mp3"
)
communicate = Communicate(text, voice['Name'])
await communicate.save(output_path)
# 标准化音频格式和音量
audio = AudioSegment.from_mp3(output_path)
audio = audio.normalize()
audio.export(output_path, format="mp3")
return True
except Exception as e:
print(f"生成 {voice['Name']} 样本失败: {str(e)}")
return False
async def batch_generate_samples(voice_list, text, output_dir):
success_count = 0
for voice in voice_list:
if await generate_sample(voice, text, output_dir):
success_count += 1
print(f"成功生成 {success_count}/{len(voice_list)} 个语音样本")
调用方法:
async def main():
voice_list = await get_voice_list()
await batch_generate_samples(voice_list, SAMPLE_TEXT, OUTPUT_DIR)
4. 智能分类与快速检索
生成大量样本后,我们需要一个有效的分类和检索系统。
首先创建分类目录结构:
def create_category_dirs(output_dir):
# 按语言创建主目录
voice_list = asyncio.run(get_voice_list())
languages = {voice['Locale'] for voice in voice_list}
for lang in languages:
lang_dir = os.path.join(output_dir, lang)
os.makedirs(lang_dir, exist_ok=True)
# 在每个语言目录下创建性别子目录
for gender in ['Male', 'Female']:
gender_dir = os.path.join(lang_dir, gender)
os.makedirs(gender_dir, exist_ok=True)
然后移动文件到对应目录:
def organize_samples(output_dir):
for filename in os.listdir(output_dir):
if filename.endswith('.mp3'):
parts = filename.split('_')
if len(parts) >= 2:
lang = parts[0]
gender = 'Male' if 'Neural' in parts[1] else 'Female' # 简化判断
src = os.path.join(output_dir, filename)
dest_dir = os.path.join(output_dir, lang, gender)
dest = os.path.join(dest_dir, filename)
os.rename(src, dest)
为了方便检索,我们可以创建一个索引文件:
def create_index_file(output_dir):
index = []
voice_list = asyncio.run(get_voice_list())
for voice in voice_list:
lang = voice['Locale']
gender = voice['Gender']
name = voice['ShortName']
filepath = os.path.join(lang, gender, f"{lang}_{name}.mp3")
index.append({
'name': name,
'language': lang,
'gender': gender,
'filepath': filepath
})
with open(os.path.join(output_dir, 'index.json'), 'w') as f:
json.dump(index, f, indent=2)
5. 高级功能扩展
基础功能完成后,我们可以添加一些高级功能来提升用户体验。
5.1 语音特征分析
def analyze_voice_characteristics(filepath):
audio = AudioSegment.from_file(filepath)
return {
'duration_ms': len(audio),
'sample_rate': audio.frame_rate,
'channels': audio.channels,
'max_dBFS': audio.max_dBFS,
'rms_dBFS': audio.dBFS
}
5.2 批量重命名与元数据写入
def add_metadata_to_files(output_dir):
for root, _, files in os.walk(output_dir):
for file in files:
if file.endswith('.mp3'):
filepath = os.path.join(root, file)
audio = AudioSegment.from_file(filepath)
# 提取基本信息
parts = file.split('_')
lang = parts[0]
name = parts[1].replace('.mp3', '')
# 添加ID3标签
audio.export(
filepath,
format='mp3',
tags={
'title': f"{name} Sample",
'artist': "edge-tts",
'album': f"{lang} Voices",
'language': lang
}
)
5.3 创建HTML预览页面
def generate_html_preview(output_dir):
with open(os.path.join(output_dir, 'index.json')) as f:
index = json.load(f)
html = """
<!DOCTYPE html>
<html>
<head>
<title>edge-tts Voice Samples</title>
<style>
table { width: 100%; border-collapse: collapse; }
th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
audio { width: 200px; }
</style>
</head>
<body>
<h1>edge-tts Voice Samples</h1>
<table>
<tr>
<th>Language</th>
<th>Gender</th>
<th>Name</th>
<th>Sample</th>
</tr>
"""
for item in index:
html += f"""
<tr>
<td>{item['language']}</td>
<td>{item['gender']}</td>
<td>{item['name']}</td>
<td>
<audio controls>
<source src="{item['filepath']}" type="audio/mpeg">
</audio>
</td>
</tr>
"""
html += """
</table>
</body>
</html>
"""
with open(os.path.join(output_dir, 'preview.html'), 'w') as f:
f.write(html)
6. 性能优化与错误处理
当处理大量语音模型时,性能和稳定性变得尤为重要。
6.1 异步并发处理
async def generate_samples_concurrently(voice_list, text, output_dir, max_concurrent=5):
semaphore = asyncio.Semaphore(max_concurrent)
async def limited_generate(voice):
async with semaphore:
return await generate_sample(voice, text, output_dir)
tasks = [limited_generate(voice) for voice in voice_list]
results = await asyncio.gather(*tasks)
success_count = sum(1 for r in results if r)
print(f"成功生成 {success_count}/{len(voice_list)} 个语音样本")
6.2 断点续传功能
def get_existing_samples(output_dir):
existing = set()
for root, _, files in os.walk(output_dir):
for file in files:
if file.endswith('.mp3'):
parts = file.split('_')
if len(parts) >= 2:
voice_name = f"{parts[0]}_{parts[1].replace('.mp3', '')}"
existing.add(voice_name)
return existing
async def batch_generate_with_resume(voice_list, text, output_dir):
existing = get_existing_samples(output_dir)
todo = []
for voice in voice_list:
voice_id = f"{voice['Locale']}_{voice['ShortName']}"
if voice_id not in existing:
todo.append(voice)
print(f"发现 {len(existing)} 个已存在样本,需要生成 {len(todo)} 个新样本")
await batch_generate_samples(todo, text, output_dir)
6.3 错误日志记录
def setup_logging():
logging.basicConfig(
filename='voice_generation.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
async def generate_sample_with_logging(voice, text, output_dir):
try:
success = await generate_sample(voice, text, output_dir)
if success:
logging.info(f"成功生成 {voice['Name']} 样本")
else:
logging.warning(f"生成 {voice['Name']} 样本失败")
return success
except Exception as e:
logging.error(f"生成 {voice['Name']} 样本时出错: {str(e)}")
return False
7. 实际应用案例
让我们看几个实际应用场景,展示如何利用这些脚本解决具体问题。
7.1 多语言项目语音选择
假设你正在开发一个支持多语言的应用程序,需要为每种语言选择最合适的语音。
async def find_best_voice_for_language(language_code):
voice_list = await get_voice_list()
candidates = [v for v in voice_list if v['Locale'] == language_code]
if not candidates:
print(f"没有找到 {language_code} 语言的语音模型")
return None
# 生成所有候选语音的样本
samples_dir = os.path.join(OUTPUT_DIR, language_code)
os.makedirs(samples_dir, exist_ok=True)
await batch_generate_samples(candidates, SAMPLE_TEXT, samples_dir)
print(f"已生成 {len(candidates)} 个 {language_code} 语音样本,请查看 {samples_dir} 目录")
return candidates
7.2 语音效果对比工具
创建一个工具来对比不同语音朗读同一段文本的效果。
def create_comparison_page(language_code, output_dir):
voice_list = asyncio.run(get_voice_list())
voices = [v for v in voice_list if v['Locale'] == language_code]
if not voices:
print(f"没有找到 {language_code} 语言的语音模型")
return
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>{language_code} Voice Comparison</title>
<style>
.voice-card {{
border: 1px solid #ddd;
padding: 15px;
margin: 10px;
border-radius: 5px;
display: inline-block;
width: 300px;
}}
audio {{ width: 100%; }}
</style>
</head>
<body>
<h1>{language_code} Voice Comparison</h1>
"""
for voice in voices:
filename = f"{voice['Locale']}_{voice['ShortName']}.mp3"
filepath = os.path.join(output_dir, filename)
if os.path.exists(filepath):
html += f"""
<div class="voice-card">
<h3>{voice['ShortName']} ({voice['Gender']})</h3>
<audio controls>
<source src="{filename}" type="audio/mpeg">
</audio>
</div>
"""
html += """
</body>
</html>
"""
output_file = os.path.join(output_dir, f"{language_code}_comparison.html")
with open(output_file, 'w') as f:
f.write(html)
print(f"已创建对比页面: {output_file}")
7.3 自动化测试集成
将语音生成集成到自动化测试流程中,确保语音合成服务正常工作。
async def test_voice_quality(voice, text, output_dir):
try:
output_path = os.path.join(output_dir, f"test_{voice['ShortName']}.mp3")
communicate = Communicate(text, voice['Name'])
await communicate.save(output_path)
# 检查生成的音频文件
audio = AudioSegment.from_file(output_path)
if len(audio) < 1000: # 假设至少1秒
raise ValueError("生成的音频过短")
return True
except Exception as e:
print(f"测试 {voice['Name']} 失败: {str(e)}")
return False
async def run_voice_quality_tests():
voice_list = await get_voice_list()
test_dir = os.path.join(OUTPUT_DIR, "tests")
os.makedirs(test_dir, exist_ok=True)
test_text = "This is a quality test sample for edge-tts voice synthesis."
results = []
for voice in voice_list[:10]: # 测试前10个样本
success = await test_voice_quality(voice, test_text, test_dir)
results.append((voice['Name'], success))
print("\n测试结果:")
for name, success in results:
status = "通过" if success else "失败"
print(f"{name}: {status}")
return results
更多推荐

所有评论(0)