查看原文
其他

如何基于本地语音识别,搭建一款智能聊天机器人?

李秋键 CSDN 2020-10-16

作者 | 李秋键
责编 | 屠敏
出品 | CSDN(ID:CSDNnews)

近几年来,人工智能发展火热,尤其是语音识别方面的落实项目更是普遍存在于我们的生活中,像手机中常见的语音助手、Siri 和电脑中的小娜等等,但是他们却很难做到私人订制的效果,即达到个人个性化的需求,所以今天我们的目的在于搭建一个个性化适用于自己的语音聊天机器人。这里我们这个项目的优点在于:

  1. 本地语音识别,可以彻底摆脱互联网,在自己电脑上实现语音识别;

  2. 搭建适用于自己的语音聊天库,当然这里我们将简单的借助互联网强大的知识库作为聊天库;

  3. 循环调用,实现监控效果。

下面简单介绍下语音识别应用近几年来的发展趋势:

  1. 具有越来越充实的专业知识库。就是指针对特定用例的专家级系统,比如帮助航空公司客服回答客户的问题,或者帮助医生做笔记。

  2. 趋于更强的个性化功能。使用类似的方法,可能会使得语音助手会用你喜欢的方式与你交谈。比如提供像匹配谈话对象的口音和音量这样的简单的功能。或者,智能助手也可以改变其表达方式。

  3. 由被动变主动。优秀的助手会在你提出要求的时候给你做事,而卓越的助手则不需要你提出要求,而是能够前瞻性地主动帮你解决问题。

  4. 反馈机制。我们的机器如何知道自己做对还是做错?就是通过反馈机制进行纠正错误。

  5. 新的交互方式。语音助手应该不仅仅局限于语音互动的想法,而是可以使用大量不同的信号来得出结论,比如心理学、读心术等等。

下面我们就正式进入我们今天的项目搭建!


实验前的准备


首先我们使用的python版本是3.6.5。所测试的系统有windows10,windows7,Linux系统以及苹果系统。从这点也可以看出python多平台和多拓展性、易于迁移的优点。

所使用的的Python库有request库,其目的是用来加载网络聊天库;keras库用来加载本地语音识别模型等等。


语音聊天的建立


1、录音麦克风

首先我们将要借助pyaudio库进行录音其中定义参数有取样频率,声音阈值等等。具体可见下面详细代码:

class GenAudio(object):
    def __init__(self):
        self.num_samples = 2000  # pyaudio内置缓冲大小
        self.sampling_rate = 8000  # 取样频率
        self.level = 1500  # 声音保存的阈值
        self.count_num = 20  # count_num个取样之内出现COUNT_NUM个大于LEVEL的取样则记录声音
        self.save_length = 8  # 声音记录的最小长度:save_length*num_samples个取样
        self.time_count = 8  # 录音时间,单位s
        self.voice_string = []
    def save_wav(self, filename):
        wf = wave.open(filename, 'wb')
        wf.setnchannels(1)
        wf.setsampwidth(2)
        wf.setframerate(self.sampling_rate)
        wf.writeframes(np.array(self.voice_string).tostring())
        wf.close()
    def read_audio(self):
        pa = PyAudio()
        stream = pa.open(format=paInt16, channels=1, rate=self.sampling_rate, input=True,
                         frames_per_buffer=self.num_samples)
        save_count = 0
        save_buffer = []
        time_count = self.time_count
        while True:
            time_count -= 1
            # 读入num_samples个取样
            string_audio_data = stream.read(self.num_samples)
            # 将读入的数据转换为数组
            audio_data = np.fromstring(string_audio_data, dtype=np.short)
            # 计算大于?level?的取样的个数
            large_sample_count = np.sum(audio_data > self.level)
            print(np.max(audio_data)), "large_sample_count=>", large_sample_count
            # 如果个数大于COUNT_NUM,则至少保存SAVE_LENGTH个块
            if large_sample_count > self.count_num:
                save_count = self.save_length
            else:
                save_count -= 1
            if save_count < 0:
                save_count = 0
            if save_count > 0:
                save_buffer.append(string_audio_data)
            else:
                if len(save_buffer) > 0:
                    self.voice_string = save_buffer
                    save_buffer = []
                    print("Recode?a?piece?of??voice?successfully!")
                    return True
                if time_count == 0:
                    if len(save_buffer) > 0:
                        self.voice_string = save_buffer
                        save_buffer = []
                        print("Recode?a?piece?of??voice?successfully!")
                        return True
                    else:
                        return True
r = GenAudio()
r.read_audio()
r.save_wav("test.wav")

2、本地语音识别

目的在于让电脑知道你说了什么。主要是借助于Keras库进行读取模型,glob读取录音文件,使用pickle解码,具体如下:

from keras.models import load_model
from keras import backend as K
import numpy as np
import librosa
from python_speech_features import mfcc
import pickle
import glob
wavs = glob.glob('data/*.wav')
with open('dictionary.pkl''rb'as fr:
    [char2id, id2char, mfcc_mean, mfcc_std] = pickle.load(fr)
mfcc_dim = 13
model = load_model('asr.h5')
index = np.random.randint(len(wavs))
print(wavs[index])
audio, sr = librosa.load(wavs[index])
energy = librosa.feature.rmse(audio)
frames = np.nonzero(energy >= np.max(energy) / 5)
indices = librosa.core.frames_to_samples(frames)[1]
audio = audio[indices[0]:indices[-1]] if indices.size else audio[0:0]
X_data = mfcc(audio, sr, numcep=mfcc_dim, nfft=551)
X_data = (X_data - mfcc_mean) / (mfcc_std + 1e-14)
print(X_data.shape)
with open(wavs[index] + '.trn''r', encoding='utf8'as fr:
    label = fr.readlines()[0]
    print(label)
pred = model.predict(np.expand_dims(X_data, axis=0))
pred_ids = K.eval(K.ctc_decode(pred, [X_data.shape[0]], greedy=False, beam_width=10, top_paths=1)[0][0])
pred_ids = pred_ids.flatten().tolist()
print(''.join([id2char[i] for i in pred_ids]))

3、加载聊天

在识别语音的基础上,让电脑在网上搜索如何合理的回复你的话。这里输入的结果是语音识别后的文字,输出的结果同样为文字,最后再通过文字转为语音达到语音回复效果!

num=3
    if process == '':
        print("not")
    else:
        header = {
            'User-Agent''Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
        url = requests.get("https://www.baidu.com/s?wd=" + process, headers=header)
        # 为了防止中文乱码,编码使用原网页编码
        url.raise_for_status()
        url.encoding = url.apparent_encoding
        # print(url.text)
        object = etree.HTML(url.text)
        # print(object)
        # 正则匹配搜索出来答案的所有网址
        # 获取页面
        head =object.xpath('//div[@id="page"]//a/@href')
        txt0=''
        for i in range(num):
            header0 
= {
                'User-Agent''Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
            url0 = requests.get("https://www.baidu.com" + head[i], headers=header0)
            # 为了防止中文乱码,编码使用原网页编码
            url0.raise_for_status()
            url0.encoding = url0.apparent_encoding
            # print(url.text)
            object0 = etree.HTML(url.text)
            para0 = object.xpath('/html/body//div[@class="c-abstract"]/text()')
            para10 = object.xpath('/html/body//div[@class="c-abstract"]/em/text()')
            txt0 = ''
            for i in range(len(para0)):
                try:
                    txt0 
= txt0 + para0[i] + para10[i]
                except:
                    pass
        #print(head)
        # 详细内容
        para = object.xpath('/html/body//div[@class="c-abstract"]/text()')
        para1 = object.xpath('/html/body//div[@class="c-abstract"]/em/text()')
        txt = ''
        for i in range(len(para)):
            try:
                txt 
= txt + para[i] + para1[i]+txt0
            except:
                pass
    return txt
txtk=baike()
txtd=baidu()
result=txtk+txtd
print(result) 

4、文字转语音进行回复

#文字转录音
APP_ID = '15118279'
API_KEY = 'xUx0Gm2AG2YMtA3FnGfwoKdP'
SECRET_KEY = 'hdxyMvABhUD4xnacGtDdeHbEOUGmdjNx'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
def text_to_audio(text):
    file_name ='luyin'  # 保证文件名不重复
    result  = client.synthesis(text, 'zh'1, {
        'spd':5,
        'vol'5,
        'pit':5,
        'per':0
    })
    # 识别正确返回语音二进制 错误则返回dict 参照下面错误码
    if not isinstance(result, dict):
        with open('%s.mp3'%(file_name), 'wb'as f:
            f.write(result)
return '%s.mp3'%(file_name)

最终我们的测试效果就是:语音和文字同步显示!我问了句“什么是语文?”电脑语音并加上文字显示回答了“语文是语言文字、语言文章、语言文学、的简称,其本义是语言文字。语言包括和。口头语言较随意,直接易懂,而书面语言讲究准确和语法;文学包括中外古今文学等。

作者简介:李秋键,CSDN 博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap安卓武侠游戏一部,vip视频解析,文意转换工具,写作机器人等项目,发表论文若干,多次高数竞赛获奖等等。

【End】《原力计划【第二季】- 学习力挑战》正式开始!
即日起至 3月21日,千万流量支持原创作者,更有专属【勋章】等你来挑战
推荐阅读 
官宣!阿里进军 5G,成立 XG 实验室发力新基建
上线两个月冲上 App Store 免费榜 Top 2,腾讯会议有什么独到之处?

前沿技术探秘:知识图谱构建流程及方法

留德武汉程序员在疫区:凌晨下载数据,网速影响工作

云原生的漏洞与威胁有哪些?云原生安全性如何?这里有你想知道的一切!

编程小白模拟简易比特币系统,手把手带你写一波!(附代码) | 博文精选

你点的每一个在看,我认真当成了喜欢

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存