我的订单购物车(0)会员中心
联系客服
帮助中心供应商合作
嘉立创产业服务群
立创商城
领券中心备货找料立推专区爆款推荐PLUS会员BOM配单品牌库PCB/SMT工业品面板定制

真开源了?!大佬手搓AI助手,可离线使用DeepSeekR1

2025-03-05 10:19:51阅读量:1464

这是一个特别的AI小助手——AI-Box

AI助手

不用联网!

就能用DeepSeek!

且是深度思考R1版本!

除此之外,还支持所有开源模型……

依然是全开源的好项目!

开源项目

开发文档

开发资源包

开源资源包

它是怎么设计出来的(2-3章)原理是什么(2-3章)还有什么功能&亮点(第1章)制作成本是多少(第4章)开源网址有吗(第5章)

下文咱们一个个探索~

 

01
功能&亮点

AI-Box基于立创·泰山派RK3566设计,主要功能&亮点如下:

功能亮点

咋切换开源模型

后续模型权重下载好后,修改模型名称就行

不到1分钟就能换一个开源模型!

开源模型

 

 

02
硬件设计

电路由这5部分组成——电源电路、泰山派IO拓展口,防反接电路,开关电路,模块及拓展接口。

 

原理图

原理图

 

PCB图

PCB图

01 
硬件参数
  • 本设计基于泰山派RK3566,内置WIFI功能,通过AP模式遥控

  • 屏幕支持0.96寸SSD1306/SSD1315驱动OLED显示屏,实现显示表情、对话反馈、天气等相关信息

  • 选用IP5306充放一体电源芯片,提供最大2.1A输出,为泰山派供电

  • 选用AHT10高精度温湿度传感器,可实时获取温度、湿度信息。

  • 选用驻极体麦克风,可实时获取环境音频信息。

  • 选用8R1W喇叭,提供音频输出。

  • 采用MOS管开关电路,支持驱动较大功率LED灯板。

  • 采用防反接电路,可任选Type-C接口供电。

 

 

02 
原理解析
  • 供电:本项目采用IP5306锂电池充放一体芯片,可提供最大2.1A电流输出。

  • 拓展IO:功能实现依赖于泰山派提供的IO口控制,这里为需要使用的引脚做好定义

  • 防反接:由于泰山派的DC-DC 3.3V对输入电压有较高要求,输入电压不能低于4.5V,所以这里采用MOS管和三极管实现防反接,而不是二极管。

  • 开关控制:在电路中还设计了一个MOS驱动的开关电路,帮助驱动较大电流的LED。

  • 拓展接口:拓展引出UART串口,方便充当离线语言模块对接其他主控使用。

  • 拓展模块:模块上使用OLED模块和AHT10模块,再通过音频接口引出麦克风和扬声器。

  • 按键:引出3个按键,用于与屏幕交互。

 

 

 

03
软件设计

AI-BOX是如何做到离线对话的如何通过软件设计,实现这个功能?

01 
软件参数

 

  • 系统基于Ubuntu20.04

  • 环境为Python3.8

  • 软件框架为Vosk+Ollama+espeak-ng

  • 模型权重为DeepSeek-R1 1.5B/Qwen2 0.5B

 

02 
软件流程图

 

软件流程图

 

 

03 
程序编写(9步)

接下来,咱们直接“上手”!

①导入库文件

一切开始前先导入我们需要使用的pip库。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
import time  # 导入时间模块,用于控制延时import vosk  # 导入 Vosk 语音识别库import json  # 导入 JSON 解析库import subprocess  # 用于调用外部进程(如语音合成)import ollama  # 导入 Ollama,用于聊天 AI 处理import asyncio  # 导入 asyncio 以支持异步操作import pyaudio  # 导入 PyAudio 处理音频输入import threading  # 导入多线程模块import re  # 导入正则表达式模块,用于文本处理from concurrent.futures import ThreadPoolExecutor  # 用于异步任务的线程池from board import *  # 导入 board 库,用于 I2C 设备的引脚定义import busio  # 用于 I2C 通信from PIL import Image, ImageDraw, ImageFont  # 用于处理 OLED 显示图像import adafruit_ssd1306  # 用于控制 SSD1306 OLED 屏幕

②定义变量

定义一些模型路径,字符路径等变量。

