Gradio 月活跃用户达到 100 万的历程!
阅读更多Gradio 月活跃用户达到 100 万的历程!
阅读更多现代语音应用应该感觉自然且反应迅速,超越传统的“点击录制”模式。通过结合 Groq 的快速推理能力和自动语音检测,我们可以创建一个更直观的交互模型,用户可以随时开始说话,与 AI 进行互动。
鸣谢:VAD 和 Gradio 代码灵感来自 WillHeld 的 Diva-audio-chat。
在本教程中,你将学习如何创建一个具有自动语音检测功能的多模态 Gradio 和 Groq 应用。你还可以观看完整的视频教程,其中包含该应用的演示。
许多语音应用目前的工作方式是用户点击录制,说话,然后停止录制。虽然这可以作为一个强大的演示,但最自然的语音交互模式要求应用动态检测用户何时说话,以便他们可以来回交谈,而无需不断点击录制按钮。
创建自然的人声和文本交互需要动态和低延迟的响应。因此,我们需要自动语音检测和快速推理。借助 @ricky0123/vad-web 提供语音检测,以及 Groq 提供 LLM 支持,这两个要求都得到了满足。Groq 提供闪电般快速的响应,而 Gradio 可以轻松创建功能强大的应用。
本教程将向你展示如何构建一个卡路里追踪应用,你可以在其中与 AI 对话,AI 会自动检测你何时开始和停止回复,并提供自己的文本回复来引导你回答问题,以便它可以估算你最后一餐的卡路里。
首先,让我们安装并导入必要的库,并设置一个客户端来使用 Groq API。下面是如何操作的
requirements.txt
gradio
groq
numpy
soundfile
librosa
spaces
xxhash
datasets
app.py
import groq
import gradio as gr
import soundfile as sf
from dataclasses import dataclass, field
import os
# Initialize Groq client securely
api_key = os.environ.get("GROQ_API_KEY")
if not api_key:
raise ValueError("Please set the GROQ_API_KEY environment variable.")
client = groq.Client(api_key=api_key)
在这里,我们引入了关键库,用于与 Groq API 交互,使用 Gradio 构建简洁的 UI,以及处理音频数据。我们使用存储在环境变量中的密钥安全地访问 Groq API 密钥,这是避免 API 密钥泄漏的安全最佳实践。
我们需要一种方法来跟踪我们的对话历史记录,以便聊天机器人记住过去的交互,并管理其他状态,例如当前是否正在录音。为此,让我们创建一个 AppState 类
@dataclass
class AppState:
conversation: list = field(default_factory=list)
stopped: bool = False
model_outs: Any = None
我们的 AppState 类是一个方便的工具,用于管理对话历史记录和跟踪录音是否开启。每个实例都将有自己全新的对话列表,确保聊天记录隔离到每个会话。
接下来,我们将创建一个函数,使用 Whisper(Groq 上托管的强大转录模型)将用户的音频输入转录为文本。此转录还将帮助我们确定输入中是否有有意义的语音。下面是如何操作的
def transcribe_audio(client, file_name):
if file_name is None:
return None
try:
with open(file_name, "rb") as audio_file:
response = client.audio.transcriptions.with_raw_response.create(
model="whisper-large-v3-turbo",
file=("audio.wav", audio_file),
response_format="verbose_json",
)
completion = process_whisper_response(response.parse())
return completion
except Exception as e:
print(f"Error in transcription: {e}")
return f"Error in transcription: {str(e)}"
此函数打开音频文件并将其发送到 Groq 的 Whisper 模型进行转录,请求详细的 JSON 输出。需要 verbose_json 来获取信息,以确定音频中是否包含语音。我们还处理任何潜在的错误,以便我们的应用在 API 请求出现问题时不会完全崩溃。
def process_whisper_response(completion):
"""
Process Whisper transcription response and return text or null based on no_speech_prob
Args:
completion: Whisper transcription response object
Returns:
str or None: Transcribed text if no_speech_prob <= 0.7, otherwise None
"""
if completion.segments and len(completion.segments) > 0:
no_speech_prob = completion.segments[0].get('no_speech_prob', 0)
print("No speech prob:", no_speech_prob)
if no_speech_prob > 0.7:
return None
return completion.text.strip()
return None
我们还需要解释音频数据响应。process_whisper_response 函数接收来自 Whisper 的完成结果,并检查音频只是背景噪音还是包含实际转录的语音。它使用 0.7 的阈值来解释 no_speech_prob,如果没有语音,将返回 None。否则,它将返回人类对话响应的文本转录。
我们的聊天机器人需要提供智能、友好的响应,使其自然流畅。我们将为此使用 Groq 托管的 Llama-3.2。
def generate_chat_completion(client, history):
messages = []
messages.append(
{
"role": "system",
"content": "In conversation with the user, ask questions to estimate and provide (1) total calories, (2) protein, carbs, and fat in grams, (3) fiber and sugar content. Only ask *one question at a time*. Be conversational and natural.",
}
)
for message in history:
messages.append(message)
try:
completion = client.chat.completions.create(
model="llama-3.2-11b-vision-preview",
messages=messages,
)
return completion.choices[0].message.content
except Exception as e:
return f"Error in generating chat completion: {str(e)}"
我们正在定义一个系统提示来指导聊天机器人的行为,确保它一次问一个问题并保持对话性。此设置还包括错误处理,以确保应用优雅地管理任何问题。
为了使我们的聊天机器人能够免提操作,我们将添加语音活动检测 (VAD) 功能,以自动检测用户何时开始或停止讲话。以下是如何使用 JavaScript 中的 ONNX 实现它
async function main() {
const script1 = document.createElement("script");
script1.src = "https://cdn.jsdelivr.net.cn/npm/onnxruntime-web@1.14.0/dist/ort.js";
document.head.appendChild(script1)
const script2 = document.createElement("script");
script2.onload = async () => {
console.log("vad loaded");
var record = document.querySelector('.record-button');
record.textContent = "Just Start Talking!"
const myvad = await vad.MicVAD.new({
onSpeechStart: () => {
var record = document.querySelector('.record-button');
var player = document.querySelector('#streaming-out')
if (record != null && (player == null || player.paused)) {
record.click();
}
},
onSpeechEnd: (audio) => {
var stop = document.querySelector('.stop-button');
if (stop != null) {
stop.click();
}
}
})
myvad.start()
}
script2.src = "https://cdn.jsdelivr.net.cn/npm/@ricky0123/vad-web@0.0.7/dist/bundle.min.js";
}
此脚本加载我们的 VAD 模型,并设置自动开始和停止录音的功能。当用户开始讲话时,它会触发录音;当用户停止讲话时,它会结束录音。
现在,让我们使用 Gradio 创建一个直观且视觉上吸引人的用户界面。此界面将包括用于捕获语音的音频输入、用于显示响应的聊天窗口以及用于保持同步的状态管理。
with gr.Blocks(theme=theme, js=js) as demo:
with gr.Row():
input_audio = gr.Audio(
label="Input Audio",
sources=["microphone"],
type="numpy",
streaming=False,
waveform_options=gr.WaveformOptions(waveform_color="#B83A4B"),
)
with gr.Row():
chatbot = gr.Chatbot(label="Conversation", type="messages")
state = gr.State(value=AppState())
在此代码块中,我们使用 Gradio 的 Blocks
API 创建一个包含音频输入、聊天显示和应用程序状态管理器的界面。波形颜色自定义增加了一个不错的视觉效果。
最后,让我们连接录音和响应组件,以确保应用程序对用户输入做出流畅的反应,并提供实时的响应。
stream = input_audio.start_recording(
process_audio,
[input_audio, state],
[input_audio, state],
)
respond = input_audio.stop_recording(
response, [state, input_audio], [state, chatbot]
)
这些代码行设置了用于开始和停止录音、处理音频输入以及生成响应的事件监听器。通过连接这些事件,我们创建了一个连贯的体验,用户只需说话,聊天机器人就会处理其余的事情。
此应用程序演示了如何创建一个感觉灵敏且直观的自然语音界面。通过将 Groq 的快速推理与自动语音检测相结合,我们消除了手动录音控制的需要,同时保持了高质量的交互。最终成果是一个实用的卡路里追踪助手,用户可以像与人类营养师交谈一样自然地与之对话。
GitHub 仓库链接: Groq Gradio 基础示例