UNPKG

@fine-dev/fine-js

Version:

Javascript client for Fine BaaS

117 lines 5.32 kB
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