基于ollama+deepseek R1 1.5B本地部署语音交互助手(原创、附代码)

目录

  • 现有的一些功能
  • 记录一些过程中遇到的问题
    • 安装llama_cpp
  • 1、安装ollama和部署deepseek R1
  • 2、使用本地部署的deepseek R1模型
  • 3、语音识别
  • 4、代码实现
  • 运行演示

现有的一些功能

1、正常与人沟通,但受限于电脑性能,还存在一定延迟;
2、可以根据交流内容修改提示词,例如用户名称;
3、拥有文本和json两种输出形式,为未来拓展至智能机器人提供可能;
4、根据简单指令实现关闭程序操作。
更多功能和设想等待开发与实现中。。。

记录一些过程中遇到的问题

安装llama_cpp

正常是直接install llama-cpp-python,但是在编译过程中会出现各种各样的报错,这里推荐根据环境直接安装预编译版本的llama-cpp。 我是Windows环境,python版本是3.11,所以直接下载llama_cpp_python-0.3.2-cp311-cp311-win_amd64.whl并安装即可。

1、安装ollama和部署deepseek R1

这一步比较简单,直接按照官网教程一步步安装即可,安装完成之后,就可以打开终端,下载自己想要部署在本地的大模型了,例如想在本地部署deepseek R1 1.5B模型,那么在终端内输入ollama run deepseek-r1:1.5b即可,注意,除了目前开源的671B模型,其余ollama提供的R1模型均为蒸馏模型,具体可在官网找到详细介绍。

2、使用本地部署的deepseek R1模型

使用也非常简单,最直接的是在终端内直接运行和使用,注意不要输错模型的名称即可。但是这种方法毕竟不够优美,缺少一个与用户自然交互的前台。有两款比较好用的前台推荐给大家,一个是AnythingLLM,很多文章都基于这款软件去使用本地部署的大模型,灵活且具有一定可玩性;但其实面向我们普通使用者而言我更推荐的是page assist,作为一款浏览器插件,简直不要太方便,可以在浏览器中直接调用本地部署的大模型来帮助答疑解惑,用的还是很频繁,上手也很简单,基本上有手就行。
当然,以上只是作为普通使用者推荐的一些使用本地大模型的方法,作为开发者,我们当然希望能够在程序中调用大模型,帮助我们完成更加个性化的操作,这里我们还是使用ollama所提供的API。由于我们已经安装了llama_cpp,所以理论上我们可以直接使用llama_cpp所提供的接口即可,但是很遗憾,目前llama_cpp预编译版本没有最新版的,直接调用deepseek模型会出现无法加载模型的问题,而一些其他比较早期的模型,例如Llama系列或者Qwen系列是不会出现这个问题。上网一番搜索发现,需要将llama_cpp升级为最新,所以就尴尬了。好在我们还有ollama提供的API可以使用。

3、语音识别

解决完使用本地大模型的问题后,接下来我们要实现语音识别。我们的目标是能够访问本地的模型,与人进行语音对话交谈。那就需要将人的语音,转换为文本,再与大模型交互。原本我是想使用本地部署openai的开源语音模型whisper,但是笔记本性能太过有限,一番折腾后最终还是选择用线上的语音识别模型。目前所使用的是科大讯飞的实时语音转写API,在网络条件还不错的情况下识别速度很快,而且准确性较高,最重要的是新用户一年免费使用50完次,还是很香的。
在这里插入图片描述
此外,讯飞的星火大模型,据说在文本生成、语言理解等方面超越GPT 4-Turbo,而且也有免费token,之后也可以试试。

4、代码实现

有了调用本地大模型的API和在线语音的API后,我们就非常轻松的实现一个语音交互助手。直接上代码:

