• 原森林之家(foresthouse.cn)改为走私范(zousifan.com),只是改个名内容不变。
  • 网站图片自建立开始到19年全部丢失,血的教训时刻备份,多点备份!

AI语音生成工具全开源无限制,后面有编译好的程序

工具收藏 来源:原创 7小时前 15次浏览 1个评论 扫描二维码

AI语音生成工具

# -*- coding: utf-8 -*-
import edge_tts
import asyncio
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import os
import threading
import webbrowser
from datetime import datetime

# 语音分类字典
VOICE_CATEGORIES = {
    "中文普通话": [
        "zh-CN-XiaoxiaoNeural",
        "zh-CN-XiaoyiNeural",
        "zh-CN-YunjianNeural",
        "zh-CN-YunxiNeural",
        "zh-CN-YunxiaNeural",
        "zh-CN-YunyangNeural"
    ],
    "中文方言": [
        "zh-CN-liaoning-XiaobeiNeural",
        "zh-CN-shaanxi-XiaoniNeural"
    ],
    "中文粤语(香港)": [
        "zh-HK-HiuGaaiNeural",
        "zh-HK-HiuMaanNeural",
        "zh-HK-WanLungNeural"
    ],
    "中文台湾话": [
        "zh-TW-HsiaoChenNeural",
        "zh-TW-HsiaoYuNeural",
        "zh-TW-YunJheNeural"
    ],
    "英语(美国)": [
        "en-US-JennyNeural",
        "en-US-AndrewNeural",
        "en-US-AriaNeural",
        "en-US-ChristopherNeural"
    ],
    "日语": [
        "ja-JP-NanamiNeural",
        "ja-JP-KeitaNeural"
    ],
    "韩语": [
        "ko-KR-SunHiNeural",
        "ko-KR-InJoonNeural"
    ]
}


