even-toolkit 1.1.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +74 -0
  2. package/dist/glasses/action-bar.d.ts +1 -1
  3. package/dist/glasses/action-bar.js +4 -4
  4. package/dist/glasses/action-bar.js.map +1 -1
  5. package/dist/glasses/bridge.d.ts +5 -2
  6. package/dist/glasses/bridge.d.ts.map +1 -1
  7. package/dist/glasses/bridge.js +25 -2
  8. package/dist/glasses/bridge.js.map +1 -1
  9. package/dist/glasses/composer.js +2 -2
  10. package/dist/glasses/layout.d.ts +2 -0
  11. package/dist/glasses/layout.d.ts.map +1 -1
  12. package/dist/glasses/layout.js +4 -0
  13. package/dist/glasses/layout.js.map +1 -1
  14. package/dist/glasses/types.d.ts +23 -0
  15. package/dist/glasses/types.d.ts.map +1 -1
  16. package/dist/glasses/types.js +15 -0
  17. package/dist/glasses/types.js.map +1 -1
  18. package/dist/glasses/useGlasses.d.ts.map +1 -1
  19. package/dist/glasses/useGlasses.js +17 -4
  20. package/dist/glasses/useGlasses.js.map +1 -1
  21. package/dist/stt/debug.d.ts +8 -0
  22. package/dist/stt/debug.d.ts.map +1 -0
  23. package/dist/stt/debug.js +34 -0
  24. package/dist/stt/debug.js.map +1 -0
  25. package/dist/stt/engine.d.ts +9 -6
  26. package/dist/stt/engine.d.ts.map +1 -1
  27. package/dist/stt/engine.js +141 -75
  28. package/dist/stt/engine.js.map +1 -1
  29. package/dist/stt/index.d.ts +1 -0
  30. package/dist/stt/index.d.ts.map +1 -1
  31. package/dist/stt/index.js +1 -0
  32. package/dist/stt/index.js.map +1 -1
  33. package/dist/stt/providers/deepgram.d.ts +1 -1
  34. package/dist/stt/providers/deepgram.d.ts.map +1 -1
  35. package/dist/stt/providers/deepgram.js +24 -9
  36. package/dist/stt/providers/deepgram.js.map +1 -1
  37. package/dist/stt/providers/whisper-api.d.ts.map +1 -1
  38. package/dist/stt/providers/whisper-api.js +75 -4
  39. package/dist/stt/providers/whisper-api.js.map +1 -1
  40. package/dist/stt/react/useSTT.d.ts.map +1 -1
  41. package/dist/stt/react/useSTT.js +44 -11
  42. package/dist/stt/react/useSTT.js.map +1 -1
  43. package/dist/stt/registry.d.ts.map +1 -1
  44. package/dist/stt/registry.js +0 -8
  45. package/dist/stt/registry.js.map +1 -1
  46. package/dist/stt/sources/glass-bridge.d.ts +8 -15
  47. package/dist/stt/sources/glass-bridge.d.ts.map +1 -1
  48. package/dist/stt/sources/glass-bridge.js +66 -9
  49. package/dist/stt/sources/glass-bridge.js.map +1 -1
  50. package/dist/stt/sources/microphone.d.ts.map +1 -1
  51. package/dist/stt/sources/microphone.js +4 -0
  52. package/dist/stt/sources/microphone.js.map +1 -1
  53. package/dist/stt/types.d.ts +7 -3
  54. package/dist/stt/types.d.ts.map +1 -1
  55. package/glasses/action-bar.ts +4 -4
  56. package/glasses/bridge.ts +24 -3
  57. package/glasses/composer.ts +2 -2
  58. package/glasses/layout.ts +6 -0
  59. package/glasses/types.ts +28 -0
  60. package/glasses/useGlasses.ts +18 -5
  61. package/package.json +7 -19
  62. package/stt/debug.ts +38 -0
  63. package/stt/engine.ts +158 -83
  64. package/stt/index.ts +1 -0
  65. package/stt/providers/deepgram.ts +26 -9
  66. package/stt/providers/whisper-api.ts +78 -4
  67. package/stt/react/useSTT.ts +45 -11
  68. package/stt/registry.ts +0 -8
  69. package/stt/sources/glass-bridge.ts +69 -25
  70. package/stt/sources/microphone.ts +7 -0
  71. package/stt/types.ts +4 -3
  72. package/dist/stt/providers/web-speech.d.ts +0 -25
  73. package/dist/stt/providers/web-speech.d.ts.map +0 -1
  74. package/dist/stt/providers/web-speech.js +0 -153
  75. package/dist/stt/providers/web-speech.js.map +0 -1
  76. package/dist/stt/providers/whisper-local/provider.d.ts +0 -31
  77. package/dist/stt/providers/whisper-local/provider.d.ts.map +0 -1
  78. package/dist/stt/providers/whisper-local/provider.js +0 -174
  79. package/dist/stt/providers/whisper-local/provider.js.map +0 -1
  80. package/dist/stt/providers/whisper-local/worker.d.ts +0 -2
  81. package/dist/stt/providers/whisper-local/worker.d.ts.map +0 -1
  82. package/dist/stt/providers/whisper-local/worker.js +0 -35
  83. package/dist/stt/providers/whisper-local/worker.js.map +0 -1
  84. package/stt/providers/web-speech.ts +0 -221
  85. package/stt/providers/whisper-local/provider.ts +0 -226
  86. package/stt/providers/whisper-local/worker.ts +0 -40
