even-toolkit 1.0.0 → 1.1.0

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 (70) hide show
  1. package/README.md +5 -5
  2. package/dist/stt/audio/buffer.d.ts +12 -0
  3. package/dist/stt/audio/buffer.d.ts.map +1 -0
  4. package/dist/stt/audio/buffer.js +35 -0
  5. package/dist/stt/audio/buffer.js.map +1 -0
  6. package/dist/stt/audio/pcm-utils.d.ts +9 -0
  7. package/dist/stt/audio/pcm-utils.d.ts.map +1 -0
  8. package/dist/stt/audio/pcm-utils.js +52 -0
  9. package/dist/stt/audio/pcm-utils.js.map +1 -0
  10. package/dist/stt/audio/resample.d.ts +3 -0
  11. package/dist/stt/audio/resample.d.ts.map +1 -0
  12. package/dist/stt/audio/resample.js +17 -0
  13. package/dist/stt/audio/resample.js.map +1 -0
  14. package/dist/stt/audio/vad.d.ts +17 -0
  15. package/dist/stt/audio/vad.d.ts.map +1 -0
  16. package/dist/stt/audio/vad.js +43 -0
  17. package/dist/stt/audio/vad.js.map +1 -0
  18. package/dist/stt/engine.d.ts +38 -0
  19. package/dist/stt/engine.d.ts.map +1 -0
  20. package/dist/stt/engine.js +233 -0
  21. package/dist/stt/engine.js.map +1 -0
  22. package/dist/stt/i18n.d.ts +13 -0
  23. package/dist/stt/i18n.d.ts.map +1 -0
  24. package/dist/stt/i18n.js +31 -0
  25. package/dist/stt/i18n.js.map +1 -0
  26. package/dist/stt/index.d.ts +11 -0
  27. package/dist/stt/index.d.ts.map +1 -0
  28. package/dist/stt/index.js +11 -0
  29. package/dist/stt/index.js.map +1 -0
  30. package/dist/stt/providers/deepgram.d.ts +29 -0
  31. package/dist/stt/providers/deepgram.d.ts.map +1 -0
  32. package/dist/stt/providers/deepgram.js +145 -0
  33. package/dist/stt/providers/deepgram.js.map +1 -0
  34. package/dist/stt/providers/web-speech.d.ts +25 -0
  35. package/dist/stt/providers/web-speech.d.ts.map +1 -0
  36. package/dist/stt/providers/web-speech.js +153 -0
  37. package/dist/stt/providers/web-speech.js.map +1 -0
  38. package/dist/stt/providers/whisper-api.d.ts +26 -0
  39. package/dist/stt/providers/whisper-api.d.ts.map +1 -0
  40. package/dist/stt/providers/whisper-api.js +120 -0
  41. package/dist/stt/providers/whisper-api.js.map +1 -0
  42. package/dist/stt/providers/whisper-local/provider.d.ts +31 -0
  43. package/dist/stt/providers/whisper-local/provider.d.ts.map +1 -0
  44. package/dist/stt/providers/whisper-local/provider.js +174 -0
  45. package/dist/stt/providers/whisper-local/provider.js.map +1 -0
  46. package/dist/stt/providers/whisper-local/worker.d.ts +2 -0
  47. package/dist/stt/providers/whisper-local/worker.d.ts.map +1 -0
  48. package/dist/stt/providers/whisper-local/worker.js +35 -0
  49. package/dist/stt/providers/whisper-local/worker.js.map +1 -0
  50. package/dist/stt/react/useSTT.d.ts +3 -0
  51. package/dist/stt/react/useSTT.d.ts.map +1 -0
  52. package/dist/stt/react/useSTT.js +99 -0
  53. package/dist/stt/react/useSTT.js.map +1 -0
  54. package/dist/stt/registry.d.ts +3 -0
  55. package/dist/stt/registry.d.ts.map +1 -0
  56. package/dist/stt/registry.js +23 -0
  57. package/dist/stt/registry.js.map +1 -0
  58. package/dist/stt/sources/glass-bridge.d.ts +28 -0
  59. package/dist/stt/sources/glass-bridge.d.ts.map +1 -0
  60. package/dist/stt/sources/glass-bridge.js +47 -0
  61. package/dist/stt/sources/glass-bridge.js.map +1 -0
  62. package/dist/stt/sources/microphone.d.ts +17 -0
  63. package/dist/stt/sources/microphone.d.ts.map +1 -0
  64. package/dist/stt/sources/microphone.js +69 -0
  65. package/dist/stt/sources/microphone.js.map +1 -0
  66. package/dist/stt/types.d.ts +89 -0
  67. package/dist/stt/types.d.ts.map +1 -0
  68. package/dist/stt/types.js +3 -0
  69. package/dist/stt/types.js.map +1 -0
  70. package/package.json +40 -3
