Files
tts/scripts/generate_podcast_voxcpm.py
2026-01-19 10:27:41 +08:00

153 lines
6.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()