赞
踩
最近有文字转语音功能的需求,虽然也有一些免费工具,不过并没有找到好用的在线的文本转语音工具,因此便有了这篇文章。
这是一个基于微软edge浏览器大声朗读功能的python库,作者将其进行封装,因此我们可以借由它来实现文字转语音功能,那么首先我先介绍一下这个库。edge-tts的github地址
pip3 install edge_tts
import asyncio
import edge_tts
Content = "注意看,这是一段文字转语音的测试"
voiceName = "zh-TW-YunJheNeural"
output = "sound.mp3"
rate = '+5%'
volume = '+0%'
pitch = '+0Hz'
async def main():
communicate = edge_tts.Communicate(text = Content, voice=voiceName ,rate=rate, volume=volume,pitch=pitch)
await communicate.save(output)
asyncio.run(main())
asyncio.run 是 Python 标准库中 asyncio 模块提供的一个函数,用于运行一个异步函数直到它完成。它通常用于简化异步代码的执行,特别是在运行一个完整的异步应用程序时,而edge_tts所需要的就是这么一个异步执行,使用edge_tts.Communicate来生成音频内容,然后使用communicate.save来将文件保存到本地路径,其中text为所需要的文本,voice为所需要的音色,这个一会介绍,rate为语速,volume为音量,默认0就是满的,pitch为音调,后三个所接收的数据需要带上 正负号 数字 百分比的形式,其中pitch需要 正负号 数字 Hz的形式。
voice为音色参数,对于音色的获取,需要在安装完库之后在cmd里输入
edge-tts --list-voices
来查询,我列举一下这个库所支持的中文音色:
{ "Value": "zh-CN-XiaoxiaoNeural", "text": "晓晓" },
{ "Value": "zh-CN-XiaoyiNeural", "text": "小艺" },
{ "Value": "zh-CN-YunjianNeural", "text": "云建" },
{ "Value": "zh-CN-YunxiNeural", "text": "云溪" },
{ "Value": "zh-CN-YunxiaNeural", "text": "云霞" },
{ "Value": "zh-CN-YunyangNeural", "text": "云阳" },
{ "Value": "zh-CN-liaoning-XiaobeiNeural", "text": "东北小贝" },
{ "Value": "zh-CN-shaanxi-XiaoniNeural", "text": "山西小妮" },
{ "Value": "zh-HK-HiuGaaiNeural", "text": "粤语小妹" },
{ "Value": "zh-HK-HiuMaanNeural", "text": "粤语小妹2" },
{ "Value": "zh-HK-WanLungNeural", "text": "粤语小哥" },
{ "Value": "zh-TW-HsiaoChenNeural", "text": "台湾小妹" },
{ "Value": "zh-TW-HsiaoYuNeural", "text": "台湾小妹2" },
{ "Value": "zh-TW-YunJheNeural", "text": "台湾小哥" }
如果你跟着教程做了下来,你可以尝试使用一段超过5000字的长文本,你会发现生成速度明显慢了下来,我们可以使用多线程来同时生成多段文本,然后再把他们拼接到一起,这样速度便会有明显的提升
下面是一段多线程同步生成文件的测试,我们需要在项目目录下创建texts的文件夹,里面放上我们想要生成的文本:
import asyncio import time import edge_tts import os async def convert(text, file_name) -> None: start_time = time.time() communicate = edge_tts.Communicate(text, "zh-CN-XiaoxiaoNeural") await communicate.save(f"sounds/{file_name}.mp3") print(f"{file_name}用时:{int(time.time() - start_time)}秒") async def main(): # 创建输出文件夹 if not os.path.exists("sounds"): os.makedirs("sounds") tasks = [] # 遍历输入文件夹 for root, dirs, files in os.walk("texts"): for file in files: # 将文件中的文本读出来 with open(os.path.join(root, file), "r", encoding='utf-8') as text_file: text = text_file.read() # 获取文件名 file_name, ext = os.path.splitext(file) # 加入任务列表 tasks.append(convert(text, file_name)) # 等待所有任务完成 await asyncio.gather(*tasks) asyncio.run(main())
可以看到这几篇文章都在同步下载,那么如果我们有一段很长的长文本,那么就可以按照这种方式来快速生成了。
pydub 是一个用于处理音频文件的 Python 库,对音频进行各种操作变得更加容易。以下是一些 pydub 的主要功能:
音频格式转换: pydub 支持多种音频格式之间的转换,例如将 MP3 转换为 WAV 或反之。
音频剪辑和拼接: 你可以使用 pydub 对音频进行剪辑或拼接,合并多个音频文件。
音频格式调整: 调整音频的采样率、声道数、比特率等属性。
音频切片: 从音频文件中提取特定时间范围的片段。
音频效果: 提供一些简单的音频效果,例如增加音量、降低音量、应用均衡器等
我们只需要用到其中的音频拼接功能就可以,需要注意的是,使用这个库需要用到ffmpeg,对于ffmpeg的安装方法请移步至此:ffmpeg官网
使用它来拼接音频是十分简单的,这是一段示例代码:
from pydub import AudioSegment
#读取音频文件
audio1 = AudioSegment.from_file("file1.wav")
audio2 = AudioSegment.from_file("file2.wav")
#拼接音频文件
merged_audio0=audio1+audio2
#保存拼接后的音频文件
merged_audio.export("merged.wav", format="wav")
需要texts,cache,download三个文件夹,其中texts里为你的文章,然后pwd需要设置为项目运行路径
import asyncio import edge_tts import time from pydub import AudioSegment import hashlib pwd = "/var/www/html/sound" rate = '+0%' volume = '+0%' pitch = '+0Hz' def calculate_8_digit_md5(input_string): md5 = hashlib.md5() md5.update(input_string.encode('utf-8')) md5_hash = md5.hexdigest()[:8] return md5_hash def get_current_time(): current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) return current_time async def convert(text, file_name, count,voice_name) -> None: global result start_time = time.time() communicate = edge_tts.Communicate(text=text,voice=voice_name,rate=rate,volume=volume,pitch=pitch) await communicate.save(pwd+f"/cache/{file_name}{count}.mp3") print(f"{file_name}用时:{int(time.time() - start_time)}秒") def split_and_terminate(input_string, chunk_size=3000): res = [] start = 0 while start < len(input_string): # 截取指定大小的片段 chunk = input_string[start:start + chunk_size] if start + chunk_size < len(input_string): last_comma = chunk.rfind(',') last_period = chunk.rfind('。') last_punctuation = max(last_comma, last_period) if last_punctuation != -1: chunk = chunk[:last_punctuation + 1] res.append(chunk) start += len(chunk) return res async def main(): print("md5:"+md5) result = split_and_terminate(text) tasks = [] for index, chunk in enumerate(result): tasks.append(convert(chunk, md5,str(index+1),"zh-CN-XiaoxiaoNeural")) await asyncio.gather(*tasks) def save_string_to_file(data, file_path): try: with open(file_path, 'w', encoding='utf-8') as file: file.write(data) print(f"字符串已成功保存到文件: {file_path}") except Exception as e: print(f"保存文件时发生错误: {e}") if __name__ == "__main__": global text,md5 with open(pwd+"/texts/测试.txt", "r", encoding='utf-8') as text_file: text = text_file.read() md5 = calculate_8_digit_md5(text + str(time.time())) asyncio.run(main()) print('音频下载完成') result = AudioSegment.from_file(pwd+"/cache/" + md5 + "1.mp3") print('第1段合成完成') count = len(split_and_terminate(text)) for i in range(2,count+1): result += AudioSegment.from_file(pwd+"/cache/" + md5 + str(i) + ".mp3") print('第' + str(i) + '段合成完成') result.export(pwd+"/download/"+md5+".mp3", format="mp3") print(md5+".mp3生成成功")
这个网站还有进度条功能和日志显示功能,他们都是用原生html实现的,如果有人感兴趣,评论区说下,我再出期文章!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。