@fine-dev/fine-js
Version:
Javascript client for Fine BaaS
117 lines • 5.32 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { useSyncExternalStore } from "react";
export class FineTranscriber {
constructor({ baseUrl, headers, fetch: customFetch }) {
this.error = null;
this.mediaRecorder = null;
this.chunks = [];
this.file = null;
this.statusListeners = new Set();
this._status = "idle";
this.recording = {
start: () => {
if (this.mediaRecorder && this.mediaRecorder.state === "paused")
return this.mediaRecorder.resume();
return navigator.mediaDevices
.getUserMedia({ audio: true })
.then((stream) => {
this.createMediaRecorder(stream).start();
this.setStatus("recording");
})
.catch((e) => {
const error = e instanceof Error ? e : new Error(typeof e === "string" ? e : JSON.stringify(e));
this.raiseError("recording", error);
});
},
stop: () => this.mediaRecorder && this.mediaRecorder.state !== "inactive" && this.mediaRecorder.stop(),
pause: () => this.mediaRecorder && this.mediaRecorder.state === "recording" && this.mediaRecorder.pause()
};
this.config = {
baseUrl: baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl,
fetch(input, init) {
if (!customFetch)
customFetch = fetch.bind(window);
return customFetch(input, Object.assign(Object.assign({}, init), { headers, credentials: "include" }));
}
};
}
createMediaRecorder(stream) {
this.mediaRecorder = new MediaRecorder(stream);
this.chunks = [];
this.mediaRecorder.addEventListener("dataavailable", (e) => e.data.size > 0 && this.chunks.push(e.data));
this.mediaRecorder.addEventListener("error", (e) => this.raiseError("recording", e.error));
this.mediaRecorder.addEventListener("start", () => this.setStatus("recording"));
this.mediaRecorder.addEventListener("pause", () => this.setStatus("paused"));
this.mediaRecorder.addEventListener("resume", () => this.setStatus("recording"));
this.mediaRecorder.addEventListener("stop", () => {
const audioBlob = new Blob(this.chunks, { type: "audio/webm" });
this.file = new File([audioBlob], "recording.webm", { type: "audio/webm" });
this.setStatus("stopped");
});
return this.mediaRecorder;
}
setStatus(status) {
this._status = status;
this.statusListeners.forEach((fn) => fn(status));
}
raiseError(phase, error) {
this.error = error;
this.setStatus(`${phase}_error`);
throw this.error;
}
get status() {
return this._status;
}
onStatusChange(callback) {
this.statusListeners.add(callback);
return () => this.statusListeners.delete(callback);
}
fromFile(file) {
if (this.mediaRecorder) {
if (this.mediaRecorder.state === "recording")
this.mediaRecorder.stop();
this.mediaRecorder = null;
}
this.file = file;
return this.transcribe();
}
transcribe() {
return __awaiter(this, void 0, void 0, function* () {
this.recording.stop();
yield new Promise((resolve) => setTimeout(resolve));
if (!this.file) {
this.raiseError("transcription", new Error("No audio to transcribe."));
throw this.error;
}
this.setStatus("transcribing");
const formData = new FormData();
formData.append("audio", this.file);
try {
const res = yield this.config.fetch(this.config.baseUrl, { method: "POST", body: formData });
if (!res.ok) {
const msg = yield res.text();
this.raiseError("transcription", new Error(`Transcription failed: ${res.status} ${msg}`));
}
const { text } = yield res.json();
this.setStatus("transcribed");
return text;
}
catch (err) {
this.raiseError("transcription", err instanceof Error ? err : new Error(typeof err === "string" ? err : JSON.stringify(err)));
throw this.error;
}
});
}
useStatus() {
return useSyncExternalStore((cb) => this.onStatusChange(cb), () => this.status, () => "idle");
}
}
//# sourceMappingURL=transcribe.js.map