esp32s3文心一言/豆包(即火山引擎)大模型實現智能語音對話--流式語音識別

一、引言

????????在之前的帖子《Esp32S3通過文心一言大模型實現智能語音對話》中,我們介紹了如何使用Esp32S3微控制器與文心一言大模型實現基本的智能語音對話功能,但受限于語音識別技術,只能處理2-3秒的音頻數據。為了提升用戶體驗,滿足更長時間的語音聊天對話需求,本次優化采用了流式語音識別技術,并添加了語音喚醒模塊,實現了語音關鍵詞喚醒功能。

二、開發環境介紹

? ? ? ? 1、arduino開發平臺;

? ? ? ? 2、所需設備:Esp32s3、inmp441、max98357、ASRPRO語音模塊、ILI9488顯示屏,杜邦線(接線);

? ? ? ? 3、大模型:百度的文心一言大模型,豆包的火山引擎大模型;

? ? ? ? 4、語音識別(STT)和語音合成(TTS):使用百度語音識別和語音合成;

? ? ? ? 5、使用語言:C/C++;

三、拓撲圖

四、設備購買鏈接


? ? ? ? 1、esp32s3:

? ? ? ? 2、inmp441:

? ? ? ? 3、max98357:

? ? ? ? 4、ASRPRO語音模塊:

? ? ? ? 5、揚聲器:

? ? ? ? 6、杜邦線:

? ? ? ? 7、ILI9488顯示屏

五、接線

1、INMP441與Esp32S3接線? ? ? ??

????????1.1、inmp44介紹? ? ? ? ?

????????INMP441是一款高性能,低功耗,數字輸出,帶底部端口的全向MEMS麥克風。該完整的INMP441解決方案由一個MEMS傳感器,信號組成調節,模數轉換器,抗混疊濾波器,電源管理和行業標準的24位I2S接口。I2S接口允許INMP441直接連接到數字處理器,如DSP和微控制器,無需使用用于系統中的音頻編解碼器。INMP441具有高信噪比,是一款出色的選擇近場應用。 INMP441具有扁平寬帶頻率響應,導致自然聲音高清晰度。

? ? ? ? 1.2、inmp441接口定義

????????????????SCK:I2S接口的串行數據時鐘。
? ? ? ? ? ? ? ? WS:用于I2S接口的串行數據字選擇。
? ? ? ? ? ? ? ? L/R:左/右聲道選擇。設置為低電平時,麥克風在I2S幀的左聲道輸出信號。設置為高電平時,麥克風在右聲道輸出信號。
? ? ? ? ? ? ? ? SD:I2S接口的串行數據輸出。
? ? ? ? ? ? ? ? VDD:輸入電源,1.8V至3.3V。
? ? ? ? ? ? ? ? GND:電源地。

? ? ? ? 1.3、實物圖

?????????????????????????????????

? ? ? ? 1.4、接線
Esp32S3?INMP441
GPIO 8引腳WS
GPIO 46引腳SCK
GPIO 9引腳SD
GND引腳L/R 和GND
3.3V引腳VDD

2、MAX98357與Esp32S3接線

? ? ? ? 2.1、max98357介紹?

? ? ? ?這是一個采用標準的I2S作為數字音頻輸入,內置解碼器,可將數字音頻信號解碼為模擬信號,并擁有內置放大器,可以直接驅動揚聲器的D類放大器。因其工作效率高,可以以2.7V~5.5V的直流電壓運行,因此非常適合便攜式及電池供電的音頻播放項目

? ? ? ?2.2、max98357接口定義

? ? ? ? ? ? ? ? VIN:電源正(2.5V-5.5V)。
? ? ? ? ? ? ? ? GND:電源地。
? ? ? ? ? ? ? ? SD:關機和頻道選擇。SD MODE拉低以將器件處于關斷狀態。
? ? ? ? ? ? ? ? GAIN:增益和頻道選擇。在TDM模式下,增益固定為12dB。
? ? ? ? ? ? ? ? DIN:數字信號輸入。
? ? ? ? ? ? ? ? BCLK:位時鐘輸入。
? ? ? ? ? ? ? ? LRC:I2S與LJ模式的左/右時鐘。同步時鐘用于TDM模式。

? ? ? ? 2.3、實物圖

