1.初始教程
1.登录百度云管理中心,点击管理控制台
2.进入后,下拉在已开通服务中选择百度语音
3.点击创建应用,得到以下应用
4.这里也可以查看它的相关技术文档
2.文字合成语音
1.安装使用Python SDK,终端下:
pip install baidu-aip
使用
from aip import AipSpeech """ 你的 APPID AK SK """ APP_ID = '11793737' API_KEY = 'Mx8wLzbFk2VNVcjybf8lDzFH' SECRET_KEY = 'DEc7I5q18z7aazW22LKDgwGocZ8h9VdR' client = AipSpeech(APP_ID,API_KEY,SECRET_KEY) result = client.synthesis("第一次把下列文字转成MP3语音","zh",1,{ "spd":4, "vol":7, "pit":8, "per":4 }) if not isinstance(result,dict): # 创建一个auido.mp3文件 with open("auido.mp3","wb") as f: f.write(result) print(result) # 打印bytes字节
此时文件中会多出一个mp3结尾的文件,我们把改文字已经转换成语音写入在了该文件中
3.语音转义成文字
参考技术文档说明,这里支持的语音格式文件有:pcm(不压缩)、wav(不压缩,pcm编码)、amr(压缩格式)
我们需要借助第三方工具ffmpeg把任意格式的语音转移成pcm格式
3.1 ffmpeg说明:
FFmpeg 是一个自由软件,可以运行音频和视频多种格式的录影、转换、流功能包含了libavcodec——这是一个用于多个项目中音频和视频的解码器库,
以及libavformat——一个音频与视频格式转换库。说简单点,这个工具可以将wav wma mp3 等音频文件转换为 pcm 无压缩音频文件
下载链接:猛戳此处
或者此处链接:链接: https://pan.baidu.com/s/1-TEQZP9QbJSlGSYedyAUFw 密码: 2z8l
下载后解压缩(我把它放在了D盘下),注意可执行的exe文件是在文件的bin目录,配置我们的环境变量
配置后,在终端测试效果:
使用
我们用命令行对这个 auido.mp3 进行pcm格式的转换然后得到 audio.pcm
命令是 : ffmpeg -y -i audio.wav -acodec pcm_s16le -f s16le -ac 1 -ar 16000 audio.pcm
from aip import AipSpeech import os """ 你的 APPID AK SK """ APP_ID = '11793737' API_KEY = 'Mx8wLzbFk2VNVcjybf8lDzFH' SECRET_KEY = 'DEc7I5q18z7aazW22LKDgwGocZ8h9VdR' client = AipSpeech(APP_ID,API_KEY,SECRET_KEY) # 读取文件 filePath = "auido.mp3" def get_file_content(filePath): # 用于将任何形式的语音文件格式转化成pcm格式,这里使用的是py3.6的模板语法,其他版本可以使用字符串的格式化语法 os.system(f"ffmpeg -y -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm") with open(f"{filePath}.pcm",'rb') as fp: return fp.read() # 识别本地文件 liu = get_file_content(filePath) res = client.asr(liu,'pcm',16000,{ 'dev_pid':1536 }) print(res) # 查看格式 # {'corpus_no': '6599876657908188502', 'err_msg': 'success.', 'err_no': 0, # 'result': ['第一次把下列文字转MP3语音'], 'sn': '465883505901536653530'} if res.get("result"): print(res.get('result')[0]) else: print(res)
# 注意这里转化后文件中会搓出一个auido.mp3.pcm格式的文件
相关参数说明:
asr函数需要四个参数 第一个参数: speech 音频文件流 建立包含语音内容的Buffer对象, 语音文件的格式,pcm 或者 wav 或者 amr 第二个参数: format 文件的格式,包括pcm(不压缩)、wav、am 第三个参数: rate 音频文件采样率 如果使用刚刚的FFmpeg的命令转换的,你的pcm文件就是16000 第四个参数: dev_pid 音频文件语言id 默认1537(普通话 输入法模型) 1636 # 普通话,支持简单英文识别 1737 # 英文
4.输入语音实现自动交互
这里需要我们的图灵机器人技术,创建一个机器人
对我们的机器人进行相关设置
4.1 api接口使用
api接口文档说明地址:猛戳此处
接口地址:http://openapi.tuling123.com/openapi/api/v2
请求方式:只有两种,HTTP POST
测试:
import requests import json apiKey = "d76b3e9669404fe7b5a1949466fd6376" userId = "taylor" # 机器人名称 data = { # 请求的类型 0 文本 1 图片 2 音频 "reqType": 0, "perception": { "inputText": { "text": "你是谁" } }, "userInfo": { "apiKey": apiKey, "userId": userId } } tuling_url = "http://openapi.tuling123.com/openapi/api/v2" res = requests.post(tuling_url,json=data) # 请求url # 将返回信息解码 res_dic = json.loads(res.content.decode("utf-8")) # type:dict # 得到返回信息中的文本信息 res_type = res_dic.get("results")[0].get("values").get("text") print(res_type)
效果:
现在有文本信息了,我们可以调用上面的文本信息转换成语音,让它实现语音播放
third.py
import os from aip import AipSpeech from aip import AipNlp """ 你的 APPID AK SK """ APP_ID = '11793737' API_KEY = 'Mx8wLzbFk2VNVcjybf8lDzFH' SECRET_KEY = 'DEc7I5q18z7aazW22LKDgwGocZ8h9VdR' client = AipSpeech(APP_ID,API_KEY,SECRET_KEY) # 用于将任何形式的语音文件格式转化成pcm格式 # 这里使用的是py3.6的模板语法,其他语言可以使用字符串的格式化语法 def get_file_content(filePath): os.system(f"ffmpeg -y -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm") with open(f"{filePath}.pcm",'rb') as fp: return fp.read() def text2audio(text): result = client.synthesis(text, 'zh', 1, { "spd": 4, 'vol': 7, "pit": 8, "per": 4 }) if not isinstance(result, dict): # 创建一个auido.mp3文件 with open('auido.mp3', 'wb') as f: f.write(result)
return get_file_content('auido.mp3')
test.py
import requests import json import third apiKey = "d76b3e9669404fe7b5a1949466fd6376" userId = "taylor" # 机器人名称 data = { # 请求的类型 0 文本 1 图片 2 音频 "reqType": 0, "perception": { "inputText": { "text": "你是谁" } }, "userInfo": { "apiKey": apiKey, "userId": userId } } tuling_url = "http://openapi.tuling123.com/openapi/api/v2" res = requests.post(tuling_url,json=data) # 请求url # 将返回信息解码 res_dic = json.loads(res.content.decode("utf-8")) # type:dict # 得到返回信息中的文本信息 res_type = res_dic.get("results")[0].get("values").get("text") # 调用text2audio函数 third.text2audio(res_type)
执行后,此时文件中会多出一个auido.mp3和一个auido.mp3.pcm文件,文件内容就是机器人对我们的文本回复的内容
5.web录音实现互动问答
5.1 websocket监听
ai.py
from flask import Flask,request,render_template from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer from geventwebsocket.websocket import WebSocket app = Flask(__name__,template_folder="../templates") @app.route("/index") def index(): # 获取请求的WebSocket对象 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket print(user_socket) # <geventwebsocket.websocket.WebSocket object at 0x000002718C07F798> print(request.remote_addr) # 远程ip地址127.0.0.1 while True: # 接收消息 msg = user_socket.receive() print(msg) @app.route("/") def home(): return render_template("index.html") if __name__ == "__main__": http_serv = WSGIServer(("0.0.0.0",9520),app,handler_class=WebSocketHandler) http_serv.serve_forever()
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> </body> <script type="application/javascript"> //创建 WebSocket 对象 var ws = new WebSocket("ws://127.0.0.1:9520/index"); </script> </html>
这里我们启动我们的程序,在浏览器输入http://127.0.0.1:9520/,此时在pycharm上就会传回我们的websocket对象以及远程IP地址
我们利用websocket已经实现了前端与后端的交互吗,现在我们需要通过websocket把我们网页上录的语音换到后端去
5.2 recorder.js录音插件
recorder.js是HTML5录音插件,它可以实现在线录音。
部分浏览器还存在兼容性(如ie,Safari)
Chrome47以上以及QQ浏览器需要HTTPS支持
github下载地址为:https://github.com/mattdiamond/Recorderjs
html5 Audio常用属性和函数事件参考链接:https://blog.csdn.net/bright2017/article/details/80041448
项目构架
./
├── ai.py
├── static
│ └── recorder.js
└── templates
└── index.html
在index.html中导入我们的recorder.js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {#audio是HTML5的标签,autoplay表示自动播放,controls表示展示组件#} <audio src="" autoplay controls id="player"></audio> <br> <button onclick="start_reco()">开始废话</button> <br> <button onclick="stop_reco()">发送语音</button> </body> <script src="/static/recorder.js"></script> <script type="application/javascript"> // 创建WebSocket对象 var ws = new WebSocket("ws://127.0.0.1:5300/index"); var reco = null; //录音对象 // 创建AudioContext对象 // AudioContext() 构造方法创建了一个新的 AudioContext 对象 它代表了一个由音频模块链接而成的音频处理图, 每一个模块由 AudioNode 表示 var audio_context = new AudioContext(); //要获取音频和视频,需要用到getUserMedia。桌面平台支持的浏览器包括Chrome, Firefox, Opera和Edge。 // 这里的|| 表示或者的关系,也就是能支持的浏览器 navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象 navigator.getUserMedia({audio: true}, create_stream, function (err) { console.log(err) }); //创建媒体流容器 function create_stream(user_media) { //AudioContext接口的createMediaStreamSource()方法用于创建一个新的MediaStreamAudioSourceNode 对象, // 需要传入一个媒体流对象(MediaStream对象)(可以从 navigator.getUserMedia 获得MediaStream对象实例), // 然后来自MediaStream的音频就可以被播放和操作。 // MediaStreamAudioSourceNode 接口代表一个音频接口,是WebRTC MediaStream (比如一个摄像头或者麦克风)的一部分。 // 是个表现为音频源的AudioNode。 var stream_input = audio_context.createMediaStreamSource(user_media); // 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流 reco = new Recorder(stream_input); } function start_reco() { //开始录音 reco.record(); //往里面写流 } function stop_reco() { //停止录音 reco.stop(); //停止写入流 get_audio(); //调用自定义方法 reco.clear(); //清空容器 } // 获取音频 function get_audio() { reco.exportWAV(function (wav_file) { // 发送数据给后端 ws.send(wav_file); }) } </script> </html>
启动程序后,点击开始按钮,后台会接收到一个bytearray类型的字符,这就是我们的声音字节,现在需要我们把它写入文件
修改我们的后台程序
from flask import Flask,request,render_template from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer from geventwebsocket.websocket import WebSocket app = Flask(__name__,template_folder="../templates") @app.route("/index") def index(): # 获取请求的WebSocket对象 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket print(user_socket) # <geventwebsocket.websocket.WebSocket object at 0x000002718C07F798> print(request.remote_addr) # 远程ip地址127.0.0.1 while True: # 接收消息 msg = user_socket.receive() if type(msg) == bytearray: # 写入文件123.wav with open("123.wav", "wb") as f: f.write(msg) @app.route("/") def home(): return render_template("index.html") if __name__ == "__main__": http_serv = WSGIServer(("0.0.0.0",5300),app,handler_class=WebSocketHandler) http_serv.serve_forever()
此时重启文件,我们就能把我们的声音录制成一个123.wav格式的文件,这个就是我们录制的声音
5.3 整合以上内容
现在我们需要完成在浏览器输入语音,在线实时和图灵机器人交互的效果,我们把以上代码进行整合
流程:通过浏览器发送语音给后端-->后端将音频文件转成文字发个图灵机器人-->后端再讲图灵回执的文字转成音频文件-->回执的音频文件发送给前端
test.py
import requests import json import third apiKey = "d76b3e9669404fe7b5a1949466fd6376" userId = "taylor" # 机器人名称 data = { # 请求的类型 0 文本 1 图片 2 音频 "reqType": 0, "perception": { "inputText": { "text": "你是谁" } }, "userInfo": { "apiKey": apiKey, "userId": userId } } tuling_url = "http://openapi.tuling123.com/openapi/api/v2" def to_tuling(question,user_id): # 修改请求参数中的inputText,也就是问题 data["perception"]["inputText"]["text"] = question # # 修改userInfo data["userInfo"]["userId"] = user_id res = requests.post(tuling_url,json=data) # 请求url # 将返回信息解码 res_dic = json.loads(res.content.decode("utf-8")) # type:dict # 得到返回信息中的文本信息 result = res_dic.get("results")[0].get("values").get("text") # print(res_type) return result
third.py
import os from aip import AipSpeech from aip import AipNlp import test """ 你的 APPID AK SK """ APP_ID = '11793737' API_KEY = 'Mx8wLzbFk2VNVcjybf8lDzFH' SECRET_KEY = 'DEc7I5q18z7aazW22LKDgwGocZ8h9VdR' client = AipSpeech(APP_ID,API_KEY,SECRET_KEY) nlp_client = AipNlp(APP_ID, API_KEY, SECRET_KEY) # 用于将任何形式的语音文件格式转化成pcm格式 # 这里使用的是py3.6的模板语法,其他语言可以使用字符串的格式化语法 def get_file_content(filePath): os.system(f"ffmpeg -y -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm") with open(f"{filePath}.pcm",'rb') as fp: return fp.read() def text2audio(text): result = client.synthesis(text, 'zh', 1, { "spd": 4, 'vol': 7, "pit": 8, "per": 4 }) if not isinstance(result, dict): # 创建一个auido.mp3文件 with open('audio.mp3', 'wb') as f: f.write(result) return 'audio.mp3' # 识别本地文件,转义成文本信息 def audio2text(file_path): a = client.asr(get_file_content(file_path), 'pcm', 16000, { 'dev_pid': 1536, }) if a.get("result") : return a.get("result")[0] def my_nlp(q,uid): a = test.to_tuling(q,uid) return a
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {#audio是HTML5的标签,autoplay表示自动播放,controls表示展示组件#} <audio src="" autoplay controls id="player"></audio> <br> <button onclick="start_reco()">开始废话</button> <br> <button onclick="stop_reco()">发送语音</button> </body> <script src="/static/recorder.js"></script> <script type="application/javascript"> // 创建WebSocket对象,index后面的是userid,是图灵机器人需要的 var ws = new WebSocket("ws://127.0.0.1:5300/index/taylor"); var reco = null; //录音对象 // 创建AudioContext对象 // AudioContext() 构造方法创建了一个新的 AudioContext 对象 它代表了一个由音频模块链接而成的音频处理图, 每一个模块由 AudioNode 表示 var audio_context = new AudioContext(); //要获取音频和视频,需要用到getUserMedia。桌面平台支持的浏览器包括Chrome, Firefox, Opera和Edge。 // 这里的|| 表示或者的关系,也就是能支持的浏览器 navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象 navigator.getUserMedia({audio: true}, create_stream, function (err) { console.log(err) }); //创建媒体流容器 function create_stream(user_media) { //AudioContext接口的createMediaStreamSource()方法用于创建一个新的MediaStreamAudioSourceNode 对象, // 需要传入一个媒体流对象(MediaStream对象)(可以从 navigator.getUserMedia 获得MediaStream对象实例), // 然后来自MediaStream的音频就可以被播放和操作。 // MediaStreamAudioSourceNode 接口代表一个音频接口,是WebRTC MediaStream (比如一个摄像头或者麦克风)的一部分。 // 是个表现为音频源的AudioNode。 var stream_input = audio_context.createMediaStreamSource(user_media); // 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流 reco = new Recorder(stream_input); } function start_reco() { //开始录音 reco.record(); //往里面写流 } function stop_reco() { //停止录音 reco.stop(); //停止写入流 get_audio(); //调用自定义方法 reco.clear(); //清空容器 } // 获取音频 function get_audio() { reco.exportWAV(function (wav_file) { // 发送数据给后端 ws.send(wav_file); }) } // 接收到服务端数据时触发 ws.onmessage = function (data) { console.log(data.data); //打印文件名 } </script> </html>
ai.py -->执行文件
from flask import Flask,request,render_template,send_file from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer from geventwebsocket.websocket import WebSocket import third app = Flask(__name__,template_folder="../templates",static_folder="../static") @app.route("/index/<uid>") def index(uid): # 接收uid # 获取请求的WebSocket对象 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket print(user_socket) # print(request.remote_addr) # 远程ip地址 while True: # 接收消息 msg = user_socket.receive() if type(msg) == bytearray: # 写入文件123.wav with open("123.wav", "wb") as f: f.write(msg) # 将音频文件转换为文字 res_q = third.audio2text("123.wav") # 调用my_nlp函数,内部调用图灵机器人 res_a = third.my_nlp(res_q,uid) # 将文字转换为音频文件 file_name = third.text2audio(res_a) # 发送文件名给前端 user_socket.send(file_name) @app.route("/") def home_page(): return render_template("index.html") @app.route("/get_file/<file_name>") # 获取音频文件 def get_file(file_name): # 此方法用于前端调取后端的音频文件,用于自动播放 return send_file(file_name) if __name__ == "__main__": http_serv = WSGIServer(("0.0.0.0",5300),app,handler_class=WebSocketHandler) http_serv.serve_forever()
相关说明:这里浏览器很关键,很容易失败,多试几个浏览器,我调试的是谷歌浏览器,需要我们把油猴插件关掉,还需要把静态文件路径加上
执行完后,页面打印台会输出一个audio.mp3文件
5.4 实现自动播放
实现页面自动播放生成的audio.mp3文件
index.html -->直接替换上面html的即可
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {#audio是HTML5的标签,autoplay表示自动播放,controls表示展示组件#} <audio src="" autoplay controls id="player"></audio> <br> <button onclick="start_reco()">开始废话</button> <br> <button onclick="stop_reco()">发送语音</button> </body> <script src="/static/recorder.js"></script> <script type="application/javascript"> // 访问后端的get_file,得到一个文件名 var get_file = "http://127.0.0.1:5300/get_file/"; // 创建WebSocket对象,index后面的是userid,是图灵机器人需要的 var ws = new WebSocket("ws://127.0.0.1:5300/index/taylor"); var reco = null; //录音对象 // 创建AudioContext对象 // AudioContext() 构造方法创建了一个新的 AudioContext 对象 它代表了一个由音频模块链接而成的音频处理图, 每一个模块由 AudioNode 表示 var audio_context = new AudioContext(); //要获取音频和视频,需要用到getUserMedia。桌面平台支持的浏览器包括Chrome, Firefox, Opera和Edge。 // 这里的|| 表示或者的关系,也就是能支持的浏览器 navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象 navigator.getUserMedia({audio: true}, create_stream, function (err) { console.log(err) }); //创建媒体流容器 function create_stream(user_media) { //AudioContext接口的createMediaStreamSource()方法用于创建一个新的MediaStreamAudioSourceNode 对象, // 需要传入一个媒体流对象(MediaStream对象)(可以从 navigator.getUserMedia 获得MediaStream对象实例), // 然后来自MediaStream的音频就可以被播放和操作。 // MediaStreamAudioSourceNode 接口代表一个音频接口,是WebRTC MediaStream (比如一个摄像头或者麦克风)的一部分。 // 是个表现为音频源的AudioNode。 var stream_input = audio_context.createMediaStreamSource(user_media); // 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流 reco = new Recorder(stream_input); } function start_reco() { //开始录音 reco.record(); //往里面写流 } function stop_reco() { //停止录音 reco.stop(); //停止写入流 get_audio(); //调用自定义方法 reco.clear(); //清空容器 } // 获取音频 function get_audio() { reco.exportWAV(function (wav_file) { // 发送数据给后端 ws.send(wav_file); }) } // 接收到服务端数据时触发 ws.onmessage = function (data) { // console.log(data.data); console.log(get_file + data.data); //打印文件名 // 修改id为player的src属性, document.getElementById("player").src = get_file + data.data; } </script> </html>
ok,下来就可以听到声音了
# 补充说明:这里生成的文件名我们给写死了,最好生成动态文件名,可以引入uuid,否则会出现缓存现象,得不到我们的效果