#!/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()