????????????????????????????????


? ? ? ? 2.4、接線
Esp32S3MAX98357
GPIO 19引腳DIN
GPIO 20引腳BCLK
GPIO 21引腳LRC
GND引腳GND
3.3V引腳VIN


3、ASRPRO與Esp32S3接線

? ? ? ? 3.1、ASRPRO語音模塊介紹

? ? ? ? ASRPRO是一款高性能、低功耗的語音識別芯片,在使用過程中可以設置喚醒詞和命令詞。喚醒詞用于將模塊從待機狀態切換到工作狀態,防止誤觸發;命令詞則用于執行具體的語音指令。本文中主要是借用了喚醒詞的功能,使得esp32s3板子可以依賴語音喚醒。

? ? ? ? 3.2、接口定義? ? ? ??

? ? ? ? ? ? ? ? 該模塊接口可自行查資料了解。

? ? ? ? 3.3、實物圖

????????????????? ? ? ? ? ?

?????????3.4、接線? ? ? ? ? ? ? ?
Esp32S3?? ?ASRPRO
GPIO 10引腳PA_2
GPIO 11引腳PA_3

4、揚聲器與MAX98357接線

????????這個接線比較簡單,自己看著接就行。

六、源碼-模塊化開發

文件目錄如下:

1、ASRPRO語音模塊上的代碼

1.1、拖拉式編程如下:

1.2、字符編程如下:
#include "asr.h"
extern "C"{ void * __dso_handle = 0 ;}
#include "setup.h"
#include "HardwareSerial.h"uint32_t snid;
String Rec;
void UART_RX();
void ASR_CODE();
void app();//{speak:小蝶-清新女聲,vol:2,speed:10,platform:haohaodada}
//{playid:10001,voice:歡迎使用語音助手,用天問五幺喚醒我。}
//{playid:10002,voice:我退下了,用天問五幺喚醒我}void UART_RX(){while (1) {if(Serial.available() > 0){Rec = Serial.readString();if(Rec == "on"){digitalWrite(4,1);Serial1.print("nihao xiaodi");}else if(Rec == "off"){digitalWrite(4,0);Serial1.print("off");}}delay(2);}vTaskDelete(NULL);
}/*描述該功能...
*/
void ASR_CODE(){//語音識別功能框,與語音識別成功時被自動調用一次。set_state_enter_wakeup(15000);switch (snid) {case 1:digitalWrite(4,1);break;case 2:digitalWrite(4,0);break;case 3:Serial1.print("nihao xiaodi");break;}}void app(){//操作系統的一個線程,獨立主循環任務,可支持多個類似線程任務。//當存在多個線程任務時,注意優先級與占用內存設置。while (1) {delay(100);}vTaskDelete(NULL);
}void hardware_init(){//需要操作系統啟動后初始化的內容vol_set(1);setPinFun(13,SECOND_FUNCTION);setPinFun(14,SECOND_FUNCTION);Serial.begin(9600);setPinFun(2,FORTH_FUNCTION);setPinFun(3,FORTH_FUNCTION);Serial1.begin(9600);Rec = "";xTaskCreate(UART_RX,"UART_RX",128,NULL,4,NULL);xTaskCreate(app,"app",128,NULL,4,NULL);vTaskDelete(NULL);
}void setup()
{//需要操作系統啟動前初始化的內容//{ID:0,keyword:"喚醒詞",ASR:"天問五幺",ASRTO:"我在呢"}//{ID:3,keyword:"喚醒詞",ASR:"你好小迪",ASRTO:"在呢"}//{ID:1,keyword:"命令詞",ASR:"打開繼電器",ASRTO:"已經打開繼電器"}//{ID:2,keyword:"命令詞",ASR:"關閉繼電器",ASRTO:"已經關閉繼電器"}setPinFun(4,FIRST_FUNCTION);pinMode(4,output);digitalWrite(4,0);
}

2、INMP441與MAX98357初始化接口

在my_inmp441_max98357.h文件中,實現初始化inmp441與max98357的接口。