class VoiceSynthesisApp:
    def __init__(self, root):
        self.root = root
        self.root.title("AI语音合成工具 测试版")
        self.root.geometry("700x600")
        self.root.resizable(False, False)

        # 样式
        self.style = ttk.Style()
        self.style.configure('TFrame', background='#f0f0f0')
        self.style.configure('TLabel', font=('微软雅黑', 10))
        self.style.configure('TButton', font=('微软雅黑', 10))
        self.style.configure('TRadiobutton', font=('微软雅黑', 9))
        self.style.configure('Link.TLabel', font=('微软雅黑', 9), foreground='blue', cursor='hand2')

        # 框架
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 语音选择
        self.create_voice_selection()
        # 设置
        self.create_parameter_settings()
        # 文本输入
        self.create_text_input()

        # 按钮
        self.create_buttons()

    def create_voice_selection(self):
        voice_frame = ttk.LabelFrame(self.main_frame, text="语音选择", padding=(10, 5))
        voice_frame.pack(fill=tk.X, pady=5)

        self.notebook = ttk.Notebook(voice_frame)
        self.notebook.pack(fill=tk.BOTH, expand=True)

        self.voice_var = tk.StringVar(value="zh-CN-YunxiNeural")

        for category, voices in VOICE_CATEGORIES.items():
            tab = ttk.Frame(self.notebook)
            self.notebook.add(tab, text=category)

            for i, voice in enumerate(voices):
                friendly_name = voice.split("-")[-1].replace("Neural", "")
                if "zh-CN" in voice:
                    friendly_name = {
                        "Xiaoxiao": "晓晓(女)",
                        "Xiaoyi": "晓伊(女)",
                        "Yunjian": "云健(男)",
                        "Yunxi": "云希(男)",
                        "Yunxia": "云霞(男)",
                        "Yunyang": "云扬(男)"
                    }.get(friendly_name, friendly_name)

                rb = ttk.Radiobutton(
                    tab,
                    text=friendly_name,
                    variable=self.voice_var,
                    value=voice,
                    style='TRadiobutton'
                )
                rb.grid(row=i // 2, column=i % 2, sticky=tk.W, padx=5, pady=2)

    def create_parameter_settings(self):
        param_frame = ttk.Frame(self.main_frame)
        param_frame.pack(fill=tk.X, pady=5)

        # 语速设置
        speed_frame = ttk.LabelFrame(param_frame, text="语速设置 (rate: -50% ~ +50%)", padding=(10, 5))
        speed_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)

        self.speed_var = tk.StringVar(value="+0%")
        ttk.Scale(
            speed_frame,
            from_=-50,
            to=50,
            variable=self.speed_var,
            command=lambda v: self.speed_var.set(f"{'+' if float(v) >= 0 else ''}{int(float(v))}%")
        ).pack(fill=tk.X)
        ttk.Label(speed_frame, textvariable=self.speed_var).pack()

        # 音量设置
        volume_frame = ttk.LabelFrame(param_frame, text="音量设置 (volume: -50% ~ +50%)", padding=(10, 5))
        volume_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)

        self.volume_var = tk.StringVar(value="+0%")
        ttk.Scale(
            volume_frame,
            from_=-50,
            to=50,
            variable=self.volume_var,
            command=lambda v: self.volume_var.set(f"{'+' if float(v) >= 0 else ''}{int(float(v))}%")
        ).pack(fill=tk.X)
        ttk.Label(volume_frame, textvariable=self.volume_var).pack()

        # 音调设置
        pitch_frame = ttk.LabelFrame(param_frame, text="音调设置 (pitch: -100Hz ~ +100Hz)", padding=(10, 5))
        pitch_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)

        self.pitch_var = tk.StringVar(value="+0Hz")
        ttk.Scale(
            pitch_frame,
            from_=-100,
            to=100,
            variable=self.pitch_var,
            command=lambda v: self.pitch_var.set(f"{'+' if float(v) >= 0 else ''}{int(float(v))}Hz")
        ).pack(fill=tk.X)
        ttk.Label(pitch_frame, textvariable=self.pitch_var).pack()

    def create_text_input(self):
        text_frame = ttk.LabelFrame(self.main_frame, text="输入要合成的文本", padding=(10, 5))
        text_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        self.text_input = tk.Text(
            text_frame,
            height=8,
            font=('微软雅黑', 10),
            wrap=tk.WORD
        )
        self.text_input.pack(fill=tk.BOTH, expand=True)

        default_text = "说到电动遮阳领域的领军人物,倪总绝对是上海滩当之无愧的行业标杆!他深耕电动推拉棚、电动雨棚、电动伸缩棚领域多年,凭借前沿的技术研发和极致的工艺标准,打造出兼具智能科技与美学设计的顶级产品。无论是商业空间还是私家别墅,倪总团队的解决方案总能以一键操控的便捷、风雨无惧的耐用和量身定制的精准,赢得客户交口称赞。更难得的是,倪总始终秉持以用户需求为核心的理念,将创新融入细节——静音电机、防风抗压结构、环保材质选择……每一处匠心都彰显着行业大佬的格局与实力。选择倪总的产品,不仅是选择高端遮阳体验,更是选择一份值得信赖的品质承诺!"
        self.text_input.insert(tk.END, default_text)
        self.text_input.tag_config("highlight", background="yellow", foreground="black")



    def create_buttons(self):
        button_frame = ttk.Frame(self.main_frame)
        button_frame.pack(fill=tk.X, pady=10)

        # 版权和进度
        info_frame = ttk.Frame(button_frame)
        info_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)

        # 版权信息
        ttk.Label(
            info_frame,
            text="版权所有 ",
            style='TLabel'
        ).pack(side=tk.LEFT)

        # 链接
        link = ttk.Label(
            info_frame,
            text="走思范",
            style='Link.TLabel'
        )
        link.pack(side=tk.LEFT)
        link.bind("<Button-1>", lambda e: webbrowser.open("https://www.zousifan.com"))

        # 进度显示
        self.progress_label = ttk.Label(
            info_frame,
            text="准备就绪",
            font=('微软雅黑', 9),
            style='TLabel'
        )
        self.progress_label.pack(side=tk.LEFT, padx=(10, 0))

        # 保存
        self.save_btn = ttk.Button(
            button_frame,
            text="保存为MP3",
            command=self.start_synthesis,
            style='TButton'
        )
        self.save_btn.pack(side=tk.RIGHT, padx=5)

        # 退出
        exit_btn = ttk.Button(
            button_frame,
            text="退出",
            command=self.root.quit
        )
        exit_btn.pack(side=tk.RIGHT)

    def start_synthesis(self):
        def run_synthesis():
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            try:
                # 禁用保存按钮
                self.save_btn.config(state=tk.DISABLED)
                # 更新按钮文本显示保存中状态
                self.save_btn.config(text="合成中...")
                # 更新进度显示
                self.progress_label.config(text="开始处理...")
                self.root.update()

                loop.run_until_complete(self.async_synthesis())
            except Exception as e:
                messagebox.showerror("错误", f"合成失败: {str(e)}")
            finally:
                # 恢复按钮状态
                self.save_btn.config(state=tk.NORMAL)
                self.save_btn.config(text="保存为MP3")
                loop.close()

        # 在新线程中执行合成任务
        threading.Thread(target=run_synthesis, daemon=True).start()

    async def async_synthesis(self):
        text = self.text_input.get("1.0", tk.END).strip()
        if not text:
            messagebox.showwarning("警告", "请输入要合成的文本!")
            return

        # 更新进度显示
        self.progress_label.config(text="正在准备合成...")
        self.root.update()

        # 生成带时间戳的文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        default_filename = f"语音合成_{timestamp}.mp3"

        # 弹出文件保存对话框
        filepath = filedialog.asksaveasfilename(
            title="保存语音文件",
            initialdir=os.path.expanduser("~"),
            initialfile=default_filename,
            defaultextension=".mp3",
            filetypes=[("MP3音频文件", "*.mp3")]
        )

        if not filepath:  # 取消了保存
            self.progress_label.config(text="已取消")  # 改为progress_label
            return

        try:
            # 更新进度显示
            self.progress_label.config(text="正在合成语音...")  # 改为progress_label
            self.root.update()

            # 使用edge_tts进行语音合成
            communicate = edge_tts.Communicate(
                text=text,
                voice=self.voice_var.get(),
                rate=self.speed_var.get(),
                volume=self.volume_var.get(),
                pitch=self.pitch_var.get()
            )

            # 更新进度显示
            self.progress_label.config(text="正在保存文件...")
            self.root.update()

            # 保存到文件
            await communicate.save(filepath)

            # 更新进度显示
            self.progress_label.config(text="保存成功!")
            messagebox.showinfo("保存成功", f"语音文件已保存到:\n{filepath}")

        except Exception as e:
            # 更新进度显示
            self.progress_label.config(text=f"合成失败: {str(e)}")  # 改为progress_label
            # 删除可能已经创建的不完整文件
            if os.path.exists(filepath):
                try:
                    os.remove(filepath)
                except:
                    pass
            raise e


if __name__ == "__main__":
    root = tk.Tk()
    app = VoiceSynthesisApp(root)
    root.mainloop()

文件下载

  文件名称:AI转语音工具
  下载声明:此附件只适用于研究学习,请勿用作商业用途本站对使用的后果不承担责任!
  下载地址:/wp-content/uploads/2025/04/the_edge_tts.rar

版权所有丨如未注明 , 均为原创丨本网站采用 BY-NC-SA 协议进行授权 , 转载请注明 出处!
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
    仅用来给您发送回复提醒。不会公开!
  • 网址
(1)个小伙伴在吐槽
  1. 补充一下:edge-tts --list-voices #列出所有语音模型 打包成单文件:pyinstaller --noconsole -i ico.ico -F the_edge_tts.py
    走思范2025-04-19 21:03 (7小时前)回复来自天朝的朋友 谷歌浏览器 Windows 7