UNPKG

@raghavendra_kj/stt-js

Version:

A wrapper around the Web Speech API for speech-to-text functionality.

226 lines (224 loc) 7.63 kB
var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // src/STT.ts var STTErrorCode = /* @__PURE__ */ ((STTErrorCode2) => { STTErrorCode2["SPEECH_NOT_SUPPORTED"] = "SPEECH_NOT_SUPPORTED"; STTErrorCode2["GENERAL_ERROR"] = "GENERAL_ERROR"; STTErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED"; return STTErrorCode2; })(STTErrorCode || {}); var STTError = class extends Error { constructor(code, message) { super(message); this.code = code; this.name = "STTError"; } }; var STT = class { // ──────────────────────────────────────────── // Construction & binding // ──────────────────────────────────────────── constructor() { this.recognizing = false; this.finalTranscript = ""; // One Set per event ➜ maximum type safety this.startListeners = /* @__PURE__ */ new Set(); this.endListeners = /* @__PURE__ */ new Set(); this.resultListeners = /* @__PURE__ */ new Set(); this.partialResultListeners = /* @__PURE__ */ new Set(); this.errorListeners = /* @__PURE__ */ new Set(); if (typeof window === "undefined") return; const Impl = window.SpeechRecognition || window.webkitSpeechRecognition; if (!Impl) return; this.recognition = new Impl(); this.bindEvents(); } // ──────────────────────────────────────────── // Public listener helpers // ──────────────────────────────────────────── /* ADDERS */ onStart(handler) { this.startListeners.add(handler); } onEnd(handler) { this.endListeners.add(handler); } onResult(handler) { this.resultListeners.add(handler); } onPartialResult(handler) { this.partialResultListeners.add(handler); } onError(handler) { this.errorListeners.add(handler); } /* REMOVERS */ offStart(handler) { this.startListeners.delete(handler); } offEnd(handler) { this.endListeners.delete(handler); } offResult(handler) { this.resultListeners.delete(handler); } offPartialResult(handler) { this.partialResultListeners.delete(handler); } offError(handler) { this.errorListeners.delete(handler); } /** Clear listeners for a specific event or *all* events */ removeAllListeners(event) { switch (event) { case "start": this.startListeners.clear(); break; case "end": this.endListeners.clear(); break; case "result": this.resultListeners.clear(); break; case "partialResult": this.partialResultListeners.clear(); break; case "error": this.errorListeners.clear(); break; default: this.startListeners.clear(); this.endListeners.clear(); this.resultListeners.clear(); this.partialResultListeners.clear(); this.errorListeners.clear(); } } // ──────────────────────────────────────────── // SpeechRecognition wiring // ──────────────────────────────────────────── bindEvents() { const r = this.recognition; r.onstart = () => { this.recognizing = true; this.emitStart(); }; r.onend = () => { this.recognizing = false; this.emitEnd(); }; r.onerror = (event) => { const code = event.error === "not-allowed" || event.error === "permission-denied" ? "PERMISSION_DENIED" /* PERMISSION_DENIED */ : "GENERAL_ERROR" /* GENERAL_ERROR */; this.emitError(new STTError(code, event.error)); }; r.onresult = (event) => { let interim = ""; for (let i = event.resultIndex; i < event.results.length; i++) { const transcript = event.results[i][0].transcript; if (event.results[i].isFinal) { this.finalTranscript += transcript; this.emitResult(this.finalTranscript.trim()); } else { interim += transcript; } } if (interim) { this.emitPartialResult(interim.trim()); } }; } // ──────────────────────────────────────────── // Emit helpers (private) // ──────────────────────────────────────────── emitStart() { this.startListeners.forEach((fn) => fn()); } emitEnd() { this.endListeners.forEach((fn) => fn()); } emitResult(text) { this.resultListeners.forEach((fn) => fn(text)); } emitPartialResult(text) { this.partialResultListeners.forEach((fn) => fn(text)); } emitError(err) { this.errorListeners.forEach((fn) => fn(err)); } // ──────────────────────────────────────────── // Public API // ──────────────────────────────────────────── /** Begin recognition (prompts for mic permission if needed) */ start() { return __async(this, arguments, function* (options = {}) { if (!this.recognition) { throw new STTError( "SPEECH_NOT_SUPPORTED" /* SPEECH_NOT_SUPPORTED */, "Speech recognition is not supported in this browser." ); } if (navigator.permissions) { const status = yield navigator.permissions.query({ name: "microphone" }); if (status.state === "denied") { throw new STTError("PERMISSION_DENIED" /* PERMISSION_DENIED */, "Microphone permission was denied."); } } const { lang = "en-US", continuous = true, interimResults = true } = options; this.recognition.lang = lang; this.recognition.continuous = continuous; this.recognition.interimResults = interimResults; this.finalTranscript = ""; try { this.recognition.start(); } catch (err) { const error = err instanceof STTError ? err : new STTError("GENERAL_ERROR" /* GENERAL_ERROR */, err.message); this.emitError(error); throw error; } }); } /** Gracefully stop after the current utterance */ stop() { var _a; (_a = this.recognition) == null ? void 0 : _a.stop(); } /** Immediately abort recognition */ abort() { var _a; (_a = this.recognition) == null ? void 0 : _a.abort(); } /** `true` while SpeechRecognition is active */ isRecognizing() { return this.recognizing; } /** Stop recognition and detach all listeners */ dispose() { this.stop(); this.removeAllListeners(); this.recognition = void 0; } }; export { STT, STTError, STTErrorCode }; //# sourceMappingURL=STT.bundle.js.map