logo
3

Linux命令行机器人之---5.语音识别+千帆大模型实现个人专属语音助理

Linux命令行机器人系列文章导航

如果前三步骤都很熟悉了,请跳过直接第4步。否则强烈建议查看学习!!!
Linux命令行机器人之---1.初识百度智能云千帆大模型平台: https://cloud.baidu.com/qianfandev/topic/267409
Linux命令行机器人之---2.初学者快速入门千帆大模型平台: https://cloud.baidu.com/qianfandev/topic/267410
Linux命令行机器人之---3.千帆大模型平台HelloWorld实例: https://cloud.baidu.com/qianfandev/topic/267411
Linux命令行机器人之---(4.)100行代码挑战开发一个完整的命令行机器人: https://cloud.baidu.com/qianfandev/topic/267413
Linux命令行机器人之---5. 语音识别+千帆大模型实现个人专属语音助理: https://cloud.baidu.com/qianfandev/topic/267428
功能演示可以直接翻到最下面。

前言

上一篇文章,实现了纯文字的小助手,接下来,我们实现语音版的小助手。
完成本节的内容,需要你具备一些音视频领域的简单知识,例如音频的采样率,音频的编码格式。
不会也没关系,先做后理解皆可。
先来回顾一下上一个篇文章实现的功能:
如下图所示,这就是我们上一篇文章里不到100行代码,实现的文字版的问答小助手。
支持你输入问题,我回答问题的形式。
文字版的还是不太舒服,还需要手动输入才行。
如果我们实现了语音版的该多好,可以节省很多时间。
那么问答的形式就会改进成:
  • 1、你语音录入问题;
  • 2、我回答你;

实现智能语音助手的流程

至少完成以下几部分,才能完成整体的功能:
  • 1、语音输入;(那么就需要支持声音的录制)
  • 2、语音识别;(那么就需要支持声音的识别+声音转文字功能)
  • 3、问答功能;(以上一篇文章实现的代码为基础进行改进实现)
功能流程大致如下:
不卖官司了,本篇文章是结合百度语音识别功能+百度千帆大模型实现了你的“智能语音小助手”。

具体实现步骤

步骤如下:
1、录音功能;(因为需要上传录音才能转文字,所以这是前提)
2、语音转文字;
3、扩展代码;

1、实现录音功能

因为本次开发的案例,是全使用的python,所以也会使用python的库。
使用pyaudio库进行音频的录制;
有以下几点需要注意:
  • 1、百度语音识别技术,要求的语音的格式包括PCM格式,PCM是语音的一种格式,是无压缩的,所以无需转码的操作,可以节省时间。
  • 2、要求采样率需要是16000或者8000单位是Hz;(如果你开发过音视频领域的项目,一定很熟悉,否则需要百度下进行简单学习)
  • 3、要求是单声道;
