Web 端语音对话 AI 示例:使用 Whisper 和 llama.cpp 构建语音聊天机器人

大语言模型(LLM)为基于文本的对话提供了强大的能力。那么,能否进一步扩展,将其转化为语音对话的形式呢?本文将展示如何使用 Whisper 语音识别和 llama.cpp 构建一个 Web 端语音聊天机器人。

系统概览

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

  1. 用户通过语音输入。
  2. 语音识别,转换为文本。
  3. 文本通过大语言模型(LLM)生成文本响应。
  4. 最后,文本转语音播放结果。

系统实现

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

下图展示了系统架构:

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

Web 端

Web 端的实现主要依赖 HTML5 和 JavaScript。我们使用浏览器的 Web API 进行语音采集和语音播放。以下是简化的 Web 端代码示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Voice Chat AI</title><style>#loading { display: none; font-weight: bold; color: blue }#response { white-space: pre-wrap; }</style>
</head>
<body><h1>Voice Chat AI</h1><button id="start">Start Recording</button><button id="stop" disabled>Stop Recording</button><p id="loading">Loading...</p><p>AI Response: <span id="response"></span></p><script>let audioContext, mediaRecorder;const startButton = document.getElementById("start");const stopButton = document.getElementById("stop");const responseElement = document.getElementById("response");const loadingElement = document.getElementById("loading");let socket = new WebSocket("ws://localhost:8765/ws");socket.onmessage = (event) => {const data = JSON.parse(event.data);const inputText = data.input || "No input detected";responseElement.textContent += `\nUser said: ${inputText}`;const aiResponse = data.response || "No response from AI";responseElement.textContent += `\nAI says: ${aiResponse}\n`;loadingElement.style.display = "none";const utterance = new SpeechSynthesisUtterance(aiResponse);speechSynthesis.speak(utterance);};socket.onerror = (error) => {console.error("WebSocket error:", error);loadingElement.style.display = "none";};startButton.addEventListener("click", async () => {audioContext = new (window.AudioContext || window.webkitAudioContext)();const stream = await navigator.mediaDevices.getUserMedia({ audio: true });mediaRecorder = new MediaRecorder(stream);const audioChunks = [];mediaRecorder.ondataavailable = (event) => {audioChunks.push(event.data);};mediaRecorder.onstop = () => {const audioBlob = new Blob(audioChunks, { type: "audio/webm" });loadingElement.style.display = "block";socket.send(audioBlob);};mediaRecorder.start();startButton.disabled = true;stopButton.disabled = false;});stopButton.addEventListener("click", () => {mediaRecorder.stop();startButton.disabled = false;stopButton.disabled = true;});</script>
</body>
</html>

为了简化示例代码,使用了开始和结束按钮来手动控制语音的录制。如果要实现实时对话,除了需要合理设置语音采集的时间间隔,还需要确保后端能够快速响应,避免延迟影响用户体验(这在我的笔记本电脑上无法做到)。

WebSocket 服务端

服务端实现为:

  • 使用 Pythonfastapi 框架搭建 WebSocket 服务。
  • 使用 whisper 进行语音识别,将语音转换为文本,注意系统环境需要额外安装 ffmpeg 命令行工具。
  • 通过 llama.cpp 加载 LLM(我使用的是 llama3.2-1B 模型) 并生成响应文本。

以下是服务端的代码示例:

from fastapi import FastAPI, WebSocket
import uvicorn
import whisper
import tempfile
import os
import signalapp = FastAPI()# 加载 Whisper 模型,默认存储位置 ~/.cache/whisper,可以通过 download_root 设置
model = whisper.load_model("base", download_root="WHISPER_MODEL")@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):try:await websocket.accept()while True:# 接收音频数据audio_data = await websocket.receive_bytes()# 保存临时音频文件with tempfile.NamedTemporaryFile(delete=False, suffix=".webm") as temp_audio:temp_audio.write(audio_data)temp_audio_path = temp_audio.name# Whisper 语音识别result = model.transcribe(temp_audio_path)os.remove(temp_audio_path)text = result["text"]print("user input: ", text)# 生成 AI 回复response_text = LLMResponse(text)print("AI response: ", response_text)await websocket.send_json({"input": text, "response": response_text})except Exception as e:print("Error: ", e)def handle_shutdown(signal_num, frame):print(f"Received shutdown signal: {signal_num}")def setup_signal_handlers():signal.signal(signal.SIGTERM, handle_shutdown)signal.signal(signal.SIGINT, handle_shutdown)if __name__ == "__main__":setup_signal_handlers()config = uvicorn.Config("main:app", port=8765, log_level="info")server = uvicorn.Server(config)server.run()

此外,llama.cpp 使用 Docker 容器运行,作为 HTTP 服务来提供 LLM 的能力。启动命令如下:

docker run -p 8080:8080 -v ~/ai-models:/models \ghcr.io/ggerganov/llama.cpp:server \-m /models/llama3.2-1B.gguf -c 512 \--host 0.0.0.0 --port 8080

WebSocket serverllama.cpp 之间则可以直接使用 HTTP 的方式通信,示例代码如下:

import requests
import jsonclass LlamaCppClient:def __init__(self, host="http://localhost", port=8080):self.base_url = f"{host}:{port}"def completion(self, prompt):url = f"{self.base_url}/v1/chat/completions"headers = {"Content-Type": "application/json"}payload = {"messages": [{"role": "system","content": """You are a friendly conversation partner. Be natural, engaging, and helpful in our discussions. Respond to questions clearly and follow the conversation flow naturally."""},{"role": "user","content": prompt}]}try:response = requests.post(url, headers=headers, data=json.dumps(payload))response.raise_for_status()return response.json()except requests.exceptions.RequestException as e:return {"error": str(e)}

最后,用户与 AI 的聊天结果类似下图:

总结

通过结合 Web 端的语音识别和语音合成功能、Whisper 的语音转文本能力、以及 llama.cpp 提供的 LLM 服务,我们成功构建了一个语音对话系统。语音对话的场景非常丰富,例如口语外教、语音问答等等。希望本文的示例能够为你在构建语音交互式 AI 系统时提供启发。


(我是凌虚,关注我,无广告,专注技术,不煽动情绪,欢迎与我交流)


参考资料:

  • https://github.com/openai/whisper
  • https://github.com/ggerganov/llama.cpp/blob/master/examples/server/README.md
  • https://github.com/fastapi/fastapi
  • https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络地址转换

NAT概述 解决公有地址不足&#xff0c;并且分配不均匀的问题 公有地址&#xff1a;由专门的机构管理、分配&#xff0c;可以在因特网上直接通信 私有地址&#xff1a;组织和个人可以任意使用&#xff0c;只能在内网使用的IP地址 A、B、C类地址中各预留了一些私有IP地址 A&…

电脑无互联网连接怎么解决?分享5种解决方案

无互联网连接是指设备无法与互联网进行通信或连接失败。这可能会导致我们无法正常上网&#xff0c;给我们的日常生活和工作带来很大的不便。但请不要担心&#xff0c;下面将为您介绍一些解决无互联网连接问题的方法。 一、检查网络是否正常连接 首先&#xff0c;确保您的路由器…

使用 F5 TTS 文字转音频

F5 TTS 支持 ZeroShot 音频克隆&#xff0c;只有将需要音频传给模型&#xff0c;模型既可以生成以对应声音生成的音频&#xff0c;F5 最强大的地方就是可以使用定制的人声。F5 使用了 DIT 架构进行训练&#xff0c;结构如下&#xff1a; 本地使用 F5 TTS F5 使用很简单&#x…

【Redis】Redis 预备知识

目录 1. 基本全局命令 KEYS EXISTS DEL EXPIRE TTL TYPE 2. 数据结构和内部编码 3. 单线程架构 Redis 提供了5种数据结构&#xff0c;理解每种数据结构的特点对于 Redis 开发运维非常重要&#xff0c;同时掌握每种数据结构的常见命令&#xff0c;会在使用 Redis 的时…

【从零开始的LeetCode-算法】3304. 找出第 K 个字符 I

Alice 和 Bob 正在玩一个游戏。最初&#xff0c;Alice 有一个字符串 word "a"。 给定一个正整数 k。 现在 Bob 会要求 Alice 执行以下操作 无限次 : 将 word 中的每个字符 更改 为英文字母表中的 下一个 字符来生成一个新字符串&#xff0c;并将其 追加 到原始的…

软件设计模式复习

一、软件生存周期 二、软件开发过程模型 瀑布模型 特征&#xff1a; 从上一阶段承接的成果物作为本阶段的工作对象&#xff1b; 对上一阶段成果实施本阶段的活动&#xff1b; 给出本阶段的成果&#xff0c;作为下一阶段的输入&#xff1b; 对本阶段的工作进行评审&#xff0c…

搭建文件服务器并使用Qt实现文件上传和下载(带账号和密码)

文章目录 0 背景1 搭建文件服务器2 代码实现文件上传和下载2.1 在pro文件中添加网络支持2.2 创建网络管理类2.3 文件上传2.4 文件下载 3 扩展&#xff08;其他方法实现文件上传和下载&#xff09;3.1 python3.2 npm3.3 ftp服务器 4 完整的代码 0 背景 因为需要使程序具备在远程…

自动化运维(k8s)之微服务信息自动抓取:namespaceName、deploymentName等全解析

