AI.py
# -*- coding: utf-8 -*-
# ################## 入口类 ##################
import os
from flask import Flask,render_template,request
from LogX import Log1
from AI_TTS_Azure import Azure
from AI_VoiceToText_Baidu import BaiduAi
log1 = Log1.log(None)
# static_url_path='' 指明静态资源在 /static/ 下,URL 路径则可以直接省略 static 路径
App3 = Flask(__name__, static_url_path='')
App3.secret_key = os.urandom(32) #'U2FsdGVkX19B/bZVZXszkfQOBEseDukn' # AES,jiami,Hsbc123#
########## 首页
@App3.route('/', methods=['GET', 'POST'])
@App3.route('/home', methods=['GET', 'POST'])
@App3.route('/index', methods=['GET', 'POST'])
def home():
return render_template('home.html')
########## 文本转语音
@App3.route('/index1', methods=['GET'])
def index1():
return render_template('index1.html')
########## 文本转语音
@App3.route('/index1', methods=['POST'])
def index1_tts():
result = Azure.ttsMain(None,request0=request)
return render_template('index1.html', msg=result['msg'], filepath=result['filepath'])
########## 文本转语音
@App3.route('/index2', methods=['GET'])
def index2():
return render_template('index2.html')
########## 文本转语音
@App3.route('/index2', methods=['POST'])
def index2_stt():
result = BaiduAi.sttMain(None,request0=request)
return render_template('index2.html', msg=result['msg'], filepath=result['filepath'])
if __name__=='__main__':
App3.run(host='0.0.0.0', port=6789)
AI_TTS_Azure.py
# -*- coding: utf-8 -*-
### 文本转语音 Azure ###
import os
import requests
import time
from xml.etree import ElementTree
from LogX import Log1
from ConfigFile import Config
log1 = Log1.log(None)
msg1 = '处理失败.'
filepath1 = ''
'''
快速入门:https://docs.microsoft.com/zh-cn/azure/cognitive-services/speech-service/quickstart-python-text-to-speech
官方源码:https://github.com/Azure-Samples/Cognitive-Speech-TTS/blob/master/Samples-Http/Python/TTSSample.py
获取密钥:https://azure.microsoft.com/zh-cn/try/cognitive-services/my-apis/?apiSlug=speech-services&country=China&allowContact=true&fromLogin=True
终结点: https://westus.api.cognitive.microsoft.com/sts/v1.0
获取Token接口:https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken
文本转语音接口:https://westus.tts.speech.microsoft.com/cognitiveservices/v1
密钥 1: 8c0779e6846c43478f83fb2bd2fdd610
密钥 2: c7fa26e8ea4c46368ddafbe76fdf0827
'''
proxyHttp = Config.getBasic(None, 'http-proxy','http')
proxyHttps = Config.getBasic(None, 'http-proxy','https')
azureKey1 = Config.getBasic(None, 'Azure-Key','key1')
azureKey2 = Config.getBasic(None, 'Azure-Key','key2')
azureKey = azureKey1 if azureKey1=='' else azureKey2
class Azure(object):
def ttsMain(self,request0):
log1.warn(' >>> 进入 ttsMain ')
global msg1
global filepath1
nowtime1 = time.strftime('%Y%m%d%H%M%S')
texttype = request0.form['texttype']
caiyanglv = request0.form['caiyanglv']
yinse = request0.form['yinse']
voicefilename1 = 'voice_' + nowtime1 + '_[' + caiyanglv + ']_[' + yinse + '].wav'
voice_key = ''
if texttype != '': # 文本类型<表单输入文本,上传文件文本,指定网页文本>
textcontent = ''
uploadPath = os.getcwd() + '/upload/'
if not os.path.exists(uploadPath):
os.makedirs(uploadPath)
#####[1] 表单文本
if texttype == 'formtext':
textcontent = request0.form['text1']
if textcontent != '':
# log1.info(' 待转换的文本内容:\n' + textcontent)
log1.warn(' 开始转换语音-表单文本 ...')
filepath1 = Azure.textToVoice(None, text0=textcontent, voicefilename=voicefilename1,
voice_encode_type=caiyanglv, voice_speeker_type=yinse,
subscription_key=voice_key)
if filepath1 != '':
msg1 = '处理成功!'
else:
error = '处理失败!'
else:
msg1 = '处理失败!请输入文本内容'
log1.error(' ' + msg1)
#####[2] 文件文本
elif texttype == 'filetext':
fileObj1 = request0.files['file1']
if fileObj1 != '':
filename0 = fileObj1.filename
filename0_ext = filename0.split('.')[-1]
filename0_ext_accept = ['txt', 'log', 'ini', 'conf']
if filename0_ext not in filename0_ext_accept:
msg1 = '处理失败!请上传纯文本格式的文件,支持的后缀:txt,log,ini,conf'
log1.error(' ' + msg1)
else:
filenamenew = nowtime1 + '.' + filename0_ext
abPath = uploadPath + '/text_' + filenamenew
log1.info(' 开始上传文件 ...')
fileObj1.save(abPath)
log1.info(' 文件上传成功:' + abPath)
fileUpload = open(abPath, 'r', encoding='utf-8').read()
for textline in fileUpload:
textcontent = textcontent + textline
log1.info(' 开始转换语音-上传文件 ...')
filepath1 = Azure.fileToVoice(None, filePath0=abPath, voicefilename=voicefilename1,
voice_encode_type=caiyanglv, voice_speeker_type=yinse,
subscription_key=voice_key)
if filepath1 != '':
msg1 = '处理成功!'
else:
msg1 = '处理失败!'
else:
msg1 = '处理失败!请选择文件'
log1.error('>>> ' + msg1)
#####[3] 网页文本
elif texttype == 'webpagetext':
msg1 = '您好,暂不支持网页方式.'
log1.info(' ' + msg1)
'''
weburl1 = request.form['weburl1']
if textcontent != '':
textcontent = weburl1 # 通过URL获取网页文本,应该加点过滤参数,获取指定DOM元素内的文本
log1.info('>>> 开始转换语音-网页地址 ...')
filepath1 = Azure.tts_text(None, text0=textcontent, voicefilename=voicefilename1,
voice_encode_type=caiyanglv, voice_speeker_type=yinse, subscription_key=voice_key)
msg1 = '处理成功'
else:
msg1 = '处理失败!请输入网页地址(URL)'
log1.info('>>> ' + msg1)
'''
#####[0] 参数错误
else:
msg1 = '处理失败!文本类型参数错误:texttype=' + texttype
log1.error('>>> ' + msg1)
else:
msg1 = '处理失败!文本类型参数不能为空.'
log1.error('>>> ' + msg1)
if filepath1!='' :
filepath1 = request0.url_root + filepath1.replace('static/', '')
result = {'msg': msg1, 'filepath': filepath1} # 返回结果,键值对,字典
log1.warn('>>> 全部操作已经完成')
log1.warn('>>> 返回结果:\nresult=' + str(result))
return result
### 文件转语音
def fileToVoice(self, filePath0, voicefilename, voice_encode_type, voice_speeker_type, subscription_key):
filepath = ''
log1.debug('传入的参数值:'
+ '\nfilePath0=' + filePath0
+ '\nvoicefilename=' + voicefilename
+ '\nvoice_encode_type=' + voice_encode_type
+ '\nvoice_speeker_type=' + voice_speeker_type)
if subscription_key == '':
subscription_key = 'c7fa26e8ea4c46368ddafbe76fdf0827'
# tts = input('Input some text to convert to speech: ') # 控制台输入
# tts = 'Hello everyone, I am 18 years old and have a deposit of 1.23 million. I want to get a wife.'
file_obj = open(filePath0, 'rb') # 英文内容:'rU',中文内容:,'rb'
# tts = ''
# for eachline in file_obj: # 一行一行读取
# if eachline != '':
# tts += eachline
# tts = file_obj.read() # 英文内容
tts = str(file_obj.read(), encoding='utf-8') # 中文内容
#log1.debug(' 待转换文本:' + tts )
timestr = time.strftime('%Y%m%d%H%M')
proxies = {
'http': proxyHttp,
'https': proxyHttps,
}
fetch_token_url = 'https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken'
headers = {
'Ocp-Apim-Subscription-Key': subscription_key
}
response = requests.post(fetch_token_url, headers=headers, proxies=proxies, verify=False)
access_token = str(response.text)
#log1.debug(' 获取到Token:' + access_token)
constructed_url = 'https://westus.tts.speech.microsoft.com/cognitiveservices/v1'
headers = {
# 前面带有单词 Bearer 的授权令牌
'Authorization': 'Bearer ' + access_token,
# 指定所提供的文本的内容类型。 接受的值:application/ssml+xml。
'Content-Type': 'application/ssml+xml',
# 指定音频输出格式,取值如下:
# raw-16khz-16bit-mono-pcm (百度AI的语音转文本时,需要采用这个格式,但Windows自带的播放器是无法播放的)
# raw-8khz-8bit-mono-mulaw
# riff-8khz-8bit-mono-alaw
# riff-8khz-8bit-mono-mulaw
# riff-16khz-16bit-mono-pcm
# audio-16khz-128kbitrate-mono-mp3
# audio-16khz-64kbitrate-mono-mp3
# audio-16khz-32kbitrate-mono-mp3
# raw-24khz-16bit-mono-pcm
# riff-24khz-16bit-mono-pcm (这个格式 可以播放)
# audio-24khz-160kbitrate-mono-mp3
# audio-24khz-96kbitrate-mono-mp3
# audio-24khz-48kbitrate-mono-mp3
'X-Microsoft-OutputFormat': voice_encode_type,
# 应用程序名称,少于 255 个字符。
# Chrome的 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36
'User-Agent': 'Chrome/73.0.3683.86'
}
xml_body = ElementTree.Element('speak', version='1.0')
xml_body.set('{http://www.w3.org/XML/1998/namespace}lang', 'en-us')
voice = ElementTree.SubElement(xml_body, 'voice')
voice.set('{http://www.w3.org/XML/1998/namespace}lang', 'en-US')
# 标准语音列表:https://docs.microsoft.com/zh-cn/azure/cognitive-services/speech-service/language-support#standard-voices
# 【下面5行:英语(美国)】 【语音性别,语音全称,语音简称】
# 女 'Microsoft Server Speech Text to Speech Voice (en-US, ZiraRUS)' 'en-US-ZiraRUS'
# 女 'Microsoft Server Speech Text to Speech Voice (en-US, JessaRUS)' 'en-US-JessaRUS'
# 男 'Microsoft Server Speech Text to Speech Voice (en-US, BenjaminRUS)' 'en-US-BenjaminRUS'
# 女 'Microsoft Server Speech Text to Speech Voice (en-US, Jessa24kRUS)' 'en-US-Jessa24kRUS'
# 男 'Microsoft Server Speech Text to Speech Voice (en-US, Guy24kRUS)' 'en-US-Guy24kRUS'
# 【下面3行:中文(中国)】
# 女 'Microsoft Server Speech Text to Speech Voice (zh-CN, HuihuiRUS)' 'zh-CN-HuihuiRUS'
# 女 'Microsoft Server Speech Text to Speech Voice (zh-CN, Yaoyao, Apollo)' 'zh-CN-Yaoyao-Apollo'
# 男 'Microsoft Server Speech Text to Speech Voice (zh-CN, Kangkang, Apollo)' 'zh-CN-Kangkang-Apollo'
voice.set('name',voice_speeker_type)
voice.text = tts
body = ElementTree.tostring(xml_body)
log1.debug(' 调用接口转换语音中......')
response = requests.post(constructed_url, headers=headers, data=body, proxies=proxies, verify=False)
if response.status_code == 200:
filepath = 'static/voice/' + voicefilename
with open(filepath, 'wb') as audio:
audio.write(response.content)
log1.warn(' 文本转语音已完成,生成的音频文件:' + filepath)
else:
print('[失败] response code: ' + str(response.status_code)
+ '\nresponse headers: ' + str(response.headers) )
return filepath
### 文本转语音
def textToVoice(self, text0, voicefilename, voice_encode_type, voice_speeker_type, subscription_key):
filepath = ''
log1.debug('传入的参数值:'
#+ '\ntext0=' + text0
+ '\nvoicefilename=' + voicefilename
+ '\nvoice_encode_type=' + voice_encode_type
+ '\nvoice_speeker_type=' + voice_speeker_type )
if subscription_key=='':
subscription_key = 'c7fa26e8ea4c46368ddafbe76fdf0827'
# tts = input('Input some text to convert to speech: ') # 控制台输入
tts = text0
timestr = time.strftime('%Y%m%d%H%M')
proxies = {
'http': proxyHttp,
'https': proxyHttps,
}
fetch_token_url = 'https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken'
headers = {
'Ocp-Apim-Subscription-Key': subscription_key
}
response = requests.post(fetch_token_url, headers=headers, proxies=proxies, verify=False)
access_token = str(response.text)
#log1.debug(' 获取到Token:' + access_token)
constructed_url = 'https://westus.tts.speech.microsoft.com/cognitiveservices/v1'
headers = {
# 前面带有单词 Bearer 的授权令牌
'Authorization': 'Bearer ' + access_token,
# 指定所提供的文本的内容类型
'Content-Type': 'application/ssml+xml',
# 指定音频输出格式
'X-Microsoft-OutputFormat': voice_encode_type,
# 应用程序名称,少于 255 个字符。
'User-Agent': 'Chrome/73.0.3683.86'
}
xml_body = ElementTree.Element('speak', version='1.0')
xml_body.set('{http://www.w3.org/XML/1998/namespace}lang', 'en-us')
voice = ElementTree.SubElement(xml_body, 'voice')
voice.set('{http://www.w3.org/XML/1998/namespace}lang', 'en-US')
# 'en-US-Guy24kRUS',全称:'Microsoft Server Speech Text to Speech Voice (en-US, Guy24KRUS)'
voice.set('name',voice_speeker_type)
voice.text = tts
body = ElementTree.tostring(xml_body)
log1.debug(' 调用接口转换语音中......')
response = requests.post(constructed_url, headers=headers, data=body, proxies=proxies, verify=False)
if response.status_code == 200:
filepath = 'static/voice/' + voicefilename
with open(filepath, 'wb') as audio:
audio.write(response.content)
log1.warn(' 文本转语音已完成,生成的音频文件:' + filepath)
else:
print('[失败] response code: ' + str(response.status_code)
+ '\nresponse : ' + str(response.content) )
return filepath
### 函数入口
if __name__ == '__main__':
test = Azure()
abPath = 'static/backup/text/tts_txt_zhcn.txt'
caiyanglv = 'riff-24khz-16bit-mono-pcm'
yinse = 'zh-CN-HuihuiRUS'
voicefilename1 = 'voice_1001_[' + caiyanglv + ']_['+yinse+'].wav'
test.fileToVoice( filePath0 = abPath, voicefilename = voicefilename1, voice_encode_type = caiyanglv,
voice_speeker_type = yinse, subscription_key = '')
AI_VoiceToText_Baidu.py
# -*- coding: utf-8 -*-
### 语音识别 百度API ###
# Home:https://ai.baidu.com/tech/speech/asr
# API: https://ai.baidu.com/docs#/ASR-Online-Python-SDK/top
# Q&A: https://ai.baidu.com/docs#/FAQ/a53b4698
# 在线文本转语音(汇丰无法试听和下载):https://developer.baidu.com/vcast
from aip import AipSpeech
from ConfigFile import Config
from LogX import Log1
import time
import os
log1 = Log1.log(None)
msg1 = '处理失败.'
filepath1 = ''
class BaiduAi(object):
""" 你的 APPID AK SK """
proxyHttp = Config.getBasic(None, group0='http-proxy', key0='http')
proxyHttps = Config.getBasic(None, group0='http-proxy', key0='https')
APP_ID = Config.getBasic(None, group0='Baidu-Ai', key0='appid')
API_KEY = Config.getBasic(None, group0='Baidu-Ai', key0='appkey')
SECRET_KEY = Config.getBasic(None, group0='Baidu-Ai', key0='secretkey')
# ### 语音转文本,表单入口
def sttMain(self, request0):
global msg1
global filepath1
nowtime1 = time.strftime('%Y%m%d%H%M%S')
fromLanguage = request0.form['fromLanguage'] # 来源语言
toLanguage = request0.form['toLanguage'] # 目标语言
textfilename1 = 'text_' + nowtime1 + '_[' + fromLanguage + ']_[' + toLanguage + '].txt'
uploadPath = os.getcwd() + '/upload/'
fileObj1 = request0.files['file1']
if fileObj1 != '':
filename0 = fileObj1.filename
filename0_ext = filename0.split('.')[-1]
filename0_ext_accept = ['wav']
if filename0_ext not in filename0_ext_accept:
msg1 = '处理失败!请上传wav格式的音频文件。'
log1.error('>>> ' + msg1)
else:
filenamenew = nowtime1 + '.' + filename0_ext
abPath = uploadPath + '/voice_' + filenamenew
log1.info('>>> 开始上传文件 ...')
fileObj1.save(abPath)
log1.info('>>> 文件上传成功:' + abPath)
# 开始转换语音
textDict = BaiduAi.aiMain(None, filePath0=abPath, toLanguage0=toLanguage)
if textDict != '':
err_no = textDict['err_no']
err_msg = textDict['err_msg']
result = textDict['result'][0]
log1.debug('>>> 状态码:' + str(err_no))
log1.debug('>>> 状态:' + err_msg)
log1.debug('>>> 结果:' + result)
# TODO 将文本写入文件
filepath1 = 'static/textfile/'+textfilename1
open(filepath1, "w", encoding='UTF-8').write(result)
log1.debug('>>> 写入文件完成:' + filepath1)
filepath1 = request0.url_root + 'textfile/' + textfilename1
if filepath1 != '':
msg1 = '处理成功!'
else:
msg1 = '处理失败!'
else:
msg1 = '处理失败!请选择文件'
log1.error('>>> ' + msg1)
result = {'msg': msg1, 'filepath': filepath1} # 返回结果,键值对,字典
log1.warn('>>> 全部操作已经完成')
log1.warn('>>> 返回结果:\nresult=' + str(result))
return result
# ### 语音转文本,转换函数,返回字典类型
def aiMain(self, filePath0, toLanguage0):
# AipSpeech是语音识别的Python SDK客户端
client = AipSpeech(BaiduAi.APP_ID, BaiduAi.API_KEY, BaiduAi.SECRET_KEY) # 访问百度API,内置访问http的函数,并写死了URL路径
proxies = {
"http": BaiduAi.proxyHttp,
"https": BaiduAi.proxyHttps,
}
client.setProxies(proxies)
# client.setConnectionTimeoutInMillis( 10000 ) # 建立连接的超时时间(毫秒),默认不需要设置
# client.setSocketTimeoutInMillis(300000) # 通过打开的连接传输数据的超时时间(毫秒)
# 上传 本地音频文件(SpeechToText.wav)
# 支持的格式:原始 PCM 的录音参数必须符合 16k 采样率、16bit 位深、单声道,支持的格式有:pcm(不压缩)、wav(不压缩,pcm编码)、amr(压缩格式)。
# 有长度限制(测试时尽量短一点)
# 返回结果为字典类型(Dict / json)
response = client.asr(BaiduAi.get_file_content(None,filePath=filePath0), 'wav', 16000, {
# 1536:普通话(支持简单的英文识别)
# 默认1537:普通话(纯中文识别)
# 1737:英语
# 1637:粤语
'dev_pid': int(toLanguage0),
})
return response
# {'corpus_no': '6714166347641437907', 'err_msg': 'success.', 'err_no': 0, 'result': ['识别后的内容'], 'sn': '602626830571563263672'}
# ### 语音转文本,读取本地文件
def get_file_content(self,filePath):
with open(filePath, 'rb') as fp:
return fp.read()
### 函数入口
if __name__ == "__main__":
baidu = BaiduAi()
filepath9 = 'static/backup/sound/voice_20190916142927_[raw-16khz-16bit-mono-pcm]_[en-US-ZiraRUS].wav'
languageNum = 1737
textDict = baidu.aiMain( filePath0=filepath9, toLanguage0=languageNum)
print (str(textDict))
if textDict!='':
err_no = textDict['err_no']
err_msg = textDict['err_msg']
result = textDict['result'][0]
print ('状态码:' + err_no)
print ('状态:' + err_msg)
print ('结果:' + result)
ConfigFile
# -*- coding: utf-8 -*-
import os
from configparser import ConfigParser
class Config(object):
def __init__(self):
super(Config, self).__init__()
self.config = ConfigParser()
#print('配置文件路径:'+os.getcwd()+'/configs/basic.ini')
self.config.read(os.getcwd()+'/configs/basic.ini',encoding='utf-8')
# ### 代理配置
# user
# pass
def getBasic (self,group0, key0):
cfg0 = Config().config
value0 = cfg0.get(group0, key0)
return value0
if __name__ == "__main__":
cc = Config()
# print (cc.getBasic( group0='http-proxy', key0='http' ))
LogX.py
# -*- coding: utf-8 -*-
import logging
import logging.handlers
class Log1(object):
def log(self):
# 日志对象
logger1 = logging.getLogger('AIFuture')
if not logger1.handlers:
# 日志级别-会覆盖 Handler的子级别
logfilePath = 'logs/AI.log'
logger1.setLevel(logging.DEBUG)
# 用于输出到文件
#logfile1 = logging.FileHandler(logfilePath)
logfile1 = logging.handlers.RotatingFileHandler(logfilePath, maxBytes=10 * 1024 * 1024, backupCount=5, encoding='utf-8')
#logfile1.setLevel(logging.DEBUG)
# 用于输出到控制台
logcmd1 = logging.StreamHandler()
#logcmd1.setLevel(logging.INFO)
# 格式化日志
logformatter = logging.Formatter('[%(asctime)s] [%(levelname)s] [%(filename)s(line:%(lineno)d)] %(message)s')
# 应用格式
logfile1.setFormatter(logformatter)
logcmd1.setFormatter(logformatter)
# 注入对象
logger1.addHandler(logcmd1)
logger1.addHandler(logfile1)
return logger1
start_AI.sh
#! /bin/bash
. ~/.bash_profile
mypython -u AI.py
'''
进入目录: cd /home/pyai/tts
启动命令: nohup sh start_AI.sh > start_AI.sh.out &
停止命令:
查看进程: ps -ef|grep AI
显示 端口占用:netstat -lnt|grep 6789
sudo netstat -antup
sudo netstat -antup|grep PID号
sudo ps -ef|grep 进程名
'''
'''
依赖插件:mypip install configparser --user
flask
jinja2
requests
logger1
baidu-aip
configparser
'''
configs/basic.ini
# http 代理配置
[http-proxy]
http = http://***
https = http://***
# 微软 Azure 语音密钥
[Azure-Key]
key1 = 8c0779e6846c43478f83fb2bd2fdd610
key2 = c7fa26e8ea4c46368ddafbe76fdf0827
[Baidu-Ai]
appid = 16735297
appkey = P7IGlBm443VcSaCWCQT6WrXh
secretkey = pdlslL0ysPFUU8yF6dQtoN5yxrfdSupD
相关目录结构:
项目根目录/configs/basic.ini
项目根目录/logs
项目根目录/static/backup/sound
项目根目录/static/backup/text
项目根目录/static/history
项目根目录/static/textfile
项目根目录/static/voice
项目根目录/templates/***.html
项目根目录/upload
项目根目录/AI.py
项目根目录/AI_TTS_Azure.py
项目根目录/AI_VoiceToText_Baidu.py
项目根目录/ConfigFile.py
项目根目录/LogX.py
项目根目录/start_AI.py