// 頭文件
#include <driver/i2s.h>
#include <hal/i2s_types.h>//按照接線確定編號
#define INMP441_WS 8
#define INMP441_SCK 46
#define INMP441_SD 9#define MAX98357_LRC 21
#define MAX98357_BCLK 20
#define MAX98357_DIN 19i2s_config_t inmp441_i2s_config = {.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),.sample_rate = 16000,.bits_per_sample = i2s_bits_per_sample_t(16),.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),.intr_alloc_flags = ESP_INTR_FLAG_EDGE,.dma_buf_count = 8,   // buffer 的數量.dma_buf_len = 128    // buffer的大小,單位是i2s_bits_per_sample_t 采樣位數,越小播放需要越及時時延越小,否則相反
};const i2s_pin_config_t inmp441_gpio_config = {.bck_io_num = INMP441_SCK,.ws_io_num = INMP441_WS,.data_out_num = -1,.data_in_num = INMP441_SD
};i2s_config_t max98357_i2s_config = {.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),.sample_rate = 16000,.bits_per_sample = i2s_bits_per_sample_t(16),.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_MSB),.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,.dma_buf_count = 8,.dma_buf_len = 128
};const i2s_pin_config_t max98357_gpio_config = {.bck_io_num = MAX98357_BCLK,.ws_io_num = MAX98357_LRC,.data_out_num = MAX98357_DIN,.data_in_num = -1
};void inmp441_max98357_setup()
{i2s_driver_install(I2S_NUM_0, &inmp441_i2s_config, 0, NULL);i2s_set_pin(I2S_NUM_0, &inmp441_gpio_config);i2s_driver_install(I2S_NUM_1, &max98357_i2s_config, 0, NULL);i2s_set_pin(I2S_NUM_1, &max98357_gpio_config);
}void inmp441_max98357_loop() {uint16_t data[1024];esp_err_t result;size_t bytes_read = 0;result = i2s_read(I2S_NUM_0, &data, sizeof(data), &bytes_read, portMAX_DELAY);//Serial.println(bytes_read);size_t bytes_write;result = i2s_write(I2S_NUM_1, &data, sizeof(data), &bytes_write, portMAX_DELAY);
}

2、STT和TTS(語音識別和語音合成接口)

在my_stt_tts.h文件中通過百度語音識別和語音合成API接口實現語音與文字互轉功能。

