top of page
Buscar

Reconhecimento de fala com o m5stick!

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.


ree

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


Seja o primeiro a saber das novidades

2024 Mundo do Arduino

bottom of page