当前位置: 首页 > ops >正文

Python的语音配音软件,使用edge-tts进行文本转语音,支持多种声音选择和语速调节

功能特性

  • ✅ 多种中文语音选择(微软Edge TTS引擎)

  • ✅ 语速调节(0.5倍速到2倍速)

  • ✅ 文本输入和编辑

  • ✅ 实时试听功能

  • ✅ 保存为MP3文件

  • ✅ 简洁易用的GUI界面

安装依赖

pip install edge-tts pygame 

使用方法

  1. 运行程序:

    python voice_assistant.py
  2. 界面操作:

    • 选择声音: 从下拉菜单选择喜欢的语音

    • 调节语速: 使用滑块调整语速(左慢右快)

    • 输入文本: 在文本框中输入要转换的文字

    • 试听: 点击"试听"按钮预览生成的语音

    • 保存: 点击"保存MP3"将语音保存为文件

    • 清除: 点击"清除"清空文本框

支持的声音

  • 晓晓 (zh-CN-XiaoxiaoNeural) - 女声

  • 晓伊 (zh-CN-XiaoyiNeural) - 女声

  • 云健 (zh-CN-YunjianNeural) - 男声

  • 云希 (zh-CN-YunxiNeural) - 男声

  • 云夏 (zh-CN-YunxiaNeural) - 男声

  • 云扬 (zh-CN-YunyangNeural) - 男声

技术栈

  • Python 3.6+

  • tkinter (GUI界面)

  • edge-tts (文本转语音)

  • pygame (音频播放)

  • asyncio (异步处理)

打包成EXE 

用下面代码:

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import threading
import os
import edge_tts
import asyncio
import tempfile
import subprocess
import platformclass VoiceAssistant:def __init__(self, root):self.root = rootself.root.title("语音配音助手")self.root.geometry("800x600")# 音频播放设置self.audio_player = self.get_audio_player()# 创建主框架main_frame = ttk.Frame(root, padding="20")main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))# 配置网格权重root.columnconfigure(0, weight=1)root.rowconfigure(0, weight=1)main_frame.columnconfigure(1, weight=1)main_frame.rowconfigure(4, weight=1)# 声音选择ttk.Label(main_frame, text="选择声音:").grid(row=0, column=0, sticky=tk.W, pady=5)self.voice_var = tk.StringVar()self.voice_combo = ttk.Combobox(main_frame, textvariable=self.voice_var, state="readonly")self.voice_combo.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5)# 语速调节ttk.Label(main_frame, text="语速:").grid(row=1, column=0, sticky=tk.W, pady=5)self.speed_var = tk.DoubleVar(value=1.0)self.speed_scale = ttk.Scale(main_frame, from_=0.5, to=2.0, variable=self.speed_var, orient=tk.HORIZONTAL)self.speed_scale.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5)ttk.Label(main_frame, textvariable=tk.StringVar(value="慢")).grid(row=1, column=2, sticky=tk.W, pady=5)ttk.Label(main_frame, textvariable=tk.StringVar(value="快")).grid(row=1, column=3, sticky=tk.W, pady=5)# 文本输入ttk.Label(main_frame, text="输入文本:").grid(row=2, column=0, sticky=tk.W, pady=5)self.text_input = tk.Text(main_frame, height=10, wrap=tk.WORD)self.text_input.grid(row=2, column=1, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)# 按钮框架button_frame = ttk.Frame(main_frame)button_frame.grid(row=3, column=0, columnspan=4, pady=10)ttk.Button(button_frame, text="试听", command=self.preview_audio).pack(side=tk.LEFT, padx=5)ttk.Button(button_frame, text="保存MP3", command=self.save_audio).pack(side=tk.LEFT, padx=5)ttk.Button(button_frame, text="清除", command=self.clear_text).pack(side=tk.LEFT, padx=5)# 状态标签self.status_var = tk.StringVar(value="就绪")ttk.Label(main_frame, textvariable=self.status_var).grid(row=4, column=0, columnspan=4, pady=5)# 加载可用声音self.load_voices()def load_voices(self):"""加载可用的声音列表"""try:# 这里可以添加更多声音选项voices = ["zh-CN-XiaoxiaoNeural",    # 晓晓-女声"zh-CN-XiaoyiNeural",      # 晓伊-女声"zh-CN-YunjianNeural",     # 云健-男声"zh-CN-YunxiNeural",       # 云希-男声"zh-CN-YunxiaNeural",      # 云夏-男声"zh-CN-YunyangNeural"      # 云扬-男声]self.voice_combo['values'] = voicesself.voice_combo.set(voices[0])  # 默认选择第一个声音except Exception as e:messagebox.showerror("错误", f"加载声音列表失败: {e}")async def generate_audio_async(self, text, voice, rate, output_file):"""异步生成音频文件"""try:communicate = edge_tts.Communicate(text, voice, rate=rate)await communicate.save(output_file)return True, ""except Exception as e:return False, str(e)def generate_audio(self, text, voice, rate, output_file):"""生成音频文件"""loop = asyncio.new_event_loop()asyncio.set_event_loop(loop)try:success, error = loop.run_until_complete(self.generate_audio_async(text, voice, rate, output_file))return success, errorfinally:loop.close()def preview_audio(self):"""试听功能"""text = self.text_input.get("1.0", tk.END).strip()if not text:messagebox.showwarning("警告", "请输入要转换的文本")returnvoice = self.voice_var.get()rate = f"+{(self.speed_var.get() - 1) * 100:.0f}%"self.status_var.set("正在生成试听音频...")# 在新线程中生成音频threading.Thread(target=self._preview_thread, args=(text, voice, rate), daemon=True).start()def _preview_thread(self, text, voice, rate):"""试听线程"""try:# 创建临时文件with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as tmp_file:temp_path = tmp_file.name# 生成音频success, error = self.generate_audio(text, voice, rate, temp_path)if success:# 在主线程中播放音频self.root.after(0, lambda: self._play_audio(temp_path))self.root.after(0, lambda: self.status_var.set("试听音频生成完成"))else:self.root.after(0, lambda: messagebox.showerror("错误", f"生成音频失败: {error}"))self.root.after(0, lambda: self.status_var.set("生成失败"))except Exception as e:self.root.after(0, lambda: messagebox.showerror("错误", f"试听过程中发生错误: {e}"))self.root.after(0, lambda: self.status_var.set("错误"))def get_audio_player(self):"""获取系统音频播放器"""system = platform.system()if system == "Windows":return "start"elif system == "Darwin":  # macOSreturn "afplay"else:  # Linuxreturn "aplay"def _play_audio(self, file_path):"""播放音频"""try:if self.audio_player == "start":  # Windowssubprocess.Popen(["cmd", "/c", "start", "", "/min", file_path], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)else:  # macOS or Linuxsubprocess.Popen([self.audio_player, file_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)# 延迟后清理文件def cleanup():try:os.unlink(file_path)except:passself.root.after(10000, cleanup)  # 10秒后清理except Exception as e:messagebox.showerror("错误", f"播放音频失败: {e}")def save_audio(self):"""保存MP3文件"""text = self.text_input.get("1.0", tk.END).strip()if not text:messagebox.showwarning("警告", "请输入要转换的文本")return# 选择保存路径file_path = filedialog.asksaveasfilename(defaultextension=".mp3",filetypes=[("MP3文件", "*.mp3"), ("所有文件", "*.*")],title="保存音频文件")if not file_path:returnvoice = self.voice_var.get()rate = f"+{(self.speed_var.get() - 1) * 100:.0f}%"self.status_var.set("正在生成并保存音频...")# 在新线程中保存音频threading.Thread(target=self._save_thread, args=(text, voice, rate, file_path), daemon=True).start()def _save_thread(self, text, voice, rate, file_path):"""保存线程"""try:success, error = self.generate_audio(text, voice, rate, file_path)if success:self.root.after(0, lambda: messagebox.showinfo("成功", f"音频已保存到: {file_path}"))self.root.after(0, lambda: self.status_var.set("保存完成"))else:self.root.after(0, lambda: messagebox.showerror("错误", f"保存音频失败: {error}"))self.root.after(0, lambda: self.status_var.set("保存失败"))except Exception as e:self.root.after(0, lambda: messagebox.showerror("错误", f"保存过程中发生错误: {e}"))self.root.after(0, lambda: self.status_var.set("错误"))def clear_text(self):"""清除文本"""self.text_input.delete("1.0", tk.END)self.status_var.set("已清除文本")def main():root = tk.Tk()app = VoiceAssistant(root)root.mainloop()if __name__ == "__main__":main()