这里为了避免内存超出,MAX_HISTORY_LENGTH限制会话最多保存1条,如果你设备内存或虚拟内存足够,可以增加。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
# 选择合适的字体font_path = "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc"  # OLED 屏幕显示的字体路径font = ImageFont.truetype(font_path, 16)  # 设置字体大小适应屏幕
# 初始化 I2C 设备i2c = busio.I2C(I2C2_SCL, I2C2_SDA) # 通过 I2C2_SCL 和 I2C2_SDA 初始化 I2C 通信disp = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c) # 通过 I2C 初始化 128x64 分辨率的 OLED 屏幕
# 清空屏幕disp.fill(0)disp.show()
# 获取屏幕宽高width = disp.widthheight = disp.height
# 创建一个空白图像用于绘制image = Image.new("1", (width, height))draw = ImageDraw.Draw(image)
# 设置 Vosk 语音识别模型路径,根据自己的路径设置model_path = "/home/linaro/vosk-model-small-cn-0.22"model = vosk.Model(model_path) # 加载 Vosk 语音识别模型recognizer = vosk.KaldiRecognizer(model, 16000) # 以 16kHz 采样率初始化语音识别器
# 记录会话历史conversation_history = [ {"role": "system", "content": "你是嘉立创EDA-小嘉,是一个运行在泰山派上的离线本地大模型语音助手。"},]MAX_HISTORY_LENGTH = 1 # 限制会话历史的最大条数asr_running = False # 语音识别时的动画状态控制变量

③OLED文本显示函数

屏幕显示这里进行了封装,确保每次显示前能自动清屏,同样的限制只能显示8个字符,避免超出显示长度。

  •  
  •  
  •  
  •  
  •  
def show_on_oled(text):    draw.rectangle((0, 0, width, height), outline=0, fill=0)  # 清除屏幕    draw.text((0, 0), text[:8], font=font, fill=255)  # 仅显示前8个字符    disp.image(image)  # 更新屏幕内容    disp.show()

④动画表情绘制函数

动画表情直接利用库函数绘制圆和弧线实现。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
def draw_face(mouth_state=0):     """显示不同表情的脸部动画"""    draw.rectangle((0, 0, width, height), outline=0, fill=0)  # 清空屏幕
# 绘制眼睛 draw.ellipse((32, 15, 40, 25), outline=255, fill=255) # 左眼 draw.ellipse((88, 15, 96, 25), outline=255, fill=255) # 右眼
# 嘴巴动画 if mouth_state == 0: draw.line((50,50, 78, 50), fill=255, width=2) # 直线嘴巴 elif mouth_state == 1: draw.arc((50, 40, 78, 60), start=0, end=180, fill=255) # 微笑嘴巴 elif mouth_state == 2: draw.ellipse((58, 50, 70, 60), outline=255, fill=255) # 张嘴嘴巴
disp.image(image) # 更新屏幕内容 disp.show()

⑤嘴巴动画

嘴巴动画通过该函数来控制变换,因为采用了多线程,可以避免动画影响Vosk识别语音。
  •  
  •  
  •  
  •  
  •  
  •  
  •  
def asr_animation():    global asr_running    frame = 0    while asr_running:        draw_face(frame % 3)  # 按 0、1、2 的顺序切换嘴巴形态        frame += 1        time.sleep(0.2)  # 控制动画速度

⑥Vosk 语音识别

怎么实现边录边传?

配置音频采样率16kHz,然后设置一个20480帧的缓冲区大小(约1.28s),16位PCM格式

然后配置asr_running 全局标志用于控制动画线程运行,独立线程运行asr_animation实现非阻塞式用户体验。

这里循环中启用流式传输,每次读取 2048 字节(约 128ms )实现非阻塞读取:exception_on_overflow=False 允许忽略缓冲区溢出错误,这样无需等待完整录音文件,实现边录边传

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
def recognize_speech(p):    global asr_running    stream = p.open(format=pyaudio.paInt16,                    channels=1,                    rate=16000,                    input=True,                    frames_per_buffer=20480)    stream.start_stream()    print("正在识别语音...")    asr_running = True  # 启动动画    animation_thread = threading.Thread(target=asr_animation)  # 创建动画线程    animation_thread.start()    try:        while True:            data = stream.read(2048, exception_on_overflow=False)  # 读取音频数据            if recognizer.AcceptWaveform(data):  # 处理音频流                result = recognizer.Result()  # 获取识别结果                result_json = json.loads(result)  # 解析 JSON 数据                if "text" in result_json:                    text = result_json['text']  # 提取识别文本                    print(f"识别到的文字: {text}")                    asr_running = False  # 停止动画                    animation_thread.join()  # 等待动画线程结束                    draw_face(1)  # 识别完成后显示微笑表情                    time.sleep(1)
# 释放音频资源 stream.stop_stream() stream.close() return text except IOError: pass
# 释放资源 asr_running = False animation_thread.join() stream.stop_stream() stream.close()

⑦保留中文字符

说出来的话,要转换成文字呀!如何只保留中文字符,避免识别出乱码呢?

由于我们使用的espeak-ng是轻量化的,只能支持一种语言,所以这里我们要过滤掉除中文外的文字和特殊符号

这里使用正则表达式"[^\u4e00-\u9fa5,。!?]"。

正则表达式中的方括号表示字符集^符号在开头表示取反,也就是匹配不在这个字符集里的任何字符。所以这个正则表达式的作用是匹配所有不属于指定Unicode范围的字符,以及标点符号,。!?。

  •  
  •  
def clean_text(text):    return re.sub(r"[^\u4e00-\u9fa5,。!?]", "", text)

⑧模型处理

已经搞定了语音识别转文字了,那怎么让模型“理解”它的含义呢?

——将语音识别的文字传给Ollama然后交给模型处理,使用stream=True实现流式逐块生成,然后通过for chunk in response: if 'message' in chunk and 'content' in chunk['message']:典型的流式响应处理模式,主要用于处理流式返回的数据结构

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
async def generate_and_play_text(input_text):    draw_face(1)  # 显示微笑表情    time.sleep(1)    conversation_history.append({"role": "user", "content": input_text})  # 记录用户输入    response = ollama.chat(model="qwen2:0.5b", messages=conversation_history, stream=True)  # AI 生成回答    generated_text = ""    for chunk in response:        if 'message' in chunk and 'content' in chunk['message']:            raw_text = chunk['message']['content']            clean_tts_text = clean_text(raw_text)  # 清理文本            generated_text += raw_text            show_on_oled(raw_text)            print(f"当前生成: {generated_text}")            if clean_tts_text:  # 确保有中文内容才播放
# 显示在 OLED 上 subprocess.run(['espeak-ng', '-v', 'zh', clean_tts_text]) # 语音朗读
conversation_history.append({"role": "assistant", "content": generated_text}) # 记录 AI 回应 draw_face(1) # 结束后显示微笑 time.sleep(1)

⑨主函数

如何让动画和语音识别,能共同运行,且互不干涉呢?

这里max_workers=2 采用双线程实现互不干涉。然后通过pyaudio库用于输入音频数据,代入我们前面创建的函数中。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
async def main():    loop = asyncio.get_event_loop()  # 获取事件循环    executor = ThreadPoolExecutor(max_workers=2)  # 线程池用于并发任务    p = pyaudio.PyAudio()  # 创建 pyaudio 实例    while True:        recognized_text = await loop.run_in_executor(executor, recognize_speech, p)  # 识别语音        await generate_and_play_text(recognized_text)  # 生成回答并朗读    p.terminate()  # 释放音频资源if __name__ == "__main__":    asyncio.run(main())  # 运行主程序

 

 

04
成本说明

如果你没有泰山派

本项目的DIY成本为193.5元153.5元

如果你已经有了泰山派

那么本项目的DIY成本仅需25.5元

*立创·泰山派是一款开源的卡片电脑,提供全面开放的软硬件资料参数资源如下:

立创泰山派

如果你想尝试复刻AI-BOX

想采购泰山派

那您真来巧啦!

泰山派正进行限时特价!

直降40元!

 

1G+0G版本的泰山派

不要168!

仅需128!

 

2G+16G版本的泰山派

不要228!

仅需188元!

 

扫码即可抢购

扫码

电脑端打开:https://lckfb.com/project/detail/lctspi-2g-16g

扫码后,4步领取优惠

领取优惠步骤

 

 

05
开源网址

本项目已开源!

——想复刻想给作者点赞复制开源网址 前往原文。

开源网址:https://oshwhub.com/course-examples/ai-rk3566

点击咨询客服咨询客服
  • 优惠券图标优惠券
  • 芯媒体芯媒体
  • 意见反馈建议反馈
  • 意见反馈投诉意见
  • 收起收起
  • 海量现货

    海量现货

    60万+现货SKU

    品类不断扩充中

  • 闪电发货

    闪电发货

    科技智能大仓储

    最快4小时发货

  • 严控渠道

    严控渠道

    正品有保障

    物料可追溯

  • 降低成本

    降低成本

    明码标价节省时间

    一站式采购元器件

    联系我们
  • 服务热线:0755-83865666
  • 企业QQ :4000800709
  • 服务时间:
    • 8:30-18:30(工作日)
    • 9:00-18:00(节假日)
关注立创商城公众号

关注立创商城公众号

字母索引:

© 深圳市立创电子商务有限公司 版权所有

备案粤公网安备 44030402002194粤ICP备13005967号工商网监工商网监ISO/IEC