@@ -1,174 +0,0 @@
1
- export class WhisperLocalProvider {
2
- constructor() {
3
- this.type = 'whisper-local';
4
- this.supportedModes = ['batch'];
5
- this._state = 'idle';
6
- this.worker = null;
7
- this.config = {};
8
- this.ready = false;
9
- this.transcriptCbs = [];
10
- this.stateCbs = [];
11
- this.errorCbs = [];
12
- this.pendingResolve = null;
13
- this.pendingReject = null;
14
- this.initResolve = null;
15
- this.initReject = null;
16
- }
17
- get state() {
18
- return this._state;
19
- }
20
- async init(config) {
21
- this.config = config;
22
- this.setState('loading');
23
- return new Promise((resolve, reject) => {
24
- this.initResolve = resolve;
25
- this.initReject = reject;
26
- this.worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
27
- this.worker.onmessage = (e) => {
28
- this.handleWorkerMessage(e.data);
29
- };
30
- this.worker.onerror = (err) => {
31
- const sttError = {
32
- code: 'model-load',
33
- message: err.message || 'Worker error',
34
- provider: this.type,
35
- };
36
- this.emitError(sttError);
37
- this.setState('error');
38
- if (this.initReject) {
39
- this.initReject(new Error(sttError.message));
40
- this.initResolve = null;
41
- this.initReject = null;
42
- }
43
- };
44
- const msg = {
45
- type: 'init',
46
- modelId: config.modelId,
47
- language: config.language,
48
- };
49
- this.worker.postMessage(msg);
50
- });
51
- }
52
- start() {
53
- // Batch mode: start is a no-op; audio is fed via transcribe()
54
- if (this.ready) {
55
- this.setState('listening');
56
- }
57
- }
58
- stop() {
59
- if (this._state === 'listening' || this._state === 'processing') {
60
- this.setState('idle');
61
- }
62
- }
63
- abort() {
64
- if (this.pendingReject) {
65
- this.pendingReject(new Error('Aborted'));
66
- this.pendingResolve = null;
67
- this.pendingReject = null;
68
- }
69
- this.setState('idle');
70
- }
71
- dispose() {
72
- this.abort();
73
- if (this.worker) {
74
- this.worker.terminate();
75
- this.worker = null;
76
- }
77
- this.ready = false;
78
- this.transcriptCbs = [];
79
- this.stateCbs = [];
80
- this.errorCbs = [];
81
- }
82
- async transcribe(audio, sampleRate) {
83
- if (!this.worker || !this.ready) {
84
- throw new Error('Provider not initialized');
85
- }
86
- this.setState('processing');
87
- return new Promise((resolve, reject) => {
88
- this.pendingResolve = resolve;
89
- this.pendingReject = reject;
90
- this.worker.postMessage({ type: 'transcribe', audio, language: this.config.language ?? 'en', sampleRate }, [audio.buffer]);
91
- });
92
- }
93
- onTranscript(cb) {
94
- this.transcriptCbs.push(cb);
95
- return () => { this.transcriptCbs = this.transcriptCbs.filter((c) => c !== cb); };
96
- }
97
- onStateChange(cb) {
98
- this.stateCbs.push(cb);
99
- return () => { this.stateCbs = this.stateCbs.filter((c) => c !== cb); };
100
- }
101
- onError(cb) {
102
- this.errorCbs.push(cb);
103
- return () => { this.errorCbs = this.errorCbs.filter((c) => c !== cb); };
104
- }
105
- // ── Private ──
106
- handleWorkerMessage(data) {
107
- switch (data.type) {
108
- case 'ready':
109
- this.ready = true;
110
- this.setState('idle');
111
- if (this.initResolve) {
112
- this.initResolve();
113
- this.initResolve = null;
114
- this.initReject = null;
115
- }
116
- break;
117
- case 'progress':
118
- // Model download progress — stay in loading state
119
- break;
120
- case 'result': {
121
- const transcript = {
122
- text: data.text ?? '',
123
- isFinal: true,
124
- confidence: data.confidence ?? 0.95,
125
- timestamp: Date.now(),
126
- };
127
- this.emitTranscript(transcript);
128
- this.setState('listening');
129
- if (this.pendingResolve) {
130
- this.pendingResolve(transcript);
131
- this.pendingResolve = null;
132
- this.pendingReject = null;
133
- }
134
- break;
135
- }
136
- case 'error': {
137
- const sttError = {
138
- code: 'model-load',
139
- message: data.message ?? 'Worker error',
140
- provider: this.type,
141
- };
142
- this.emitError(sttError);
143
- this.setState('error');
144
- if (this.pendingReject) {
145
- this.pendingReject(new Error(sttError.message));
146
- this.pendingResolve = null;
147
- this.pendingReject = null;
148
- }
149
- if (this.initReject) {
150
- this.initReject(new Error(sttError.message));
151
- this.initResolve = null;
152
- this.initReject = null;
153
- }
154
- break;
155
- }
156
- }
157
- }
158
- setState(s) {
159
- if (this._state === s)
160
- return;
161
- this._state = s;
162
- for (const cb of this.stateCbs)
163
- cb(s);
164
- }
165
- emitTranscript(t) {
166
- for (const cb of this.transcriptCbs)
167
- cb(t);
168
- }
169
- emitError(e) {
170
- for (const cb of this.errorCbs)
171
- cb(e);
172
- }
173
- }
174
- //# sourceMappingURL=provider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../../stt/providers/whisper-local/provider.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- declare let pipe: any;
2
- //# sourceMappingURL=worker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../../stt/providers/whisper-local/worker.ts"],"names":[],"mappings":"AAEA,QAAA,IAAI,IAAI,EAAE,GAAU,CAAC"}
@@ -1,35 +0,0 @@
1
- "use strict";
2
- // WebWorker for Whisper local inference via @huggingface/transformers
3
- let pipe = null;
4
- self.onmessage = async (e) => {
5
- const { type } = e.data;
6
- if (type === 'init') {
7
- try {
8
- const { pipeline } = await import('@huggingface/transformers');
9
- pipe = await pipeline('automatic-speech-recognition', e.data.modelId ?? 'onnx-community/whisper-tiny', {
10
- progress_callback: (p) => self.postMessage({ type: 'progress', ...p }),
11
- });
12
- self.postMessage({ type: 'ready' });
13
- }
14
- catch (err) {
15
- self.postMessage({ type: 'error', message: err?.message ?? 'Failed to load model' });
16
- }
17
- }
18
- if (type === 'transcribe') {
19
- if (!pipe) {
20
- self.postMessage({ type: 'error', message: 'Model not loaded' });
21
- return;
22
- }
23
- try {
24
- const result = await pipe(e.data.audio, {
25
- language: e.data.language ?? 'en',
26
- return_timestamps: false,
27
- });
28
- self.postMessage({ type: 'result', text: result.text, confidence: 0.95 });
29
- }
30
- catch (err) {
31
- self.postMessage({ type: 'error', message: err?.message ?? 'Transcription failed' });
32
- }
33
- }
34
- };
35
- //# sourceMappingURL=worker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../../stt/providers/whisper-local/worker.ts"],"names":[],"mappings":";AAAA,sEAAsE;AAEtE,IAAI,IAAI,GAAQ,IAAI,CAAC;AAErB,IAAI,CAAC,SAAS,GAAG,KAAK,EAAE,CAAe,EAAE,EAAE;IACzC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC;IAExB,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;YAC/D,IAAI,GAAG,MAAM,QAAQ,CACnB,8BAA8B,EAC9B,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,6BAA6B,EAC/C;gBACE,iBAAiB,EAAE,CAAC,CAAM,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;aAC5E,CACF,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,IAAI,sBAAsB,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE;gBACtC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI;gBACjC,iBAAiB,EAAE,KAAK;aACzB,CAAC,CAAC;YACH,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5E,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,IAAI,sBAAsB,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
@@ -1,221 +0,0 @@
1
- import type {
2
- STTProvider,
3
- STTProviderConfig,
4
- STTMode,
5
- STTState,
6
- STTTranscript,
7
- STTError,
8
- } from '../types';
9
-
10
- // ── Inline SpeechRecognition types (not in standard TS lib) ──
11
-
12
- interface SpeechRecognitionEvent extends Event {
13
- readonly results: SpeechRecognitionResultList;
14
- readonly resultIndex: number;
15
- }
16
-
17
- interface SpeechRecognitionErrorEvent extends Event {
18
- readonly error: string;
19
- readonly message: string;
20
- }
21
-
22
- interface SpeechRecognitionResultList {
23
- readonly length: number;
24
- item(index: number): SpeechRecognitionResult;
25
- [index: number]: SpeechRecognitionResult;
26
- }
27
-
28
- interface SpeechRecognitionResult {
29
- readonly length: number;
30
- readonly isFinal: boolean;
31
- item(index: number): SpeechRecognitionAlternative;
32
- [index: number]: SpeechRecognitionAlternative;
33
- }
34
-
35
- interface SpeechRecognitionAlternative {
36
- readonly transcript: string;
37
- readonly confidence: number;
38
- }
39
-
40
- interface SpeechRecognitionInstance {
41
- continuous: boolean;
42
- interimResults: boolean;
43
- lang: string;
44
- onresult: ((event: SpeechRecognitionEvent) => void) | null;
45
- onerror: ((event: SpeechRecognitionErrorEvent) => void) | null;
46
- onstart: (() => void) | null;
47
- onend: (() => void) | null;
48
- start(): void;
49
- stop(): void;
50
- abort(): void;
51
- }
52
-
53
- type SpeechRecognitionConstructor = new () => SpeechRecognitionInstance;
54
-
55
- function getSpeechRecognitionCtor(): SpeechRecognitionConstructor | null {
56
- if (typeof window === 'undefined') return null;
57
- const w = window as unknown as Record<string, unknown>;
58
- return (w.SpeechRecognition ?? w.webkitSpeechRecognition) as SpeechRecognitionConstructor | null;
59
- }
60
-
61
- // ── Provider ──
62
-
63
- export class WebSpeechProvider implements STTProvider {
64
- readonly type = 'web-speech' as const;
65
- readonly supportedModes: STTMode[] = ['streaming'];
66
-
67
- private _state: STTState = 'idle';
68
- private recognition: SpeechRecognitionInstance | null = null;
69
- private config: STTProviderConfig = {};
70
- private stopping = false;
71
-
72
- private transcriptCbs: Array<(t: STTTranscript) => void> = [];
73
- private stateCbs: Array<(s: STTState) => void> = [];
74
- private errorCbs: Array<(e: STTError) => void> = [];
75
-
76
- get state(): STTState {
77
- return this._state;
78
- }
79
-
80
- async init(config: STTProviderConfig): Promise<void> {
81
- const Ctor = getSpeechRecognitionCtor();
82
- if (!Ctor) {
83
- this.emitError({ code: 'unsupported', message: 'SpeechRecognition not available in this browser', provider: this.type });
84
- throw new Error('SpeechRecognition not supported');
85
- }
86
- this.config = config;
87
- }
88
-
89
- start(): void {
90
- const Ctor = getSpeechRecognitionCtor();
91
- if (!Ctor) {
92
- this.emitError({ code: 'unsupported', message: 'SpeechRecognition not available', provider: this.type });
93
- return;
94
- }
95
-
96
- // Tear down previous instance if any
97
- if (this.recognition) {
98
- try { this.recognition.abort(); } catch { /* ignore */ }
99
- }
100
-
101
- this.stopping = false;
102
- const recognition = new Ctor();
103
- recognition.continuous = this.config.continuous ?? true;
104
- recognition.interimResults = true;
105
- recognition.lang = this.config.language ?? 'en-US';
106
-
107
- recognition.onstart = () => {
108
- this.setState('listening');
109
- };
110
-
111
- recognition.onresult = (event: SpeechRecognitionEvent) => {
112
- for (let i = event.resultIndex; i < event.results.length; i++) {
113
- const result = event.results[i];
114
- if (!result?.[0]) continue;
115
-
116
- const transcript: STTTranscript = {
117
- text: result[0].transcript,
118
- isFinal: result.isFinal,
119
- confidence: result[0].confidence ?? 0,
120
- timestamp: Date.now(),
121
- };
122
- this.emitTranscript(transcript);
123
- }
124
- };
125
-
126
- recognition.onerror = (event: SpeechRecognitionErrorEvent) => {
127
- // Suppress no-speech and aborted-while-stopping
128
- if (event.error === 'no-speech') return;
129
- if (event.error === 'aborted' && this.stopping) return;
130
-
131
- const code = mapErrorCode(event.error);
132
- this.emitError({ code, message: event.message || event.error, provider: this.type });
133
-
134
- if (code !== 'no-speech') {
135
- this.setState('error');
136
- }
137
- };
138
-
139
- recognition.onend = () => {
140
- this.recognition = null;
141
- this.setState('idle');
142
- };
143
-
144
- this.recognition = recognition;
145
- recognition.start();
146
- }
147
-
148
- stop(): void {
149
- this.stopping = true;
150
- if (this.recognition) {
151
- this.recognition.stop();
152
- }
153
- }
154
-
155
- abort(): void {
156
- this.stopping = true;
157
- if (this.recognition) {
158
- this.recognition.abort();
159
- }
160
- }
161
-
162
- dispose(): void {
163
- this.abort();
164
- this.transcriptCbs = [];
165
- this.stateCbs = [];
166
- this.errorCbs = [];
167
- }
168
-
169
- onTranscript(cb: (t: STTTranscript) => void): () => void {
170
- this.transcriptCbs.push(cb);
171
- return () => {
172
- this.transcriptCbs = this.transcriptCbs.filter((c) => c !== cb);
173
- };
174
- }
175
-
176
- onStateChange(cb: (s: STTState) => void): () => void {
177
- this.stateCbs.push(cb);
178
- return () => {
179
- this.stateCbs = this.stateCbs.filter((c) => c !== cb);
180
- };
181
- }
182
-
183
- onError(cb: (e: STTError) => void): () => void {
184
- this.errorCbs.push(cb);
185
- return () => {
186
- this.errorCbs = this.errorCbs.filter((c) => c !== cb);
187
- };
188
- }
189
-
190
- // ── Private helpers ──
191
-
192
- private setState(s: STTState): void {
193
- if (this._state === s) return;
194
- this._state = s;
195
- for (const cb of this.stateCbs) cb(s);
196
- }
197
-
198
- private emitTranscript(t: STTTranscript): void {
199
- for (const cb of this.transcriptCbs) cb(t);
200
- }
201
-
202
- private emitError(e: STTError): void {
203
- for (const cb of this.errorCbs) cb(e);
204
- }
205
- }
206
-
207
- function mapErrorCode(error: string): STTError['code'] {
208
- switch (error) {
209
- case 'not-allowed':
210
- case 'service-not-allowed':
211
- return 'not-allowed';
212
- case 'no-speech':
213
- return 'no-speech';
214
- case 'network':
215
- return 'network';
216
- case 'aborted':
217
- return 'aborted';
218
- default:
219
- return 'unknown';
220
- }
221
- }
@@ -1,226 +0,0 @@
1
- import type {
2
- STTProvider,
3
- STTProviderConfig,
4
- STTMode,
5
- STTState,
6
- STTTranscript,
7
- STTError,
8
- } from '../../types';
9
-
10
- interface WorkerMessage {
11
- type: 'init' | 'transcribe';
12
- modelId?: string;
13
- language?: string;
14
- audio?: Float32Array;
15
- }
16
-
17
- interface WorkerResponse {
18
- type: 'ready' | 'progress' | 'result' | 'error';
19
- loaded?: number;
20
- total?: number;
21
- text?: string;
22
- confidence?: number;
23
- message?: string;
24
- }
25
-
26
- export class WhisperLocalProvider implements STTProvider {
27
- readonly type = 'whisper-local' as const;
28
- readonly supportedModes: STTMode[] = ['batch'];
29
-
30
- private _state: STTState = 'idle';
31
- private worker: Worker | null = null;
32
- private config: STTProviderConfig = {};
33
- private ready = false;
34
-
35
- private transcriptCbs: Array<(t: STTTranscript) => void> = [];
36
- private stateCbs: Array<(s: STTState) => void> = [];
37
- private errorCbs: Array<(e: STTError) => void> = [];
38
-
39
- private pendingResolve: ((t: STTTranscript) => void) | null = null;
40
- private pendingReject: ((e: Error) => void) | null = null;
41
- private initResolve: (() => void) | null = null;
42
- private initReject: ((e: Error) => void) | null = null;
43
-
44
- get state(): STTState {
45
- return this._state;
46
- }
47
-
48
- async init(config: STTProviderConfig): Promise<void> {
49
- this.config = config;
50
- this.setState('loading');
51
-
52
- return new Promise<void>((resolve, reject) => {
53
- this.initResolve = resolve;
54
- this.initReject = reject;
55
-
56
- this.worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
57
-
58
- this.worker.onmessage = (e: MessageEvent<WorkerResponse>) => {
59
- this.handleWorkerMessage(e.data);
60
- };
61
-
62
- this.worker.onerror = (err) => {
63
- const sttError: STTError = {
64
- code: 'model-load',
65
- message: err.message || 'Worker error',
66
- provider: this.type,
67
- };
68
- this.emitError(sttError);
69
- this.setState('error');
70
- if (this.initReject) {
71
- this.initReject(new Error(sttError.message));
72
- this.initResolve = null;
73
- this.initReject = null;
74
- }
75
- };
76
-
77
- const msg: WorkerMessage = {
78
- type: 'init',
79
- modelId: config.modelId,
80
- language: config.language,
81
- };
82
- this.worker.postMessage(msg);
83
- });
84
- }
85
-
86
- start(): void {
87
- // Batch mode: start is a no-op; audio is fed via transcribe()
88
- if (this.ready) {
89
- this.setState('listening');
90
- }
91
- }
92
-
93
- stop(): void {
94
- if (this._state === 'listening' || this._state === 'processing') {
95
- this.setState('idle');
96
- }
97
- }
98
-
99
- abort(): void {
100
- if (this.pendingReject) {
101
- this.pendingReject(new Error('Aborted'));
102
- this.pendingResolve = null;
103
- this.pendingReject = null;
104
- }
105
- this.setState('idle');
106
- }
107
-
108
- dispose(): void {
109
- this.abort();
110
- if (this.worker) {
111
- this.worker.terminate();
112
- this.worker = null;
113
- }
114
- this.ready = false;
115
- this.transcriptCbs = [];
116
- this.stateCbs = [];
117
- this.errorCbs = [];
118
- }
119
-
120
- async transcribe(audio: Float32Array, sampleRate: number): Promise<STTTranscript> {
121
- if (!this.worker || !this.ready) {
122
- throw new Error('Provider not initialized');
123
- }
124
-
125
- this.setState('processing');
126
-
127
- return new Promise<STTTranscript>((resolve, reject) => {
128
- this.pendingResolve = resolve;
129
- this.pendingReject = reject;
130
-
131
- this.worker!.postMessage(
132
- { type: 'transcribe', audio, language: this.config.language ?? 'en', sampleRate },
133
- [audio.buffer],
134
- );
135
- });
136
- }
137
-
138
- onTranscript(cb: (t: STTTranscript) => void): () => void {
139
- this.transcriptCbs.push(cb);
140
- return () => { this.transcriptCbs = this.transcriptCbs.filter((c) => c !== cb); };
141
- }
142
-
143
- onStateChange(cb: (s: STTState) => void): () => void {
144
- this.stateCbs.push(cb);
145
- return () => { this.stateCbs = this.stateCbs.filter((c) => c !== cb); };
146
- }
147
-
148
- onError(cb: (e: STTError) => void): () => void {
149
- this.errorCbs.push(cb);
150
- return () => { this.errorCbs = this.errorCbs.filter((c) => c !== cb); };
151
- }
152
-
153
- // ── Private ──
154
-
155
- private handleWorkerMessage(data: WorkerResponse): void {
156
- switch (data.type) {
157
- case 'ready':
158
- this.ready = true;
159
- this.setState('idle');
160
- if (this.initResolve) {
161
- this.initResolve();
162
- this.initResolve = null;
163
- this.initReject = null;
164
- }
165
- break;
166
-
167
- case 'progress':
168
- // Model download progress — stay in loading state
169
- break;
170
-
171
- case 'result': {
172
- const transcript: STTTranscript = {
173
- text: data.text ?? '',
174
- isFinal: true,
175
- confidence: data.confidence ?? 0.95,
176
- timestamp: Date.now(),
177
- };
178
- this.emitTranscript(transcript);
179
- this.setState('listening');
180
-
181
- if (this.pendingResolve) {
182
- this.pendingResolve(transcript);
183
- this.pendingResolve = null;
184
- this.pendingReject = null;
185
- }
186
- break;
187
- }
188
-
189
- case 'error': {
190
- const sttError: STTError = {
191
- code: 'model-load',
192
- message: data.message ?? 'Worker error',
193
- provider: this.type,
194
- };
195
- this.emitError(sttError);
196
- this.setState('error');
197
-
198
- if (this.pendingReject) {
199
- this.pendingReject(new Error(sttError.message));
200
- this.pendingResolve = null;
201
- this.pendingReject = null;
202
- }
203
- if (this.initReject) {
204
- this.initReject(new Error(sttError.message));
205
- this.initResolve = null;
206
- this.initReject = null;
207
- }
208
- break;
209
- }
210
- }
211
- }
212
-
213
- private setState(s: STTState): void {
214
- if (this._state === s) return;
215
- this._state = s;
216
- for (const cb of this.stateCbs) cb(s);
217
- }
218
-
219
- private emitTranscript(t: STTTranscript): void {
220
- for (const cb of this.transcriptCbs) cb(t);
221
- }
222
-
223
- private emitError(e: STTError): void {
224
- for (const cb of this.errorCbs) cb(e);
225
- }
226
- }