ToB企服应用市场:ToB评测及商务社交产业平台

标题: Web 端语音对话 AI 示例:利用 Whisper 和 llama.cpp 构建语音聊天呆板人 [打印本页]

作者: 科技颠覆者    时间: 2024-11-28 12:30
标题: Web 端语音对话 AI 示例:利用 Whisper 和 llama.cpp 构建语音聊天呆板人
大语言模型(LLM)为基于文本的对话提供了强盛的本领。那么,可否进一步扩展,将其转化为语音对话的情势呢?本文将展示怎样利用 Whisper 语音辨认和 llama.cpp 构建一个 Web 端语音聊天呆板人。
系统概览


如上图所示,系统的工作流程如下:
系统实现

端侧的具体形态(如 web 端、桌面端、手机端)直接影响了第一步用户语言的输入,以及末了一步响应结果的语音播放。
在本文中,我们选择利用 Web 端作为示例,利用浏览器本身的语言采集和语音播放功能,来实现用户与系统的互动。
下图展示了系统架构:

用户通过 Web 端与系统交互,语音数据通过 WebSocket 传输到后端服务,后端服务利用 Whisper 将语音转换为文本,接着通过 llama.cpp 调用 LLM 天生文本响应,末了,文本响应通过 WebSocket 发送回前端,并利用浏览器的语音播放功能将其朗读出来。
Web 端

Web 端的实现主要依赖 HTML5 和 JavaScript。我们利用浏览器的 Web API 进行语音采集和语音播放。以下是简化的 Web 端代码示例:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Voice Chat AI</title>
  7.     <style>
  8.         #loading { display: none; font-weight: bold; color: blue }
  9.         #response { white-space: pre-wrap; }
  10.     </style>
  11. </head>
  12. <body>
  13.     <h1>Voice Chat AI</h1>
  14.     <button id="start">Start Recording</button>
  15.     <button id="stop" disabled>Stop Recording</button>
  16.     <p id="loading">Loading...</p>
  17.     <p>AI Response: <span id="response"></span></p>
  18.     <script>
  19.         let audioContext, mediaRecorder;
  20.         const startButton = document.getElementById("start");
  21.         const stopButton = document.getElementById("stop");
  22.         const responseElement = document.getElementById("response");
  23.         const loadingElement = document.getElementById("loading");
  24.         let socket = new WebSocket("ws://localhost:8765/ws");
  25.         socket.onmessage = (event) => {
  26.             const data = JSON.parse(event.data);
  27.             const inputText = data.input || "No input detected";
  28.             responseElement.textContent += `\nUser said: ${inputText}`;
  29.             const aiResponse = data.response || "No response from AI";
  30.             responseElement.textContent += `\nAI says: ${aiResponse}\n`;
  31.             loadingElement.style.display = "none";
  32.             const utterance = new SpeechSynthesisUtterance(aiResponse);
  33.             speechSynthesis.speak(utterance);
  34.         };
  35.         socket.onerror = (error) => {
  36.             console.error("WebSocket error:", error);
  37.             loadingElement.style.display = "none";
  38.         };
  39.         startButton.addEventListener("click", async () => {
  40.             audioContext = new (window.AudioContext || window.webkitAudioContext)();
  41.             const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  42.             mediaRecorder = new MediaRecorder(stream);
  43.             const audioChunks = [];
  44.             mediaRecorder.ondataavailable = (event) => {
  45.                 audioChunks.push(event.data);
  46.             };
  47.             mediaRecorder.onstop = () => {
  48.                 const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
  49.                 loadingElement.style.display = "block";
  50.                 socket.send(audioBlob);
  51.             };
  52.             mediaRecorder.start();
  53.             startButton.disabled = true;
  54.             stopButton.disabled = false;
  55.         });
  56.         stopButton.addEventListener("click", () => {
  57.             mediaRecorder.stop();
  58.             startButton.disabled = false;
  59.             stopButton.disabled = true;
  60.         });
  61.     </script>
  62. </body>
  63. </html>
复制代码
为了简化示例代码,利用了开始和结束按钮来手动控制语音的录制。如果要实实际时对话,除了需要合理设置语音采集的时间间隔,还需要确保后端能够快速响应,避免延迟影响用户体验(这在我的笔记本电脑上无法做到)。
WebSocket 服务端

