单词发音,为语音识别准备素材

环境

这里我用的是python3.7.9。pycharm编译器。windows系统。

windows下安装pyttsx3

pip install pyttsx3

linux下安装pyttsx3

linux下安装pyttsx3时,要先安装两个插件,要不用起来会报错
sudo apt-get install alsa-utils
sudo apt-get install espeak
pip install pyttsx3

界面展示

图形化界面

图形化界面,很简陋的一个
在这里插入图片描述

输出文档

是我做好之后的音频素材文档
在这里插入图片描述
保存单词的word.txt
在这里插入图片描述
单词发音
在这里插入图片描述

写作过程

1.导入相关包。
os,用来进行文件的读写。re,正则匹配。pyttsx3,文字读语音。

import os
import tkinter
from tkinter.filedialog import *
from tkinter import ttk
import pyttsx3
import re

2.这里我准备了一个类来做图形化界面,函数功能也直接在类里面实现了。结果就是看起来十分臃肿,一点都不美观。不过这解决了函数放在类外面出现的一些问题。比如说变量调用很麻烦之类的。

里面变量有些数字大的在前面,这是因为我写的时候是按照从小到大开始写的,但刚开始有些功能没有想明白,把新代码插在了中间。

self.path: 存放文件的输入框
self.path1: 单词的输入框
self.language: 选择发音
self.prompt_statement: 提示语句
self.batch_file: 批文件的输入框。文件里面存放多个英文单词
self.words: 文件里面的单词数量

class painting():
    def __init__(self):
        self.app1 = tkinter.Tk()
        self.app1.title("单词音频保存")
        self.app1.geometry("760x430")

        self.path = tkinter.StringVar()
        self.path1 = tkinter.StringVar()
        self.languages = tkinter.StringVar()
        self.prompt_statement = tkinter.StringVar()
        self.prompt_statement.set('提示语句!')
        self.batch_file = tkinter.StringVar()
        self.words = []
        # 初始化输入框
        # self.path.set(os.path.abspath('.'))

        self.label1 = tkinter.Label(self.app1, text="单词:", width=9).place(x=70, y=30)
        self.entry1 = tkinter.Entry(self.app1, width=50, textvariable=self.path1).place(x=130, y=30)
        self.button1 = tkinter.Button(self.app1, text="下载", command=self.audio_save).place(x=500, y=25)

        self.label4 = tkinter.Label(self.app1, text="批量下载:", width=9).place(x=70, y=65)
        self.entry4 = tkinter.Entry(self.app1, textvariable=self.batch_file, width=50).place(x=130, y=65)
        self.button4 = tkinter.Button(self.app1, text="批量导入", command=self.batch_load).place(x=500, y=65)
        self.button5 = tkinter.Button(self.app1, text="批量下载", command=self.batch_save).place(x=580, y=65)

        self.label2 = tkinter.Label(self.app1, text="保存目录:", width=9).place(x=70, y=100)
        self.entry2 = tkinter.Entry(self.app1, width=50, textvariable=self.path).place(x=130, y=100)
        self.button2 = tkinter.Button(self.app1, text="选择目录", command=self.output_file_path).place(x=500, y=100)

        self.label3 = tkinter.Label(self.app1, text="发音语言:", width=9).place(x=70, y=150)
        self.values = ["Chinese", "English"]
        self.dropdown_box = ttk.Combobox(values=self.values, textvariable=self.languages).place(x=130, y=150)

        self.label4 = tkinter.Label(self.app1, textvariable=self.prompt_statement).place(x=200, y=200)
        self.app1.mainloop()

3.图像化界面创建好了,接下来就可以写功能了。以下功能写在类里面。
定义输出文件。

# 定义输出文件
    def output_file_path(self):
        # 打开文件
        # file_name=str(askopenfile())[25:-28]
        # 选择文件夹
        file_path = askdirectory()
        self.path.set(file_path)
        # print(file_path)

检查文字与发音选择是否对应:

    # 检测发音
    def detect_languages(self):
        language = self.languages.get()
        if language == "Chinese":
            if not self.is_Chinese(self.path1.get()):
                # print('不是中文!')
                self.prompt_statement.set('不是中文')
                return False
            return "Chinese"
        elif language == "English":
            return "English"
        else:
            # print('发音选择错误,请重新开始选择!')
            self.prompt_statement.set('发音选择错误,请重新开始选择!')
            return False

里面用到了判断是否是中文的函数。这是因为在linux下中文如果用不小心用了英文发音器,只会发出letter,letter的声音。很不友好。

# 判断是否中文
    def is_Chinese(self, word):
        for ch in word:
            if '\u4e00' <= ch <= '\u9fff':
                return True
        return False

检查单词长度。这里我们不希望单词太长,对单词长度做了限制。