import websocket
import hashlib
import base64
import hmac
import json
import pyaudio
import sys
import re
from ollama import Client
import pyttsx3
from typing import Dict, List
import _thread as thread
from urllib.parse import urlencode
from wsgiref.handlers import format_date_time
from time import mktime
from datetime import datetime
import sslSTATUS_FIRST_FRAME = 0
STATUS_CONTINUE_FRAME = 1
STATUS_LAST_FRAME = 2class VoiceAssistant:def __init__(self, endpoint, mode, model_name):self.ollama_endpoint = endpointself.mode = modeself.history: List[Dict] = []self.model_name = model_nameself.username = Noneself.is_first_interaction = Trueself.presets = {"text": {"system": "你是一个有帮助的助手,请用非常简单直接的方式回答"},"json": {"system": "请始终用JSON格式回答,包含'response'和'sentiment'字段","response_template": {"response": "", "sentiment": ""}}}self.tts_engine = pyttsx3.init()self.setup_voice_engine()self.ws_param = Nonedef setup_voice_engine(self):"""配置语音引擎参数"""voices = self.tts_engine.getProperty('voices')self.tts_engine.setProperty('voice', voices[0].id)self.tts_engine.setProperty('rate', 150)def update_ws_param(self, ws_param, username="AI助手"):self.ws_param = ws_paramself.presets = {"text": {"system": "你的名字叫" + username + ",用户的名字叫主人,每次回答加上用户的名字,并且用非常简短直接的方式回答"},"json": {"system": "请始终用JSON格式回答,包含'response'和'sentiment'字段","response_template": {"response": "", "sentiment": ""}}}def update_username(self, username="AI助手"):self.presets = {"text": {"system": "你的名字叫" + username + ",每次回答请带上自己的名字,并且用非常简短直接的方式回答"},"json": {"system": "请始终用JSON格式回答,包含'response'和'sentiment'字段","response_template": {"response": "", "sentiment": ""}}}class Ws_Param:def __init__(self, APPID, APIKey, APISecret, vad_eos=10000):self.APPID = APPIDself.APIKey = APIKeyself.APISecret = APISecretself.CommonArgs = {"app_id": self.APPID}self.BusinessArgs = {"domain": "iat", "language": "zh_cn", "accent": "mandarin", "vad_eos": int(vad_eos)}def create_url(self):now = datetime.now()date = format_date_time(mktime(now.timetuple()))signature_origin = "host: ws-api.xfyun.cn\ndate: {}\nGET /v2/iat HTTP/1.1".format(date)signature_sha = hmac.new(self.APISecret.encode('utf-8'), signature_origin.encode('utf-8'),digestmod=hashlib.sha256).digest()signature_sha = base64.b64encode(signature_sha).decode('utf-8')authorization_origin = 'api_key="{}", algorithm="hmac-sha256", headers="host date request-line", signature="{}"'.format(self.APIKey, signature_sha)authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode('utf-8')v = {"authorization": authorization, "date": date, "host": "ws-api.xfyun.cn"}return 'wss://ws-api.xfyun.cn/v2/iat?' + urlencode(v)def generate_response(prompt: str, assistant: VoiceAssistant) -> str:"""处理命令并生成响应"""# 命令处理if re.search(r"切换(到|为)JSON模式", prompt):assistant.mode = "json"return "已切换到JSON模式"elif re.search(r"切换(到|为)文本模式", prompt):assistant.mode = "text"return "已切换到文本模式"# 正常响应生成current_preset = assistant.presets[assistant.mode]messages = [{"role": "system", "content": current_preset["system"]},*assistant.history[-5:],{"role": "user", "content": prompt}]try:client = Client(host=assistant.ollama_endpoint)response = client.chat(model=assistant.model_name, messages=messages)return response["message"]["content"]except Exception as e:return f"请求API出错: {str(e)}"def parse_response(response: str, mode: str) -> str:"""解析不同模式的响应"""s1 = "<think>"s2 = "</think>"new_response = deleteByStartAndEnd(response, s1, s2)if mode == "json":try:data = json.loads(new_response)return data.get("response", "无效的JSON格式")except json.JSONDecodeError:return "响应解析失败"return new_response
def deleteByStartAndEnd(s, start, end):# 找出两个字符串在原始字符串中的位置,开始位置是:开始始字符串的最左边第一个位置,结束位置是:结束字符串的最右边的第一个位置x1 = s.index(start)x2 = s.index(end) + len(end)  # s.index()函数算出来的是字符串的最左边的第一个位置# 找出两个字符串之间的内容x3 = s[x1:x2]# 将内容替换为控制符串result = s.replace(x3, "")return result
def speak(text: str, assistant: VoiceAssistant):"""文本转语音输出"""print(f"{assistant.username}回答: {text}")assistant.tts_engine.say(text)assistant.tts_engine.runAndWait()start_listening(assistant)  # 语音输出完成后重新开始监听def on_message(ws, message, assistant):try:result = json.loads(message)if result['code'] == 0:text = ''.join([w['w'] for item in result['data']['result']['ws'] for w in item['cw']])print(f"用户输入: {text}")if re.search(r"退出|再见|关闭|结束|停止|拜拜", text):ws.close()sys.exit(0)elif assistant.is_first_interaction:assistant.username = text.strip() or "AI助手"response = f"感谢您为我命名,现在我叫{assistant.username},请问有什么可以帮您?"assistant.is_first_interaction = Falseassistant.update_username(assistant.username)else:raw_response = generate_response(text, assistant)response = parse_response(raw_response, assistant.mode)speak(response, assistant)except Exception as e:print("处理错误:", e)def on_error(ws, error):print(f"### 错误: {error}")if "SSL" in str(error) or "EOF" in str(error):print("检测到SSL错误,尝试重新连接...")start_listening(ws.assistant)  # 需要确保assistant对象可以通过ws访问def on_close(ws, close_status_code, close_msg):print(f"### 连接关闭 ### 状态码: {close_status_code}, 消息: {close_msg}")def on_open(ws):print("### 连接已打开 ###")def run(*args):audio_generator = record_audio()send_audio(ws, audio_generator)thread.start_new_thread(run, ())def send_audio(ws, audio_generator):status = STATUS_FIRST_FRAMEprint("开始发送音频...")try:for chunk in audio_generator:if not ws.sock or not ws.sock.connected:  # 新增连接状态检查print("连接已断开,停止发送音频")break# 原有发送逻辑保持不变...data = {"common": ws.ws_param.CommonArgs,"business": ws.ws_param.BusinessArgs,"data": {"status": STATUS_FIRST_FRAME if status == 0 else STATUS_CONTINUE_FRAME,"format": "audio/L16;rate=16000","audio": base64.b64encode(chunk).decode('utf-8')}}ws.send(json.dumps(data))status = STATUS_CONTINUE_FRAMEif ws.sock and ws.sock.connected:ws.send(json.dumps({"data": {"status": STATUS_LAST_FRAME}}))except Exception as e:print("发送错误:", e)ws.close()  # 确保关闭失效连接def record_audio(rate=16000, chunk_size=1024):p = pyaudio.PyAudio()stream = p.open(format=pyaudio.paInt16, channels=1,rate=rate, input=True, frames_per_buffer=chunk_size)try:while True:yield stream.read(chunk_size)except KeyboardInterrupt:print("停止录音")finally:stream.stop_stream()stream.close()p.terminate()def start_listening(assistant):"""启动新的语音识别会话"""print("开始新的语音识别会话...")websocket.enableTrace(False)ws_url = assistant.ws_param.create_url() ws = websocket.WebSocketApp(ws_url,on_message=lambda ws, msg: on_message(ws, msg, assistant),on_error=on_error,on_close=on_close)ws.ws_param = assistant.ws_paramws.on_open = on_open# 修改运行参数ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
if __name__ == "__main__":with open("config.json") as f:config = json.load(f)# 初始化语音助手voice_assistant = VoiceAssistant(endpoint=config["endpoint"],mode=config["mode"],model_name=config["model_name"])# 配置语音识别参数ws_param = Ws_Param(APPID=config["APPID"],APIKey=config["APIKey"],APISecret=config["APISecret"],vad_eos=config["vad_eos"])voice_assistant.update_ws_param(ws_param)# 初始问候voice_assistant.tts_engine.say("您好,请为我命名")voice_assistant.tts_engine.runAndWait()# 开始首次监听start_listening(voice_assistant)# 保持主线程运行while True:pass