#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <base64.h>
#include <cJSON.h>
#include <UrlEncode.h>#define TXT_DATA_LEN 1024 //STT txt len
#define ADC_DATA_LEN 1024*16 //read data len
const int data_json_len = ADC_DATA_LEN * 2 * 1.4;// 1、修改百度語言技術的用戶信息:https://console.bce.baidu.com/ai/?fromai=1#/ai/speech/app/list
const int STT_DEV_PID = 1537; //選填,輸入法模型 1737-英語 1537-普通話(近場識別模型) 1936-普通話遠程識別 1837-四川話 
const char *STT_TTS_CUID = "CoPY70iMA468o2r4PVLWmlLCruuYQd6G"; //用戶唯一標識,用來區分用戶,計算UV值。建議填寫能區分用戶的機器 MAC 地址或 IMEI 碼,長度為60字符以內。
const char *STT_TTS_CLIENT_ID = "sOKyRkOGpc76TYCNvGcd2F1i"; //API Key
const char *STT_TTS_CLIENT_SECRET = "CoPY70iMA468o2r4PVLWmlLCruuYQd6G"; //Secret KeyString stt_tts_token;
String stt_tts_gainToken() {HTTPClient stt_http;String token;String url = String("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=") + STT_TTS_CLIENT_ID + "&client_secret=" + STT_TTS_CLIENT_SECRET;stt_http.begin(url);int httpCode = stt_http.GET();if (httpCode > 0) {String payload = stt_http.getString();DynamicJsonDocument doc(1024);deserializeJson(doc, payload);token = doc["access_token"].as<String>();Serial.println("stt:" + token);} else {Serial.println("Error on HTTP request for token");}stt_http.end();return token;
}void stt_tts_setup()
{stt_tts_token = stt_tts_gainToken();//Serial.println(stt_tts_token.c_str());
}void stt_assembleJson(uint16_t *data, char *data_json)
{if (stt_tts_token == ""){stt_tts_setup();}strcat(data_json, "{");strcat(data_json, "\"format\":\"pcm\",");strcat(data_json, "\"rate\":16000,");strcat(data_json, "\"dev_pid\":1537,");strcat(data_json, "\"channel\":1,");strcat(data_json, "\"cuid\":\""); strcat(data_json, STT_TTS_CUID); strcat(data_json, "\",");strcat(data_json, "\"token\":\""); strcat(data_json, stt_tts_token.c_str()); strcat(data_json, "\",");sprintf(data_json + strlen(data_json), "\"len\":%d,", ADC_DATA_LEN * sizeof(uint16_t));strcat(data_json, "\"speech\":\"");strcat(data_json, base64::encode((uint8_t *)data, ADC_DATA_LEN * sizeof(uint16_t)).c_str());//int tmp = base64::decode((char *)adc_data, adc_data_len, data_json);strcat(data_json, "\"");strcat(data_json, "}");//Serial.println(data_json);return;
}String getTextFromResponse(String response)
{// Parse JSON responseDynamicJsonDocument jsonDoc(1024);deserializeJson(jsonDoc, response);String outputText = jsonDoc["result"];int len = strlen(outputText.c_str());String output = outputText.substring(2, len-2);//Serial.println(output);return output;
}//待優化,合成成功,返回的Content-Type以“audio”開頭, 
//合成出現錯誤,則會返回json文本,具體header信息為:Content-Type: application/json
int getInfoFromTtsResponse(String response, LLM_MSG_RSP_T *rsp)
{// Parse JSON responseDynamicJsonDocument jsonDoc(1024);deserializeJson(jsonDoc, response);rsp->err_msg = (String)jsonDoc["err_msg"];//rsp->err_msg = tmp1.c_str();rsp->err_no = jsonDoc["err_no"];;//Serial.println(rsp->err_msg);//Serial.println(rsp->err_no);return rsp->err_no;
}HTTPClient http_client_stt;String sendToSTT_test(uint16_t *data)
{char *data_json = (char *)malloc(data_json_len*sizeof(char));memset(data_json, '\0', data_json_len*sizeof(char));stt_assembleJson(data, data_json);int httpCode = http_client_stt.POST(data_json);free(data_json);
}String sendToSTT(uint16_t *data)
{HTTPClient http_client_stt;http_client_stt.begin("http://vop.baidu.com/server_api");//短語音識別請求地址: 標準版http://vop.baidu.com/server_api, 極速版https://vop.baidu.com/pro_apihttp_client_stt.addHeader("Content-Type", "application/json");char *data_json = (char *)malloc(data_json_len*sizeof(char));memset(data_json, '\0', data_json_len*sizeof(char));stt_assembleJson(data, data_json);int httpCode = http_client_stt.POST(data_json);free(data_json);if (httpCode > 0) {if (httpCode == HTTP_CODE_OK) {String response = http_client_stt.getString();//Serial.println(response);String outputText = getTextFromResponse(response);http_client_stt.end();return outputText;}} else {Serial.printf("[HTTP] POST failed, error: %s\n", http_client_stt.errorToString(httpCode).c_str());http_client_stt.end();return String("響應失敗請重新獲取!");}
}String sendToTTS(String InputText, int *len) {InputText = urlEncode(InputText);//tex字段2次urlencodeInputText = urlEncode(InputText);//百度為了更好地兼容,支持1次及2次urlencode, 其中2次urlencode可以覆蓋全部的特殊字符。因而推薦傳遞tex 參數時做2次urlencode編碼。HTTPClient http;char* tts_url = "https://tsn.baidu.com/text2audio"; // 百度語音合成的API URLhttp.begin(tts_url); // 初始化HTTP請求  http.addHeader("Content-Type", "application/x-www-form-urlencoded"); // 根據API要求添加HTTP頭  application/x-www-form-urlencodedif (stt_tts_token == ""){stt_tts_setup();}String payload = String("tex=")+InputText.c_str()+String("&tok=")+stt_tts_token.c_str()+String("&cuid=")+STT_TTS_CUID+String("&ctp=1&lan=zh&spd=5&pit=1&vol=1&per=5&aue=4");  //Serial.println(payload);  String outputText;int httpCode = http.POST(payload); // 發送POST請求  if (httpCode == HTTP_CODE_OK) {  String response = http.getString(); // 獲取響應體  //Serial.println(response);LLM_MSG_RSP_T rsp_info;if (getInfoFromTtsResponse(response, &rsp_info)){Serial.println(response);outputText = rsp_info.err_msg;return outputText;}*len = http.getSize();//Serial.println(*len);http.end(); // 結束HTTP請求  return response;} else {  Serial.println("Error in the HTTP request");outputText = String("Error in the HTTP request");}  http.end(); // 結束HTTP請求  return outputText;
}void audio_play_by_text(String input)
{g_current_state |= LLM_PLAY_AUDIO_FLAG;int len = 0, i = 0, tmp = 0;String Output;uint16_t *wr_data = NULL;size_t bytes_write = 0;Output = sendToTTS(input, &len);wr_data = (uint16_t *)malloc(1024*16*sizeof(uint16_t));//1sfor (i = 0; i < len; i+=(1024*16*sizeof(uint16_t))){memset(wr_data, '\0', 1024*16*sizeof(uint16_t));tmp = len - i;if (len - i > 1024*16*sizeof(uint16_t))tmp = 1024*16*sizeof(uint16_t);memcpy(wr_data, Output.c_str()+i, tmp);esp_err_t result = i2s_write(I2S_NUM_1, wr_data, tmp, &bytes_write, portMAX_DELAY);}free(wr_data);g_current_state &= ~LLM_PLAY_AUDIO_FLAG;return;
}

3、通過API接口訪問文心一言大模型

在my_ErnieBot.h文件中實現訪問文心一言大模型API接口獲取響應結果。

#include <HTTPClient.h>
#include <ArduinoJson.h>
#include "my_common.h"// Replace with your OpenAI API key
const char* ERNIE_BOT_CLIENT_ID = "vCe0kXozst5OI6LC8BJNJsQ9";//API Key
const char* ERNIE_BOT_CLIENT_SECRET = "3iTfEAnHRaoP0Uiml00ACw6TPFsHbFt6";//Secret KeyString ErnieBot_accessToken;String ErnieBotGainToken() {HTTPClient http;String token;String url = String("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=") + ERNIE_BOT_CLIENT_ID + "&client_secret=" + ERNIE_BOT_CLIENT_SECRET;http.begin(url);int httpCode = http.GET();if (httpCode > 0) {String payload = http.getString();DynamicJsonDocument doc(1024);deserializeJson(doc, payload);token = doc["access_token"].as<String>();Serial.println("ErnieBot:" +  token);} else {Serial.println("Error on HTTP request for token");}http.end();return token;
}String getErnieBotAnswer(String inputText, int *ret) {//Serial.println(inputText.c_str());HTTPClient http;http.setTimeout(1000000);String apiUrl = String("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=") + ErnieBot_accessToken.c_str();http.begin(apiUrl);http.addHeader("Content-Type", "application/json");String payload = "{\"messages\":[{\"role\": \"user\",\"content\": \"" + inputText + "兩百字以內。" + "\"}],\"disable_search\": false,\"enable_citation\": false}";Serial.println(payload.c_str());int httpResponseCode = http.POST(payload);if (httpResponseCode == 200) {String response = http.getString();http.end();if (ret)*ret = ESP_SUCCEED;Serial.println(response);// Parse JSON responseDynamicJsonDocument jsonDoc(1024);deserializeJson(jsonDoc, response);String outputText = jsonDoc["result"];return outputText;} else {http.end();Serial.printf("Error %i \n", httpResponseCode);if (ret)*ret = ESP_FAILT;return "<error>";}
}void ErnieBot_setup() {ErnieBot_accessToken = ErnieBotGainToken();//Serial.println(ErnieBot_accessToken.c_str());String answer = getErnieBotAnswer("你好,文心一言", NULL);Serial.println("<Test Answer: " + answer);
}

4、通過API接口訪問豆包(火山引擎)大模型

在my_Doubao.h文件中實現訪問文心一言大模型API接口獲取響應結果。