pyinstaller --onefile --windowed --name="语音配音助手" voice_assistant.py 

http://www.xdnf.cn/news/20028.html

相关文章:

  • MySQL 主从复制详解:部署与进阶配置
  • NGUI--三大基础控件
  • VBA 中的 Excel 工作表函数
  • 新后端漏洞(上)- Java RMI Registry反序列化漏洞
  • Struts2 工作总结
  • B树,B+树,B*树(无代码)
  • React JSX 语法讲解
  • bat脚本- 将jar 包批量安装到 Maven 本地仓库
  • Highcharts 数据源常见问题解析:连接方式、格式处理与性能优化指南
  • React 样式隔离核心方法和最佳实践
  • 【展厅多媒体】AI虚拟数字人在展厅互动中的应用
  • [VF2] Boot Ubuntu和Debian发行版
  • 智慧城市SaaS平台之智慧城管十大核心功能(五):监督检查综合管理系统
  • AI急速搭建网站:Gemini、Bolt或Jules、GitHub、Cloudflare Pages实战全流程!
  • FastAPI 中的 Pydantic 的作用
  • docker 部署RustDesk服务
  • 零知开源——基于STM32F103RBT6的智能风扇控制系统设计与实现
  • 头一次见问这么多kafka的问题
  • 针对nvm不能导致npm和node生效的解决办法
  • java.nio.file.InvalidPathException异常
  • 文章采集发布帝国ECMS网站技巧
  • K8s访问控制(一)
  • MySQL高级进阶(流程控制、循环语句、触发器)
  • 电机试验平台:从实验到应用的创新突破
  • OpenCV C++ 进阶:图像直方图与几何变换全解析
  • 大数据毕业设计推荐:基于Spark的零售时尚精品店销售数据分析系统【Hadoop+python+spark】
  • 孟子GPT
  • Ruoyi-vue-plus-5.x第五篇Spring框架核心技术:5.1 Spring Boot自动配置
  • React中使用DDD(领域驱动设计)
  • java,通过SqlSessionFactory实现动态表明的插入和查询(适用于一个版本一个表的场景)