AI数字人入门系列004:接入百度ASR,实现“能听会答”交互闭环

大家好,我是数字实现AI工程师王杰。经过前三篇的人入入百铺垫,我们的门系AI数字人已经实现了“自然说话”和“唇形同步”,但目前还只能被动念固定文本,列接无法和我们互动。交互今天是闭环系列第4篇,我们就打通“听”的能听会答能力——接入百度语音识别(ASR),再结合简单的数字实现问答逻辑,实现“你说话→数字人听懂→数字人回答”的人入入百完整交互闭环。
先梳理下核心流程,门系让大家一目了然:① 你通过麦克风说话,列接录音保存为音频文件;② 调用百度ASR接口,交互将音频转成文字(语音→文字);③ 通过预设问答库匹配回答(后续会替换成大模型,闭环实现自由对话);④ 调用百度TTS将回答转成语音,能听会答再结合上一篇的唇形同步功能,让数字人说出答案。整个流程完全自动化,无需手动输入文字。
今天我们依然选用百度智能云的服务,原因有两个:一是百度ASR免费额度充足(新用户有200万次免费调用),二是和上一篇的TTS共用一个应用,无需额外创建密钥,降低接入成本。话不多说,直接上实操。
一、前置准备:确认百度应用支持ASR功能
我们直接复用第2篇创建的百度智能云应用,只需确认应用已开通“语音识别”权限:
1. 登录百度智能云控制台,进入“语音技术→应用管理”;
2. 找到之前创建的应用(如“AI数字人TTS”),查看“开通服务”列表,确保“语音识别”已勾选(默认创建应用时会自动开通,若未开通,点击“编辑”添加即可);
3. 复制该应用的APP_ID、API_KEY、SECRET_KEY,和上一篇完全一致,无需重新创建。
二、环境准备(补充依赖库)
上一篇我们已经安装了baidu-aip、librosa、opencv-python等库,这一篇需要额外安装“录音库”(用于采集麦克风声音),命令行输入:
pip install pyaudio # 麦克风录音核心库 pip install wave # 辅助保存WAV音频文件温馨提示:Windows用户若安装pyaudio失败,可先下载对应Python版本的whl文件(下载地址:
https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio),再执行pip install 下载的文件名.whl;Mac用户可先执行brew install portaudio,再安装pyaudio。三、完整代码(ASR+TTS+唇形同步+问答交互)
代码整合了前3篇的核心功能(百度TTS、唇形同步),新增“麦克风录音”“百度ASR语音转文字”“预设问答匹配”模块,带详细注释,新手可直接复制使用:
# 导入依赖库 from aip import AipSpeech import cv2 import numpy as np from playsound import playsound import os import librosa import threading import time import pyaudio import wave # 1. 百度服务配置(复用之前的密钥,替换成你的) APP_ID = 你的APP_ID API_KEY = 你的API_KEY SECRET_KEY = 你的SECRET_KEY # 初始化百度语音客户端(同时支持TTS和ASR) client = AipSpeech(APP_ID, API_KEY, SECRET_KEY) # 2. 麦克风录音功能(采集用户语音) def record_audio(output_file=user_voice.wav, record_seconds=5): # 录音参数配置 FORMAT = pyaudio.paInt16 # 音频格式 CHANNELS = 1 # 单声道(兼容性更好) RATE = 16000 # 采样率(百度ASR推荐16000Hz) CHUNK = 1024 # 数据块大小 # 初始化录音对象 p = pyaudio.PyAudio() # 打开麦克风流 stream = p.open( format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK ) print(f"请说话,录音将持续{ record_seconds}秒...") frames = [] # 采集音频数据 for _ in range(0, int(RATE / CHUNK * record_seconds)): data = stream.read(CHUNK) frames.append(data) print("录音结束!") # 停止录音并释放资源 stream.stop_stream() stream.close() p.terminate() # 保存音频文件(WAV格式,百度ASR推荐) wf = wave.open(output_file, wb) wf.setnchannels(CHANNELS) wf.setsampwidth(p.get_sample_size(FORMAT)) wf.setframerate(RATE) wf.writeframes(b.join(frames)) wf.close() return output_file # 3. 百度ASR语音转文字(核心功能) def baidu_asr(audio_file): # 读取音频文件(百度ASR要求格式:WAV,采样率16000Hz,单声道) with open(audio_file, rb) as f: audio_data = f.read() # 调用百度ASR接口 result = client.asr( speech=audio_data, format=wav, # 音频格式 rate=16000, # 采样率(和录音参数一致) channel=1 # 单声道 ) # 处理识别结果 if result[err_no] == 0: # 识别成功(err_no=0为成功) user_text = result[result][0] print(f"你说的话:{ user_text}") return user_text else: print(f"语音识别失败:{ result[err_msg]}") return None # 4. 预设问答库(简化版交互,后续替换成大模型) def get_answer(user_text): # 简单的关键词匹配逻辑,可根据需求扩展 qa_dict = { "你好": "你好呀!很高兴收到你的问候~", "你叫什么名字": "我是基于AI技术打造的数字人,你可以叫我小凯~", "今天天气怎么样": "抱歉呀,我暂时还不能查询实时天气,后续会添加这个功能哦~", "怎么实现唇形同步": "唇形同步的核心是通过分析语音能量判断发音节奏,再切换对应的唇形图片,具体可以看系列第3篇内容~", "再见": "再见啦!期待下次和你聊天~" } # 匹配关键词(忽略大小写和空格) user_text_clean = user_text.strip().lower() for question, answer in qa_dict.items(): if question in user_text_clean: return answer # 无匹配答案时的默认回复 return "抱歉,我还没理解你的意思~ 你可以问我‘你好’‘你叫什么名字’哦~" # 5. 复用百度TTS合成语音(来自第2篇) def baidu_tts(text, output_file=digital_human_voice.mp3): result = client.synthesis( text=text, lang=zh, ctp=1, per=3 # 情感女声,可自行修改 ) if not isinstance(result, dict): with open(output_file, wb) as f: f.write(result) return output_file else: print(f"语音合成失败:{ result[err_msg]}") return None # 6. 复用语音能量分析(来自第3篇) def get_voice_energy(audio_file): y, sr = librosa.load(audio_file, sr=None) frame_length = 2048 hop_length = 512 energy = np.array([ np.sum(np.square(y[i:i+frame_length])) for i in range(0, len(y), hop_length) ]) threshold = np.mean(energy) * 1.2 energy_state = [1 if e > threshold else 0 for e in energy] return energy_state, sr, hop_length # 7. 复用唇形同步显示(来自第3篇) def show_lip_sync(lip_images, energy_state, sr, hop_length): lips = [] for img_path in lip_images: lip = cv2.imread(img_path) if lip is None: print(f"错误:未找到唇形图片{ img_path}") return lip = cv2.resize(lip, (640, 960)) lips.append(lip) frame_time = hop_length / sr lip_index = 0 for state in energy_state: if state == 1: lip_index = np.random.choice([1, 2, 3]) else: lip_index = 0 cv2.imshow(能听会答的AI数字人, lips[lip_index]) if cv2.waitKey(int(frame_time * 1000)) & 0xFF == 27: break cv2.destroyAllWindows() # 8. 主函数:整合完整交互流程 def run_interactive_digital_human(lip_image_paths): # 步骤1:麦克风录音(采集用户问题) user_audio = record_audio(record_seconds=5) # 录音5秒,可调整 if not os.path.exists(user_audio): print("录音失败!") return # 步骤2:语音识别(用户语音→文字) user_text = baidu_asr(user_audio) os.remove(user_audio) # 删除临时录音文件 if user_text is None: return # 步骤3:匹配回答(文字→回答文字) answer_text = get_answer(user_text) print(f"数字人回答:{ answer_text}") # 步骤4:语音合成(回答文字→语音) digital_audio = baidu_tts(answer_text) if digital_audio is None: return # 步骤5:分析回答语音能量(用于唇形同步) energy_state, sr, hop_length = get_voice_energy(digital_audio) # 步骤6:同步播放语音和显示唇形 play_thread = threading.Thread(target=playsound, args=(digital_audio,)) play_thread.start() show_lip_sync(lip_image_paths, energy_state, sr, hop_length) play_thread.join() os.remove(digital_audio) # 删除临时合成语音文件 # 9. 程序入口 if __name__ == "__main__": # 唇形图片路径(和第3篇一致,无需重新准备) lip_images = ["lip_0.jpg", "lip_1.jpg", "lip_2.jpg", "lip_3.jpg"] print("启动交互式AI数字人... 按ESC键可退出") # 循环交互(可多次提问) while True: run_interactive_digital_human(lip_images) # 每次回答后暂停2秒,再进入下一轮录音 time.sleep(2) # 检测ESC键退出循环 if cv2.waitKey(1) & 0xFF == 27: break cv2.destroyAllWindows()四、关键说明与问题解决
1. 核心功能拆解:
- 录音模块:采用16000Hz采样率、单声道、WAV格式,完全匹配百度ASR的要求,确保识别准确率;录音时长默认5秒,可通过record_seconds参数调整;
- ASR识别:调用百度ASR的短语音识别接口(适合1分钟内的语音),err_no=0表示识别成功,直接提取result中的文字即可;
- 交互逻辑:目前用预设问答库(qa_dict)实现简单匹配,后续会替换成ChatGPT、通义千问等大模型,实现无限制自由对话;
- 循环交互:主函数中用while循环实现多次提问,每次回答后暂停2秒,给用户准备下一个问题的时间。
2. 常见问题解决:
- 录音无声音:检查麦克风是否正常工作,确保录音时没有静音;Windows用户可在“声音设置”中确认默认麦克风为当前使用的设备;
- 识别准确率低:说话时尽量靠近麦克风,避免环境噪音;确保录音格式为WAV(代码已默认处理),采样率16000Hz;
- 循环交互时卡顿:降低录音时长(如改成3秒),或增大每次回答后的暂停时间(调整time.sleep(2)中的参数)。
3. 功能扩展建议:
- 扩展问答库:在qa_dict中添加更多“问题-答案”对,支持更多场景的提问;
- 优化匹配逻辑:用关键词模糊匹配(如“名字”同时匹配“你叫什么名字”“你的名字是什么”),提升交互体验;
- 限制录音时长:添加音量检测,当用户停止说话后自动结束录音,无需等待固定时长(后续文章会实现)。
五、系列预告(第5篇核心内容)
目前的问答逻辑依赖预设库,灵活性很差。下一篇我们将实现“质的飞跃”——接入ChatGPT(或国内大模型如通义千问),替换掉简单的qa_dict匹配,让数字人拥有“举一反三”的能力,无论你问什么问题,都能给出精准、自然的回答。
今天的内容就到这里,重点是帮大家搭建“能听会答”的完整交互闭环。按照步骤操作,你就能和自己制作的数字人对话啦!如果运行代码时遇到录音、识别等问题,欢迎在评论区留言,我会逐一解答。记得关注专栏,下一篇我们接入大模型,实现自由对话!
本文地址:https://www.45854.cn/news/80f599914.html
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。