#include <HTTPClient.h>
#include <ArduinoJson.h>
#include "my_common.h"// Replace with your OpenAI API key
const char* doubao_apiKey = "4ab25fbb-ce6c-4f02-95f6-63073227d141";String getDoubaoAnswer(String inputText, int *ret) {//Serial.println(inputText.c_str());HTTPClient http;http.setTimeout(1000000);String apiUrl = "https://ark.cn-beijing.volces.com/api/v3/chat/completions";http.begin(apiUrl);http.addHeader("Content-Type", "application/json");String token_key = String("Bearer ") + doubao_apiKey;http.addHeader("Authorization", token_key);//256k上下文推理: ep-20241230152833-5fcsh//快速響應: ep-20241230144301-t84jjString payload = "{\"model\":\"ep-20241230152833-5fcsh\",\"messages\":[{\"role\":\"system\",\"content\":\"你是我的AI助手vor,你必須用中文回答且字數不超過85個\"},{\"role\":\"user\",\"content\":\"" + inputText + "\"}],\"temperature\": 0.3}";//Serial.println(payload.c_str());int httpResponseCode = http.POST(payload);if (httpResponseCode == 200) {String response = http.getString();http.end();if (ret)*ret = ESP_SUCCEED;//Serial.println(response);// Parse JSON responseDynamicJsonDocument jsonDoc(1024);deserializeJson(jsonDoc, response);String outputText = jsonDoc["choices"][0]["message"]["content"];return outputText;} else {http.end();Serial.printf("Error %i \n", httpResponseCode);if (ret)*ret = ESP_FAILT;return "<error>";}
}void Doubao_setup() {String answer = getDoubaoAnswer("你好,豆包!", NULL);Serial.println("<Test Answer: " + answer);
}

5、WiFi模塊

在my_wifi.h文件中初始化wifi功能。

#include <WiFi.h>void wifi_setup() {Serial.println("\n-- Start connecting to WiFi! --");WiFi.disconnect(true);// 3、填寫您的wifi賬號密碼WiFi.begin("wifi name", "password");  while (WiFi.status() != WL_CONNECTED) {Serial.print(".");vTaskDelay(200);}Serial.println("\n-- wifi connect success! --");
}

6、common文件

在my_common.h文件中定義各個模塊共同調用的參數。

#ifndef MY_COMMON
#define MY_COMMON
#if 1
#include <Arduino.h>
#include "base64.h"
#include <WiFiClientSecure.h>
#include "HTTPClient.h"
#include <ArduinoJson.h>
#include <ArduinoWebsockets.h>
#include <Wire.h>
#include <SD.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// 與AP模式和Web服務器有關的庫
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Preferences.h>
#endif#define ESP_SUCCEED 0
#define ESP_FAILT 1#define BIT(n)             (1LLU << (n))
#define SET_BIT(mask, n)   ((mask) |= BIT(n))
#define RESET_BIT(mask, n) ((mask) &= ~BIT(n))
#define ISSET_BIT(mask, n) (!!((mask)&BIT(n)))
#define LLM_STANDBY_MODE              BIT(1) //待機狀態標記
#define LLM_CONTINUOUS_DIALOGUE_STATE BIT(2) //連續對話狀態標記
#define LLM_TTS_STANDBY_STATE         BIT(3) //TTS線程進入待機狀態
#define LLM_RECORDING_STANDBY_STATE   BIT(4) //音頻數據采集線程進入待機狀態
#define LLM_REAWAKEN_FLAG             BIT(5) //重復喚醒標記
#define LLM_TTS_POLL_FLAG             BIT(6) //POLL task結束標記
#define LLM_PLAY_AUDIO_FLAG           BIT(7) //音頻播放狀態,置位1--播放中
#define LLM_FIRST_RSP_FLAG            BIT(8) //大模型響應標記,第一個響應后置位,即哪個模型響應快使用哪個做TTSint g_current_state = 0;typedef struct LLM_MSG_RSP
{String err_msg;int err_no;
}LLM_MSG_RSP_T;#endif

7、核心邏輯代碼文件

????????在esp32_ai_llm.h文件中編碼實現調用各個模塊接口代碼,把各個模塊功能串聯起來實現最終語音喚醒以及連續對話的功能。

? ? ? ? 流式語音識別邏輯目前在該文件中,后續會摘出來單獨作為一個模塊。

七、效果展示

整體流程已經基本調通,效果展示后面拍好視頻后補上來。

各模塊源碼無保留在第五章節,loop()函數各位老鐵自己調用模塊接口實現。

從無到有實現目前的效果,有參考其他大佬的帖子,也有自己摸索實現的部分,知識勞動成果,實屬不易。

