🦁

stackchanのソース備忘録

2024/02/19に公開

M5Unified_AI_StackChan/src/Whisper.cpp

できあがったspeak.wavをwhisperAPIに送って結果を返す

コンストラクタ

  • SSL証明書の設定
  • タイムアウトの設定
  • whisperAPIへの接続
Whisper::Whisper(const char* root_ca, const char* api_key) : client(), key(api_key) {
  client.setCACert(root_ca);
  client.setTimeout(10000); 
  if (!client.connect(API_HOST, API_PORT)) {
    Serial.println("Connection failed!");
  }
}

デストラクタ(チルダをつけるとデストラクタになる)

Whisper::~Whisper() {
  client.stop();
}

Transcribeの解説

ユニークな区切り文字の生成

String Whisper::Transcribe(AudioWhisper* audio) {
  char boundary[64] = "------------------------";
  for (auto i = 0; i < 2; ++i) {
    ltoa(random(0x7fffffff), boundary + strlen(boundary), 16);
  }

API通信のためのヘッダ構築

  const String header = "--" + String(boundary) + "\r\n"
    "Content-Disposition: form-data; name=\"model\"\r\n\r\nwhisper-1\r\n"
    "--" + String(boundary) + "\r\n"
    "Content-Disposition: form-data; name=\"language\"\r\n\r\nja\r\n"
    "--" + String(boundary) + "\r\n"
    "Content-Disposition: form-data; name=\"file\"; filename=\"speak.wav\"\r\n"
    "Content-Type: application/octet-stream\r\n\r\n";
  const String footer = "\r\n--" + String(boundary) + "--\r\n";

通信結果を待つ

  // wait response
  const auto now = ::millis();
  while (client.available() == 0) {
    if (::millis() - now > 10000) {
      Serial.println(">>> Client Timeout !");
      return "";
    }
  }

  bool isBody = false;
  String body = "";
  while(client.available()){
    const auto line = client.readStringUntil('\r');
    if (isBody) {
      body += line;
    } else if (line.equals("\n")) {
      isBody = true;
    }
  }

結果を返す

  StaticJsonDocument<200> doc;
  ::deserializeJson(doc, body);
  return doc["text"].as<String>();

Discussion