Skip to content

Instantly share code, notes, and snippets.

@hollyhockberry
Last active May 22, 2023 00:14
Show Gist options
  • Save hollyhockberry/174749a9963e9637966161c7afb9bee6 to your computer and use it in GitHub Desktop.
Save hollyhockberry/174749a9963e9637966161c7afb9bee6 to your computer and use it in GitHub Desktop.
Sample: Using Whisper API with M5 CoreS3
// Copyright (c) 2023 Inaba (@hollyhockberry)
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
#include <SD.h>
#include <M5Unified.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <gob_unifiedButton.hpp>
constexpr char* ROOT_CA = "openai.comの証明書";
constexpr char* API_KEY = "API KEY";
gob::UnifiedButton unfiedButton;
bool transcriptions(File& file, String* result) {
char boundary[64] = "------------------------";
for (auto i = 0; i < 2; ++i) {
ltoa(random(0x7fffffff), boundary + strlen(boundary), 16);
}
const char* API_HOST = "api.openai.com";
const uint16_t API_PORT = 443;
const char* API_PATH = "/v1/audio/transcriptions";
WiFiClientSecure client;
client.setCACert(ROOT_CA);
if (!client.connect(API_HOST, API_PORT)) {
Serial.println("connection failed");
return false;
}
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=\"file\"; filename=\"" + file.name() + "\"\r\n"
"Content-Type: application/octet-stream\r\n\r\n";
const String footer = "\r\n--" + String(boundary) + "--\r\n";
// header
client.printf("POST %s HTTP/1.1\n", API_PATH);
client.printf("Host: %s\n", API_HOST);
client.println("Accept: */*");
client.printf("Authorization: Bearer %s\n", API_KEY);
client.printf("Content-Length: %d\n", header.length() + file.size() + footer.length());
client.printf("Content-Type: multipart/form-data; boundary=%s\n", boundary);
client.println();
client.print(header.c_str());
client.flush();
// body
uint8_t buf[512];
while (file.available()) {
const auto sz = file.read(buf, sizeof(buf));
client.write(buf, sz);
client.flush();
}
client.flush();
file.close();
// footer
client.print(footer.c_str());
client.flush();
// wait response
while (client.available() == 0) {
}
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;
}
}
client.stop();
StaticJsonDocument<200> doc;
deserializeJson(doc, body);
const auto text = doc["text"].as<String>();
if (text.length() <= 0) {
return false;
}
*result = text;
return true;
}
void setup() {
M5.begin();
unfiedButton.begin(&M5.Display);
SD.begin(GPIO_NUM_4, SPI, 25000000);
WiFi.begin();
while (WiFi.status() != WL_CONNECTED) {
::delay(500);
}
Serial.println("WiFi connected");
::randomSeed(::analogRead(G6));
}
void loop() {
unfiedButton.update();
M5.update();
if (!M5.BtnA.wasPressed()) {
return;
}
File f = SD.open("/sample.wav");
if (!f) {
Serial.println("file open error");
return;
}
String text;
if (transcriptions(f, &text)) {
Serial.println(text);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment