看到一个用esp32实现的AI对话方案,这里学习一下代码:https://github.com/wangzongming/esp-ai/tree/master
基本的原理比较简单:
INMP441(MIC) -> audio -> ESP32 -> wake-on-voice -> audio -> esp-ai -> IAT Server -> text -> esp-ai -> LLM -> reply -> esp-ai -> TTS -> esp-ai -> ESP32 -> max98357(loudspeaker)
这里就是看一下具体的代码细节
Client
esp32上跑的代码就是client,需要一个麦克风,以及一个声音放大器。
然后主体的代码分几块,有和server交互的websocket,以及和硬件交互的一些逻辑
这里是声音调节的逻辑,analogRead是从指定的引脚处读取电压,然后计算出音量并设置。这里模拟引脚读出来的是模拟信号,即连续的电压值,值域是0~1023,与之对应的是数字信号,只会读出来0/1
然后看看inference的逻辑:
typedef struct {
int16_t *buffer;
uint8_t buf_ready;
uint32_t buf_count;
uint32_t n_samples;
} inference_t;
static inference_t inference;
在setup的时候,会调用microphone_inference_start()
* 先分配一个buffer,这个估计是模型的窗口
* i2s_init()
* 看了下介绍,i2s是数字音频传输协议,用来把麦克风得到的信号转化为数字信号
* 这里细节应该没什么可看的,就是麦克风初始化相关的逻辑了,传入的参数中会有buf count和buf len
* xTaskCreate(),创建capture_samples这个任务
* 这里相当于启动了一个持续执行的后台线程,栈的大小为32k,参数为sample_buffer_size,目前是4096
* capture_samples()
* 持续polling,然后用i2s_read从麦克风中读取数据
* 如果目前start_ed 1 && can_voice 1,这里会把这段buffer通过websocket的sendBIN发出去
* 然后在把sample buffer中的数据扩大一倍,提高音量
* 调用audio_inference_callback()
* 把刚刚读取到的sample buffer,传给inference.buffer中,并在数据量大于inference.n_samples的时候,把buf_ready设为1
- 当上面的一个buffer读满了以后,在主循环中的buf_ready就会设置为true,此时会重置buf的状态。
- 调用run_classifier(),这里用的是edge impulse这个平台,是专门用来做嵌入式机器学习的
- 输入是一个singal,里面带了数据的total length,以及一个get_data的callback。这里的get data就是读取inference.buffer中的数据。
- 同步调用,返回成功之后,会有一个classifier的输出值,是
result.classification[2].value
。如果大于voice_key_threshold的话,目前是0.8,这里就会被唤醒,并设置start_ed = 1,表示开始录音了。开始录音之后,后续的从麦克风中读取出来的数据就会通过webSock发送到server端了。
这里的websocket设置了onEvent,用来在一些事件发生的时候,调用对应的callback。基本上比较关键的就两个:
* WStype_TEXT,是对端发来text类型的消息,这里会根据发来的字符串做一些操作,比如指明本次对话结束,本次语音识别结束等
* WStype_BIN,是对端发来的binary类型的消息,这里具体就是音频,会直接通过i2s播放出来
Server
感觉不用看了,就是接收esp32发来的消息,调用对应的api得到数据,再把音频发回去。感觉逻辑比较简单,就不看了,后续在实现过程中如果遇到了问题再来
初步看了看感觉IAT的流程稍微恶心一点,服务商应该都有基本的实例,问题也不大。
文章评论