另外一个配置文件(config.json)如下格式:

{"APPID": "Websocket服务接口认证信息","APIKey": "Websocket服务接口认证信息","APISecret": "Websocket服务接口认证信息","vad_eos": "10000","endpoint": "http://localhost:11434","mode": "text","model_name": "deepseek-r1:1.5b"
}

其中前三项为讯飞语音接口的验证信息,注册后根据自己的接口信息进行修改即可,"vad_eos"为录音时长,最多不超过60秒,即600000毫秒,以毫秒为单位;”endpoint“为访问ollama的本地大模型的端口,默认为11434; "mode"为输出形式,即text或json;"model_name"为部署在本地的大模型名字,确保下载的模型和本程序使用的模型保持一直即可。

运行演示

打开ollama,运行程序效果如下:
在这里插入图片描述

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

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

相关文章

惠普HP Color LaserJet CP1215彩色激光打印机套色不准及套色错位的解决方法

一台惠普HP Color LaserJet CP1215彩色激光打印机出现故障&#xff0c;转印带断裂&#xff0c;于是更换了转印地&#xff0c;当更换完成测试的时候发现这台惠普HP Color LaserJet CP1215彩色激光打印机打印的颜色比较淡且颜色有错位的问题&#xff0c;继续检查机器之后&#xf…