# 检查单词长度
    def detect_word_length(self):
        word = self.path1.get()
        if len(word) > 10:
            self.prompt_statement.set("单词太长了!")
            return False
        else:
            return word

单词发音,没有储存目录则默认不会存储。

# 单词发音转音频,未选择保存目录则只发音不保存音频
    def word_to_audio(self, word, output_path, language):
        engine = pyttsx3.init()
        # 增大音量
        volume = engine.getProperty('volume')
        volume = engine.setProperty('volume', volume + 10)
        # 选择是否中文
        if language == "Chinese":
            voices = engine.getProperty('voices')
            engine.setProperty('voice', voices[0].id)
            engine.say(word)
            engine.save_to_file(word, output_path)
            # print("language:","Chinese")
            self.prompt_statement.set("Language: Chinese")
        else:
            # 默认英文。
            voices = engine.getProperty('voices')
            engine.setProperty('voice', voices[1].id)
            engine.say(word)
            engine.save_to_file(word, output_path)
            # print("language:", "English")
            self.prompt_statement.set("Language:English")
        engine.runAndWait()

存储文件的路径问题:

# 发音保存
    def audio_save(self):
        word = self.detect_word_length()
        if word:
            word_save_folder = self.path.get() + "/" + word
            if os.path.exists(word_save_folder):
                word_save_path = word_save_folder + '/' + word + '.wav'
            else:
                os.mkdir(word_save_folder)
                word_save_path = word_save_folder + '/' + word + '.wav'
        language = self.detect_languages()
        if language:
            # print(language)
            # print(word,word_save_path,"English")
            self.word_to_audio(word, word_save_path, language)
        else:
            return False

4.一个个单词发音太麻烦了。这里,我选择从文本导入英文单词,执行发音函数。当然,也可以选择从网上爬取英文单词和音频。不过我爬虫学的不怎么好,这里就不献丑了。
这里我只选择了前四个单词作输入。我单词文本第一行不是英文。

# 批量导入英文单词
    def batch_load(self):
        file_path = askopenfilename()
        self.batch_file.set(file_path)
        file_name = self.batch_file.get()
        f = open(file_name, 'r', encoding='utf-8')
        try:
            content = f.readlines()[1:5]
            for i in range(len(content)):
                word = re.match(r'[A-Za-z0-9]*', content[i])
                self.words.append(word.group(0))
        finally:
            f.close()
        print(self.words)

批量保存:

# 批量下载
    def batch_save(self):
        if not self.words:
            # print('没有单词')
            self.prompt_statement.set("没有单词!")
            return False
        if self.path.get() == '':
            self.prompt_statement.set('批量下载输出路径没有定义!')
            return False
        for word in self.words:
            word_save_folder = self.path.get() + "/" + word
            if os.path.exists(word_save_folder):
                word_save_path = word_save_folder + '/' + word + '.wav'
            else:
                os.mkdir(word_save_folder)
                word_save_path = word_save_folder + '/' + word + '.wav'
            self.word_to_audio(word, word_save_path, 'English')

注意事项

1.在创建图像化界面的时候,点击函数对应的功能。记住函数后面不能带"()"。否则打开图像化界面,按钮就被默认点击了一次,里面的函数也会同步执行一次。
错误:self.button1 = tkinter.Button(self.app1, text=“下载”, command=self.audio_save()).place(x=500, y=25)
正确:self.button1 = tkinter.Button(self.app1, text=“下载”, command=self.audio_save).place(x=500, y=25)

2.在linux执行保存音频的时候,出现了错误。查找之后发现是python版本的问题。**python3.7以下不能用pyttsx3保存音频。**由于我做机器学习linux下的python版本用的是python3.6,所以这个准备素材的活在Windows下写了。

3.Linux下选择中文发音器时。普通话中文发音器是倒数第二个,而windows下是第一个。

voices = engine.getProperty('voices')
engine.setProperty('voice', voices[-2].id)

完整代码

# tkinter进行图像化设计
import os
import tkinter
from tkinter.filedialog import *
from tkinter import ttk
import pyttsx3
import re


