阿里云语音合成(汉语英语)带UI界面的小程序(python)
一,项目说明
将汉文转汉语、英文转英语,同时又有逗号<###English###>,<,,,>和句号<...>标志符用于文件处理。其中英文包含在### 英文 ###中。
程序A:三个逗号<,,,>和三个句号<...>前面的句段独立成块小分段,同时三个句号<...>前面的句段划分成为另一种较大的分段。其中程序中有控制<,,,>和<...>重复次数的数值
程序A输入样例1:
1 ###bring###拿来,带来,,, 2 ###Bronze###青铜色的... 3 ###brush###刷;檫,,, 4 ###build###建筑;造,,, 5 ###building###建筑物;房屋;大楼...
程序A输出样例1:(下文为音频发音的内容)
1 bring拿来,带来bring拿来,带来 2 Bronze青铜色的Bronze青铜色的 3 4 bring拿来,带来Bronze青铜色的 5 6 brush刷;檫brush刷;檫 7 build建筑;造build建筑;造 8 building建筑物;房屋;大楼building建筑物;房屋;大楼 9 10 brush刷;檫build建筑;造building建筑物;房屋;大楼 11 12 bring拿来,带来Bronze青铜色的brush刷;檫build建筑;造building建筑物;房屋;大楼
程序B输入样例1:
###bring###拿来,带来,,, ###Bronze###青铜色的... ###brush###刷;檫,,, ###build###建筑;造,,, ###building###建筑物;房屋;大楼...
程序B输出样例1:(下文为音频发音的内容)
1 bring拿来,带来bring拿来,带来bring拿来,带来 2 3 Bronze青铜色的 4 5 brush刷;檫brush刷;檫brush刷;檫 6 build建筑;造build建筑;造造build建筑;造 7 8 building建筑物;房屋;大楼 9 10 bring拿来,带来Bronze青铜色的brush刷;檫build建筑;造building建筑物;房屋;大楼
备注:上文中的程序A、程序B都是使用的默认配置
二,界面解析
图1 主界面
图2 文本导入界面(支持txt和docx文件格式)
图3 参数设置界面
图4 近期调用统计图(更新2019-06-16,尾款到手不再更新)
三,源码开放
界面显示(主函数) ui2show.pyw
1 import tkinter as tk 2 import netWork 3 import split2summary 4 import tkinter.filedialog 5 import os 6 import shutil 7 import docx 8 from configobj import ConfigObj 9 from tkinter import ttk 10 from tkinter import messagebox 11 import struct 12 13 14 class ui2show(tk.Tk): 15 def __init__(self): 16 super().__init__() 17 18 rootPath = os.path.split(os.path.realpath(__file__))[0] 19 os.chdir(rootPath) 20 self.dictSpace = {0: 'chinese', 1: 'english'} 21 22 # *** 系统初始化检测网络 *** # 23 self.netWork = netWork.netWork() 24 self.netState, self.textShow = self.netWork.isConnected() 25 26 # *** 提前加载功能库 *** # 27 self.split2summary = split2summary.split2summary() 28 self.config = ConfigObj("config.ini", encoding='UTF8') 29 #print(self.config) 30 31 self.vartext = tk.StringVar() 32 self.vartext.set(self.textShow) 33 self.geometry('597x100') 34 self.resizable(0, 0) 35 self.title('文字处理&音频合成') 36 self.fileFeedback = [] 37 38 self.homePage() 39 40 def homePage(self): # 默认主页 41 self.top1 = tk.Frame() 42 self.top1.pack(fill="x") 43 44 tk.Button(self.top1, text='文本导入', width=27, command=self.file4manage).grid(row=0, column=0) 45 tk.Button(self.top1, text='参数设置', width=27, command=self.config4set).grid(row=0, column=1) 46 tk.Button(self.top1, text='音频合成', width=27, command=self.txt2run).grid(row=0, column=2) 47 tk.Label(self.top1, height=3, textvariable=self.vartext, bg='white', font=('黑体', 10), anchor='w').grid(row=1, 48 column=0, 49 columnspan=3) 50 51 def file4manage(self): # 文件初始化 成功√ 52 path = tkinter.filedialog.askopenfilename(initialdir='C:\\Users\\Administrator\\Desktop', filetypes=( 53 ("txt or docx files", "*.txt;*.docx"), ("All files", "*.*"))) 54 if path == "": 55 self.fileState, self.textShow, self.fileFeedback = False, '未导入任何文件', [] 56 else: # 已导入文件 57 p, f = os.path.split(path) 58 path_directory = os.path.dirname(os.path.realpath(__file__)) + '\\data\\' + str(os.path.splitext(f)[0]) 59 isExists = os.path.exists(path_directory) 60 if not isExists: # 如果不存在这个目录 61 os.makedirs(path_directory) # 创建一个新的路径 62 shutil.copyfile(path, path_directory + '\\' + f) 63 64 if str(os.path.splitext(f)[1]) == '.txt': 65 file_object = open(path, 'r') 66 file_context = file_object.read() 67 file_object.close() 68 69 elif str(os.path.splitext(f)[1]) == '.docx': 70 document = docx.Document(path) 71 file_context = '' 72 for paragraph in document.paragraphs: 73 file_context += paragraph.text 74 self.fileState, self.textShow, self.fileFeedback = True, '已导入文本数据', [path_directory, file_context] 75 self.vartext.set(self.textShow) 76 77 def config4set(self): # 参数配置界面 78 self.top2 = tk.Toplevel() 79 self.top2.title('参数配置') 80 81 self.txtShow = [] # 直接全部设置成int型文件 82 for i in range(16): 83 if i == 11 or 15: 84 self.txtShow.append(tk.StringVar()) 85 else: 86 self.txtShow.append(tk.IntVar()) 87 88 txtShow = [] 89 #print(self.config['txtA']) 90 txtA = self.config['txtA'] 91 for i in enumerate(txtA['name']): 92 txtShow.append(int(txtA[i[1]])) 93 txtB = self.config['txtB'] 94 for i in enumerate(txtB['name']): 95 txtShow.append(int(txtB[i[1]])) 96 txtC = self.config['chinese'] 97 for i in enumerate(txtC['name']): 98 txtShow.append(int(txtC[i[1]])) 99 txtD = self.config['english'] 100 for i in enumerate(txtD['name']): 101 txtShow.append(int(txtD[i[1]])) 102 103 # print(txtShow) 104 for keyi, valuei in enumerate(txtShow): 105 self.txtShow[keyi].set(valuei) 106 107 tk.Label(self.top2, text='程序A', width=30).grid(row=0, column=0, columnspan=2) 108 tk.Label(self.top2, text='逗号次数', width=10).grid(row=1, column=0, columnspan=1) 109 tk.Label(self.top2, text='句号次数', width=10).grid(row=2, column=0, columnspan=1) 110 tk.Label(self.top2, text='全部文本次数', width=10).grid(row=3, column=0, columnspan=1) 111 tk.Label(self.top2, text='是否生成音频', width=10).grid(row=4, column=0, columnspan=1) 112 tk.Entry(self.top2, textvariable=self.txtShow[0], width=10).grid(row=1, column=1) 113 tk.Entry(self.top2, textvariable=self.txtShow[1], width=10).grid(row=2, column=1) 114 tk.Entry(self.top2, textvariable=self.txtShow[2], width=10).grid(row=3, column=1) 115 checkA = tk.Checkbutton(self.top2, text="是", variable=self.txtShow[3], width=10) 116 checkA.select() 117 checkA.grid(column=1, row=4, sticky=tk.W) 118 119 tk.Label(self.top2, text='程序B', width=30).grid(row=0, column=2, columnspan=2) 120 tk.Label(self.top2, text='逗号次数', width=10).grid(row=1, column=2, columnspan=1) 121 tk.Label(self.top2, text='句号次数', width=10).grid(row=2, column=2, columnspan=1) 122 tk.Label(self.top2, text='全部文本次数', width=10).grid(row=3, column=2, columnspan=1) 123 tk.Label(self.top2, text='是否生成音频', width=10).grid(row=4, column=2, columnspan=1) 124 tk.Entry(self.top2, textvariable=self.txtShow[4], width=10).grid(row=1, column=3) 125 tk.Entry(self.top2, textvariable=self.txtShow[5], width=10).grid(row=2, column=3) 126 tk.Entry(self.top2, textvariable=self.txtShow[6], width=10).grid(row=3, column=3) 127 checkB = tk.Checkbutton(self.top2, text="是", variable=self.txtShow[7], width=10) 128 checkB.select() 129 checkB.grid(column=3, row=4, sticky=tk.W) 130 131 tk.Label(self.top2, text='汉语', width=10).grid(row=0, column=4, columnspan=2) 132 tk.Label(self.top2, text='音量', width=10).grid(row=1, column=4, columnspan=1) 133 tk.Label(self.top2, text='语速', width=10).grid(row=2, column=4, columnspan=1) 134 tk.Label(self.top2, text='语调', width=10).grid(row=3, column=4, columnspan=1) 135 tk.Label(self.top2, text='发言人', width=10).grid(row=4, column=4, columnspan=1) 136 tk.Entry(self.top2, textvariable=self.txtShow[8], width=13).grid(row=1, column=5) 137 tk.Entry(self.top2, textvariable=self.txtShow[9], width=13).grid(row=2, column=5) 138 tk.Entry(self.top2, textvariable=self.txtShow[10], width=13).grid(row=3, column=5) 139 chosenC = ttk.Combobox(self.top2, textvariable=self.txtShow[11], width=10) 140 chosenC['values'] = ( 141 'Xiaoyun', 'Xiaogang', 'Ruoxi', 'Xiaomeng', 'Xiaowei', 'Amei', 'Xiaoxue', 'Siqi', 'Sijia', 'Sicheng', 142 'Siyue', 143 'Xiaomei', 'Sitong', 'Ninger', 'Xiaobei', 'Yina', 'Sijing', 'Shanshan') 144 chosenC.current(txtShow[11]) 145 chosenC.grid(row=4, column=5) 146 147 tk.Label(self.top2, text='英语', width=10).grid(row=0, column=6, columnspan=2) 148 tk.Label(self.top2, text='音量', width=10).grid(row=1, column=6, columnspan=1) 149 tk.Label(self.top2, text='语速', width=10).grid(row=2, column=6, columnspan=1) 150 tk.Label(self.top2, text='语调', width=10).grid(row=3, column=6, columnspan=1) 151 tk.Label(self.top2, text='发言人', width=10).grid(row=4, column=6, columnspan=1) 152 tk.Entry(self.top2, textvariable=self.txtShow[12], width=13).grid(row=1, column=7) 153 tk.Entry(self.top2, textvariable=self.txtShow[13], width=13).grid(row=2, column=7) 154 tk.Entry(self.top2, textvariable=self.txtShow[14], width=13).grid(row=3, column=7) 155 chosenD = ttk.Combobox(self.top2, textvariable=self.txtShow[15], width=10) 156 chosenD['values'] = ('Wendy', 'William', 'Halen', 'Harry') 157 chosenD.current(txtShow[15]) 158 chosenD.grid(row=4, column=7) 159 160 tk.Button(self.top2, text='确定', command=self.config2ok, width=27).grid(row=5, column=0, columnspan=2) 161 tk.Button(self.top2, text='重置', command=self.config2reset, width=27).grid(row=5, column=2, columnspan=2) 162 tk.Button(self.top2, text='帮助', command=self.config2help, width=27).grid(row=5, column=4, columnspan=2) 163 164 # for keyi,valuei in enumerate(txtShow): 165 self.txtShow[3].set(txtShow[3]) 166 self.txtShow[7].set(txtShow[7]) 167 168 def config2ok(self): # 参数设置-成功√ 169 txtShow = [] 170 for i in self.txtShow: 171 txtShow.append(i.get()) 172 173 txtShow[11] = self.config['chinese']['voice_parameter'].index(txtShow[11]) 174 txtShow[15] = self.config['english']['voice_parameter'].index(txtShow[15]) 175 # print('txtShow:',txtShow[3],txtShow[7]) 176 177 for i in enumerate(txtShow[:4]): 178 self.config['txtA'][self.config['txtA']['name'][i[0]]] = i[1] 179 for i in enumerate(txtShow[4:8]): 180 self.config['txtB'][self.config['txtB']['name'][i[0]]] = i[1] 181 for i in enumerate(txtShow[8:12]): 182 self.config['chinese'][self.config['chinese']['name'][i[0]]] = i[1] 183 for i in enumerate(txtShow[12:16]): 184 self.config['english'][self.config['english']['name'][i[0]]] = i[1] 185 self.config.write() 186 187 def config2reset(self): # 恢复出厂设置 成功√ 188 for i in ['txtA', 'txtB', 'chinese', 'english']: 189 for j in self.config[i]['name']: 190 self.config[i][j] = self.config[i]['default_' + j][1] 191 self.config.write() 192 193 txtShow = [] # 获取最新的参数配置并更新界面数据 194 txtA = self.config['txtA'] 195 for i in enumerate(txtA['name']): 196 txtShow.append(int(txtA[i[1]])) 197 txtB = self.config['txtB'] 198 for i in enumerate(txtB['name']): 199 txtShow.append(int(txtB[i[1]])) 200 txtC = self.config['chinese'] 201 for i in enumerate(txtC['name']): 202 txtShow.append(int(txtC[i[1]])) 203 txtD = self.config['english'] 204 for i in enumerate(txtD['name']): 205 txtShow.append(int(txtD[i[1]])) 206 207 for keyi, valuei in enumerate(txtShow): 208 self.txtShow[keyi].set(valuei) 209 self.txtShow[11].set(self.config['chinese']['voice_parameter'][txtShow[11]]) 210 self.txtShow[15].set(self.config['english']['voice_parameter'][txtShow[15]]) 211 212 def config2help(self): 213 tk.messagebox.showinfo("参数设置帮助", "语音合成参数设置范围:\n1,音量范围0~100;\n2,语速范围-500~500;\n3,语调范围-500~500;") 214 215 def txt2run(self): 216 if len(self.fileFeedback) == 0: 217 self.textShow = '没有导入文本文件\n请先进行{文本导入}' 218 self.vartext.set(self.textShow) 219 else: # 已正常导入【路径,文本】 220 # self.dictSpace 221 dataASet = [] 222 for i in self.config['txtA']['name']: 223 dataASet.append(int(self.config['txtA'][i])) 224 dataBSet = [] 225 for i in self.config['txtB']['name']: 226 dataBSet.append(int(self.config['txtB'][i])) 227 if dataASet[-1]+dataBSet[-1]==0: 228 self.textShow='设置中未勾选{是否生成音频}\n请先勾选相关选项再做操作' 229 self.vartext.set(self.textShow) 230 return None 231 txt_value, txt_state = self.split2summary.txt2split(self.fileFeedback[1]) 232 self.textShow = '正在将文字转化为音频...' 233 self.vartext.set(self.textShow) 234 for keyi, valuei in enumerate(txt_value): 235 for keyj, valuej in enumerate(valuei): 236 for keyk, valuek in enumerate(valuej): 237 txt_value[keyi][keyj][keyk] = self.netWork.txt2audio(txt_value[keyi][keyj][keyk], 238 self.dictSpace[ 239 txt_state[keyi][keyj][keyk]]) 240 241 # *** 合成音频完整性测试 *** # 测试成功√ 242 # audioTest=[] 243 # for keyi, valuei in enumerate(txt_value): # 句号 244 # for keyj, valuej in enumerate(valuei): 245 # for keyk, valuek in enumerate(valuej): 246 # pathTest = self.fileFeedback[0] + '\\' + self.fileFeedback[0].split('\\')[-1] + str(keyi)+str(keyj)+str(keyk) +'Test.wav' 247 # with open(pathTest, mode='wb') as f: 248 # f.write(txt_value[keyi][keyj][keyk]) 249 250 # *** 音频文件合并成逗号分段 *** # 251 wav_format = txt_value[0][0][0][:44] # wav音频文件的帧头信息,后续保存文件需要进行二次修改 252 for keyi, valuei in enumerate(txt_value): # 句号 253 for keyj, valuej in enumerate(valuei): 254 # str_comma = [] 255 for keyk, valuek in enumerate(valuej): 256 if keyk == 0: 257 str_comma = txt_value[keyi][keyj][keyk] 258 else: 259 str_comma += txt_value[keyi][keyj][keyk][44:] 260 txt_value[keyi][keyj] = str_comma 261 262 # *** 合成音频英汉合并完整性测试 *** # 测试成功√ 263 # audioTest=[] 264 # for keyi, valuei in enumerate(txt_value): # 句号 265 # for keyj, valuej in enumerate(valuei): 266 # pathTest = self.fileFeedback[0] + '\\' + self.fileFeedback[0].split('\\')[-1] + 'comma'+str(keyi)+str(keyj)+'Test.wav' 267 # with open(pathTest, mode='wb') as f: 268 # f.write(txt_value[keyi][keyj]) 269 270 # *** 程序A *** # 271 if dataASet[-1]: 272 self.textShow = '正在生成音频A' 273 self.vartext.set(self.textShow) 274 # print('runA',dataASet) 275 pathA = self.fileFeedback[0] + '\\' + self.fileFeedback[0].split('\\')[-1] + 'A.wav' 276 audioA = self.split2summary.programA(txt_value, dataASet) 277 278 audioA_len = len(audioA) 279 wav_format = wav_format[:4] + struct.pack('<L', audioA_len + 44) + wav_format[8:] 280 wav_format = wav_format[:40] + struct.pack('<L', audioA_len) + wav_format[44:] 281 with open(pathA, mode='wb') as f: 282 f.write(wav_format + audioA) 283 self.textShow = '已生成音频A' 284 self.vartext.set(self.textShow) 285 286 # *** 程序B *** # 287 if dataBSet[-1]: 288 self.textShow += '正在成音频B' 289 self.vartext.set(self.textShow) 290 291 pathB = self.fileFeedback[0] + '\\' + self.fileFeedback[0].split('\\')[-1] + 'B.wav' 292 audioB = self.split2summary.programB(txt_value, dataBSet) 293 294 audioB_len = len(audioB) 295 wav_format = wav_format[:4] + struct.pack('<L', audioB_len + 44) + wav_format[8:] 296 wav_format = wav_format[:40] + struct.pack('<L', audioB_len) + wav_format[44:] 297 with open(pathB, mode='wb') as f: 298 f.write(wav_format + audioB) 299 300 if dataASet[-1] and dataBSet[-1]: 301 self.textShow='已合成音频A、B' 302 elif dataBSet[-1]: 303 self.textShow = '已合成音频B' 304 elif dataASet[-1]: 305 self.textShow = '已合成音频A' 306 307 self.vartext.set(self.textShow) 308 309 if __name__ == '__main__': 310 # *** 测试ui界面显示 *** # 311 ui2show = ui2show() 312 ui2show.mainloop()
网络相关支持函数 netWork.pyw
1 #-*- coding:utf-8 -*- 2 from configobj import ConfigObj # config.ini参数操作函数 3 import urllib.parse 4 import requests # 网络操作函数 5 import http.client 6 from aliyunsdkcore.client import AcsClient 7 from aliyunsdkcore.request import CommonRequest 8 import json 9 import datetime 10 11 # *** 网络连接函数 *** # 12 class netWork: 13 # def __init__(self): 14 # pass 15 16 def isConnected(self): # 检测网络是否已正常连接 17 try: 18 html = requests.get("https://www.baidu.com/", timeout=2) 19 except: 20 return False, '无法连接网络,请检查网络是否正常连接' 21 return True, '网络连接正常' 22 23 def getToken(self): # 获取token值,后续需要在version3.0解决 24 config = ConfigObj("config.ini", encoding='UTF8') 25 client = AcsClient(config['user']['AccessKeyID'], config['user']['AccessKeySecret'], "cn-shanghai") 26 request = CommonRequest() 27 request.set_method('POST') 28 request.set_domain('nls-meta.cn-shanghai.aliyuncs.com') 29 request.set_version('2019-02-28') 30 request.set_action_name('CreateToken') 31 response = client.do_action_with_exception(request) 32 response = json.loads(str(response, 'utf-8')) 33 return response['Token']['Id'] 34 35 def txt2audio(self, text, type): # 小段文本转音频的程序,输入text、 36 config = ConfigObj("config.ini", encoding='UTF8') 37 if config['user']['nowTime']!=str(datetime.datetime.now())[:10]: # 按天进行token值更新 38 config['user']['nowTime'] = str(datetime.datetime.now())[:10] 39 config['user']['&token'] = self.getToken() 40 config.write() 41 42 conn = http.client.HTTPSConnection(config['user']['host']) 43 du = config['user'] 44 dc = config[type] # 这里分汉文、英文 45 46 url = '' 47 url = 'https://' + du['host'] + '/stream/v1/tts' 48 url = url + '?appkey=' + du['?appkey'] 49 url = url + '&token=' + du['&token'] 50 url = url + '&format=' + du['&format'] 51 url = url + '&sample_rate=' + du['&sample_rate'] 52 url = url + '&voice=' + dc['voice_parameter'][int(dc['&voice'])] 53 url = url + '&volume=' + dc['&volume'] 54 url = url + '&speech_rate=' + dc['&speech_rate'] 55 url = url + '&pitch_rate=' + dc['&pitch_rate'] 56 57 if type == 'chinese': 58 if len(text) < 300: # 满足文本长度要求 59 list_text = [text] 60 else: # 不满足文本长度要求 61 list_text = text.split('.') # 很少有文本能够一段超过300字 62 elif type == 'english': 63 num = len(text.split()) # 英文和汉文不同使用空格区分单词 64 if num < 300: 65 list_text = [text] 66 else: 67 list_text = text.split('.') 68 list_audio = [] 69 for i in list_text: 70 textUrlencode = urllib.parse.quote_plus(i) 71 textUrlencode = textUrlencode.replace("+", "%20") 72 textUrlencode = textUrlencode.replace("*", "%2A") 73 textUrlencode = textUrlencode.replace("%7E", "~") 74 conn.request(method='GET', url=url + '&text=' + textUrlencode) 75 response = conn.getresponse() 76 body = response.read() 77 list_audio.append(body) 78 conn.close() 79 80 audio_all = list_audio[0] 81 if len(list_text) > 1: 82 for i in list_audio[1:]: 83 audio_all += i 84 return audio_all 85 86 87 if __name__ == '__main__': 88 net = netWork() 89 # *** 测试网络连接是否正常 *** # 成功√ 90 netState, feedbackWord=net.isConnected() 91 print(netState, feedbackWord) 92 93 # *** 测试自动获取token值 *** # 成功√ 94 # Token=net.getToken() 95 # print(Token) 96 97 # *** 测试语音合成是否正常 *** # 成功√ 98 # text = '你好,万雨。测试成功' 99 # type = 'chinese' 100 # fileName = 'testAudio1.wav' 101 # audio = net.txt2audio(text, type) 102 # with open(fileName, mode='wb') as f: 103 # f.write(audio)
文本处理相关函数 split2summary.pyw
1 #-*- coding:utf-8 -*- 2 """ 3 函数说明: 4 ①将原始文本进行拆分-合并 5 ②将获得音频进行按要求重复合并 6 7 """ 8 9 10 class split2summary: 11 def findCE(self, text): # 区分汉文英文 12 index = [] 13 for i in range(len(text) - 2): 14 if text[i:i + 3] == '###': 15 index.append(i) 16 # elif text[i:i + 3] == '>>>': 17 # index.append(i) 18 # print(index) 19 if len(index) == 0: 20 return [text], [0] 21 text_list = [] 22 text_state = [] 23 index_history = [0, 0] 24 for key, value in enumerate(index): 25 # print(key,value) 26 if key % 2 == 0: # 汉文 27 if index[key] == 0: 28 continue 29 index_history = [index_history[1], index[key]] 30 if key == 0: 31 text_list.append(text[index_history[0]:index_history[1]]) 32 else: 33 text_list.append(text[index_history[0] + 3:index_history[1]]) 34 text_state.append(0) 35 else: # 英文 36 index_history = [index_history[1], index[key]] 37 text_list.append(text[index_history[0] + 3:index_history[1]]) 38 text_state.append(1) 39 # 解决句尾的问题 40 if index[-1] + 3 != len(text): 41 text_list.append(text[index[-1] + 3:len(text)]) 42 text_state.append(0) 43 return text_list, text_state 44 45 def txt2split(self, text): 46 txt_mid = text.split('...') 47 for i in range(len(txt_mid)): 48 txt_mid[i] = txt_mid[i].split(',,,') 49 txt_value = [] 50 txt_state = [] 51 for i in txt_mid[:-1]: 52 txt_state_mid = [] 53 txt_value_mid = [] 54 for j in i: 55 text_list, text_state = self.findCE(j) 56 txt_value_mid.append(text_list) 57 txt_state_mid.append(text_state) 58 txt_value.append(txt_value_mid) 59 txt_state.append(txt_state_mid) 60 return txt_value, txt_state 61 62 # *** 将最小分段合并一级到逗号分段 *** # 63 def value2comma(self, value): 64 for keyi, valuei in enumerate(value): # 句号 65 for keyj, valuej in enumerate(valuei): 66 for keyk, valuek in enumerate(valuej): 67 if keyk == 0: 68 str_comma = value[keyi][keyj][keyk] 69 else: 70 str_comma += value[keyi][keyj][keyk] 71 value[keyi][keyj] = str_comma 72 return value 73 74 # *** 处理分段函数A 成功√ *** # 75 def programA(self, value, dataASet): 76 valueA = [] 77 for keyi, valuei in enumerate(value): # 句号 78 value_end = [] 79 for keyj, valuej in enumerate(valuei): 80 if keyj == 0 and (dataASet[0] != 0 or dataASet[1] != 0): 81 value_end = value[keyi][keyj] 82 if dataASet[0] != 0: 83 for times in range(dataASet[0] - 1): 84 value_end += value[keyi][keyj] 85 elif dataASet[0] != 0: 86 for times in range(dataASet[0]): 87 value_end += value[keyi][keyj] 88 elif dataASet[1] != 0: 89 value_end += value[keyi][keyj] 90 91 if keyi == 0 and dataASet[0] != 0: 92 valueA = value_end 93 elif dataASet[0] != 0: 94 valueA += value_end 95 96 # *** 专门针对句号分段 *** # 97 # for keyi, valuei in enumerate(value): 98 for times in range(dataASet[1]): 99 for keyj, valuej in enumerate(valuei): 100 if (keyi == 0 and keyj == 0) and (dataASet[0] == 0 and valueA == []): 101 valueA = value[keyi][keyj] 102 else: 103 valueA += value[keyi][keyj] 104 105 # *** 专门针对整个篇幅的分段 *** # 106 for times in range(dataASet[2]): 107 for keyi, valuei in enumerate(value): # 句号 108 for keyj, valuej in enumerate(valuei): 109 # print(keyi, keyj) 110 if (keyi, keyj) == (0, 0) and valueA == []: 111 112 valueA = value[keyi][keyj] 113 else: 114 valueA += value[keyi][keyj] 115 116 # print(valueA) 117 return valueA 118 119 def programB(self, value, dataBSet): 120 valueB=[] 121 # *** 逗号分段处理 *** # 122 for keyi, valuei in enumerate(value): # 句号 123 value_end = [] 124 for keyj, valuej in enumerate(valuei[:-1]): 125 if keyj == 0 and (dataBSet[0] != 0 or dataBSet[1] != 0): 126 value_end = value[keyi][keyj] 127 if dataBSet[0] != 0: 128 for times in range(dataBSet[0] - 1): 129 value_end += value[keyi][keyj] 130 elif dataBSet[0] != 0: 131 for times in range(dataBSet[0]): 132 value_end += value[keyi][keyj] 133 elif dataBSet[1] != 0: 134 value_end += value[keyi][keyj] 135 136 if keyi == 0 and dataBSet[0] != 0: 137 valueB = value_end 138 elif dataBSet[0] != 0: 139 valueB += value_end 140 141 # *** 专门针对句号分段 *** # 142 for times in range(dataBSet[1]): 143 if (keyi == 0) and (valueB == []): 144 valueB = value[keyi][-1] 145 else: 146 valueB += value[keyi][-1] 147 148 # *** 专门针对整个篇幅的分段 *** # 149 for times in range(dataBSet[2]): 150 for keyi, valuei in enumerate(value): # 句号 151 for keyj, valuej in enumerate(valuei): 152 if (keyi, keyj) == (0, 0) and valueB == []: 153 # print('run') 154 valueB = value[keyi][keyj] 155 else: 156 valueB += value[keyi][keyj] 157 158 # print(valueB) 159 return valueB 160 161 162 if __name__=="__main__": 163 split2summary = split2summary() 164 text = '1你好<<<2don\'t do that>>>,,,<<<3I have a dream>>>4万雨...5什么<<<6hello>>>,,,<<<7Game of thrones>>>8烂尾了...' 165 dataASet=[0,0,1,1] 166 dataBSet=[2,0,0,1] 167 txt_value, txt_state = split2summary.txt2split(text) 168 print(txt_value) 169 print(txt_state) 170 171 value = split2summary.value2comma(txt_value) 172 print(value) 173 split2summary.programA(value,dataASet) 174 # split2summary.programB(value,dataBSet)
参数配置文件 config.ini
1 # 标准汉语英语-语音处理合成程序-配置文件setting.ini 2 # 参数说明: 3 # ①txtA:程序A的处理参数 4 # name其他参数的名称,comma逗号重复次数,end句号重复次数,full全文重复次数,run是否运行,default默认参数 5 # ②txtB:程序B的处理参数 6 # ③chinese:标准汉语语音合成参数设置 7 # volume音量大小,tones音调,speed语速,spokesman发言人 8 # ④english:标准英语语音合成参数设置 9 # ⑤user:token需要自己更新数据,这是一个有期限的数据 10 11 [user] 12 name = url, ?appkey, &token, &format, &sample_rate 13 nowTime = 2019-05-17 14 &token = 07ee4200162547a39aebcd4325679219 15 AccessKeyID = 【这里需要自己的阿里云-参数】 16 AccessKeySecret = oPSg3IswMi8kNOpkRaAhkZBTtOPgkr 17 host = nls-gateway.cn-shanghai.aliyuncs.com 18 url = https://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/tts 19 ?appkey = 【这里需要自己的阿里云-语音服务-参数】 20 &format = wav 21 &sample_rate = 16000 22 wav_format = "b'RIFF\xac\xdc9\x00WAVEfmt\x10\x00\x00\x00\x01\x00\x01\x00\x80>\x00\x00\x00}\x00\x00\x02\x00\x10\x00data\x80\xdc9\x00'" 23 24 25 [txtA] 26 name = comma, end, full, run 27 comma = 2 28 end = 2 29 full = 1 30 run = 0 31 default_comma = 1, 2, 5 32 default_end = 1, 2, 5 33 default_full = 0, 1, 3 34 default_run = 0, 1 35 36 [txtB] 37 name = comma, end, full, run 38 comma = 3 39 end = 1 40 full = 1 41 run = 0 42 default_comma = 1, 3, 5 43 default_end = 1, 1, 5 44 default_full = 0, 1, 3 45 default_run = 0, 1 46 47 [chinese] 48 # voice发言人、volume音量、speech_rate语速、pitch_rate语调 49 name = &volume, &speech_rate, &pitch_rate, &voice 50 &volume = 50 51 &speech_rate = 0 52 &pitch_rate = 0 53 &voice = 9 54 55 default_&volume = 0, 50, 100 56 default_&speech_rate = -500, 0, 500 57 default_&pitch_rate = -500, 0, 500 58 default_&voice = 0, 9, 18 59 voice_parameter = Xiaoyun, Xiaogang, Ruoxi, Xiaomeng, Xiaowei, Amei, Xiaoxue, Siqi, Sijia, Sicheng, Siyue, Xiaomei, Sitong, Ninger, Xiaobei, Yina, Sijing, Shanshan 60 61 [english] 62 # voice发言人、volume音量、speech_rate语速、pitch_rate语调 63 name = &volume, &speech_rate, &pitch_rate, &voice 64 &volume = 50 65 &speech_rate = 0 66 &pitch_rate = 0 67 &voice = 1 68 69 default_&volume = 0, 50, 100 70 default_&speech_rate = -500, 0, 500 71 default_&pitch_rate = -500, 0, 500 72 default_&voice = 0, 1, 3 73 voice_parameter = Wendy, William, Halen, Harry 74 75 [help] 76 77 [about]
四,总结
使用tkinter构建UI界面,ini文件充当参数配置文件,其中WAV音频文件合并过程中遇到一些问题,但是后续通过学习WAV音频格式文件的数据帧信息也顺利的解决了相关问题
五,参考链接
源码链接:https://pan.baidu.com/s/1yRzK4EFAeXg4tHIgZMsHjA 提取码:e24q 注意:AccessKeyID和AccessKeySecret需要填写自己的阿里云ID和密钥【这个很重要】
阿里云自动获取token值(python) https://www.cnblogs.com/Mufasa/p/10880698.html
WAV格式文件无损合并&帧头数据体解析(python)(原创) https://www.cnblogs.com/Mufasa/p/10878777.html
python读写增删修改ini配置文件 https://www.cnblogs.com/Mufasa/p/10845535.html