开放签电子签章工具版 2.0 正式发布,构建全场景电子签约能力、满足复杂的签章管理场景

根据近半年开源用户和市场需求反馈&#xff0c;开放签团队推出电子签章工具版2.0版本&#xff0c;主要解决复杂的签约流程集成和电子印章授权管理场景。以API接口对外提供服务和配置一套可视化后台管理系统&#xff0c;可与业务系统无缝集成&#xff0c;用户使用起来毫无“违和…

docker 安装 Rabbitmq 详解

在平常的开发工作中&#xff0c;我们经常会使用到 rabbitmq&#xff0c;rabbitmq 主要可以进行应用解耦、异步通信、流量削峰、负载均衡、消息持久化、死信队列等。比如商城系统&#xff0c;下单后&#xff0c;通过消息队列通知库存系统、积分系统、物流系统等。发送短信时通过…

零基础学yolo系列

1.目标检测算法分类 基于深度学习的主流目标检测算法根据有无候选框生成阶段&#xff0c;分为双阶段目标检 测算法和单阶段目标检测算法两类 双阶段检测模型 将检测问题划分为两个阶段&#xff0c;首先产生候选区域&#xff0c;然后对候选区域分类并对目标位置进行精修&#x…

本智慧监考系统

本智慧监考系统共分为4个部分&#xff0c;分别为&#xff1a;展示层、业务层、算法层和数据库。 本系统的展示层基于Vue.js框架和Ant Design Vue UI框架编写。用户通过浏览器访问前端界面来实现与系统的交互。 业务层是基于SpringBoot框架编写的Java后台服务器。该层负责本系…

从开发到部署:EasyRTC嵌入式视频通话SDK如何简化实时音视频通信的集成与应用

嵌入式设备和视频综合管理平台均支持B/S架构。在B/S架构下&#xff0c;传统的视频观看方式依赖于微软的OCX控件&#xff0c;然而OCX控件的使用正面临越来越多的挑战&#xff1a; 首先&#xff0c;用户需要安装浏览器插件、调整浏览器安全级别&#xff0c;并允许ActiveX控件弹出…

如何查看 Linux 服务器的 MAC 地址:深入解析与实践指南

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

RabbitMQ 3.12.2:单节点与集群部署实战指南

前言&#xff1a;在当今的分布式系统架构中&#xff0c;消息队列已经成为不可或缺的组件之一。它不仅能够实现服务之间的解耦&#xff0c;还能有效提升系统的可扩展性和可靠性。RabbitMQ 作为一款功能强大且广泛使用的开源消息中间件&#xff0c;凭借其高可用性、灵活的路由策略…

Ubuntu22.04配置cuda/cudnn/pytorch

Ubuntu22.04配置cuda/cudnn/pytorch 安装cuda官网下载.run文件并且安装/etc/profile中配置cuda环境变量 cudnn安装官网找cuda版本对应的cudnn版本下载复制相应文件到系统文件中 安装pytorch官网找cuda对应版本的pytorchpython代码测试pytorch-GPU版本安装情况 安装cuda 官网下…

动态规划算法篇:枚举的艺术

那么本篇文章就正式进入了动态规划的算法的学习&#xff0c;那么动态规划算法也可谓是算法内容中的一座大山&#xff0c;那么在大厂算法笔试乃至算法比赛中出现的频率也逐渐变高&#xff0c;那么可见学习好动态规划算法的一个重要性&#xff0c;那么对于动态规划最难理解的&…

