【案例实践】ernie-bot打造语音对话功能
大模型开发/技术交流
- LLM
- 文心大模型
- 大模型推理
2023.12.093214看过
GPT-4的语音对话功能前段时间在网上火了一把,许多人被其强大的自然语言处理能力和流畅的语音交互所吸引。现在,让我们来看看如何使用类似的技术,即基于百度的ERNIE-Bot,来打造自己的语音对话功能。ERNIE-Bot是一种先进的语言理解模型,可以处理复杂的语言任务,包括语音到文本的转换和自然语言理解。
视频演示:
涉及技术:
-
langchain Memory、Chain
-
Ernie-bot
依赖:
-
ffmpeg
langchain调用Ernie-bot并实现记忆功能
值得一提的是,在langchain构建ernie-bot多轮对话能力上,社区中已有成员对此进行了深入研究和实践:https://cloud.baidu.com/qianfandev/topic/267682
from langchain.chat_models import ErnieBotChatfrom langchain.chains import LLMChainfrom langchain.prompts import PromptTemplatefrom langchain.memory import ConversationBufferMemory# 定义一个大语言模型对象llm = ErnieBotChat(ernie_client_id="xxxxx",ernie_client_secret="xxxxxx",model_name='ERNIE-Bot',temperature=0.01)# 定义prompt templatetemplate = """You are a chatbot having a conversation with a human. Please answer as briefly as possible.{chat_history}Human: {human_input}Chatbot:"""prompt = PromptTemplate(input_variables=["chat_history", "human_input"], template=template)# memorymemory = ConversationBufferMemory(llm=llm,memory_key="chat_history",return_messages=True)# chainconversation = LLMChain(llm=llm, memory=memory,prompt=prompt)# 推理response = conversation.predict(human_input=input)
语音识别部分
目前,百度语音识别服务支持固定的采样率:16000Hz 和 8000Hz。为了确保您的音频文件与这些标准兼容,可能需要对原始音频的采样率进行适当调整。这意味着,如果您的音频文件采样率与上述两个固定值不符,您将需要通过音频处理软件或编程方法,将其转换为这两种支持的采样率之一。这个步骤是确保音频识别准确性的关键,可以显著提高语音识别的效果和准确度。
from aip import AipSpeechimport tempfileimport os, uuidfrom pydub import AudioSegmentAPP_ID = 'xxx'API_KEY = 'xxxxx'SECRET_KEY = 'xxxxxxxxx'client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)def transcribe(audio):with tempfile.TemporaryDirectory() as tempdir:print(f"Temporary directory created at {tempdir}")audio = AudioSegment.from_file(audio)new_frame_rate = 16000new_audio = audio.set_frame_rate(new_frame_rate)random_code = uuid.uuid4()temp_audio_path = f"{tempdir}/output_audio_16000_{random_code}.wav"new_audio.export(temp_audio_path, format="wav")def get_file_content(filePath):with open(filePath, 'rb') as fp:return fp.read()ret = client.asr(get_file_content(temp_audio_path), 'wav', 16000, {'dev_pid': 1537})# 注意:退出 with 块后,tempdir 及其内容会被自动删除return ret.get('result')[0]
语音合成部分
将大型语言模型生成的文本内容转换成语音输出是一个引人入胜的过程。通过这种转换,我们可以将模型的文字回应转化为更加生动、直观的语音形式。这不仅提升了用户体验,还增加了交互的可访问性和便利性。无论是为视觉受限用户提供更加友好的界面,还是为智能助理增添自然的交流方式,这一过程都显得至关重要。
from pydub import AudioSegmentfrom pydub.playback import playdef play_voice(text):result = client.synthesis(text, 'zh', 1, {'vol': 5})# 识别正确返回语音二进制 错误则返回dict 参照下面错误码if not isinstance(result, dict):with tempfile.NamedTemporaryFile(delete=True, suffix='.mp3', mode='wb') as temp_audio_file:temp_audio_file.write(result)temp_audio_file.seek(0) # 回到文件开头# print(temp_audio_file.name)# 使用 pydub 播放音频audio = AudioSegment.from_file(temp_audio_file.name, format="mp3")play(audio)
gradio交互逻辑
gradio的核心代码框架如下:
def clear_history():# 返回一个空列表来清空聊天记录return [], []with gr.Blocks(css="#chatbot{height:800px} .overflow-y-auto{height:800px}") as demo:chatbot = gr.Chatbot(elem_id="chatbot")state = gr.State([])with gr.Row():txt = gr.Textbox(show_label=False, placeholder="Enter text and press enter")# 录音功能with gr.Row():# 得到音频文件地址audio = gr.Audio(sources="microphone", type="filepath")with gr.Row():clear_button = gr.Button("清空聊天记录")# 重要逻辑txt.submit(predict, [txt, state], [chatbot, txt, state])audio.change(process_audio, [audio, state], [chatbot, audio, state])clear_button.click(clear_history, [], [chatbot, state])# 启动gradiodemo.launch(share=False)
代码18/19行重点介绍下
-
txt.submit(predict, [txt, state], [chatbot, txt, state])
-
-
txt.submit
: 这是Gradio中Textbox
组件的一个方法,用于绑定一个函数(在本例中是predict
函数)到文本框的输入动作上。当用户在文本框中输入文本并提交(通常是按下回车键)时,绑定的predict
函数会被触发。 -
predict
: 这是绑定到文本框提交动作的函数。这个函数会在用户提交文本后执行。 -
[txt, state]
: 这是传递给predict
函数的参数列表。在这里,txt
代表文本框的内容,state
是一个State
组件,用于在Gradio界面中维持状态。 -
[chatbot, txt, state]
: 这是predict
函数执行后,其输出将被传递的组件列表。在此,函数的输出将被用来更新Chatbot
组件(显示对话内容)、清空Textbox
组件的文本,以及更新State
组件的状态。
-
-
audio.change(process_audio, [audio, state], [chatbot, audio, state])
-
-
audio.change
: 这是Gradio中Audio
组件的一个方法,用于将一个函数(在这个例子中是process_audio
函数)绑定到音频输入的变化上。当用户通过音频组件提供新的音频输入时,绑定的process_audio
函数会被触发。 -
process_audio
: 这是绑定到音频组件变化的函数。当音频输入改变时,这个函数会执行。 -
[audio, state]
: 这是传递给process_audio
函数的参数列表。在这里,audio
代表音频组件的输入,state
仍然是用于维持状态的State
组件。 -
[chatbot, audio, state]
: 这是process_audio
函数执行后,其输出将被传递的组件列表。这意味着函数的输出将用于更新Chatbot
组件、重置Audio
组件的输入,以及更新State
组件的状态。
-
总的来说,这两行代码将用户界面的交互(文本输入和音频输入)与相应的处理函数(
predict
和process_audio
)关联起来,并定义了这些函数执行后如何更新界面组件。
两个函数的实现逻辑:
def play_voice(text):result = client.synthesis(text, 'zh', 1, {'vol': 5})# 识别正确返回语音二进制 错误则返回dict 参照下面错误码if not isinstance(result, dict):with tempfile.NamedTemporaryFile(delete=True, suffix='.mp3', mode='wb') as temp_audio_file:temp_audio_file.write(result)temp_audio_file.seek(0) # 回到文件开头# print(temp_audio_file.name)# 使用 pydub 播放音频audio = AudioSegment.from_file(temp_audio_file.name, format="mp3")play(audio)# 录音文件转文本的过程def process_audio(audio, history=[]):if audio:text = transcribe(audio)# print(text)if text is None:text="你好"responses, clear, updated_history = predict(text, history)# print(f"====={responses}")# print(f"++++{updated_history}")# 返回处理结果和 None 来清空音频输入return responses, None, updated_historyelse:# print(f"------{history}")return [(u,b) for u,b in zip(history[::2], history[1::2])], None, history# 调用ernie-bot对话功能def predict(input, history=[]):history.append(input)response = conversation.predict(human_input=input)history.append(response)# history[::2] 切片语法,每隔两个元素提取一个元素,即提取出所有的输入,# history[1::2]表示从历史记录中每隔2个元素提取一个元素,即提取出所有的输出# zip函数把两个列表元素打包为元组的列表的方式play_voice(response)responses = [(u,b) for u,b in zip(history[::2], history[1::2])]print("==取出输入:",history[::2])print("==取出输出:",history[1::2])print("组合元组:",responses)return responses, "", history
通过本文的介绍,我们探索了如何利用ERNIE-Bot来打造一个高效的语音对话功能。从设置开发环境、处理音频文件,到利用ERNIE-Bot进行语言理解和生成语音回应,每一步都是构建这一创新交互体验的关键部分。
最后,希望大家在社区多发好文,相互学习!
评论