even-toolkit 1.1.1 → 1.3.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.
- package/README.md +74 -0
- package/dist/glasses/bridge.d.ts +5 -2
- package/dist/glasses/bridge.d.ts.map +1 -1
- package/dist/glasses/bridge.js +25 -2
- package/dist/glasses/bridge.js.map +1 -1
- package/dist/glasses/composer.js +2 -2
- package/dist/glasses/layout.d.ts +2 -0
- package/dist/glasses/layout.d.ts.map +1 -1
- package/dist/glasses/layout.js +4 -0
- package/dist/glasses/layout.js.map +1 -1
- package/dist/glasses/types.d.ts +23 -0
- package/dist/glasses/types.d.ts.map +1 -1
- package/dist/glasses/types.js +15 -0
- package/dist/glasses/types.js.map +1 -1
- package/dist/glasses/useGlasses.d.ts.map +1 -1
- package/dist/glasses/useGlasses.js +17 -4
- package/dist/glasses/useGlasses.js.map +1 -1
- package/dist/stt/debug.d.ts +8 -0
- package/dist/stt/debug.d.ts.map +1 -0
- package/dist/stt/debug.js +34 -0
- package/dist/stt/debug.js.map +1 -0
- package/dist/stt/engine.d.ts +9 -6
- package/dist/stt/engine.d.ts.map +1 -1
- package/dist/stt/engine.js +141 -75
- package/dist/stt/engine.js.map +1 -1
- package/dist/stt/index.d.ts +1 -0
- package/dist/stt/index.d.ts.map +1 -1
- package/dist/stt/index.js +1 -0
- package/dist/stt/index.js.map +1 -1
- package/dist/stt/providers/deepgram.d.ts +1 -1
- package/dist/stt/providers/deepgram.d.ts.map +1 -1
- package/dist/stt/providers/deepgram.js +24 -9
- package/dist/stt/providers/deepgram.js.map +1 -1
- package/dist/stt/providers/whisper-api.d.ts.map +1 -1
- package/dist/stt/providers/whisper-api.js +75 -4
- package/dist/stt/providers/whisper-api.js.map +1 -1
- package/dist/stt/react/useSTT.d.ts.map +1 -1
- package/dist/stt/react/useSTT.js +44 -11
- package/dist/stt/react/useSTT.js.map +1 -1
- package/dist/stt/registry.d.ts.map +1 -1
- package/dist/stt/registry.js +0 -8
- package/dist/stt/registry.js.map +1 -1
- package/dist/stt/sources/glass-bridge.d.ts +8 -15
- package/dist/stt/sources/glass-bridge.d.ts.map +1 -1
- package/dist/stt/sources/glass-bridge.js +66 -9
- package/dist/stt/sources/glass-bridge.js.map +1 -1
- package/dist/stt/sources/microphone.d.ts.map +1 -1
- package/dist/stt/sources/microphone.js +4 -0
- package/dist/stt/sources/microphone.js.map +1 -1
- package/dist/stt/types.d.ts +7 -3
- package/dist/stt/types.d.ts.map +1 -1
- package/glasses/bridge.ts +24 -3
- package/glasses/composer.ts +2 -2
- package/glasses/layout.ts +6 -0
- package/glasses/types.ts +28 -0
- package/glasses/useGlasses.ts +18 -5
- package/package.json +7 -19
- package/stt/debug.ts +38 -0
- package/stt/engine.ts +158 -83
- package/stt/index.ts +1 -0
- package/stt/providers/deepgram.ts +26 -9
- package/stt/providers/whisper-api.ts +78 -4
- package/stt/react/useSTT.ts +45 -11
- package/stt/registry.ts +0 -8
- package/stt/sources/glass-bridge.ts +69 -25
- package/stt/sources/microphone.ts +7 -0
- package/stt/types.ts +4 -3
- package/dist/stt/providers/web-speech.d.ts +0 -25
- package/dist/stt/providers/web-speech.d.ts.map +0 -1
- package/dist/stt/providers/web-speech.js +0 -153
- package/dist/stt/providers/web-speech.js.map +0 -1
- package/dist/stt/providers/whisper-local/provider.d.ts +0 -31
- package/dist/stt/providers/whisper-local/provider.d.ts.map +0 -1
- package/dist/stt/providers/whisper-local/provider.js +0 -174
- package/dist/stt/providers/whisper-local/provider.js.map +0 -1
- package/dist/stt/providers/whisper-local/worker.d.ts +0 -2
- package/dist/stt/providers/whisper-local/worker.d.ts.map +0 -1
- package/dist/stt/providers/whisper-local/worker.js +0 -35
- package/dist/stt/providers/whisper-local/worker.js.map +0 -1
- package/stt/providers/web-speech.ts +0 -221
- package/stt/providers/whisper-local/provider.ts +0 -226
- package/stt/providers/whisper-local/worker.ts +0 -40
|
@@ -7,8 +7,67 @@ import type {
|
|
|
7
7
|
STTError,
|
|
8
8
|
} from '../types';
|
|
9
9
|
import { float32ToWav } from '../audio/pcm-utils';
|
|
10
|
+
import { sttLog } from '../debug';
|
|
11
|
+
|
|
12
|
+
// Use proxy path to avoid WebView fetch restrictions (CORS/upload limits)
|
|
13
|
+
// The proxy is configured in vite.config.ts: /__whisper → api.openai.com
|
|
14
|
+
const WHISPER_API_URL = '/__whisper/v1/audio/transcriptions';
|
|
15
|
+
|
|
16
|
+
// Whisper hallucinates these on silence/low audio — filter them out
|
|
17
|
+
const HALLUCINATION_PATTERNS = [
|
|
18
|
+
/sottotitoli/i,
|
|
19
|
+
/amara\.org/i,
|
|
20
|
+
/qtss/i,
|
|
21
|
+
/continua\./i,
|
|
22
|
+
/al prossimo episodio/i,
|
|
23
|
+
/prossimo episodio/i,
|
|
24
|
+
/alla prossima/i,
|
|
25
|
+
/a presto/i,
|
|
26
|
+
/thank you for watching/i,
|
|
27
|
+
/thanks for watching/i,
|
|
28
|
+
/please subscribe/i,
|
|
29
|
+
/see you next time/i,
|
|
30
|
+
/see you in the next/i,
|
|
31
|
+
/next episode/i,
|
|
32
|
+
/sous-titres/i,
|
|
33
|
+
/untertitel/i,
|
|
34
|
+
/subtítulos/i,
|
|
35
|
+
/bis zum nächsten/i,
|
|
36
|
+
/字幕/,
|
|
37
|
+
/you$/i,
|
|
38
|
+
/^\s*$/,
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/** Common phrases Whisper appends at the end of audio — strip them */
|
|
42
|
+
const TRAILING_HALLUCINATIONS = [
|
|
43
|
+
/\s*al prossimo episodio\.?\s*$/i,
|
|
44
|
+
/\s*alla prossima\.?\s*$/i,
|
|
45
|
+
/\s*a presto\.?\s*$/i,
|
|
46
|
+
/\s*grazie per la visione\.?\s*$/i,
|
|
47
|
+
/\s*thank you for watching\.?\s*$/i,
|
|
48
|
+
/\s*thanks for watching\.?\s*$/i,
|
|
49
|
+
/\s*see you next time\.?\s*$/i,
|
|
50
|
+
/\s*see you in the next episode\.?\s*$/i,
|
|
51
|
+
/\s*please subscribe\.?\s*$/i,
|
|
52
|
+
/\s*bis zum nächsten mal\.?\s*$/i,
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/** Check if text is just dots, punctuation, or too short to be real speech */
|
|
56
|
+
function isJunkTranscription(text: string): boolean {
|
|
57
|
+
const cleaned = text.replace(/[\s.,!?;:…\-–—]+/g, '');
|
|
58
|
+
if (cleaned.length === 0) return true;
|
|
59
|
+
if (cleaned.length < 2) return true;
|
|
60
|
+
return HALLUCINATION_PATTERNS.some(p => p.test(text));
|
|
61
|
+
}
|
|
10
62
|
|
|
11
|
-
|
|
63
|
+
/** Strip trailing hallucination phrases from otherwise valid text */
|
|
64
|
+
function cleanTranscription(text: string): string {
|
|
65
|
+
let result = text;
|
|
66
|
+
for (const pattern of TRAILING_HALLUCINATIONS) {
|
|
67
|
+
result = result.replace(pattern, '');
|
|
68
|
+
}
|
|
69
|
+
return result.trim();
|
|
70
|
+
}
|
|
12
71
|
|
|
13
72
|
export class WhisperApiProvider implements STTProvider {
|
|
14
73
|
readonly type = 'whisper-api' as const;
|
|
@@ -29,11 +88,11 @@ export class WhisperApiProvider implements STTProvider {
|
|
|
29
88
|
|
|
30
89
|
async init(config: STTProviderConfig): Promise<void> {
|
|
31
90
|
this.apiKey = config.apiKey ?? '';
|
|
32
|
-
this.language = config.language ?? 'en';
|
|
91
|
+
this.language = (config.language ?? 'en').split('-')[0];
|
|
33
92
|
this.modelId = config.modelId ?? 'whisper-1';
|
|
34
93
|
|
|
35
94
|
if (!this.apiKey) {
|
|
36
|
-
const err: STTError = { code: 'not-allowed', message: 'API key
|
|
95
|
+
const err: STTError = { code: 'not-allowed', message: 'OpenAI API key required — set it in Settings', provider: this.type };
|
|
37
96
|
this.emitError(err);
|
|
38
97
|
throw new Error(err.message);
|
|
39
98
|
}
|
|
@@ -63,6 +122,7 @@ export class WhisperApiProvider implements STTProvider {
|
|
|
63
122
|
|
|
64
123
|
try {
|
|
65
124
|
const wavBlob = float32ToWav(audio, sampleRate);
|
|
125
|
+
sttLog('whisper-api: sending', (audio.length / sampleRate).toFixed(1), 's audio,', (wavBlob.size / 1024).toFixed(0), 'KB WAV');
|
|
66
126
|
|
|
67
127
|
const formData = new FormData();
|
|
68
128
|
formData.append('file', wavBlob, 'audio.wav');
|
|
@@ -88,8 +148,22 @@ export class WhisperApiProvider implements STTProvider {
|
|
|
88
148
|
|
|
89
149
|
const json = (await response.json()) as { text: string };
|
|
90
150
|
|
|
151
|
+
// Filter and clean Whisper hallucinations
|
|
152
|
+
const rawText = json.text?.trim() ?? '';
|
|
153
|
+
const text = cleanTranscription(rawText);
|
|
154
|
+
if (isJunkTranscription(text)) {
|
|
155
|
+
const transcript: STTTranscript = {
|
|
156
|
+
text: '',
|
|
157
|
+
isFinal: true,
|
|
158
|
+
confidence: 0,
|
|
159
|
+
timestamp: Date.now(),
|
|
160
|
+
};
|
|
161
|
+
this.setState('idle');
|
|
162
|
+
return transcript;
|
|
163
|
+
}
|
|
164
|
+
|
|
91
165
|
const transcript: STTTranscript = {
|
|
92
|
-
text
|
|
166
|
+
text,
|
|
93
167
|
isFinal: true,
|
|
94
168
|
confidence: 1,
|
|
95
169
|
timestamp: Date.now(),
|
package/stt/react/useSTT.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
2
2
|
import type { UseSTTConfig, UseSTTReturn, STTState, STTError } from '../types';
|
|
3
3
|
import { STTEngine } from '../engine';
|
|
4
|
+
import { sttLog } from '../debug';
|
|
4
5
|
|
|
5
6
|
export function useSTT(config: UseSTTConfig = {}): UseSTTReturn {
|
|
6
7
|
const [transcript, setTranscript] = useState('');
|
|
7
8
|
const [interimTranscript, setInterimTranscript] = useState('');
|
|
8
9
|
const [isListening, setIsListening] = useState(false);
|
|
9
10
|
const [isLoading, setIsLoading] = useState(false);
|
|
10
|
-
const [loadProgress] = useState(0);
|
|
11
11
|
const [error, setError] = useState<STTError | null>(null);
|
|
12
12
|
const [state, setState] = useState<STTState>('idle');
|
|
13
13
|
|
|
14
14
|
const engineRef = useRef<STTEngine | null>(null);
|
|
15
|
+
const busyRef = useRef(false); // prevent start/stop race
|
|
15
16
|
const configRef = useRef(config);
|
|
16
17
|
configRef.current = config;
|
|
17
18
|
|
|
@@ -24,31 +25,50 @@ export function useSTT(config: UseSTTConfig = {}): UseSTTReturn {
|
|
|
24
25
|
}, []);
|
|
25
26
|
|
|
26
27
|
const start = useCallback(async () => {
|
|
27
|
-
|
|
28
|
+
if (busyRef.current) {
|
|
29
|
+
sttLog('useSTT: start() blocked — busy');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
busyRef.current = true;
|
|
33
|
+
|
|
28
34
|
engineRef.current?.dispose();
|
|
29
35
|
|
|
30
36
|
const cfg = configRef.current;
|
|
37
|
+
|
|
38
|
+
sttLog('useSTT: start()', cfg.provider, 'apiKey?', !!cfg.apiKey);
|
|
31
39
|
const engine = new STTEngine({
|
|
32
|
-
provider: cfg.provider ?? '
|
|
40
|
+
provider: cfg.provider ?? 'whisper-api',
|
|
33
41
|
source: cfg.source,
|
|
34
42
|
language: cfg.language,
|
|
35
43
|
mode: cfg.mode,
|
|
36
44
|
apiKey: cfg.apiKey,
|
|
37
45
|
modelId: cfg.modelId,
|
|
38
46
|
continuous: cfg.continuous,
|
|
39
|
-
vad: cfg.vad,
|
|
47
|
+
vad: cfg.vad ?? true,
|
|
48
|
+
chunkIntervalMs: cfg.chunkIntervalMs,
|
|
40
49
|
fallback: cfg.fallback,
|
|
41
50
|
});
|
|
42
51
|
|
|
43
52
|
engineRef.current = engine;
|
|
44
53
|
|
|
45
|
-
//
|
|
54
|
+
// Accumulate final results for streaming providers
|
|
55
|
+
let accumulated = '';
|
|
56
|
+
|
|
46
57
|
engine.onTranscript((t) => {
|
|
47
58
|
if (t.isFinal) {
|
|
48
|
-
|
|
59
|
+
// Append final to accumulated text
|
|
60
|
+
const clean = t.text.replace(/\.+$/, '').trim();
|
|
61
|
+
if (clean) {
|
|
62
|
+
accumulated = accumulated ? accumulated + ' ' + clean : clean;
|
|
63
|
+
}
|
|
64
|
+
setTranscript(accumulated);
|
|
49
65
|
setInterimTranscript('');
|
|
50
66
|
} else {
|
|
51
|
-
|
|
67
|
+
// Interim: show accumulated + current interim
|
|
68
|
+
const clean = t.text.replace(/\.+$/, '').trim();
|
|
69
|
+
const full = accumulated ? accumulated + ' ' + clean : clean;
|
|
70
|
+
setInterimTranscript(full);
|
|
71
|
+
setTranscript(full);
|
|
52
72
|
}
|
|
53
73
|
cfg.onTranscript?.(t.text, t.isFinal);
|
|
54
74
|
});
|
|
@@ -57,29 +77,44 @@ export function useSTT(config: UseSTTConfig = {}): UseSTTReturn {
|
|
|
57
77
|
setState(s);
|
|
58
78
|
setIsListening(s === 'listening');
|
|
59
79
|
setIsLoading(s === 'loading');
|
|
60
|
-
if (s === 'idle') {
|
|
80
|
+
if (s === 'idle' || s === 'error') {
|
|
61
81
|
setInterimTranscript('');
|
|
82
|
+
busyRef.current = false;
|
|
62
83
|
}
|
|
63
84
|
});
|
|
64
85
|
|
|
65
86
|
engine.onError((e) => {
|
|
66
87
|
setError(e);
|
|
88
|
+
busyRef.current = false;
|
|
67
89
|
});
|
|
68
90
|
|
|
69
91
|
setError(null);
|
|
70
|
-
|
|
92
|
+
try {
|
|
93
|
+
await engine.start();
|
|
94
|
+
busyRef.current = false;
|
|
95
|
+
} catch {
|
|
96
|
+
busyRef.current = false;
|
|
97
|
+
}
|
|
71
98
|
}, []);
|
|
72
99
|
|
|
73
100
|
const stop = useCallback(() => {
|
|
74
|
-
|
|
101
|
+
sttLog('useSTT: stop()');
|
|
102
|
+
if (!engineRef.current) return;
|
|
103
|
+
// Stop mic immediately, then engine handles final transcription
|
|
104
|
+
engineRef.current.stop();
|
|
75
105
|
}, []);
|
|
76
106
|
|
|
77
107
|
const abort = useCallback(() => {
|
|
108
|
+
sttLog('useSTT: abort()');
|
|
78
109
|
engineRef.current?.abort();
|
|
110
|
+
busyRef.current = false;
|
|
79
111
|
}, []);
|
|
80
112
|
|
|
81
113
|
const reset = useCallback(() => {
|
|
114
|
+
sttLog('useSTT: reset()');
|
|
82
115
|
engineRef.current?.abort();
|
|
116
|
+
engineRef.current = null;
|
|
117
|
+
busyRef.current = false;
|
|
83
118
|
setTranscript('');
|
|
84
119
|
setInterimTranscript('');
|
|
85
120
|
setError(null);
|
|
@@ -102,7 +137,6 @@ export function useSTT(config: UseSTTConfig = {}): UseSTTReturn {
|
|
|
102
137
|
interimTranscript,
|
|
103
138
|
isListening,
|
|
104
139
|
isLoading,
|
|
105
|
-
loadProgress,
|
|
106
140
|
error,
|
|
107
141
|
state,
|
|
108
142
|
start,
|
package/stt/registry.ts
CHANGED
|
@@ -2,14 +2,6 @@ import type { STTProvider } from './types';
|
|
|
2
2
|
|
|
3
3
|
export async function createProvider(type: string): Promise<STTProvider> {
|
|
4
4
|
switch (type) {
|
|
5
|
-
case 'web-speech': {
|
|
6
|
-
const { WebSpeechProvider } = await import('./providers/web-speech');
|
|
7
|
-
return new WebSpeechProvider();
|
|
8
|
-
}
|
|
9
|
-
case 'whisper-local': {
|
|
10
|
-
const { WhisperLocalProvider } = await import('./providers/whisper-local/provider');
|
|
11
|
-
return new WhisperLocalProvider();
|
|
12
|
-
}
|
|
13
5
|
case 'whisper-api': {
|
|
14
6
|
const { WhisperApiProvider } = await import('./providers/whisper-api');
|
|
15
7
|
return new WhisperApiProvider();
|
|
@@ -1,46 +1,65 @@
|
|
|
1
1
|
import type { AudioSource } from '../types';
|
|
2
|
-
import {
|
|
2
|
+
import { sttLog } from '../debug';
|
|
3
3
|
|
|
4
4
|
const GLASS_SAMPLE_RATE = 16000;
|
|
5
5
|
|
|
6
|
-
export interface GlassBridgeSourceConfig {
|
|
7
|
-
/** The EvenHub bridge instance that fires audio events */
|
|
8
|
-
bridge: {
|
|
9
|
-
onEvent(handler: (event: GlassAudioEvent) => void): void;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface GlassAudioEvent {
|
|
14
|
-
audioEvent?: {
|
|
15
|
-
audioPcm?: Uint8Array;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
6
|
/**
|
|
20
7
|
* AudioSource for G2 smart glasses.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
8
|
+
*
|
|
9
|
+
* Automatically opens/closes the glasses microphone via the EvenHub SDK bridge
|
|
10
|
+
* and listens for PCM audio chunks from `audioEvent.audioPcm`.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* const source = new GlassBridgeSource();
|
|
14
|
+
* // It auto-detects the bridge from window.__evenBridge
|
|
23
15
|
*/
|
|
24
16
|
export class GlassBridgeSource implements AudioSource {
|
|
25
|
-
private config: GlassBridgeSourceConfig;
|
|
26
17
|
private listeners: Array<(pcm: Float32Array, sampleRate: number) => void> = [];
|
|
27
18
|
private listening = false;
|
|
28
|
-
|
|
29
|
-
constructor(config: GlassBridgeSourceConfig) {
|
|
30
|
-
this.config = config;
|
|
31
|
-
}
|
|
19
|
+
private bridge: any = null;
|
|
32
20
|
|
|
33
21
|
async start(): Promise<void> {
|
|
34
22
|
if (this.listening) return;
|
|
23
|
+
|
|
24
|
+
// Get bridge from global (set by useGlasses)
|
|
25
|
+
this.bridge = (window as any).__evenBridge ?? null;
|
|
26
|
+
sttLog('GlassBridgeSource.start()', 'bridge found:', !!this.bridge);
|
|
27
|
+
|
|
28
|
+
if (!this.bridge) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
'Glasses bridge not available. Make sure useGlasses is mounted and __evenBridge is set.'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
35
34
|
this.listening = true;
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
// Open the glasses microphone
|
|
37
|
+
try {
|
|
38
|
+
if (this.bridge.rawBridge?.audioControl) {
|
|
39
|
+
sttLog('GlassBridgeSource', 'calling audioControl(true)');
|
|
40
|
+
await this.bridge.rawBridge.audioControl(true);
|
|
41
|
+
sttLog('GlassBridgeSource', 'audioControl(true) succeeded');
|
|
42
|
+
} else if (this.bridge.rawBridge?.callEvenApp) {
|
|
43
|
+
sttLog('GlassBridgeSource', 'calling callEvenApp("audioControl", {isOpen: true})');
|
|
44
|
+
await this.bridge.rawBridge.callEvenApp('audioControl', { isOpen: true });
|
|
45
|
+
sttLog('GlassBridgeSource', 'callEvenApp audioControl succeeded');
|
|
46
|
+
} else {
|
|
47
|
+
sttLog('GlassBridgeSource', 'WARNING: no audioControl method found on bridge');
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
sttLog('GlassBridgeSource', 'audioControl(true) error:', err);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Listen for audio PCM events
|
|
54
|
+
this.bridge.onEvent((event: any) => {
|
|
38
55
|
if (!this.listening) return;
|
|
39
|
-
const audioPcm = event
|
|
56
|
+
const audioPcm = event?.audioEvent?.audioPcm;
|
|
40
57
|
if (!audioPcm || audioPcm.length === 0) return;
|
|
41
58
|
|
|
42
|
-
|
|
43
|
-
|
|
59
|
+
sttLog('GlassBridgeSource', 'got audioPcm chunk, bytes:', audioPcm.length);
|
|
60
|
+
|
|
61
|
+
// Convert Uint8Array (16-bit PCM little-endian) to Float32Array
|
|
62
|
+
const float32 = pcm16ToFloat32(audioPcm);
|
|
44
63
|
|
|
45
64
|
for (const cb of this.listeners) {
|
|
46
65
|
cb(float32, GLASS_SAMPLE_RATE);
|
|
@@ -49,7 +68,21 @@ export class GlassBridgeSource implements AudioSource {
|
|
|
49
68
|
}
|
|
50
69
|
|
|
51
70
|
stop(): void {
|
|
71
|
+
sttLog('GlassBridgeSource.stop()');
|
|
52
72
|
this.listening = false;
|
|
73
|
+
|
|
74
|
+
// Close the glasses microphone
|
|
75
|
+
if (this.bridge) {
|
|
76
|
+
try {
|
|
77
|
+
if (this.bridge.rawBridge?.audioControl) {
|
|
78
|
+
this.bridge.rawBridge.audioControl(false);
|
|
79
|
+
} else if (this.bridge.rawBridge?.callEvenApp) {
|
|
80
|
+
this.bridge.rawBridge.callEvenApp('audioControl', { isOpen: false });
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
sttLog('GlassBridgeSource', 'audioControl(false) error:', err);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
53
86
|
}
|
|
54
87
|
|
|
55
88
|
onAudioData(cb: (pcm: Float32Array, sampleRate: number) => void): () => void {
|
|
@@ -65,3 +98,14 @@ export class GlassBridgeSource implements AudioSource {
|
|
|
65
98
|
this.listeners.length = 0;
|
|
66
99
|
}
|
|
67
100
|
}
|
|
101
|
+
|
|
102
|
+
/** Convert raw bytes (16-bit PCM little-endian) to Float32Array */
|
|
103
|
+
function pcm16ToFloat32(bytes: Uint8Array): Float32Array {
|
|
104
|
+
const samples = bytes.length / 2;
|
|
105
|
+
const float32 = new Float32Array(samples);
|
|
106
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
107
|
+
for (let i = 0; i < samples; i++) {
|
|
108
|
+
float32[i] = view.getInt16(i * 2, true) / 32768;
|
|
109
|
+
}
|
|
110
|
+
return float32;
|
|
111
|
+
}
|
|
@@ -15,6 +15,13 @@ export class MicrophoneSource implements AudioSource {
|
|
|
15
15
|
private listeners: Array<(pcm: Float32Array, sampleRate: number) => void> = [];
|
|
16
16
|
|
|
17
17
|
async start(): Promise<void> {
|
|
18
|
+
if (!navigator.mediaDevices?.getUserMedia) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
'getUserMedia not available — likely running in a WebView. ' +
|
|
21
|
+
'Use glass-bridge source or pass a custom AudioSource instead.'
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
this.stream = await navigator.mediaDevices.getUserMedia({
|
|
19
26
|
audio: { sampleRate: DEFAULT_SAMPLE_RATE, channelCount: 1 },
|
|
20
27
|
});
|
package/stt/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// ── STT Provider Types ──
|
|
2
2
|
|
|
3
|
-
export type STTProviderType = '
|
|
3
|
+
export type STTProviderType = 'whisper-api' | 'deepgram' | string;
|
|
4
4
|
export type STTMode = 'streaming' | 'batch';
|
|
5
5
|
export type STTState = 'idle' | 'loading' | 'listening' | 'processing' | 'error';
|
|
6
6
|
|
|
@@ -70,6 +70,7 @@ export interface STTEngineConfig {
|
|
|
70
70
|
continuous?: boolean;
|
|
71
71
|
vad?: boolean | { silenceMs?: number; thresholdDb?: number };
|
|
72
72
|
sampleRate?: number;
|
|
73
|
+
chunkIntervalMs?: number;
|
|
73
74
|
fallback?: STTProviderType;
|
|
74
75
|
}
|
|
75
76
|
|
|
@@ -83,7 +84,8 @@ export interface UseSTTConfig {
|
|
|
83
84
|
apiKey?: string;
|
|
84
85
|
modelId?: string;
|
|
85
86
|
continuous?: boolean;
|
|
86
|
-
vad?: boolean;
|
|
87
|
+
vad?: boolean | { silenceMs?: number; thresholdDb?: number };
|
|
88
|
+
chunkIntervalMs?: number;
|
|
87
89
|
autoStart?: boolean;
|
|
88
90
|
fallback?: STTProviderType;
|
|
89
91
|
onTranscript?: (text: string, isFinal: boolean) => void;
|
|
@@ -94,7 +96,6 @@ export interface UseSTTReturn {
|
|
|
94
96
|
interimTranscript: string;
|
|
95
97
|
isListening: boolean;
|
|
96
98
|
isLoading: boolean;
|
|
97
|
-
loadProgress: number;
|
|
98
99
|
error: STTError | null;
|
|
99
100
|
state: STTState;
|
|
100
101
|
start: () => Promise<void>;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { STTProvider, STTProviderConfig, STTMode, STTState, STTTranscript, STTError } from '../types';
|
|
2
|
-
export declare class WebSpeechProvider implements STTProvider {
|
|
3
|
-
readonly type: "web-speech";
|
|
4
|
-
readonly supportedModes: STTMode[];
|
|
5
|
-
private _state;
|
|
6
|
-
private recognition;
|
|
7
|
-
private config;
|
|
8
|
-
private stopping;
|
|
9
|
-
private transcriptCbs;
|
|
10
|
-
private stateCbs;
|
|
11
|
-
private errorCbs;
|
|
12
|
-
get state(): STTState;
|
|
13
|
-
init(config: STTProviderConfig): Promise<void>;
|
|
14
|
-
start(): void;
|
|
15
|
-
stop(): void;
|
|
16
|
-
abort(): void;
|
|
17
|
-
dispose(): void;
|
|
18
|
-
onTranscript(cb: (t: STTTranscript) => void): () => void;
|
|
19
|
-
onStateChange(cb: (s: STTState) => void): () => void;
|
|
20
|
-
onError(cb: (e: STTError) => void): () => void;
|
|
21
|
-
private setState;
|
|
22
|
-
private emitTranscript;
|
|
23
|
-
private emitError;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=web-speech.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"web-speech.d.ts","sourceRoot":"","sources":["../../../stt/providers/web-speech.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,QAAQ,EACR,aAAa,EACb,QAAQ,EACT,MAAM,UAAU,CAAC;AAuDlB,qBAAa,iBAAkB,YAAW,WAAW;IACnD,QAAQ,CAAC,IAAI,eAAyB;IACtC,QAAQ,CAAC,cAAc,EAAE,OAAO,EAAE,CAAiB;IAEnD,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,WAAW,CAA0C;IAC7D,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,QAAQ,CAAoC;IAEpD,IAAI,KAAK,IAAI,QAAQ,CAEpB;IAEK,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IASpD,KAAK,IAAI,IAAI;IA2Db,IAAI,IAAI,IAAI;IAOZ,KAAK,IAAI,IAAI;IAOb,OAAO,IAAI,IAAI;IAOf,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI;IAOxD,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,MAAM,IAAI;IAOpD,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,MAAM,IAAI;IAS9C,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,SAAS;CAGlB"}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
function getSpeechRecognitionCtor() {
|
|
2
|
-
if (typeof window === 'undefined')
|
|
3
|
-
return null;
|
|
4
|
-
const w = window;
|
|
5
|
-
return (w.SpeechRecognition ?? w.webkitSpeechRecognition);
|
|
6
|
-
}
|
|
7
|
-
// ── Provider ──
|
|
8
|
-
export class WebSpeechProvider {
|
|
9
|
-
constructor() {
|
|
10
|
-
this.type = 'web-speech';
|
|
11
|
-
this.supportedModes = ['streaming'];
|
|
12
|
-
this._state = 'idle';
|
|
13
|
-
this.recognition = null;
|
|
14
|
-
this.config = {};
|
|
15
|
-
this.stopping = false;
|
|
16
|
-
this.transcriptCbs = [];
|
|
17
|
-
this.stateCbs = [];
|
|
18
|
-
this.errorCbs = [];
|
|
19
|
-
}
|
|
20
|
-
get state() {
|
|
21
|
-
return this._state;
|
|
22
|
-
}
|
|
23
|
-
async init(config) {
|
|
24
|
-
const Ctor = getSpeechRecognitionCtor();
|
|
25
|
-
if (!Ctor) {
|
|
26
|
-
this.emitError({ code: 'unsupported', message: 'SpeechRecognition not available in this browser', provider: this.type });
|
|
27
|
-
throw new Error('SpeechRecognition not supported');
|
|
28
|
-
}
|
|
29
|
-
this.config = config;
|
|
30
|
-
}
|
|
31
|
-
start() {
|
|
32
|
-
const Ctor = getSpeechRecognitionCtor();
|
|
33
|
-
if (!Ctor) {
|
|
34
|
-
this.emitError({ code: 'unsupported', message: 'SpeechRecognition not available', provider: this.type });
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
// Tear down previous instance if any
|
|
38
|
-
if (this.recognition) {
|
|
39
|
-
try {
|
|
40
|
-
this.recognition.abort();
|
|
41
|
-
}
|
|
42
|
-
catch { /* ignore */ }
|
|
43
|
-
}
|
|
44
|
-
this.stopping = false;
|
|
45
|
-
const recognition = new Ctor();
|
|
46
|
-
recognition.continuous = this.config.continuous ?? true;
|
|
47
|
-
recognition.interimResults = true;
|
|
48
|
-
recognition.lang = this.config.language ?? 'en-US';
|
|
49
|
-
recognition.onstart = () => {
|
|
50
|
-
this.setState('listening');
|
|
51
|
-
};
|
|
52
|
-
recognition.onresult = (event) => {
|
|
53
|
-
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
54
|
-
const result = event.results[i];
|
|
55
|
-
if (!result?.[0])
|
|
56
|
-
continue;
|
|
57
|
-
const transcript = {
|
|
58
|
-
text: result[0].transcript,
|
|
59
|
-
isFinal: result.isFinal,
|
|
60
|
-
confidence: result[0].confidence ?? 0,
|
|
61
|
-
timestamp: Date.now(),
|
|
62
|
-
};
|
|
63
|
-
this.emitTranscript(transcript);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
recognition.onerror = (event) => {
|
|
67
|
-
// Suppress no-speech and aborted-while-stopping
|
|
68
|
-
if (event.error === 'no-speech')
|
|
69
|
-
return;
|
|
70
|
-
if (event.error === 'aborted' && this.stopping)
|
|
71
|
-
return;
|
|
72
|
-
const code = mapErrorCode(event.error);
|
|
73
|
-
this.emitError({ code, message: event.message || event.error, provider: this.type });
|
|
74
|
-
if (code !== 'no-speech') {
|
|
75
|
-
this.setState('error');
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
recognition.onend = () => {
|
|
79
|
-
this.recognition = null;
|
|
80
|
-
this.setState('idle');
|
|
81
|
-
};
|
|
82
|
-
this.recognition = recognition;
|
|
83
|
-
recognition.start();
|
|
84
|
-
}
|
|
85
|
-
stop() {
|
|
86
|
-
this.stopping = true;
|
|
87
|
-
if (this.recognition) {
|
|
88
|
-
this.recognition.stop();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
abort() {
|
|
92
|
-
this.stopping = true;
|
|
93
|
-
if (this.recognition) {
|
|
94
|
-
this.recognition.abort();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
dispose() {
|
|
98
|
-
this.abort();
|
|
99
|
-
this.transcriptCbs = [];
|
|
100
|
-
this.stateCbs = [];
|
|
101
|
-
this.errorCbs = [];
|
|
102
|
-
}
|
|
103
|
-
onTranscript(cb) {
|
|
104
|
-
this.transcriptCbs.push(cb);
|
|
105
|
-
return () => {
|
|
106
|
-
this.transcriptCbs = this.transcriptCbs.filter((c) => c !== cb);
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
onStateChange(cb) {
|
|
110
|
-
this.stateCbs.push(cb);
|
|
111
|
-
return () => {
|
|
112
|
-
this.stateCbs = this.stateCbs.filter((c) => c !== cb);
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
onError(cb) {
|
|
116
|
-
this.errorCbs.push(cb);
|
|
117
|
-
return () => {
|
|
118
|
-
this.errorCbs = this.errorCbs.filter((c) => c !== cb);
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
// ── Private helpers ──
|
|
122
|
-
setState(s) {
|
|
123
|
-
if (this._state === s)
|
|
124
|
-
return;
|
|
125
|
-
this._state = s;
|
|
126
|
-
for (const cb of this.stateCbs)
|
|
127
|
-
cb(s);
|
|
128
|
-
}
|
|
129
|
-
emitTranscript(t) {
|
|
130
|
-
for (const cb of this.transcriptCbs)
|
|
131
|
-
cb(t);
|
|
132
|
-
}
|
|
133
|
-
emitError(e) {
|
|
134
|
-
for (const cb of this.errorCbs)
|
|
135
|
-
cb(e);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function mapErrorCode(error) {
|
|
139
|
-
switch (error) {
|
|
140
|
-
case 'not-allowed':
|
|
141
|
-
case 'service-not-allowed':
|
|
142
|
-
return 'not-allowed';
|
|
143
|
-
case 'no-speech':
|
|
144
|
-
return 'no-speech';
|
|
145
|
-
case 'network':
|
|
146
|
-
return 'network';
|
|
147
|
-
case 'aborted':
|
|
148
|
-
return 'aborted';
|
|
149
|
-
default:
|
|
150
|
-
return 'unknown';
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
//# sourceMappingURL=web-speech.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"web-speech.js","sourceRoot":"","sources":["../../../stt/providers/web-speech.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { STTProvider, STTProviderConfig, STTMode, STTState, STTTranscript, STTError } from '../../types';
|
|
2
|
-
export declare class WhisperLocalProvider implements STTProvider {
|
|
3
|
-
readonly type: "whisper-local";
|
|
4
|
-
readonly supportedModes: STTMode[];
|
|
5
|
-
private _state;
|
|
6
|
-
private worker;
|
|
7
|
-
private config;
|
|
8
|
-
private ready;
|
|
9
|
-
private transcriptCbs;
|
|
10
|
-
private stateCbs;
|
|
11
|
-
private errorCbs;
|
|
12
|
-
private pendingResolve;
|
|
13
|
-
private pendingReject;
|
|
14
|
-
private initResolve;
|
|
15
|
-
private initReject;
|
|
16
|
-
get state(): STTState;
|
|
17
|
-
init(config: STTProviderConfig): Promise<void>;
|
|
18
|
-
start(): void;
|
|
19
|
-
stop(): void;
|
|
20
|
-
abort(): void;
|
|
21
|
-
dispose(): void;
|
|
22
|
-
transcribe(audio: Float32Array, sampleRate: number): Promise<STTTranscript>;
|
|
23
|
-
onTranscript(cb: (t: STTTranscript) => void): () => void;
|
|
24
|
-
onStateChange(cb: (s: STTState) => void): () => void;
|
|
25
|
-
onError(cb: (e: STTError) => void): () => void;
|
|
26
|
-
private handleWorkerMessage;
|
|
27
|
-
private setState;
|
|
28
|
-
private emitTranscript;
|
|
29
|
-
private emitError;
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../../stt/providers/whisper-local/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,QAAQ,EACR,aAAa,EACb,QAAQ,EACT,MAAM,aAAa,CAAC;AAkBrB,qBAAa,oBAAqB,YAAW,WAAW;IACtD,QAAQ,CAAC,IAAI,kBAA4B;IACzC,QAAQ,CAAC,cAAc,EAAE,OAAO,EAAE,CAAa;IAE/C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,KAAK,CAAS;IAEtB,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,QAAQ,CAAoC;IAEpD,OAAO,CAAC,cAAc,CAA6C;IACnE,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAAqC;IAEvD,IAAI,KAAK,IAAI,QAAQ,CAEpB;IAEK,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCpD,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,IAAI;IAMZ,KAAK,IAAI,IAAI;IASb,OAAO,IAAI,IAAI;IAYT,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAkBjF,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI;IAKxD,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,MAAM,IAAI;IAKpD,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,MAAM,IAAI;IAO9C,OAAO,CAAC,mBAAmB;IA0D3B,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,SAAS;CAGlB"}
|