如果需要技術支持,歡迎騷擾(+v:Sw-striving)!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90900.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90900.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90900.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

面試150 最長遞增子序列

思路 定義 dp[i] 表示以第 i 個元素結尾的最長遞增子序列的長度&#xff0c;初始時每個位置的最長子序列長度為 1。然后通過雙重循環遍歷每一對元素 j < i&#xff0c;如果 nums[i] > nums[j]&#xff0c;說明 nums[i] 可以接在 nums[j] 的遞增序列之后&#xff0c;更新 …

TCP 套接字--服務器相關

1.創建 TCP 套接字int server_sockfd socket(AF_INET,SOCK_STREAM, 0);函數原型&#xff1a;#include <sys/socket.h>int socket(int domain, int type, int protocol);domain協議族&#xff08;地址族&#xff09;AF_INET&#xff08;IPv4&#xff09;type套接字類型SO…

六、搭建springCloudAlibaba2021.1版本分布式微服務-admin監控中心

前言Spring Boot Actuator 是 spring-boot 自帶監控功能 &#xff0c;可以幫助實現對程序內部運行情況監控&#xff0c;比如監控狀況、Bean 加載情況、環境變量、日志信息、線程信息等。 Spring Boot Admin是一個針對 spring-boot 的 actuator 接口進行 UI 美化封裝的監控工具。…

輕量級遠程開發利器:Code Server與cpolar協同實現安全云端編碼

前言&#xff1a;作為一款專為Web環境設計的VS Code托管方案&#xff0c;Code Server通過精簡架構重新定義了遠程開發體驗。其核心優勢在于將完整的編輯器功能封裝于輕量容器中——僅需不到200MB內存即可運行基礎服務&#xff0c;并支持在樹莓派等低性能設備上流暢操作。系統采…

圖論:最小生成樹

今天要介紹兩中最小生成樹的算法&#xff0c;分別是prim算法和kruskal算法。 最小生成樹是所有節點的最小連通子圖&#xff0c;即&#xff1a;以最小的成本&#xff08;邊的權值&#xff09;將圖中所有節點鏈接到一起。 圖中有n個節點&#xff0c;那么一定可以用n-1條邊將所有節…

haproxy七層代理

1、負載均衡Load Balance(LB) 概念 負載均衡&#xff1a;是一種服務或基于硬件設備等實現的高可用反向代理技術&#xff0c;負載均衡將特定的業務(web服務、網絡流量等)分擔給指定的一個或多個后端特定的服務器或設備&#xff0c;從而提高了 公司業務的并發處理能力、保證了業務…

【NLP輿情分析】基于python微博輿情分析可視化系統(flask+pandas+echarts) 視頻教程 - 微博文章數據可視化分析-點贊區間實現

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;最近寫了一套【NLP輿情分析】基于python微博輿情分析可視化系統(flaskpandasecharts)視頻教程&#xff0c;持續更新中&#xff0c;計劃月底更新完&#xff0c;感謝支持。今天講解微博文章數據可視化分析-點贊區間實現 視頻…

Redis實戰(3)-- 高級數據結構zset

有序集合&#xff08;ZSET&#xff09;&#xff1a;可以用作相關有序集合相對于哈希、列表、集合來說會有一點點陌生,但既然叫有序集合,那么它和集合必然有著聯系,它保留了集合不能有重復成員的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下標作為排序依據…

Mistral AI開源 Magistral-Small-2507

宣布Magistral——Mistral AI推出的首款推理模型&#xff0c;專精于垂直領域、具備透明化特性與多語言推理能力。 最優秀的人類思維并非線性——它穿梭于邏輯、洞見、不確定性與發現之間。推理型語言模型讓我們得以將復雜思考和深度理解交由AI增強或代勞&#xff0c;提升了人類…

【Kotlin】如何實現靜態方法?(單例類、伴生對象、@JvmStatic)

靜態方法 靜態方法&#xff08;類方法&#xff09;&#xff1a;不需要創建實例就可以調用&#xff08;直接通過類名調用&#xff09;的方法 Java 中的靜態方法&#xff08;static&#xff09; public class Util {public static void doAction() {//...} }調用&#xff1a;Util…

SQL Schema 和Pandas Schema什么意思