从入门到精通:Postman 实用指南

Postman 是一款超棒的 API 开发工具&#xff0c;能用来测试、调试和管理 API&#xff0c;大大提升开发效率。下面就给大家详细讲讲它的安装、使用方法&#xff0c;再分享些实用技巧。 一、安装 Postman 你能在 Postman 官网&#xff08;https://www.postman.com &#xff09;下…

Android平台基于SmartPlayer实现多实例RTSP|RTMP播放器

在 Android开发中&#xff0c;实现多实例的RTSP或RTMP直播播放器是一个常见的需求&#xff0c;本文将介绍如何利用大牛直播SDK的SmartPlayer模块接口&#xff0c;快速实现Android平台上的多实例播放器。通过合理的架构设计和 API 调用&#xff0c;我们可以轻松地管理多个播放实…

Linux中进程的状态3 进程的优先级1

目录 X(dead) && Z(zombie) 僵尸进程 && 孤儿进程 进程的优先级 如何修改进程的优先级 我们至此还剩两种状态没有查看&#xff0c;X和Z状态。 X(dead) && Z(zombie) X状态是进程死亡状态&#xff0c;Z状态依照这个词可知是进程处于僵死状态&…

基于语音的阿尔茨海默病检测识别

摘要 阿尔茨海默病 &#xff08;AD&#xff09; 是一种进行性神经退行性疾病&#xff0c;会严重损害认知功能&#xff0c;导致记忆力减退和其他行为改变。它是全球第七大死因&#xff0c;有数百万人受到影响。早期准确检测 AD 对于改善患者预后和减缓疾病进展至关重要。机器学习…

Ubuntu添加桌面快捷方式

以idea为例 一. 背景 在ubuntu中&#xff0c;很多时候是自己解压的文件并没有桌面快捷方式&#xff0c;需要自己找到对应的目录的执行文件手动打开&#xff0c;很麻烦 而只需要在 /usr/share/applications 中创建自定义的desktop文件就能自动复制到桌面 二. 添加方法 创建desk…

pycharm社区版虚拟环境如何配置、如何验证配置成功

1、无配置直接新建按照以下步骤&#xff1a; 新建——自定义环境——类型确定为虚拟 2、以前设置过的只需要将虚拟环境配置上就行了 选择文件——设置——对应文件下的解释器——选择带.ven的解释器 如何检查安装成功&#xff1f; 看终端开头是否显示.venv

【有啥问啥】DeepSeek 技术原理详解

DeepSeek 技术原理详解 DeepSeek 是一款具有突破性技术的大型语言模型&#xff0c;其背后的技术原理涵盖了多个方面&#xff0c;以下是对其主要技术原理的详细介绍&#xff1a; 架构创新 多头潜在注意力机制&#xff08;MLA&#xff09; 传送门链接: DeepSeek V3中的Multi-…

Java通过ollama平台接入DeepSeek

1、配置适配jdk8的依赖 <dependency><groupId>io.github.lnyo-cly</groupId><artifactId>ai4j-spring-boot-stater</artifactId><version>0.7.0</version> </dependency>2、配置bootstrap.yml ai:ollama:api-host: http://loc…

【Ai】使用AnythingLLM访问DeepSeek,界面友好,API调用

本文假设已经安装好Ollama 如果还没安装可以看见这个https://blog.csdn.net/wlddhj/article/details/145418880 AnythingLLM是Mintplex Labs推出的一款功能强大的全栈AI应用程序&#xff1a; 功能特点 支持多种LLM和数据库&#xff1a;支持OpenAI、Azure OpenAI、AWS Bedrock…

猿大师播放器与其他网页播放RTSP方案对比有哪些优势?

1. 超低延迟播放&#xff08;300毫秒级&#xff09; - 基于VLC/FFPLAY引擎直接调用本地硬件解码&#xff0c;无需服务器转码&#xff0c;延迟低至300毫秒&#xff0c;远低于传统转码方案&#xff08;通常1-3秒&#xff09;。在消防、安防等场景中&#xff0c;毫秒级延迟可显著…