前言&#xff1a;公司云原生k8s二开工程师发了一串通用性命令用来查询以下数值&#xff0c;我想着能不能将这命令写成一个自动化脚本。 起初设计的 版本一&#xff1a;开头加一条环境变量&#xff0c;执行脚本后&#xff0c;提示输入&#xff1a;需要查询的命名空间&#xff0c…

springboot332基于springboot养老院管理系统pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 养老院管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计…

js:函数

函数 函数&#xff1a;实现抽取封装&#xff0c;执行特定任务的代码块&#xff0c;方便复用 声明 函数命名规范 尽量小驼峰 前缀应该为动词&#xff0c;如getName、hasName 函数的调用 函数体是函数的构成部分 函数传参 参数列表里的参数叫形参&#xff0c;实际上写的数据叫实…

基于Matlab的图像去噪算法仿真

中值滤波的仿真 本节选用中值滤波法对含有高斯噪声和椒盐噪声的图像进行去噪&#xff0c;并用Matlab软件仿真。 &#xff08;1&#xff09;给图像加入均值为0&#xff0c;方差为0.02的高斯噪声&#xff0c;分别选择33模板、55模板和77模板进行去噪 Matlab部分代码&#xff1…

【Linux】-学习笔记06

第二章、时间同步服务器 2.1时间同步服务器的使用 2.1.1系统时区时间的管理 timedatectl set-time "2024-02-13 10:41:55" ##设定系统时间 timedatectl list-timezones ##显示系统的所有时区 timedatectl set-timezone "Asia/Shangh…

UE5_建立自己的资产库

资产库需要用到一个插件&#xff1a; UAsset Browser - 直接在当前项目预览其他UE项目资产&#xff08;.uasset 文件&#xff09; - 直接迁移其他UE项目资产到当前项目 - 不用另外打开资产项目查看资产&#xff0c;迁移资产&#xff08;麻烦&#xff09; 插件官网插件文档插…

详解登录MySQL时出现SSL connection error: unknown error number错误

目录 登录MySQL时出错SSL connection error: unknown error number 出错原因 使用MySQL自带的工具登录MySQL 登陆之后&#xff0c;使用如下命令进行查看 解决方法 找到MySQL8安装目录下的my.ini配置文件 记事本打开my.ini文件&#xff0c;然后按下图所示添加配置 此时再…

深度学习基本单元结构与输入输出维度解析

深度学习基本单元结构与输入输出维度解析 在深度学习领域&#xff0c;模型的设计和结构是理解其性能和应用的关键。本文将介绍深度学习中的基本单元结构&#xff0c;包括卷积神经网络&#xff08;CNN&#xff09;、反卷积&#xff08;转置卷积&#xff09;、循环神经网络&…

乐鑫发布 esp-iot-solution v2.0 版本

今天&#xff0c;乐鑫很高兴地宣布&#xff0c;esp-iot-solution v2.0 版本已经发布&#xff0c;release/v2.0 分支下的正式版本组件将为用户提供为期两年的 Bugfix 维护&#xff08;直到 2027.01.25 ESP-IDF v5.3 EOL&#xff09;。该版本将物联网开发中常用的功能进行了分类整…

面经-综合面/hr面

面经-综合面/hr面 概述1.大学期间遇到的困难&#xff0c;怎么解决的2. 大学期间印象最深/最难忘的是什么3. 大学里面担任了什么职务没&#xff1f;做了什么工作&#xff1f;4. 大学最大的遗憾是什么&#xff1f;5. 对自己的未来规划6. 对自己的评价7. 自己的优缺点8. 对公司的认…

pyspark实现基于协同过滤的电影推荐系统

最近在学一门大数据的课&#xff0c;课程要求很开放&#xff0c;任意做一个大数据相关的项目即可&#xff0c;不知道为什么我就想到推荐算法&#xff0c;一直到着手要做之前还没有新的更好的来代替&#xff0c;那就这个吧。 推荐算法 推荐算法的发展由来已久&#xff0c;但和…

十、Spring Boot集成Spring Security之HTTP请求授权

文章目录 往期回顾&#xff1a;Spring Boot集成Spring Security专栏及各章节快捷入口前言一、HTTP请求授权工作原理二、HTTP请求授权配置1、添加用户权限2、配置ExceptionTranslationFilter自定义异常处理器3、HTTP请求授权配置 三、测试接口1、测试类2、测试 四、总结 往期回顾…

Unity3d C# 实现一个基于UGUI的自适应尺寸图片查看器(含源码)

前言 Unity3d实现的数字沙盘系统中&#xff0c;总有一些图片或者图片列表需要点击后弹窗显示大图&#xff0c;这个弹窗在不同尺寸分辨率的图片查看处理起来比较麻烦&#xff0c;所以&#xff0c;需要图片能够根据容器的大小自适应地进行缩放&#xff0c;兼容不太尺寸下的横竖图…