在數據處理和分析領域&#xff0c;SQL Schema 和 Pandas Schema 分別指的是在不同數據處理環境中數據的結構定義&#xff0c;以下為你詳細介紹&#xff1a;SQL Schema含義SQL Schema&#xff08;模式&#xff09;是數據庫對象的一個邏輯容器&#xff0c;它定義了數據庫中表、視…

機器學習(一)KNN,K近鄰算法(K-Nearest Neighbors)

&#x1f4a1; 建議初學者掌握KNN作為理解其他復雜算法&#xff08;如SVM、決策樹、神經網絡&#xff09;的基石。K近鄰算法&#xff08;K-Nearest Neighbors, KNN&#xff09;詳解&#xff1a;原理、實踐與優化K近鄰算法&#xff08;K-Nearest NeighboKrs&#xff0c;簡稱KNN&…

Qt 多線程數據庫操作優化

在多線程應用中&#xff0c;數據庫操作往往是性能瓶頸與穩定性風險的高發區。當多個線程同時讀寫數據庫時&#xff0c;若處理不當&#xff0c;輕則出現查詢卡頓、事務沖突&#xff0c;重則導致數據錯亂、連接泄漏甚至程序崩潰。Qt作為跨平臺框架&#xff0c;提供了QSql系列類支…

Qt 狀態機框架:復雜交互邏輯的處理

Qt狀態機框架&#xff08;Qt State Machine Framework&#xff09;是一個強大的工具&#xff0c;用于簡化復雜的交互邏輯和狀態管理。它基于UML狀態圖概念&#xff0c;提供了聲明式的方式來定義對象行為&#xff0c;特別適合處理具有多種狀態和轉換的場景&#xff08;如GUI交互…

【docker】DM8達夢數據庫的docker-compose以及一些啟動踩坑

摘要&#xff1a;本文介紹了通過docker-compose配置啟動達夢數據庫(DM8)的方法。配置包括容器鏡像、端口映射、數據卷掛載以及關鍵環境變量設置&#xff08;如字符集、大小寫敏感等&#xff09;。也說明了啟動過程可能遇到的一些問題。通過docker-compose啟動達夢數據庫可以按照…

服務器中的防火墻設置需要打開嗎

服務器中的防火墻屬于是一種保護計算機網絡不會受到未經授權的網絡設備所訪問的技術手段&#xff0c;防火墻還有著將內部網絡和外部網絡進行隔離的功能&#xff0c;在網絡之間創建安全屏障&#xff0c;以此來保護網絡中數據的安全。防火墻是一種網絡安全系統&#xff0c;可以幫…

Java項目:基于SSM框架實現的社區團購管理系統【ssm+B/S架構+源碼+數據庫+畢業論文+答辯PPT+遠程部署】

摘 要 使用舊方法對社區團購信息進行系統化管理已經不再讓人們信賴了&#xff0c;把現在的網絡信息技術運用在社區團購信息的管理上面可以解決許多信息管理上面的難題&#xff0c;比如處理數據時間很長&#xff0c;數據存在錯誤不能及時糾正等問題。 這次開發的社區團購系統有…

介紹一下static關鍵字

在Java中&#xff0c;被static修飾的成員稱為靜態成員&#xff0c;static關鍵字可以用來修飾方法或者成員變量&#xff0c;且被static修飾的方法或者成員變量屬于類方法或者類屬性&#xff0c;也就是說被static修飾的方法或者成員變量不是單獨存儲在某一個對象的空間&#xff0…

【Java學習|黑馬筆記|Day23】網絡編程、反射、動態代理

【DAY23】 文章目錄【DAY23】一.網絡編程1&#xff09;三要素1.1&#xff09;IPInetAddress類的使用1.2&#xff09;端口號1.3&#xff09;協議2.1&#xff09;UDP協議發送數據2.2&#xff09;UDP協議接收數據2.3&#xff09;UDP的三種通信方式3.1&#xff09;TCP協議的發送和接…

【Zephyr】Window下的Zephyr編譯和使用

工具下載 參考文檔&#xff08;Getting Started Guide — Zephyr Project Documentation&#xff09;中介紹&#xff0c;可以直接通過winget下載&#xff1a; winget download Kitware.CMake Ninja-build.Ninja oss-winget.gperf python Git.Git oss-winget.dtc wget 7zip.7z…