1. 任务定义

  • 搭建以展品讲解为主要内容的语音对话系统
    1. 展品导览:通过对话,确认用户感兴趣的展品(假设展品为展馆内所展示的物品或图、画),以及导引用户参观其余展品。
    2. 展品讲解:通过对话,介绍展品。能够回答用户关于展品的n>1个提问。
    3. 闲聊:打招呼、再见、自我介绍等。
  • 实现方法不限

2. 实验环境

  • Windows 10
  • python 3.7.8
  • 图灵机器人
  • 百度语音识别

3. 系统功能

  • 机器人自我介绍
  • 打招呼和再见
  • 画展概况介绍
  • 指定展品编号进行介绍
  • 指定作者介绍其展品
  • 介绍展品作者信息
  • 介绍剩余展品内容
  • 部分闲聊

4. 方法说明

4.1 本地录音

4.1.1 初始化

framerate = 16000       # 采样率
num_samples = 2000      # 采样点
channels  = 1           # 声道
sampwidth = 2           # 采样宽度2bytes
FILEPATH  = 'speech.wav'

4.1.2 录音

  • 调用PyAudio库进行录音,recordTime为录音时长,默认为4秒
def my_record(recordTime=4):
    pa = PyAudio()
    # 打开一个新的音频stream
    stream = pa.open(format=paInt16, channels=channels,
                     rate=framerate, input=True, frames_per_buffer=num_samples)
    
    # 存放录音数据
    my_buf = [] 

    t = time.time()
    print('正在录音...')
 
    while time.time() < t + recordTime:  # 设置录音时间(秒)
    	# 循环read,每次read 2000frames
        string_audio_data = stream.read(num_samples)
        my_buf.append(string_audio_data)
    print('录音结束.')
    save_wave_file(FILEPATH, my_buf)
    stream.close()

4.1.3 保存音频

filepath:保存音频路径
data:音频内容

def save_wave_file(filepath, data):
    wf = wave.open(filepath, 'wb')
    wf.setnchannels(channels)
    wf.setsampwidth(sampwidth)
    wf.setframerate(framerate)
    wf.writeframes(b''.join(data))
    wf.close()

4.2 百度语音识别

4.2.1 初始化

# 百度语音识别的APIKey和SecretKey
base_url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s"
APIKey = "***************"
SecretKey = "*****************"

HOST = base_url % (APIKey, SecretKey)

4.2.2 语音识别

  • 获取音频内容
  • file:音频文件路径
def get_audio(file):
    with open(file, 'rb') as f:
        data = f.read()
    return data
  • 获取token信息
def getToken(host):
    res = requests.post(host)
    return res.json()['access_token']
  • 将音频内容上传到百度语音识别系统并获取结果
  • speech_data:音频内容
  • token:token信息
  • dev_pid:百度语音识别提供的几种语言选择,1537为普通话
# 传入语音二进制数据,token
# dev_pid为百度语音识别提供的几种语言选择
def speech2text(speech_data, token, dev_pid=1537):
    FORMAT = 'wav'
    RATE = '16000'
    CHANNEL = 1
    CUID = '********'
    SPEECH = base64.b64encode(speech_data).decode('utf-8')

    data = {
        'format': FORMAT,
        'rate': RATE,
        'channel': CHANNEL,
        'cuid': CUID,
        'len': len(speech_data),
        'speech': SPEECH,
        'token': token,
        'dev_pid':dev_pid
    }
    url = 'https://vop.baidu.com/server_api'
    headers = {'Content-Type': 'application/json'}
    # r=requests.post(url,data=json.dumps(data),headers=headers)
    print('正在识别...')
    r = requests.post(url, json=data, headers=headers)
    Result = r.json()
    if 'result' in Result:
        return Result['result'][0]
    else:
        return Result

4.3 图灵机器人回答

4.3.1 在图灵机器人平台新增语料库

在这里插入图片描述

4.3.2 初始化

# 图灵机器人的API_KEY、API_URL
turing_api_key = "********************"
api_url = "http://openapi.tuling123.com/openapi/api/v2"
headers = {'Content-Type': 'application/json;charset=UTF-8'}

4.3.3 获得回复

  • 将问题上传到图灵机器人系统获得回复
  • text_words:问题文本内容
  • result:图灵机器人的回答
# 图灵机器人回复
def Turing(text_words=""):
    req = {
        "reqType": 0,
        "perception": {
            "inputText": {
                "text": text_words
            },

            "selfInfo": {
                "location": {
                    "city": "北京",
                    "province": "北京",
                    "street": "北京邮电大学西土城校区"
                }
            }
        },
        "userInfo": {
            "apiKey": '**************',
            "userId": "GZR"
        }
    }

    req["perception"]["inputText"]["text"] = text_words
    # 获得回复
    response = requests.request("post", api_url, json=req, headers=headers)
    response_dict = json.loads(response.text)
	
	# 提取回复内容
    result = response_dict["results"][0]["values"]["text"]
    print("NAO Robot said: " + result)
    return result

4.4 处理回答内容并语音回答

  • 处理图灵机器人的回答内容并进行语音回复
  • response:图灵机器人的回答
  • engine:语音引擎
  • allPaints:剩余尚未介绍展品
def answer(response, engine, allPaints):
	# 如果不需要全部介绍
    if response != '全部':
        temp = response[1]
        engine.say(response)
        engine.runAndWait()
        # 判断是否是介绍一幅展品,如果是则将其从剩余未介绍展品中剔除并介绍,否则正常回复
        if temp in allPaints:
            allPaints.remove(temp)
            temp = ""
            for i in allPaints:
                temp += i
                temp += '、'
            print("这里还剩下" + temp + "号画,请问需要继续介绍哪一幅画?")
            engine.say("这里还剩下" + temp + "号画,请问需要继续介绍哪一幅画?")
        engine.runAndWait()
    # 介绍全部剩余展品
    else:
        engine.say("那我就开始啦!")
        engine.runAndWait()
        for i in range(len(allPaints)):
            result = "介绍一下第{}幅画".format(allPaints[i])
            response = Turing(result)
            engine.say(response)
            engine.runAndWait()
        # 剩余展品清空
        allPaints = []

5. 演示视频及源码

  • 见附件
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