Initial commit for TTS project
This commit is contained in:
153
scripts/generate_podcast_voxcpm.py
Normal file
153
scripts/generate_podcast_voxcpm.py
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
播客对话生成脚本 (使用VoxCPM)
|
||||
生成Sonia和Author的对话,不使用Judy
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# 尝试导入VoxCPM
|
||||
try:
|
||||
from systems.voxcpm.voxcpm import VoxCPM
|
||||
VOXCPM_AVAILABLE = True
|
||||
except ImportError:
|
||||
VOXCPM_AVAILABLE = False
|
||||
print("警告: VoxCPM不可用,将使用模拟生成")
|
||||
|
||||
class PodcastGeneratorWithVoxCPM:
|
||||
def __init__(self):
|
||||
# 加载角色配置
|
||||
config_path = "output/podcast/characters/character_config.json"
|
||||
if os.path.exists(config_path):
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
self.config = json.load(f)
|
||||
else:
|
||||
# 如果配置文件不存在,使用默认配置
|
||||
self.config = {
|
||||
"Sonia": {"voice_model": "en-GB-RyanNeural"},
|
||||
"Author": {"voice_model": "en-US-GuyNeural"}
|
||||
}
|
||||
|
||||
# 尝试初始化VoxCPM
|
||||
self.model = None
|
||||
if VOXCPM_AVAILABLE:
|
||||
try:
|
||||
from systems.voxcpm.voxcpm import VoxCPM
|
||||
LOCAL_MODEL_PATH = "/root/tts/VoxCPM/models/openbmb__VoxCPM1.5"
|
||||
self.model = VoxCPM(
|
||||
voxcpm_model_path=LOCAL_MODEL_PATH,
|
||||
enable_denoiser=False, # 质量关键(匹配Ben的成功克隆配置)
|
||||
optimize=False # 避免优化问题
|
||||
)
|
||||
print("✓ VoxCPM模型加载成功")
|
||||
except Exception as e:
|
||||
print(f"⚠️ VoxCPM初始化失败: {e}")
|
||||
self.model = None
|
||||
|
||||
def create_podcast_script(self):
|
||||
"""创建播客对话脚本"""
|
||||
script = [
|
||||
{
|
||||
"speaker": "Sonia",
|
||||
"text": "欢迎来到本期节目,今天我们有幸邀请到作者,一起回顾2001-2009年这段特殊的历史时期。这段时间被称为'韩信的入场券',充满了复杂的地缘政治变化。能否请您为我们概述一下这个时代的主要特点?"
|
||||
},
|
||||
{
|
||||
"speaker": "Author",
|
||||
"text": "这个时代最突出的特点是中国的战略隐忍。面对1999年大使馆被炸的屈辱、2001年南海撞机的紧张局势,中国选择了与美国合作反恐,从而获得了宝贵的发展窗口期。"
|
||||
},
|
||||
{
|
||||
"speaker": "Sonia",
|
||||
"text": "在2008年金融危机中,您特别提到了一个叫'高斯联结函数'的数学模型,以及它如何影响了亚洲歌神张学友的投资。这个数学模型究竟是如何运作的?"
|
||||
},
|
||||
{
|
||||
"speaker": "Author",
|
||||
"text": "这个模型由华裔数学家李祥林提出,它巧妙地'删除'了违约的相关性,使得一篮子高风险贷款可以被评级为AAA级资产。张学友投资的雷曼兄弟迷你债券正是被这种模型包装后的产品,导致他损失了约4000万港币。"
|
||||
},
|
||||
{
|
||||
"speaker": "Sonia",
|
||||
"text": "您提到了'瓦良格'号航母和普京寻求加入北约被拒的事件。这两件事看似无关,但它们如何共同构成了中国崛起的战略机遇?"
|
||||
},
|
||||
{
|
||||
"speaker": "Author",
|
||||
"text": "这是一个非常有趣的巧合。美国忙于反恐战争,无力阻止中国购买并改造'瓦良格'号;同时,北约拒绝普京的加入请求,迫使俄罗斯转向与中国合作。这两大因素为中国创造了有利的外部环境。"
|
||||
},
|
||||
{
|
||||
"speaker": "Sonia",
|
||||
"text": "最后一个问题,您认为2001-2009年这段时间为中国后来的发展奠定了怎样的基础?"
|
||||
},
|
||||
{
|
||||
"speaker": "Author",
|
||||
"text": "这十年是中国嵌入全球产业链、积累资本和技术的关键时期。通过隐忍和务实的战略,中国不仅成功避免了与美国的直接冲突,还利用了美国的战略重心转移,实现了经济的快速发展。"
|
||||
},
|
||||
{
|
||||
"speaker": "Sonia",
|
||||
"text": "感谢您今天的精彩分享,让我们更好地理解了这一段复杂而重要的历史。"
|
||||
}
|
||||
]
|
||||
return script
|
||||
|
||||
def generate_audio_with_voxcpm(self, text, output_file):
|
||||
"""使用VoxCPM生成音频"""
|
||||
if self.model is None:
|
||||
print(f"⚠️ VoxCPM不可用,创建模拟音频文件: {output_file}")
|
||||
# 创建一个空的音频文件作为占位符
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(f"Simulated audio for: {text}")
|
||||
return
|
||||
|
||||
try:
|
||||
# 使用VoxCPM生成音频
|
||||
audio = self.model.generate(
|
||||
text=text,
|
||||
cfg_value=2.0,
|
||||
inference_timesteps=20
|
||||
)
|
||||
|
||||
# 保存音频文件
|
||||
import soundfile as sf
|
||||
sf.write(output_file, audio, self.model.tts_model.sample_rate)
|
||||
print(f"✓ 生成音频: {output_file}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 生成音频失败 {output_file}: {e}")
|
||||
# 创建一个错误文件作为占位符
|
||||
with open(output_file.replace('.mp3', '_error.txt'), 'w') as f:
|
||||
f.write(f"Error generating audio: {e}\nText: {text}")
|
||||
|
||||
def generate_podcast(self):
|
||||
"""生成播客音频"""
|
||||
script = self.create_podcast_script()
|
||||
|
||||
# 创建输出目录
|
||||
output_dir = "output/podcast/interview"
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
print(f"开始生成播客,共 {len(script)} 个片段...")
|
||||
|
||||
for i, line in enumerate(script):
|
||||
speaker = line["speaker"]
|
||||
text = line["text"]
|
||||
|
||||
# 生成音频文件
|
||||
output_file = f"{output_dir}/{speaker.lower()}_{i+1:02d}.wav" # 使用wav格式以兼容soundfile
|
||||
self.generate_audio_with_voxcpm(text, output_file)
|
||||
|
||||
# 创建脚本文件
|
||||
script_file = f"{output_dir}/podcast_script.txt"
|
||||
with open(script_file, 'w', encoding='utf-8') as f:
|
||||
for line in script:
|
||||
f.write(f"{line['speaker']}: {line['text']}\n\n")
|
||||
|
||||
print(f"\n✓ 播客脚本已保存到: {script_file}")
|
||||
print(f"✓ 共处理 {len(script)} 个音频片段")
|
||||
print("✓ 播客生成完成!")
|
||||
|
||||
def main():
|
||||
generator = PodcastGeneratorWithVoxCPM()
|
||||
generator.generate_podcast()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user