@@ -0,0 +1,174 @@
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.ts', 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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../../stt/providers/whisper-local/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ declare let pipe: any;
2
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../../stt/providers/whisper-local/worker.ts"],"names":[],"mappings":"AAEA,QAAA,IAAI,IAAI,EAAE,GAAU,CAAC"}
@@ -0,0 +1,35 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,3 @@
1
+ import type { UseSTTConfig, UseSTTReturn } from '../types';
2
+ export declare function useSTT(config?: UseSTTConfig): UseSTTReturn;
3
+ //# sourceMappingURL=useSTT.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSTT.d.ts","sourceRoot":"","sources":["../../../stt/react/useSTT.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAsB,MAAM,UAAU,CAAC;AAG/E,wBAAgB,MAAM,CAAC,MAAM,GAAE,YAAiB,GAAG,YAAY,CA4G9D"}
@@ -0,0 +1,99 @@
1
+ import { useState, useRef, useEffect, useCallback } from 'react';
2
+ import { STTEngine } from '../engine';
3
+ export function useSTT(config = {}) {
4
+ const [transcript, setTranscript] = useState('');
5
+ const [interimTranscript, setInterimTranscript] = useState('');
6
+ const [isListening, setIsListening] = useState(false);
7
+ const [isLoading, setIsLoading] = useState(false);
8
+ const [loadProgress] = useState(0);
9
+ const [error, setError] = useState(null);
10
+ const [state, setState] = useState('idle');
11
+ const engineRef = useRef(null);
12
+ const configRef = useRef(config);
13
+ configRef.current = config;
14
+ // Cleanup on unmount
15
+ useEffect(() => {
16
+ return () => {
17
+ engineRef.current?.dispose();
18
+ engineRef.current = null;
19
+ };
20
+ }, []);
21
+ const start = useCallback(async () => {
22
+ // Dispose previous engine
23
+ engineRef.current?.dispose();
24
+ const cfg = configRef.current;
25
+ const engine = new STTEngine({
26
+ provider: cfg.provider ?? 'web-speech',
27
+ source: cfg.source,
28
+ language: cfg.language,
29
+ mode: cfg.mode,
30
+ apiKey: cfg.apiKey,
31
+ modelId: cfg.modelId,
32
+ continuous: cfg.continuous,
33
+ vad: cfg.vad,
34
+ fallback: cfg.fallback,
35
+ });
36
+ engineRef.current = engine;
37
+ // Subscribe to events
38
+ engine.onTranscript((t) => {
39
+ if (t.isFinal) {
40
+ setTranscript((prev) => (prev ? prev + ' ' + t.text : t.text));
41
+ setInterimTranscript('');
42
+ }
43
+ else {
44
+ setInterimTranscript(t.text);
45
+ }
46
+ cfg.onTranscript?.(t.text, t.isFinal);
47
+ });
48
+ engine.onStateChange((s) => {
49
+ setState(s);
50
+ setIsListening(s === 'listening');
51
+ setIsLoading(s === 'loading');
52
+ if (s === 'idle') {
53
+ setInterimTranscript('');
54
+ }
55
+ });
56
+ engine.onError((e) => {
57
+ setError(e);
58
+ });
59
+ setError(null);
60
+ await engine.start();
61
+ }, []);
62
+ const stop = useCallback(() => {
63
+ engineRef.current?.stop();
64
+ }, []);
65
+ const abort = useCallback(() => {
66
+ engineRef.current?.abort();
67
+ }, []);
68
+ const reset = useCallback(() => {
69
+ engineRef.current?.abort();
70
+ setTranscript('');
71
+ setInterimTranscript('');
72
+ setError(null);
73
+ setState('idle');
74
+ setIsListening(false);
75
+ setIsLoading(false);
76
+ }, []);
77
+ // Auto-start if configured
78
+ useEffect(() => {
79
+ if (config.autoStart) {
80
+ start();
81
+ }
82
+ // Only run on mount
83
+ // eslint-disable-next-line react-hooks/exhaustive-deps
84
+ }, []);
85
+ return {
86
+ transcript,
87
+ interimTranscript,
88
+ isListening,
89
+ isLoading,
90
+ loadProgress,
91
+ error,
92
+ state,
93
+ start,
94
+ stop,
95
+ abort,
96
+ reset,
97
+ };
98
+ }
99
+ //# sourceMappingURL=useSTT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSTT.js","sourceRoot":"","sources":["../../../stt/react/useSTT.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { STTProvider } from './types';
2
+ export declare function createProvider(type: string): Promise<STTProvider>;
3
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../stt/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAqBvE"}
@@ -0,0 +1,23 @@
1
+ export async function createProvider(type) {
2
+ switch (type) {
3
+ case 'web-speech': {
4
+ const { WebSpeechProvider } = await import('./providers/web-speech');
5
+ return new WebSpeechProvider();
6
+ }
7
+ case 'whisper-local': {
8
+ const { WhisperLocalProvider } = await import('./providers/whisper-local/provider');
9
+ return new WhisperLocalProvider();
10
+ }
11
+ case 'whisper-api': {
12
+ const { WhisperApiProvider } = await import('./providers/whisper-api');
13
+ return new WhisperApiProvider();
14
+ }
15
+ case 'deepgram': {
16
+ const { DeepgramProvider } = await import('./providers/deepgram');
17
+ return new DeepgramProvider();
18
+ }
19
+ default:
20
+ throw new Error(`Unknown STT provider: ${type}`);
21
+ }
22
+ }
23
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../stt/registry.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;YACrE,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACjC,CAAC;QACD,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,oCAAoC,CAAC,CAAC;YACpF,OAAO,IAAI,oBAAoB,EAAE,CAAC;QACpC,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;YACvE,OAAO,IAAI,kBAAkB,EAAE,CAAC;QAClC,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;YAClE,OAAO,IAAI,gBAAgB,EAAE,CAAC;QAChC,CAAC;QACD;YACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { AudioSource } from '../types';
2
+ export interface GlassBridgeSourceConfig {
3
+ /** The EvenHub bridge instance that fires audio events */
4
+ bridge: {
5
+ onEvent(handler: (event: GlassAudioEvent) => void): void;
6
+ };
7
+ }
8
+ export interface GlassAudioEvent {
9
+ audioEvent?: {
10
+ audioPcm?: Uint8Array;
11
+ };
12
+ }
13
+ /**
14
+ * AudioSource for G2 smart glasses.
15
+ * Listens for audio PCM events from the EvenHub SDK bridge
16
+ * and converts 16-bit PCM to Float32.
17
+ */
18
+ export declare class GlassBridgeSource implements AudioSource {
19
+ private config;
20
+ private listeners;
21
+ private listening;
22
+ constructor(config: GlassBridgeSourceConfig);
23
+ start(): Promise<void>;
24
+ stop(): void;
25
+ onAudioData(cb: (pcm: Float32Array, sampleRate: number) => void): () => void;
26
+ dispose(): void;
27
+ }
28
+ //# sourceMappingURL=glass-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glass-bridge.d.ts","sourceRoot":"","sources":["../../../stt/sources/glass-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,MAAM,EAAE;QACN,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI,CAAC;KAC1D,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE;QACX,QAAQ,CAAC,EAAE,UAAU,CAAC;KACvB,CAAC;CACH;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,SAAS,CAA8D;IAC/E,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,uBAAuB;IAIrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B,IAAI,IAAI,IAAI;IAIZ,WAAW,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAQ5E,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,47 @@
1
+ import { uint8ToPcm16, pcm16ToFloat32 } from '../audio/pcm-utils';
2
+ const GLASS_SAMPLE_RATE = 16000;
3
+ /**
4
+ * AudioSource for G2 smart glasses.
5
+ * Listens for audio PCM events from the EvenHub SDK bridge
6
+ * and converts 16-bit PCM to Float32.
7
+ */
8
+ export class GlassBridgeSource {
9
+ constructor(config) {
10
+ this.listeners = [];
11
+ this.listening = false;
12
+ this.config = config;
13
+ }
14
+ async start() {
15
+ if (this.listening)
16
+ return;
17
+ this.listening = true;
18
+ this.config.bridge.onEvent((event) => {
19
+ if (!this.listening)
20
+ return;
21
+ const audioPcm = event.audioEvent?.audioPcm;
22
+ if (!audioPcm || audioPcm.length === 0)
23
+ return;
24
+ const pcm16 = uint8ToPcm16(audioPcm);
25
+ const float32 = pcm16ToFloat32(pcm16);
26
+ for (const cb of this.listeners) {
27
+ cb(float32, GLASS_SAMPLE_RATE);
28
+ }
29
+ });
30
+ }
31
+ stop() {
32
+ this.listening = false;
33
+ }
34
+ onAudioData(cb) {
35
+ this.listeners.push(cb);
36
+ return () => {
37
+ const idx = this.listeners.indexOf(cb);
38
+ if (idx >= 0)
39
+ this.listeners.splice(idx, 1);
40
+ };
41
+ }
42
+ dispose() {
43
+ this.stop();
44
+ this.listeners.length = 0;
45
+ }
46
+ }
47
+ //# sourceMappingURL=glass-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glass-bridge.js","sourceRoot":"","sources":["../../../stt/sources/glass-bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAElE,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAehC;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IAK5B,YAAY,MAA+B;QAHnC,cAAS,GAA2D,EAAE,CAAC;QACvE,cAAS,GAAG,KAAK,CAAC;QAGxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAEtB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAsB,EAAE,EAAE;YACpD,IAAI,CAAC,IAAI,CAAC,SAAS;gBAAE,OAAO;YAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC;YAC5C,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAE/C,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YAEtC,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBAChC,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;YACjC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI;QACF,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,WAAW,CAAC,EAAmD;QAC7D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxB,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACvC,IAAI,GAAG,IAAI,CAAC;gBAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { AudioSource } from '../types';
2
+ /**
3
+ * AudioSource that captures PCM audio from the device microphone
4
+ * using getUserMedia and ScriptProcessorNode.
5
+ */
6
+ export declare class MicrophoneSource implements AudioSource {
7
+ private stream;
8
+ private audioContext;
9
+ private scriptNode;
10
+ private sourceNode;
11
+ private listeners;
12
+ start(): Promise<void>;
13
+ stop(): void;
14
+ onAudioData(cb: (pcm: Float32Array, sampleRate: number) => void): () => void;
15
+ dispose(): void;
16
+ }
17
+ //# sourceMappingURL=microphone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"microphone.d.ts","sourceRoot":"","sources":["../../../stt/sources/microphone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C;;;GAGG;AACH,qBAAa,gBAAiB,YAAW,WAAW;IAClD,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,UAAU,CAA2C;IAC7D,OAAO,CAAC,SAAS,CAA8D;IAEzE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB5B,IAAI,IAAI,IAAI;IAsBZ,WAAW,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAQ5E,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,69 @@
1
+ const CHUNK_SIZE = 4096;
2
+ const DEFAULT_SAMPLE_RATE = 16000;
3
+ /**
4
+ * AudioSource that captures PCM audio from the device microphone
5
+ * using getUserMedia and ScriptProcessorNode.
6
+ */
7
+ export class MicrophoneSource {
8
+ constructor() {
9
+ this.stream = null;
10
+ this.audioContext = null;
11
+ this.scriptNode = null;
12
+ this.sourceNode = null;
13
+ this.listeners = [];
14
+ }
15
+ async start() {
16
+ this.stream = await navigator.mediaDevices.getUserMedia({
17
+ audio: { sampleRate: DEFAULT_SAMPLE_RATE, channelCount: 1 },
18
+ });
19
+ this.audioContext = new AudioContext({ sampleRate: DEFAULT_SAMPLE_RATE });
20
+ this.sourceNode = this.audioContext.createMediaStreamSource(this.stream);
21
+ this.scriptNode = this.audioContext.createScriptProcessor(CHUNK_SIZE, 1, 1);
22
+ this.scriptNode.onaudioprocess = (event) => {
23
+ const input = event.inputBuffer.getChannelData(0);
24
+ // Copy the buffer — it's reused by the browser
25
+ const chunk = new Float32Array(input.length);
26
+ chunk.set(input);
27
+ const rate = this.audioContext?.sampleRate ?? DEFAULT_SAMPLE_RATE;
28
+ for (const cb of this.listeners) {
29
+ cb(chunk, rate);
30
+ }
31
+ };
32
+ this.sourceNode.connect(this.scriptNode);
33
+ this.scriptNode.connect(this.audioContext.destination);
34
+ }
35
+ stop() {
36
+ if (this.scriptNode) {
37
+ this.scriptNode.onaudioprocess = null;
38
+ this.scriptNode.disconnect();
39
+ this.scriptNode = null;
40
+ }
41
+ if (this.sourceNode) {
42
+ this.sourceNode.disconnect();
43
+ this.sourceNode = null;
44
+ }
45
+ if (this.stream) {
46
+ for (const track of this.stream.getTracks()) {
47
+ track.stop();
48
+ }
49
+ this.stream = null;
50
+ }
51
+ if (this.audioContext) {
52
+ this.audioContext.close().catch(() => { });
53
+ this.audioContext = null;
54
+ }
55
+ }
56
+ onAudioData(cb) {
57
+ this.listeners.push(cb);
58
+ return () => {
59
+ const idx = this.listeners.indexOf(cb);
60
+ if (idx >= 0)
61
+ this.listeners.splice(idx, 1);
62
+ };
63
+ }
64
+ dispose() {
65
+ this.stop();
66
+ this.listeners.length = 0;
67
+ }
68
+ }
69
+ //# sourceMappingURL=microphone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"microphone.js","sourceRoot":"","sources":["../../../stt/sources/microphone.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ export type STTProviderType = 'web-speech' | 'whisper-local' | 'whisper-api' | 'deepgram' | string;
2
+ export type STTMode = 'streaming' | 'batch';
3
+ export type STTState = 'idle' | 'loading' | 'listening' | 'processing' | 'error';
4
+ export interface STTTranscript {
5
+ text: string;
6
+ isFinal: boolean;
7
+ confidence: number;
8
+ language?: string;
9
+ timestamp: number;
10
+ }
11
+ export interface STTProviderConfig {
12
+ language?: string;
13
+ mode?: STTMode;
14
+ apiKey?: string;
15
+ modelId?: string;
16
+ continuous?: boolean;
17
+ vadEnabled?: boolean;
18
+ vadSilenceMs?: number;
19
+ sampleRate?: number;
20
+ maxDurationMs?: number;
21
+ }
22
+ export interface STTError {
23
+ code: 'not-allowed' | 'no-speech' | 'network' | 'model-load' | 'aborted' | 'unsupported' | 'unknown';
24
+ message: string;
25
+ provider: STTProviderType;
26
+ }
27
+ export interface STTProvider {
28
+ readonly type: STTProviderType;
29
+ readonly supportedModes: STTMode[];
30
+ readonly state: STTState;
31
+ init(config: STTProviderConfig): Promise<void>;
32
+ start(): void;
33
+ stop(): void;
34
+ abort(): void;
35
+ dispose(): void;
36
+ onTranscript(cb: (t: STTTranscript) => void): () => void;
37
+ onStateChange(cb: (s: STTState) => void): () => void;
38
+ onError(cb: (e: STTError) => void): () => void;
39
+ /** Batch mode: feed raw audio for transcription */
40
+ transcribe?(audio: Float32Array, sampleRate: number): Promise<STTTranscript>;
41
+ }
42
+ export interface AudioSource {
43
+ start(): Promise<void>;
44
+ stop(): void;
45
+ onAudioData(cb: (pcm: Float32Array, sampleRate: number) => void): () => void;
46
+ dispose(): void;
47
+ }
48
+ export interface STTEngineConfig {
49
+ provider: STTProviderType;
50
+ source?: 'microphone' | 'glass-bridge' | AudioSource;
51
+ language?: string;
52
+ mode?: STTMode;
53
+ apiKey?: string;
54
+ modelId?: string;
55
+ continuous?: boolean;
56
+ vad?: boolean | {
57
+ silenceMs?: number;
58
+ thresholdDb?: number;
59
+ };
60
+ sampleRate?: number;
61
+ fallback?: STTProviderType;
62
+ }
63
+ export interface UseSTTConfig {
64
+ provider?: STTProviderType;
65
+ source?: 'microphone' | 'glass-bridge';
66
+ language?: string;
67
+ mode?: STTMode;
68
+ apiKey?: string;
69
+ modelId?: string;
70
+ continuous?: boolean;
71
+ vad?: boolean;
72
+ autoStart?: boolean;
73
+ fallback?: STTProviderType;
74
+ onTranscript?: (text: string, isFinal: boolean) => void;
75
+ }
76
+ export interface UseSTTReturn {
77
+ transcript: string;
78
+ interimTranscript: string;
79
+ isListening: boolean;
80
+ isLoading: boolean;
81
+ loadProgress: number;
82
+ error: STTError | null;
83
+ state: STTState;
84
+ start: () => Promise<void>;
85
+ stop: () => void;
86
+ abort: () => void;
87
+ reset: () => void;
88
+ }
89
+ //# sourceMappingURL=types.d.ts.map