如何利用python实现在线语音识别
本篇文章主要介绍使用 python 借助 百度人工智能 实现在线的 语音识别 功能。
学习经历
在正式介绍如何进行在线语音识别功能之前我想先分享一下我自己的学习顺序:
首先对核心内容语音识别模块进行编写,在编写的过程中发现音频文件需要使用 pcm格式 ,于是下载了百度AI的范例pcm文件,并且完成了语音识别,接下来学习转码,用手机录音,然后用 ffmpeg 将录音从mp3文件转换为pcm文件,开始使用cmd手动输入实现转码,顺利转码后改为学习用python调用cmd自动执行。最后是学习python录音,录音得到的文件是wav格式,于是又把mp3->pcm的代码改为wav->pcm,最后按顺序将录音,转码,识别三个模块串在一起,形成了一个在线语音识别的程序。程序可以实现固定时长的录音(说话前预设时间,中途无法中断或延长时间)保存录音文件并将录音文件转码成pcm格式,然后将pcm音频上传到百度AI平台(这就意味着必须保证网络的畅通),进行识别后传输回识别内容。
作为一个初学者在决定学习这项功能时觉得任务非常繁重,网上能搜集到的资料驳杂而零碎,但通过不断的拼凑与尝试,最终完成了程序的编写。现在将我的实现方法分享给大家,希望可以与大家互相交流学习!
逻辑顺序
用python实现在线语音识别,我们首先需要一段语音,这段语音的格式是 .pcm ,这段语音的来源用python录制,录制后的格式是 .wav ,然后利用python调用cmd,使用 ffmpeg 将格式转码成 .pcm ,最后将文件上传到百度人工智能,并接受返回的文字结果:
- 录音;
- 转码;
- 在线语音识别;
环境
- Windows 8.1
- Python 3.7
- Pycharm 5.0.3
需要安装的模块:
- PyAudio (实现录音)
- aip (实现语音识别)
一.录音
1.1 安装pyaudio
录音需要安装新的模块,名为PyAudio。安装方法: 直接打开cmd命令行,输入 pip install pyaudio。
有些人可能会出现如下错误 :
error: Microsoft Visual C++ 14.0 is required. Get it with “Microsoft Visual C++ Build Tools”: http://landinghub.visualstudio.com/visual-cpp-build-tools。
解决这个错误的方法是进入该地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio 下载对应python版本的 .whl 文件。
我下载的是 PyAudio-0.2.11-cp37-cp37m-win_amd64.whl 。安装完这个文件后就可以再次输入 pip install pyaudio 成功安装pyaudio模块了。
1.2 用python完成录音
安装完成后按照如下代码编写,实现录音功能,得到**.wav**文件。代码如下:
import pyaudio
import wave
import time as t
name = ""
t.localtime()
for i in range(0,6):
name += str(t.localtime()[i])
if i in [3 , 4]:
name += ':'
elif i == 5:
pass
else:
name += '-'
# ↑用开始录音的时间作为生成的文件名
CHUNK = 1024 # 底层缓存块的大小
FORMAT = pyaudio.paInt16 # 16K
CHANNELS = 1 # 单通道
RATE = 44100 # 采样率
RECORD_SECONDS = 1 # 录音时长(s)
WAVE_OUTPUT_FILENAME = name + '.wav'
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
# ↑设置录制的格式、参数
print("* 开始录音,您有%d秒时间输入语音内容!"%RECORD_SECONDS)
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
print("* 录音结束")
stream.stop_stream()
stream.close()
p.terminate()# 释放PortAudio资源
# ↓生成wave文件
wf = wave.open("E:/pycharmcode/语音库/" + WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
二.转码
2.1 用cmd转码
首先要下载 ffmpeg,根据百度经验:(https://jingyan.baidu.com/album/f7ff0bfcd64cea2e26bb1334.html?picindex=7) 在 ffmpeg 官网上下载 ffmpeg,下载完后将ffmpeg.exe、ffplay.exe、ffprobe.exe三个程序放到C:\Windows\System32该目录中,这样就可以直接在cmd中调用ffmpeg了,然后根据百度智能云文档提供的音频转码方式在cmd命令行中转码,其中:
wav 文件转 16k 16bits 位深的单声道pcm文件:
ffmpeg -y -i 16k.wav -acodec pcm_s16le -f s16le -ac 1 -ar 16000 16k.pcm
其中16k.wav和16k.pcm是输入路径和输出路径,自己使用的时候注意输入正确的路径名,如E:\pycharmcode\语音库\16k.pcm 。
注意:在cmd中的输入路径和输出路径不能有空格,如E:\pycharm code\语音库\16k.pcm,由于pycharm与code 之间存在空格,导致cmd报错:Permission denied
。
mp3 文件转 16K 16bits 位深的单声道 pcm文件:
ffmpeg -y -i aidemo.mp3 -acodec pcm_s16le -f s16le -ac 1 -ar 16000 16k.pcm
2.2 使用subprocess模块在python中调用cmd转码
我们的目的是实现一串代码实现所有语音转换的功能,所以需要通过python来调用cmd指令来完成转码。
Subprocess模块不需要安装,直接import调用就可以了。
PS:当时的参考文献找不到了,最后的实现是使用subprocess.Popen()功能,具体实现代码如下所示:
# ↓转码
p_name_wav = "E:\\pycharmcode\\语音库\\" + name + '.wav'
p_name_pcm = "E:\\pycharmcode\\语音库\\" + name + '.pcm'
cmd ="ffmpeg -y -i " + p_name_wav + " -acodec pcm_s16le -f s16le -ac 1 -ar 16000 " + p_name_pcm
p = subprocess.Popen(cmd , shell = True)
p.wait()
(该段代码中的 name 变量见前文录音)
注意:对cmd的赋值是通过三个字符串拼接得到的,在字符串的内容和引号之间切记要空格,不然得到的将是连在一起的一串字符导致报错。
三. 语音识别模块
3.1 安装百度aip模块
首先在cmd命令行安装百度aip:在cmd命令行输入 pip baidu-aip,我目前用的版本是2.2.13.0。
3.2 获取百度人工智能平台ID
登陆百度的AI平台 ai.baidu.com,在控制台创建应用,获取ID。获取ID的过程可以参考下面的视频链接(该视频中教你如何调用百度人工智能进行语音合成): https://v.qq.com/x/page/f0807ugi16t.html
在控制台创建应用并获取ID后根据百度语音文档中心的 Python SDK教程编写代码:
(https://ai.baidu.com/docs#/ASR-Online-Python-SDK/top)
3.3 语音识别代码
#_*_coding:utf-8_*_
# 开发人员: 批发萝莉:2019/6/17 9:51
# 文件名称:语音识别2.py
# 开发工具:PyCharm
from aip import AipSpeech
app_id = "16536506"
api_key = "xZ2Gof2ORP98FHGDxtNUqYZO"
secret_key = "**************************" # 大家将内容改为自己的秘钥
client = AipSpeech(app_id , api_key , secret_key)
# 读取文件
def get_file_content(filepath):
with open(filepath , "rb") as fp:
return fp.read()
# 识别本地文件
result = client.asr(get_file_content("E:/pycharmcode/语音库/16k.pcm") , "pcm" , 16000 , {
"dev_pid" : 1536 ,
})
# client.asr(speech语音文件的路径 , format格式 , rate采样率 , cuid用户标识 , dev_pid语言模式)
# 1536 普通话(支持简单的英文识别) 搜索模型 无标点
# 1537 普通话(纯中文识别) 输入法模型 有标点
# 1737 英语 有标点
# 1637 粤语 有标点
# 1837 四川话 有标点
# 1936 普通话远场 远场模型 有标点
result_list = list(result.values())
if result_list[1] != 'success.':
print(result)
else:
print(result_list[3])
最后附上完整的代码
#_*_coding:utf-8_*_
# 开发人员: 批发萝莉:2019/6/25 11:31
# 文件名称:录音+转码+识别.py
# 开发工具:PyCharm
import pyaudio
import wave
import time as t
import subprocess
from aip import AipSpeech
# ↓录音
name = ""
t.localtime()
for i in range(0,6):
name += str(t.localtime()[i])
if i in [3 , 4]:
name += ':'
elif i == 5:
pass
else:
name += '-'
# ↑用开始录音的时间作为生成的文件名
CHUNK = 1024 # 底层缓存块的大小
FORMAT = pyaudio.paInt16 # 16K
CHANNELS = 1 # 单通道
RATE = 44100 # 采样率
RECORD_SECONDS = 5 # 录音时长(s)
WAVE_OUTPUT_FILENAME = name + '.wav'
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
# ↑设置录制的格式、参数
print("* 开始录音,您有%d秒时间输入语音内容!"%RECORD_SECONDS)
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
print("* 录音结束")
stream.stop_stream()
stream.close()
p.terminate() # 释放PortAudio资源
# ↓生成wave文件
wf = wave.open("E:/pycharmcode/语音库/" + WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
# ↓转码
p_name_wav = "E:\\pycharmcode\\语音库\\" + name + '.wav'
p_name_pcm = "E:\\pycharmcode\\语音库\\" + name + '.pcm'
cmd ="ffmpeg -y -i " + p_name_wav + " -acodec pcm_s16le -f s16le -ac 1 -ar 16000 " + p_name_pcm
p = subprocess.Popen(cmd , shell = True)
p.wait()
# ↓语音识别
app_id = "16536506"
api_key = "xZ2Gof2ORP98FHGDxtNUqYZO"
secret_key = "*************************" # 大家将内容改为自己的秘钥
client = AipSpeech(app_id , api_key , secret_key)
# 读取文件
def get_file_content(filepath):
with open(filepath , "rb") as fp:
return fp.read()
# 识别本地文件
result = client.asr(get_file_content(p_name_pcm) ,
"pcm" ,
16000 ,
{"dev_pid" : 1536 ,})
result_list = list(result.values())
if result_list[1] != 'success.':
print(result)
else:
print(result_list[3])
运行结果如下所示: