robinkam 发表于 2023-9-20 23:53:17

免翻墙!讯飞星火大语言模型AI语音助手



https://www.bilibili.com/video/BV1Kh4y1a7rx/

https://www.bilibili.com/video/BV1cz4y1V7Ma/


## 1. 项目背景

自从OpenAI的ChatGPT从2022年底火出圈之后,2023年成为世界“AI大语言模型元年”,各种对标ChatGPT的大语言模型如雨后春笋般涌现出来,可谓百花齐放!

目前已经有很多基于ChatGPT的语音交互机器人或者音箱的创客作品,比如:

- [利用行空板开发的ChatGPT智能音箱](https://www.bilibili.com/video/BV18v4y1Y7Y8/?share_source=copy_web)
- [利用M5Stack Core2开发的ChatGPT聊天机器人](https://www.bilibili.com/video/BV1A24y1P7oU/?share_source=copy_web)

不过这些作品复刻起来有一个最大的痛点,那就是需要科学上网环境,毕竟ChatGPT对中国并不开放,而且有段时间还疯狂封杀中国的账号,我就被封杀了两个,原因可能是OpenAI识别出我用中国的IP地址调用他们的API服务,虽然我访问他们的网页版是OK的。

看起来直接调用OpenAI的API有被封号的风险,这个方案也有使用上的门槛——需要科学上网。其他的方案也有,比如可以考虑自己调用微软Azure云服务封装的OpenAI接口,可以合规使用;又或者自己利用海外的云主机自己搭建一个代理服务器。但是这些手段也有一定的学习开发门槛。

由于国内使用ChatGPT存在各种门槛,极大地限制了这些创新作品的复制和传播,即使代码开源,也只能沦为一小部分极客的私人玩物。

## 2. 项目目标

本项目的目标:面向儿童用户开发一款容易复刻和使用的大语言模型AI助手,并具备以下特性:

* 儿童通过简单的触摸屏点击操作和自然语言来使用
* 可以向AI提问,通过AI的文字+语音回复,了解万事万物
* 可以用来充当“带语音输入的电子词典”,写作文时快速查询生字怎么写。

## 3. 方案设计

本项目借鉴了“[行空板ChatGPT智能音箱](https://gitee.com/rocketscn/chat-gpt-unihiker-speaker/tree/master)”开源项目,主要从两个方面改善使用体验:

1. 大语言模型从ChatGPT换成了国内科大讯飞出品的星火认知大模型,免翻墙,随时可用,稳定可靠。
2. 扬声器从USB小喇叭换成了蓝牙小喇叭,方便将喇叭固定在出音口的位置,获得更好的音质。(背景:这个开源项目使用的是USB小喇叭,但是其智能音箱外壳的发音孔设计在行空板的左侧,如果把喇叭紧贴这个发音孔的话,刚好把行空板的USB口挡住了,所以这个开源项目把USB喇叭水平固定在外壳底座上,没有正对着发音孔,这样音质不是很好。)

## 4 硬件部分
## 4.1 材料清单

|**材料名称**|**说明**|
| - | - |
|**3D打印外壳**|从[本项目开源仓库](https://gitee.com/robinkam/xf-spark-unihiker-speaker)中获取两个stl模型文件,自行打印或者在淘宝上找商家打印。|
|**行空板**|从[行空板官网](https://www.unihiker.com.cn/)了解购买渠道|
|**蓝牙音频接收模块**|跟行空板建立蓝牙连接,将行空板的声音通过接入模块的喇叭放出来|
|**喇叭**|4Ω 5W双内磁16芯全频喇叭,直径50mm|
|**USB分线器**|将行空板的USB Type-C口引出,方便给音箱插上USB线供电或者连电脑上传代码。之所以没有直接用一根短的Type-C延长线,是因为想实现行空板和蓝牙音频接收模块共用一根USB供电线,并且希望方便固定在底座上。不过目前还有点问题,所以是分别用两根USB线进行供电的。|
|**USB Type-C公头**|带焊盘的USB Type-C公头,方便跟杜邦线进行焊接。|
|**杜邦线**|一头剪掉焊接在USB Type-C公头上,一头连接USB分线器|
|**M3螺丝若干**|3颗用于将行空板固定在3D打印底座上,至少2颗用于将外壳固定在底座上。|
|**M2自攻螺丝\*2**|将USB分线器模块固定在底座上|

## 4.2 零件组装


## 5. 软件部分

本项目所有程序已开源,git仓库地址:<https://gitee.com/robinkam/xf-spark-unihiker-speaker> 。

代码使用必读:在 services 目录下的 Privacy.py 文件中填入在百度和讯飞的开放平台申请到的API调用必填通用参数后,程序方可正常运行。 这些参数的获取请参考5.1和5.2两个小节。

## 5.1 开通百度智能云语音技术服务
1. 前往百度智能云[首页](https://cloud.baidu.com/),完成注册登录。
2. 在百度智能云控制台中查看[语音技术概览](https://console.bce.baidu.com/ai/?fromai=1#/ai/speech/overview/index),先去领取免费接口资源,本项目要用到的接口是“短语音识别-中文普通话”、“音频文件转写-中文普通话”。



3. 创建一个应用,语音技术这一项勾选刚刚开通的两个接口



4. 去[应用列表](https://console.bce.baidu.com/ai/#/ai/speech/app/list)中查看创建好的应用的AppID、API Key、Secret Key,这3个信息是后面开发程序的时候要用到的。

## 5.2 申请讯飞星火大模型API免费试用
1. 前往讯飞星火大模型[首页](https://xinghuo.xfyun.cn/),点击“API免费试用”按钮。




2. 滚动到产品价格部分,选择V2.0套餐,点击“免费试用”按钮。




3. 在下单页面创建应用。




4. 跳转到创建应用表单页,按要求填写应用信息,点击“提交”按钮。




5. 等待申请通过,通过后进入控制台,从左侧导航菜单中选择【[星火大模型V2.0](https://console.xfyun.cn/services/bm2)】,查看申请到的token配额和**服务接口认证信息(重要!后面写代码要用)。**



## 5.3 下载和封装星火大模型SDK

首先,从讯飞官方文档中找到[星火认知大模型的Web文档](https://www.xfyun.cn/doc/spark/Web.html#_2-%E8%B0%83%E7%94%A8%E7%A4%BA%E4%BE%8B),并从中找到并下载Python调用示例(是一个zip包,解压后得到Python调用示例代码)



示例代码zip包解压出来有两个文件:SparkApi.py和test.py。前者是讯飞官方封装的函数库,用websocket来调用讯飞星火大模型的API。后者看名字就知道是一个测试程序,可以直接执行,调用前者,实现在命令行里跟星火大模型AI聊天。由于test.py中对SparkApi.py的调用方法有点繁琐,分为4步:

1) 将命令行中的用户输入的提问内容追加到聊天历史数组中,存入question变量;
2) 将SparkApi模块中的answer全局变量设置为空字符串;
3) 调用SparkApi模块中的main函数,传入appid、api\_key、api\_secret、Spark\_url、domain这5个通用参数和刚刚构造的question这个变量。由于main函数是一个同步方法,程序阻塞,直到星火大模型远程接口返回结果,程序才会继续执行;
4) 从SparkApi对象的answer属性中获取星火大模型的回答内容,并通过getText函数将其也追加到聊天历史数组中,为下次提问提供上下文。



我希望将这4步简化成1步,并将示例代码进行一些封装,方便后续调用。具体做法如下:

1. 对SparkApi.py稍加修改:




   1) 在main函数每次执行的时候自动给answer全局变量设置为空字符串,省得每次调用main函数之前都需要手动设置一次。
   2) 当做完socket请求时,将answer变量的值返回出去,省得每次调用完main函数之后还得用一个语句去读取里面的值。

2. 新增SparkClient.py,在test.py的基础上进行一些重构:

   1) 封装一个SparkClient类,提供面向对象的接口,方便业务层调用;
   2) 将appid、api\_key、api\_secret这3个跟讯飞星火开放平台账号有关的个性化参数通过SparkClient类的\_\_init\_\_()方法传入,并赋值为其实例的属性;




   3) 将test.py中的while(1)死循环里的主要逻辑封装为SparkClient类的chat方法(),按需调用;




   4) 将test.py里的函数和变量重命名,提高代码可读性。

3. 将test.py重命名为SparkTest.py,保留命令行中快速测试调试SparkApi.py和星火大模型的能力。

完整代码请参考开源代码仓库中的(https://gitee.com/robinkam/xf-spark-unihiker-speaker/tree/master/services)下的SparkApi.py、SparkClient.py、SparkTest.py这3个python文件。

## 5.4 开发GUI主程序

在实现核心功能之前,我们首先需要创建基本的图形交互界面。

行空板的unihiker库中的GUI类是开发图形化界面的主要途径。它是基于python自带的GUI库tkinter进行二次封装的。由于其文档中介绍的API比较有限,如果要实现更复杂的UI,建议阅读其源代码,查出其所有暴露的方法和属性,如果还不满足需求,可以直接查询tkinter库的文档,GUI类也暴露了底层的tkinter对象。

不过我们目前的程序还算简单,GUI类的能力基本够用。本项目的GUI程序主要涉及以下一些方面:

1) 绘制文本和按钮这两种基础控件,主要用到GUI类里的add\_button和draw\_text方法。
2) 控制各种文本控件的可见性和样式,主要用到文本控件对象的config方法。
3) 控制按钮控件的样式和状态,主要用到文本控件对象的config方法。
4) 处理按钮点击事件,主要通过初始化按钮时设置的onclick属性。
5) 实现状态机,包含IDLE、RECORDING、WAITING、FAILED这4种状态,由用户交互事件和接口返回结果驱动状态轮转。
6) 在main loop中控制界面刷新,使用GUI对象的update方法,此函数仅在MAC系统下运行unihiker库时需要,用于在主线程中刷新界面,控制行空板时无需此函数。要想在Mac上测试调试,就需要用到这个update方法来刷新界面。

具体代码实现在仓库根目录()中,总共就一百多行代码,大家看看应该就明白了,细节就不赘述了。

## 5.5 实现AI问答功能

有了GUI主程序框架,加上之前封装的星火大模型SDK,实现AI问答功能就很简单了。核心流程如下:



具体代码实现在仓库根目录()中,总共就一百多行代码,大家看看应该就明白了,细节就不赘述了。

## 5.6 实现听写功能

听写功能比较简单,其实是AI问答功能的一个子集,只需要实现核心流程的前两步即可,只是将STT返回的文字内容以更大的字体显示出来,以便查看汉字结构和临摹。

具体代码实现在仓库根目录()中,总共就一百多行代码,大家看看应该就明白了,细节就不赘述了。

## 6. 心得体会

## 6.1 开发效率

在开发这个作品的过程中,我解决了一个影响开发效率的问题,那就是通过修改unihiker库内部代码解决了代码在Mac端无法直接运行调试的问题。

行空板一个很大的优点是能直接运行常规Python程序,因此理论上不牵涉到特定硬件驱动的Python程序都可以在电脑上运行。这代表我们不需要模拟器,可以直接在电脑上调试程序,这将极大提升开发效率,因为电脑上开发一般Python程序有很多高效强大的IDE,比如PyCharm,而不局限于行空板提供的Mind+和Jupiter等IDE。

行空板主要提供2个库:unihiker行空库和pingpong硬件控制库。pingpong库封装了行空板GPIO和传感器的硬件编程接口,电脑端不能直接运行,而本项目刚好也不需要使用pingpong库。而unihiker行空库中主要封装了GUI和Audio两个类,一个负责图形化界面,一个负责音频输入输出,虽然也依赖屏幕、麦克风等硬件,但是这些电脑上也有。

经过实验,基于GUI类绘制的图形化界面程序在电脑端可以直接运行和渲染,因为其底层使用的是Python自带的tkinter GUI库,而基于Audio类开发的录音和播放音频的程序在我的苹果本Mac系统上不能直接运行。但是分析这个类的源代码之后发现里面有一处判断,只考虑了Windows和Linux系统,没考虑到Mac系统。我简单将里面对于Windows系统的判断改为对Mac系统的判断,具体做法如下:



改好之后,这个程序就可以直接在Mac系统上正常运行了,下面的截图就是程序在Mac上运行的效果,看窗口顶部标题栏样式就知道了。



## 6.2 改进方向

这个作品仅是抛砖引玉实现了基本功能,仍有很多可以改进的地方,比如:

1. 硬件方面
   1) 采用一根USB线供电
   2) 重新设计音箱外壳,使之方便使用USB喇叭且音质良好,这样比蓝牙的可靠性更高
2. 软件方面
   1) 当AI回复的文字内容过多时,可以考虑实现一个长文本滚动容器,或者翻页功能,也可以考虑通过提示词或者参数设置,告诉星火大模型不要返回太多文字或者太多行数。
   2) 研究出当程序运行异常卡住的时候,如何主动退出程序,回到主菜单,否则,由于星空板被封闭在外壳里,无法通过物理按键退出程序,只能断电后重新启动。





robinkam 发表于 2023-11-20 18:01:55

Forgotten 发表于 2023-9-21 11:42
程序运行异常之后让程序跳出循环结束程序就回到这个界面了,然后点左上角这个icon可以返回主界面。




多谢提示,我之前貌似也尝试过点这个图标,但是没效果,我后面再试试看

Forgotten 发表于 2023-9-25 19:36:00

_深蓝_ 发表于 2023-9-24 15:12
太我想知道,这个喇叭和行空板怎么连接,放出行空板的声音的?请教

他用的是蓝牙音频模块,相当于一个蓝牙音响,所以应该是用行空板蓝牙连接的

robinkam 发表于 2023-10-6 00:02:55

Trump 发表于 2023-9-26 23:30
蓝牙音频接收模块是用哪个品牌的,是否有购买链接

没啥品牌,随便淘宝上买一个性价比高的就行。我买的叫“M38带5W功放版”,才4元一个。

hnyzcj 发表于 2023-9-21 07:17:55

赞一个,哈哈哈哈

木子呢 发表于 2023-9-21 10:26:07

赞一个

Forgotten 发表于 2023-9-21 11:42:00

程序运行异常之后让程序跳出循环结束程序就回到这个界面了,然后点左上角这个icon可以返回主界面。


蒋彦雄 发表于 2023-9-22 16:49:35

点赞学习

腿毛利小五郎 发表于 2023-9-23 09:04:36

这个好这个好

_深蓝_ 发表于 2023-9-24 15:12:56

太我想知道,这个喇叭和行空板怎么连接,放出行空板的声音的?请教

_深蓝_ 发表于 2023-9-25 13:53:52

赞一个,必须实践一下。

_深蓝_ 发表于 2023-9-25 13:58:58

这个作品仅是抛砖引玉实现了基本功能,仍有很多可以改进的地方
作者谦虚啦

Trump 发表于 2023-9-26 23:30:46

蓝牙音频接收模块是用哪个品牌的,是否有购买链接

Amos Young 发表于 2023-10-5 10:11:29

点赞学习

robinkam 发表于 2023-10-6 00:00:52

Forgotten 发表于 2023-9-25 19:36
他用的是蓝牙音频模块,相当于一个蓝牙音响,所以应该是用行空板蓝牙连接的 ...

多谢版主大人帮我回复!

Forgotten 发表于 2023-11-22 14:05:10

robinkam 发表于 2023-11-20 18:01
多谢提示,我之前貌似也尝试过点这个图标,但是没效果,我后面再试试看 ...

V0.3.3系统开始增加的功能:https://www.unihiker.com.cn/wiki/ReleaseLogs

JOVI 发表于 2023-11-28 20:11:43

科大讯飞的东西靠谱吗?

DeadWalking 发表于 2024-1-10 13:14:25

学习学习!

发表于 2024-1-23 19:18:33

我三年没来,这里一下子变化了这么多!!!
想问一下这个3D打印外壳打了多久

CalvinKang 发表于 2024-2-3 09:18:23

请问关于“解决Mac端无法直接运行调试的问题”,具体修改unihiker库内部代码的路径和内容是什么?

这次拿个一等奖 发表于 2024-2-24 12:07:29

升级到api升级到3.5,代码调用不成功怎么办 ,求问
页: [1] 2
查看完整版本: 免翻墙!讯飞星火大语言模型AI语音助手