Reconhecimento de fala com o m5stick!
- Eduardo Brennand Paranhos
- há 13 minutos
- 2 min de leitura
Nesse post, veremos como utilizar o microfone embutido no compacto, mas eficiente, m5stickc plu2, a fim de desenvolver um modelo simples de reconhecimento de fala.

O microfone se comunica com o controlador por meio do protocolo I2S, que é bastante robusto e nos permite obter dados precisos do sensor.
Para que seja feita a tradução da imagem em texto(speech to text, ou STT) será necessário enviar os dados obtidos pelo microfone para a API da openai, sendo preciso logar no site https://openai.com/pt-BR/index/openai-api/ e realizar o cadastro, para assim obter a sua chave única, que deverá ser posta no código.
Feito isso, faça upload do código a seguir, alterando as variáveis WIFI_SSID, WIFI_PASSWORD e OPENAI_API_KEY para a sua rede wifi, senha e chave da openai, respectivamente.
#include <M5Unified.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#define WIFI_SSID "SUA-REDE-WIFI"
#define WIFI_PASSWORD "SUA-SENHA"
#define OPENAI_API_KEY "SUA-CHAVE-OPENAI"
#define SAMPLE_RATE 16000
#define RECORD_TIME 1
#define SAMPLES (SAMPLE_RATE * RECORD_TIME)
/* ================= WAV HEADER ================= */
void writeWavHeader(uint8_t* wav, uint32_t dataSize) {
uint32_t fileSize = dataSize + 36;
memcpy(wav, "RIFF", 4);
memcpy(wav + 4, &fileSize, 4);
memcpy(wav + 8, "WAVE", 4);
memcpy(wav + 12, "fmt ", 4);
uint32_t subChunk1Size = 16;
uint16_t audioFormat = 1;
uint16_t numChannels = 1;
uint32_t sampleRate = SAMPLE_RATE;
uint16_t bitsPerSample = 16;
uint32_t byteRate = sampleRate * numChannels * bitsPerSample / 8;
uint16_t blockAlign = numChannels * bitsPerSample / 8;
memcpy(wav + 16, &subChunk1Size, 4);
memcpy(wav + 20, &audioFormat, 2);
memcpy(wav + 22, &numChannels, 2);
memcpy(wav + 24, &sampleRate, 4);
memcpy(wav + 28, &byteRate, 4);
memcpy(wav + 32, &blockAlign, 2);
memcpy(wav + 34, &bitsPerSample, 2);
memcpy(wav + 36, "data", 4);
memcpy(wav + 40, &dataSize, 4);
}
/* ================= GRAVAR + TRANSCRIBIR ================= */
String recordAndTranscribe() {
int16_t* audioBuffer = (int16_t*)malloc(SAMPLES * sizeof(int16_t));
if (!audioBuffer) return "";
M5.Speaker.end();
delay(50);
M5.Mic.begin();
bool ok = M5.Mic.record(audioBuffer, SAMPLES);
M5.Mic.end();
if (!ok) {
free(audioBuffer);
return "";
}
uint32_t pcmBytes = SAMPLES * sizeof(int16_t);
uint32_t wavBytes = pcmBytes + 44;
uint8_t* wav = (uint8_t*)malloc(wavBytes);
if (!wav) {
free(audioBuffer);
return "";
}
writeWavHeader(wav, pcmBytes);
memcpy(wav + 44, audioBuffer, pcmBytes);
free(audioBuffer);
const char* boundary = "----STICKC";
String head =
String("--") + boundary + "\r\n"
"Content-Disposition: form-data; name=\"model\"\r\n\r\n"
"whisper-1\r\n"
"--" + boundary + "\r\n"
"Content-Disposition: form-data; name=\"file\"; filename=\"audio.wav\"\r\n"
"Content-Type: audio/wav\r\n\r\n";
String tail = "\r\n--" + String(boundary) + "--\r\n";
uint32_t totalLen = head.length() + wavBytes + tail.length();
uint8_t* body = (uint8_t*)malloc(totalLen);
uint32_t offset = 0;
memcpy(body + offset, head.c_str(), head.length()); offset += head.length();
memcpy(body + offset, wav, wavBytes); offset += wavBytes;
memcpy(body + offset, tail.c_str(), tail.length());
free(wav);
WiFiClientSecure client;
client.setInsecure();
HTTPClient http;
http.begin(client, "https://api.openai.com/v1/audio/transcriptions");
http.addHeader("Authorization", String("Bearer ") + OPENAI_API_KEY);
http.addHeader("Content-Type", String("multipart/form-data; boundary=") + boundary);
int code = http.POST(body, totalLen);
free(body);
if (code <= 0) {
http.end();
return "";
}
String response = http.getString();
http.end();
DynamicJsonDocument doc(4096);
if (deserializeJson(doc, response)) return "";
return doc["text"] | "";
}
/* ================= SETUP / LOOP ================= */
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
Serial.begin(115200);
M5.Display.setRotation(1);
M5.Display.println("WiFi...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(300);
M5.Display.println("BtnA = falar");
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) {
M5.Display.clear();
M5.Display.println("Falando...");
Serial.println("Gravando...");
String texto = recordAndTranscribe();
Serial.println("Texto:");
Serial.println(texto);
M5.Display.clear();
M5.Display.print("Texto:");
M5.Display.print(texto);
}
}Após o código ter sido enviado, deverá ser observado o seguinte resultado:



Comentários