服务端实现为:

以下是服务端的代码示例:
  1. from fastapi import FastAPI, WebSocket
  2. import uvicorn
  3. import whisper
  4. import tempfile
  5. import os
  6. import signal
  7. app = FastAPI()
  8. # 加载 Whisper 模型,默认存储位置 ~/.cache/whisper,可以通过 download_root 设置
  9. model = whisper.load_model("base", download_root="WHISPER_MODEL")
  10. @app.websocket("/ws")
  11. async def websocket_endpoint(websocket: WebSocket):
  12.     try:
  13.         await websocket.accept()
  14.         while True:
  15.             # 接收音频数据
  16.             audio_data = await websocket.receive_bytes()
  17.             # 保存临时音频文件
  18.             with tempfile.NamedTemporaryFile(delete=False, suffix=".webm") as temp_audio:
  19.                 temp_audio.write(audio_data)
  20.                 temp_audio_path = temp_audio.name
  21.             # Whisper 语音识别
  22.             result = model.transcribe(temp_audio_path)
  23.             os.remove(temp_audio_path)
  24.             text = result["text"]
  25.             print("user input: ", text)
  26.             # 生成 AI 回复
  27.             response_text = LLMResponse(text)
  28.             print("AI response: ", response_text)
  29.             await websocket.send_json({"input": text, "response": response_text})
  30.     except Exception as e:
  31.         print("Error: ", e)
  32. def handle_shutdown(signal_num, frame):
  33.     print(f"Received shutdown signal: {signal_num}")
  34. def setup_signal_handlers():
  35.     signal.signal(signal.SIGTERM, handle_shutdown)
  36.     signal.signal(signal.SIGINT, handle_shutdown)
  37. if __name__ == "__main__":
  38.     setup_signal_handlers()
  39.     config = uvicorn.Config("main:app", port=8765, log_level="info")
  40.     server = uvicorn.Server(config)
  41.     server.run()
复制代码
别的,llama.cpp 利用 Docker 容器运行,作为 HTTP 服务来提供 LLM 的本领。启动命令如下:
  1. docker run -p 8080:8080 -v ~/ai-models:/models \
  2.     ghcr.io/ggerganov/llama.cpp:server \
  3.     -m /models/llama3.2-1B.gguf -c 512 \
  4.     --host 0.0.0.0 --port 8080
复制代码
WebSocket server 与 llama.cpp 之间则可以直接利用 HTTP 的方式通信,示例代码如下:
  1. import requests
  2. import json
  3. class LlamaCppClient:
  4.     def __init__(self, host="http://localhost", port=8080):
  5.         self.base_url = f"{host}:{port}"
  6.     def completion(self, prompt):
  7.         url = f"{self.base_url}/v1/chat/completions"
  8.         headers = {"Content-Type": "application/json"}
  9.         payload = {
  10.             "messages": [
  11.                 {
  12.                     "role": "system",
  13.                     "content": """
  14.                         You are a friendly conversation partner. Be natural, engaging, and helpful in our discussions. Respond to questions clearly and follow the conversation flow naturally.
  15.                     """
  16.                 },
  17.                 {
  18.                     "role": "user",
  19.                     "content": prompt
  20.                 }
  21.             ]
  22.         }
  23.         
  24.         try:
  25.             response = requests.post(url, headers=headers, data=json.dumps(payload))
  26.             response.raise_for_status()
  27.             return response.json()
  28.         except requests.exceptions.RequestException as e:
  29.             return {"error": str(e)}
复制代码
末了,用户与 AI 的聊天结果类似下图:

总结

通过联合 Web 端的语音辨认和语音合成功能、Whisper 的语音转文本本领、以及 llama.cpp 提供的 LLM 服务,我们成功构建了一个语音对话系统。语音对话的场景非常丰富,比方口语外教、语音问答等等。盼望本文的示例能够为你在构建语音交互式 AI 系统时提供开导。

(我是凌虚,关注我,无广告,专注技能,不煽动情绪,接待与我交流)

参考资料:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4