文字转语音神器+Python编程搞定语音报时小程序
今天一个好哥们发了一个文字转语音的AI神器的短视频。这个神器的网站是[ChatTTS - Text-to-Speech for Conversational Scenarios][https://chattts.com/],如下图所示:
这个开源项目可以从github.com上下载,也可以在这个网页下载。如下图所示:
在主页上大概体验了一下,文字转语音还可以,但是有些生字(镇赉县)还是不能正常识别,比方说这个”赉“字。还有就是阿拉伯数字也不能正常识别。但是可以通过程序转成汉字,然后就可以了。言归正传,这个开源项目给我的最好的体会就是免费,于是按照上图所示的步骤,下载了源码并安装了依赖库,强调一下,这个源码运行环境在Anaconda下可以,PyCharm我的电脑不能运行,报错。
我首先想到的是利用这个API编一个语音报时的小程序,之前我编了一个万年历,这回可以实现语音播报了。我首先实现一个简单的报时小程序。
下载之后的源码文件夹拷贝到你指定的目录下面,然后进入Anaconda的Jupyter-Notebook下,打开
上面说到了,阿拉伯数字是不能准确识别的。但是用datetime模块生成的时间或者日期都是阿拉伯数字,必须转成汉字才可以利用这个开源模块实现语音播报。
环境
操作系统:macOS Sonoma
开发环境:Anaconda+Python 3.11
源码如下:
import torch
import ChatTTS
from IPython.display import Audio
import datetime
chat = ChatTTS.Chat()
chat.load_models()
# 定义一个类
class PeriodDay:
def init(self):
self.now = datetime.datetime.now()
<span class="token keyword">def</span> <span class="token function">get_time_of_day</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">if</span> self<span class="token punctuation">.</span>now<span class="token punctuation">.</span>hour <span class="token operator"><</span> <span class="token number">12</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token string">"上午"</span>
<span class="token keyword">elif</span> <span class="token number">12</span> <span class="token operator"><=</span> self<span class="token punctuation">.</span>now<span class="token punctuation">.</span>hour <span class="token operator"><</span> <span class="token number">18</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token string">"下午"</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token string">"晚上"</span>
<span class="token comment"># 定义一个时间转成汉字的函数</span>
<span class="token keyword">def</span> <span class="token function">format_time_final</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
hour<span class="token punctuation">,</span> minute <span class="token operator">=</span> self<span class="token punctuation">.</span>now<span class="token punctuation">.</span>strftime<span class="token punctuation">(</span><span class="token string">'%H:%M'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">':'</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token builtin">int</span><span class="token punctuation">(</span>minute<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">:</span>
minute <span class="token operator">=</span> <span class="token string">'整'</span>
<span class="token keyword">elif</span> <span class="token builtin">int</span><span class="token punctuation">(</span>minute<span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">10</span><span class="token punctuation">:</span>
minute <span class="token operator">=</span> <span class="token string">'零'</span> <span class="token operator">+</span> number_to_chinese<span class="token punctuation">(</span><span class="token builtin">int</span><span class="token punctuation">(</span>minute<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'分'</span>
<span class="token keyword">elif</span> <span class="token builtin">int</span><span class="token punctuation">(</span>minute<span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">20</span><span class="token punctuation">:</span>
minute <span class="token operator">=</span> number_to_chinese<span class="token punctuation">(</span><span class="token builtin">int</span><span class="token punctuation">(</span>minute<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">:</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">'分'</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
minute <span class="token operator">=</span> number_to_chinese<span class="token punctuation">(</span><span class="token builtin">int</span><span class="token punctuation">(</span>minute<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'分'</span>
<span class="token keyword">if</span> <span class="token number">10</span> <span class="token operator"><=</span> <span class="token builtin">int</span><span class="token punctuation">(</span>hour<span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">20</span><span class="token punctuation">:</span>
hour <span class="token operator">=</span> number_to_chinese<span class="token punctuation">(</span><span class="token builtin">int</span><span class="token punctuation">(</span>hour<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">:</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">'时'</span>
<span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f'</span><span class="token interpolation"><span class="token punctuation">{<!-- --></span>hour<span class="token punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token punctuation">{<!-- --></span>minute<span class="token punctuation">}</span></span><span class="token string">'</span></span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f'</span><span class="token interpolation"><span class="token punctuation">{<!-- --></span>number_to_chinese<span class="token punctuation">(</span><span class="token builtin">int</span><span class="token punctuation">(</span>hour<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token format-spec">]</span><span class="token punctuation">}</span></span><span class="token string">时 </span><span class="token interpolation"><span class="token punctuation">{<!-- --></span>minute<span class="token punctuation">}</span></span><span class="token string">'</span></span>
<span class="token keyword">def</span> <span class="token function">get_month_day</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
month <span class="token operator">=</span> number_to_chinese<span class="token punctuation">(</span>self<span class="token punctuation">.</span>now<span class="token punctuation">.</span>month<span class="token punctuation">)</span>
day <span class="token operator">=</span> number_to_chinese<span class="token punctuation">(</span>self<span class="token punctuation">.</span>now<span class="token punctuation">.</span>day<span class="token punctuation">)</span>
<span class="token keyword">return</span> month<span class="token punctuation">,</span> day
<span class="token comment"># 定义一个返回星期几的函数</span>
<span class="token keyword">def</span> <span class="token function">get_weekday</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
date <span class="token operator">=</span> self<span class="token punctuation">.</span>now<span class="token punctuation">.</span>strftime<span class="token punctuation">(</span><span class="token string">'%Y-%m-%d'</span><span class="token punctuation">)</span>
<span class="token comment"># 将日期转换为datetime对象</span>
datetime_obj <span class="token operator">=</span> datetime<span class="token punctuation">.</span>datetime<span class="token punctuation">.</span>strptime<span class="token punctuation">(</span>date<span class="token punctuation">,</span> <span class="token string">'%Y-%m-%d'</span><span class="token punctuation">)</span>
<span class="token comment"># 获取星期几的数字(0代表星期日,1代表星期一,...,6代表星期六)</span>
weekday <span class="token operator">=</span> datetime_obj<span class="token punctuation">.</span>strftime<span class="token punctuation">(</span><span class="token string">'%w'</span><span class="token punctuation">)</span>
<span class="token comment"># 将星期几数字转换为中文星期几</span>
weekdays <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'星期日'</span><span class="token punctuation">,</span> <span class="token string">'星期一'</span><span class="token punctuation">,</span> <span class="token string">'星期二'</span><span class="token punctuation">,</span> <span class="token string">'星期三'</span><span class="token punctuation">,</span> <span class="token string">'星期四'</span><span class="token punctuation">,</span> <span class="token string">'星期五'</span><span class="token punctuation">,</span> <span class="token string">'星期六'</span><span class="token punctuation">]</span>
weekday_cn <span class="token operator">=</span> weekdays<span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">(</span>weekday<span class="token punctuation">)</span>
<span class="token keyword">return</span> weekday_cn
# 定义一个数字转成汉字的函数
def number_to_chinese(number):
units = [‘’, ‘十’]
digits = [‘零’, ‘一’, ‘二’, ‘三’, ‘四’, ‘五’, ‘六’, ‘七’, ‘八’, ‘九’]
<span class="token keyword">if</span> number <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token string">'零'</span>
result <span class="token operator">=</span> <span class="token string">''</span>
digit_count <span class="token operator">=</span> <span class="token number">0</span>
last_zero <span class="token operator">=</span> <span class="token boolean">True</span>
<span class="token keyword">while</span> number <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">:</span>
digit <span class="token operator">=</span> number <span class="token operator">%</span> <span class="token number">10</span>
number <span class="token operator">//=</span> <span class="token number">10</span>
<span class="token keyword">if</span> digit <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">:</span>
result <span class="token operator">=</span> digits<span class="token punctuation">[</span>number<span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">'十'</span>
<span class="token keyword">break</span>
<span class="token keyword">if</span> digit <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">:</span>
<span class="token keyword">if</span> last_zero<span class="token punctuation">:</span>
result <span class="token operator">=</span> digits<span class="token punctuation">[</span>digit<span class="token punctuation">]</span> <span class="token operator">+</span> result
<span class="token keyword">else</span><span class="token punctuation">:</span>
result <span class="token operator">=</span> digits<span class="token punctuation">[</span>digit<span class="token punctuation">]</span> <span class="token operator">+</span> units<span class="token punctuation">[</span>digit_count<span class="token punctuation">]</span> <span class="token operator">+</span> result
last_zero <span class="token operator">=</span> <span class="token boolean">False</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
<span class="token keyword">if</span> <span class="token keyword">not</span> last_zero<span class="token punctuation">:</span>
result <span class="token operator">=</span> digits<span class="token punctuation">[</span>digit<span class="token punctuation">]</span> <span class="token operator">+</span> result
last_zero <span class="token operator">=</span> <span class="token boolean">True</span>
digit_count <span class="token operator">+=</span> <span class="token number">1</span>
<span class="token keyword">return</span> result
# 实例化一个早中晚的对象
morning_noon_evening = PeriodDay()
# 获取当前的时段
time_of_day = morning_noon_evening.get_time_of_day()
# 利用当前时间提取月,日,时,分
month, day = morning_noon_evening.get_month_day()
# 将时:分转成汉字
text_time = morning_noon_evening.format_time_final()
# 要报时的文字
time_text = f"{
time_of_day}好,现在是{
month}月{
day}日 {
week_day} 北京时间{
text_time}。在干嘛?"
# 定义一个转成语音的文字列表变量
texts = [time_text]
print(time_text)
# 生成语音
wavs = chat.infer(texts, use_decoder=True)
# 播放语音
Audio(wavs[0], rate=24_000, autoplay=True)
运行效果如下:
INFO:ChatTTS.core:All initialized.
下午好,现在是五月三十一日 星期五 北京时间十四时 一十一分。在干嘛?
10%|████▏ | 38/384 [00:00<00:09, 38.29it/s]
15%|██████ | 309/2048 [00:05<00:32, 53.73it/s]