class painting():
    def __init__(self):
        self.app1 = tkinter.Tk()
        self.app1.title("单词音频保存")
        self.app1.geometry("760x430")

        self.path = tkinter.StringVar()
        self.path1 = tkinter.StringVar()
        self.languages = tkinter.StringVar()
        self.prompt_statement = tkinter.StringVar()
        self.prompt_statement.set('提示语句!')
        self.batch_file = tkinter.StringVar()
        self.words = []
        # 初始化输入框
        # self.path.set(os.path.abspath('.'))

        self.label1 = tkinter.Label(self.app1, text="单词:", width=9).place(x=70, y=30)
        self.entry1 = tkinter.Entry(self.app1, width=50, textvariable=self.path1).place(x=130, y=30)
        self.button1 = tkinter.Button(self.app1, text="下载", command=self.audio_save).place(x=500, y=25)

        self.label4 = tkinter.Label(self.app1, text="批量下载:", width=9).place(x=70, y=65)
        self.entry4 = tkinter.Entry(self.app1, textvariable=self.batch_file, width=50).place(x=130, y=65)
        self.button4 = tkinter.Button(self.app1, text="批量导入", command=self.batch_load).place(x=500, y=65)
        self.button5 = tkinter.Button(self.app1, text="批量下载", command=self.batch_save).place(x=580, y=65)

        self.label2 = tkinter.Label(self.app1, text="保存目录:", width=9).place(x=70, y=100)
        self.entry2 = tkinter.Entry(self.app1, width=50, textvariable=self.path).place(x=130, y=100)
        self.button2 = tkinter.Button(self.app1, text="选择目录", command=self.output_file_path).place(x=500, y=100)

        self.label3 = tkinter.Label(self.app1, text="发音语言:", width=9).place(x=70, y=150)
        self.values = ["Chinese", "English"]
        self.dropdown_box = ttk.Combobox(values=self.values, textvariable=self.languages).place(x=130, y=150)

        self.label4 = tkinter.Label(self.app1, textvariable=self.prompt_statement).place(x=200, y=200)
        self.app1.mainloop()

    # 检查单词长度
    def detect_word_length(self):
        word = self.path1.get()
        if len(word) > 10:
            self.prompt_statement.set("单词太长了!")
            return False
        else:
            return word

    # 判断是否中文
    def is_Chinese(self, word):
        for ch in word:
            if '\u4e00' <= ch <= '\u9fff':
                return True
        return False

    # 检测发音
    def detect_languages(self):
        language = self.languages.get()
        if language == "Chinese":
            if not self.is_Chinese(self.path1.get()):
                # print('不是中文!')
                self.prompt_statement.set('不是中文')
                return False
            return "Chinese"
        elif language == "English":
            return "English"
        else:
            # print('发音选择错误,请重新开始选择!')
            self.prompt_statement.set('发音选择错误,请重新开始选择!')
            return False

    # 单词发音转音频,未选择保存目录则只发音不保存音频
    def word_to_audio(self, word, output_path, language):
        engine = pyttsx3.init()
        # 增大音量
        volume = engine.getProperty('volume')
        volume = engine.setProperty('volume', volume + 10)
        # 选择是否中文
        if language == "Chinese":
            voices = engine.getProperty('voices')
            engine.setProperty('voice', voices[0].id)
            engine.say(word)
            engine.save_to_file(word, output_path)
            # print("language:","Chinese")
            self.prompt_statement.set("Language: Chinese")
        else:
            # 默认英文。
            voices = engine.getProperty('voices')
            engine.setProperty('voice', voices[1].id)
            engine.say(word)
            engine.save_to_file(word, output_path)
            # print("language:", "English")
            self.prompt_statement.set("Language:English")
        engine.runAndWait()

    # 发音保存
    def audio_save(self):
        word = self.detect_word_length()
        if word:
            word_save_folder = self.path.get() + "/" + word
            if os.path.exists(word_save_folder):
                word_save_path = word_save_folder + '/' + word + '.wav'
            else:
                os.mkdir(word_save_folder)
                word_save_path = word_save_folder + '/' + word + '.wav'
        language = self.detect_languages()
        if language:
            # print(language)
            # print(word,word_save_path,"English")
            self.word_to_audio(word, word_save_path, language)
        else:
            return False

    # 定义输出文件
    def output_file_path(self):
        # 打开文件
        # file_name=str(askopenfile())[25:-28]
        # 选择文件夹
        file_path = askdirectory()
        self.path.set(file_path)
        # print(file_path)

    # 批量导入英文单词
    def batch_load(self):
        file_path = askopenfilename()
        self.batch_file.set(file_path)
        file_name = self.batch_file.get()
        f = open(file_name, 'r', encoding='utf-8')
        try:
            content = f.readlines()[1:5]
            for i in range(len(content)):
                word = re.match(r'[A-Za-z0-9]*', content[i])
                self.words.append(word.group(0))
        finally:
            f.close()
        print(self.words)

    # 批量下载
    def batch_save(self):
        if not self.words:
            # print('没有单词')
            self.prompt_statement.set("没有单词!")
            return False
        if self.path.get() == '':
            self.prompt_statement.set('批量下载输出路径没有定义!')
            return False
        for word in self.words:
            word_save_folder = self.path.get() + "/" + word
            if os.path.exists(word_save_folder):
                word_save_path = word_save_folder + '/' + word + '.wav'
            else:
                os.mkdir(word_save_folder)
                word_save_path = word_save_folder + '/' + word + '.wav'
            self.word_to_audio(word, word_save_path, 'English')


if __name__ == '__main__':
    painting()