经过摸索和实践,下面这段代码就可以实现录音功能:
实现了录制16Khz采样率,单声道的PCM数据;
代码中限制了只录制5s。
  
  
  
  
  
  
import pyaudio
import wave
class Audio_AI:
def __init__(self):
# 配置录音参数
self.FORMAT = pyaudio.paInt16 # 音频格式,可以根据需要选择
self.CHANNELS = 1 # 声道数(单声道)
self.RATE = 16000 # 采样率,可以根据需要选择
self.RECORD_SECONDS = 5 # 录制时长(秒)
self.OUTPUT_FILENAME = "recorded_audio.pcm" # 输出文件名
def audio_record(self):
# 初始化PyAudio
audio = pyaudio.PyAudio()
# 打开音频输入流
stream = audio.open(format=self.FORMAT, channels=self.CHANNELS,
rate=self.RATE, input=True,
frames_per_buffer=1024)
print("开始录制...")
frames = []
# 录制音频
for i in range(0, int(self.RATE / 1024 * self.RECORD_SECONDS)):
data = stream.read(1024)
frames.append(data)
print("录制完成.")
# 停止音频流
stream.stop_stream()
stream.close()
# 关闭PyAudio
audio.terminate()
# 保存录音结果为WAV文件
with wave.open(self.OUTPUT_FILENAME, 'wb') as wf:
wf.setnchannels(self.CHANNELS)
wf.setsampwidth(audio.get_sample_size(self.FORMAT))
wf.setframerate(self.RATE)
wf.writeframes(b''.join(frames))
print(f"音频已保存为 {self.OUTPUT_FILENAME}")
return self.OUTPUT_FILENAME
运行后,会在当前目录下生成一个".pcm"为后缀的音频文件:
  
  
  
  
  
  
recorded_audio.pcm
如果想测试音频,可以使用ffplay:
  
  
  
  
  
  
```shell
ffplay -f s16le -ar 16000 -ac 1 recorded_audio.pcm

2、语音转文字

具体的语音转文字如何在官方操作的这里就不过多说明了,可以参考官方的文档和千帆大模型平台调用API的流程是一样的。需要先创建一个应用,然后就有key了。
拿到了key就可以获取token,然后才能继续调用其他语音技术的API;
下面的代码中补充了语音转文字的代码:
audio_ai.py:
  
  
  
  
  
  
import pyaudio
import wave
import requests
import json
import base64
import time
timer = time.perf_counter
API_KEY = 'xxx'
SECRET_KEY = 'zzzz'
# 需要识别的文件
# AUDIO_FILE = './16k.pcm' # 只支持 pcm/wav/amr 格式,极速版额外支持m4a 格式
AUDIO_FILE = './recorded_audio.pcm' # 只支持 pcm/wav/amr 格式,极速版额外支持m4a 格式
# 文件格式
FORMAT = AUDIO_FILE[-3:] # 文件后缀只支持 pcm/wav/amr 格式,极速版额外支持m4a 格式
CUID = '123456PYTHON'
# 采样率
RATE = 16000 # 固定值
# 普通版
DEV_PID = 1537 # 1537 表示识别普通话,使用输入法模型。根据文档填写PID,选择语言及识别模型
ASR_URL = 'http://vop.baidu.com/server_api'
TOKEN_URL = 'http://aip.baidubce.com/oauth/2.0/token'
class Audio_AI:
def __init__(self):
# 配置录音参数
self.FORMAT = pyaudio.paInt16 # 音频格式,可以根据需要选择
self.CHANNELS = 1 # 声道数(单声道)
self.RATE = 16000 # 采样率,可以根据需要选择
self.RECORD_SECONDS = 5 # 录制时长(秒)
self.OUTPUT_FILENAME = "recorded_audio.pcm" # 输出文件名
def audio_record(self):
# 初始化PyAudio
audio = pyaudio.PyAudio()
# 打开音频输入流
stream = audio.open(format=self.FORMAT, channels=self.CHANNELS,
rate=self.RATE, input=True,
frames_per_buffer=1024)
print("开始录制...")
frames = []
# 录制音频
for i in range(0, int(self.RATE / 1024 * self.RECORD_SECONDS)):
data = stream.read(1024)
frames.append(data)
print("录制完成.")
# 停止音频流
stream.stop_stream()
stream.close()
# 关闭PyAudio
audio.terminate()
# 保存录音结果为WAV文件
with wave.open(self.OUTPUT_FILENAME, 'wb') as wf:
wf.setnchannels(self.CHANNELS)
wf.setsampwidth(audio.get_sample_size(self.FORMAT))
wf.setframerate(self.RATE)
wf.writeframes(b''.join(frames))
print(f"音频已保存为 {self.OUTPUT_FILENAME}")
return self.OUTPUT_FILENAME
def get_token(self):
# 组装数据
params = {
'grant_type': 'client_credentials',
'client_id': API_KEY,
'client_secret': SECRET_KEY
}
response = requests.post(TOKEN_URL, timeout=10, params=params)
if response.status_code == 200:
# 转成JSON
result = json.loads(response.text)
# print(result)
if ('access_token' in result.keys() and 'scope' in result.keys()):
return result['access_token']
else:
print("获取token失败!")
else:
print("请求失败")
def read_audio_data(self, audio_filename):
speech_data = []
with open(audio_filename, 'rb') as speech_file:
speech_data = speech_file.read()
return speech_data
def asr_audio(self, speech_data, length, token):
# 进行base64编码
speech = base64.b64encode(speech_data)
speech = str(speech, 'utf-8')
headers = { "Content-Type": "application/json" }
# 封装识别API请求的参数
body = {'dev_pid': DEV_PID,
#"lm_id" : LM_ID, #测试自训练平台开启此项
'format': FORMAT,
'rate': RATE,
'token': token,
'cuid': CUID,
'channel': 1,
'speech': speech,
'len': length
}
result = {}
begin = timer()
json_data = json.dumps(body, indent=4) # indent 参数可选,用于格式化输出
response = requests.post(ASR_URL,headers=headers, timeout=10, data=json_data)
print(response.status_code)
if response.status_code == 200:
# 转成JSON
result_json = json.loads(response.text)
result = result_json["result"]
else:
print("请求失败")
print ("Request time cost %f" % (timer() - begin))
return result
def run_audio_asr(self, audio_filename):
# 获取token
token = self.get_token()
print("get token:", token)
# 读取音频文件
speech_data = self.read_audio_data(audio_filename)
length = len(speech_data)
if length == 0:
print("发送识别失败,录音数据可能为空")
else:
result = self.asr_audio(speech_data, length, token)
print(result)
return result

3、扩展代码

到这个阶段上面的代码,就得到了audio_ai.py文件,接下来就扩展到我们之前实现的命令行的代码上。
1、import引入文件
  
  
  
  
  
  
import audio_ai as audio_ai
2、在__init__代码中初始化audio_ai对象:
  
  
  
  
  
  
# audio
self.audio_ai = audio_ai.Audio_AI()
3、改造run_loop函数:
下面的代码就是改造后的,支持了用户选择使用语音输入还是手动输入。
  
  
  
  
  
  
def run_loop(self):
while True:
# print("##########################")
# # 使用 input() 函数接收用户输入
# user_input_msg = input("问:")
# recv_msg = self.send_chat(user_input_msg)
# print("答:", recv_msg)
# print("##########################")
while True:
print("##########################")
# 使用 input() 函数接收用户输入
print("#指令---> 1:语音输入;2:手动输入;")
user_input_msg = input("指令:")
if user_input_msg == "1":
print(" 语音输入 ")
# 1.录制声音
audio_filename = self.audio_ai.audio_record()
# 2.识别结果
results = self.audio_ai.run_audio_asr(audio_filename)
print("问:", results)
print("问:", results[0])
# 3.将识别结果发送至千帆大模型
recv_msg = self.send_chat(results[0])
print("答:", recv_msg)
elif user_input_msg == "2":
print(" 手动输入 ")
print("##########################")
# 使用 input() 函数接收用户输入
user_input_msg = input("问:")
recv_msg = self.send_chat(user_input_msg)
print("答:", recv_msg)
print("##########################")
print("##########################")

功能演示

1、首次运行:

会提供一个选项:
输入1即可语音输入,输入2即可手动输入文字;

2、先来体验一下手动输入

输入2回车,会提示选择的是手动输入,然后会提示你输入问题
例如输入:
眨眼间就会有结果:

3、再体验下语音输入

可以继续选择1,也可以重新运行:
提示“开始录制...”时,然后就可以开始说话了,因为限制了5s,所以请尽快说完.
结果:

视频演示:

因为文章中不能插入视频,录制的演示视频放到了视频号里,可以自行扫码查看。

全部代码位置

代码已放在了github上,欢迎点赞收藏:
https://github.com/truedei/cmdchat

其他问题排查

原来获取token不支持浏览器跨域,我说怎么解决都不可以。
评论
用户头像