ugly-app 0.1.282 → 0.1.283

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.
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.282";
1
+ export declare const CLI_VERSION = "0.1.283";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.282";
2
+ export const CLI_VERSION = "0.1.283";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRecorder.d.ts","sourceRoot":"","sources":["../../../src/client/audio/AudioRecorder.ts"],"names":[],"mappings":"AA8BA,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAA2C;IAE1D,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,KAAK,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAgClE,IAAI,IAAI,IAAI;CAWb"}
1
+ {"version":3,"file":"AudioRecorder.d.ts","sourceRoot":"","sources":["../../../src/client/audio/AudioRecorder.ts"],"names":[],"mappings":"AA8BA,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAA2C;IAE1D,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,KAAK,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA2DlE,IAAI,IAAI,IAAI;CAYb"}
@@ -40,6 +40,7 @@ export class AudioRecorder {
40
40
  if (this._listening)
41
41
  return;
42
42
  this.onChunk = onChunk;
43
+ console.log('[AudioRecorder] requesting mic access…');
43
44
  this.stream = await navigator.mediaDevices.getUserMedia({
44
45
  audio: {
45
46
  sampleRate: TARGET_SAMPLE_RATE,
@@ -48,13 +49,35 @@ export class AudioRecorder {
48
49
  noiseSuppression: true,
49
50
  },
50
51
  });
52
+ const track = this.stream.getAudioTracks()[0];
53
+ if (track) {
54
+ const settings = track.getSettings();
55
+ console.log(`[AudioRecorder] mic acquired: ${track.label} (${settings.sampleRate ?? '?'}Hz, ${settings.channelCount ?? '?'}ch)`);
56
+ }
51
57
  this.ctx = new AudioContext({ sampleRate: TARGET_SAMPLE_RATE });
58
+ console.log(`[AudioRecorder] AudioContext state=${this.ctx.state} sampleRate=${this.ctx.sampleRate}`);
52
59
  const source = this.ctx.createMediaStreamSource(this.stream);
53
60
  await this.ctx.audioWorklet.addModule(WORKLET_URL);
61
+ console.log('[AudioRecorder] worklet loaded');
54
62
  this.worklet = new AudioWorkletNode(this.ctx, 'audio-recorder');
63
+ let chunkCount = 0;
64
+ let silentChunks = 0;
55
65
  this.worklet.port.onmessage = (event) => {
56
66
  if (event.data?.type === 'chunk') {
57
67
  const floatData = event.data.samples;
68
+ chunkCount++;
69
+ // Check for silence (all samples near zero)
70
+ let maxAbs = 0;
71
+ for (let i = 0; i < floatData.length; i += 64) {
72
+ const abs = Math.abs(floatData[i] ?? 0);
73
+ if (abs > maxAbs)
74
+ maxAbs = abs;
75
+ }
76
+ if (maxAbs < 0.001)
77
+ silentChunks++;
78
+ if (chunkCount <= 3 || chunkCount % 100 === 0) {
79
+ console.log(`[AudioRecorder] chunk #${chunkCount} maxAbs=${maxAbs.toFixed(4)} silentChunks=${silentChunks}/${chunkCount}`);
80
+ }
58
81
  const int16 = float32ToInt16(floatData);
59
82
  const base64 = arrayBufferToBase64(int16.buffer);
60
83
  this.onChunk?.(base64);
@@ -63,10 +86,12 @@ export class AudioRecorder {
63
86
  source.connect(this.worklet);
64
87
  this.worklet.connect(this.ctx.destination);
65
88
  this._listening = true;
89
+ console.log('[AudioRecorder] recording started');
66
90
  }
67
91
  stop() {
68
92
  if (!this._listening)
69
93
  return;
94
+ console.log('[AudioRecorder] stopping');
70
95
  this.worklet?.disconnect();
71
96
  this.stream?.getTracks().forEach((t) => t.stop());
72
97
  this.ctx?.close().catch(() => { });
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRecorder.js","sourceRoot":"","sources":["../../../src/client/audio/AudioRecorder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AudioRecorder.js","sourceRoot":"","sources":["../../../src/client/audio/AudioRecorder.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBpB,CAAC;AACF,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC,CAAC;AAClF,MAAM,WAAW,GAAG,GAAG,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;AACtD,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,MAAM,OAAO,aAAa;IAChB,GAAG,GAAwB,IAAI,CAAC;IAChC,MAAM,GAAuB,IAAI,CAAC;IAClC,OAAO,GAA4B,IAAI,CAAC;IACxC,UAAU,GAAG,KAAK,CAAC;IACnB,OAAO,GAAsC,IAAI,CAAC;IAE1D,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAsC;QAChD,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;YACtD,KAAK,EAAE;gBACL,UAAU,EAAE,kBAAkB;gBAC9B,YAAY,EAAE,CAAC;gBACf,gBAAgB,EAAE,IAAI;gBACtB,gBAAgB,EAAE,IAAI;aACvB;SACF,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,iCAAiC,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,UAAU,IAAI,GAAG,OAAO,QAAQ,CAAC,YAAY,IAAI,GAAG,KAAK,CAAC,CAAC;QACnI,CAAC;QAED,IAAI,CAAC,GAAG,GAAG,IAAI,YAAY,CAAC,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,sCAAsC,IAAI,CAAC,GAAG,CAAC,KAAK,eAAe,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QACtG,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7D,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAEhE,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;YACpD,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;gBACjC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,OAAuB,CAAC;gBACrD,UAAU,EAAE,CAAC;gBAEb,4CAA4C;gBAC5C,IAAI,MAAM,GAAG,CAAC,CAAC;gBACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;oBACxC,IAAI,GAAG,GAAG,MAAM;wBAAE,MAAM,GAAG,GAAG,CAAC;gBACjC,CAAC;gBACD,IAAI,MAAM,GAAG,KAAK;oBAAE,YAAY,EAAE,CAAC;gBAEnC,IAAI,UAAU,IAAI,CAAC,IAAI,UAAU,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC;oBAC9C,OAAO,CAAC,GAAG,CAAC,0BAA0B,UAAU,WAAW,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,YAAY,IAAI,UAAU,EAAE,CAAC,CAAC;gBAC7H,CAAC;gBAED,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;gBACxC,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAqB,CAAC,CAAC;gBAChE,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;YACzB,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACnD,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAC7B,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;CACF;AAED,SAAS,cAAc,CAAC,OAAqB;IAC3C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3D,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAmB;IAC9C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QACnC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useSTT.d.ts","sourceRoot":"","sources":["../../../src/client/audio/useSTT.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,GAAE,UAAe;;;;;;;EAuGrE"}
1
+ {"version":3,"file":"useSTT.d.ts","sourceRoot":"","sources":["../../../src/client/audio/useSTT.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,GAAE,UAAe;;;;;;;EA+HrE"}
@@ -28,20 +28,27 @@ export function useSTT(socket, options = {}) {
28
28
  setIsFinal(false);
29
29
  setError(null);
30
30
  setListening(true);
31
+ const mode = options.mode ?? 'auto';
32
+ console.log(`[STT] start streamId=${streamId} mode=${mode} lang=${options.lang ?? 'auto'}`);
31
33
  await socket.acquire();
34
+ console.log('[STT] socket acquired');
32
35
  cleanupListeners();
36
+ let chunkCount = 0;
33
37
  unsubsRef.current.push(socket.on('stt:ready', (data) => {
34
38
  if (data.streamId !== streamId)
35
39
  return;
40
+ console.log(`[STT] ready streamId=${streamId}`);
36
41
  readyRef.current = true;
37
42
  }), socket.on('stt:transcript', (data) => {
38
43
  if (data.streamId !== streamId)
39
44
  return;
45
+ console.log(`[STT] transcript isFinal=${data.isFinal} text="${data.text}" (after ${chunkCount} chunks)`);
40
46
  setTranscript(data.text);
41
47
  setIsFinal(data.isFinal);
42
48
  }), socket.on('stt:error', (data) => {
43
49
  if (data.streamId !== streamId)
44
50
  return;
51
+ console.error(`[STT] error streamId=${streamId}: ${data.message}`);
45
52
  setError(data.message);
46
53
  setListening(false);
47
54
  cleanupListeners();
@@ -49,34 +56,49 @@ export function useSTT(socket, options = {}) {
49
56
  }), socket.on('stt:stopped', (data) => {
50
57
  if (data.streamId !== streamId)
51
58
  return;
59
+ console.log(`[STT] stopped streamId=${streamId} (sent ${chunkCount} audio chunks)`);
52
60
  setListening(false);
53
61
  cleanupListeners();
54
62
  socket.release();
55
63
  }));
56
64
  socket.send('stt:start', {
57
65
  streamId,
58
- mode: options.mode ?? 'auto',
66
+ mode,
59
67
  lang: options.lang,
60
68
  });
61
69
  // Wait for stt:ready (timeout after 5s)
70
+ const readyStart = Date.now();
62
71
  await new Promise((resolve) => {
63
- const startTime = Date.now();
64
72
  const poll = setInterval(() => {
65
- if (readyRef.current || Date.now() - startTime > 5000) {
73
+ if (readyRef.current || Date.now() - readyStart > 5000) {
66
74
  clearInterval(poll);
67
75
  resolve();
68
76
  }
69
77
  }, 50);
70
78
  });
71
- if (cancelledRef.current)
79
+ if (!readyRef.current) {
80
+ console.warn(`[STT] ready timeout after ${Date.now() - readyStart}ms — proceeding anyway`);
81
+ }
82
+ else {
83
+ console.log(`[STT] ready in ${Date.now() - readyStart}ms`);
84
+ }
85
+ if (cancelledRef.current) {
86
+ console.log('[STT] cancelled before recording started');
72
87
  return;
88
+ }
73
89
  if (!recorderRef.current)
74
90
  recorderRef.current = new AudioRecorder();
75
91
  await recorderRef.current.start((audio) => {
92
+ chunkCount++;
93
+ if (chunkCount <= 3 || chunkCount % 50 === 0) {
94
+ console.log(`[STT] audio chunk #${chunkCount} (${audio.length} b64 chars)`);
95
+ }
76
96
  socket.send('stt:audio', { streamId, audio });
77
97
  });
98
+ console.log('[STT] recording started');
78
99
  }, [socket, listening, options.mode, options.lang]);
79
100
  const stop = useCallback(() => {
101
+ console.log(`[STT] stop streamId=${streamIdRef.current}`);
80
102
  cancelledRef.current = true;
81
103
  recorderRef.current?.stop();
82
104
  if (streamIdRef.current) {
@@ -1 +1 @@
1
- {"version":3,"file":"useSTT.js","sourceRoot":"","sources":["../../../src/client/audio/useSTT.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSTT.js","sourceRoot":"","sources":["../../../src/client/audio/useSTT.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.282",
3
+ "version": "0.1.283",
4
4
  "type": "module",
5
5
  "main": "./dist/server/index.js",
6
6
  "exports": {
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.282";
2
+ export const CLI_VERSION = "0.1.283";
@@ -43,6 +43,7 @@ export class AudioRecorder {
43
43
  if (this._listening) return;
44
44
  this.onChunk = onChunk;
45
45
 
46
+ console.log('[AudioRecorder] requesting mic access…');
46
47
  this.stream = await navigator.mediaDevices.getUserMedia({
47
48
  audio: {
48
49
  sampleRate: TARGET_SAMPLE_RATE,
@@ -52,14 +53,39 @@ export class AudioRecorder {
52
53
  },
53
54
  });
54
55
 
56
+ const track = this.stream.getAudioTracks()[0];
57
+ if (track) {
58
+ const settings = track.getSettings();
59
+ console.log(`[AudioRecorder] mic acquired: ${track.label} (${settings.sampleRate ?? '?'}Hz, ${settings.channelCount ?? '?'}ch)`);
60
+ }
61
+
55
62
  this.ctx = new AudioContext({ sampleRate: TARGET_SAMPLE_RATE });
63
+ console.log(`[AudioRecorder] AudioContext state=${this.ctx.state} sampleRate=${this.ctx.sampleRate}`);
56
64
  const source = this.ctx.createMediaStreamSource(this.stream);
57
65
 
58
66
  await this.ctx.audioWorklet.addModule(WORKLET_URL);
67
+ console.log('[AudioRecorder] worklet loaded');
59
68
  this.worklet = new AudioWorkletNode(this.ctx, 'audio-recorder');
69
+
70
+ let chunkCount = 0;
71
+ let silentChunks = 0;
60
72
  this.worklet.port.onmessage = (event: MessageEvent) => {
61
73
  if (event.data?.type === 'chunk') {
62
74
  const floatData = event.data.samples as Float32Array;
75
+ chunkCount++;
76
+
77
+ // Check for silence (all samples near zero)
78
+ let maxAbs = 0;
79
+ for (let i = 0; i < floatData.length; i += 64) {
80
+ const abs = Math.abs(floatData[i] ?? 0);
81
+ if (abs > maxAbs) maxAbs = abs;
82
+ }
83
+ if (maxAbs < 0.001) silentChunks++;
84
+
85
+ if (chunkCount <= 3 || chunkCount % 100 === 0) {
86
+ console.log(`[AudioRecorder] chunk #${chunkCount} maxAbs=${maxAbs.toFixed(4)} silentChunks=${silentChunks}/${chunkCount}`);
87
+ }
88
+
63
89
  const int16 = float32ToInt16(floatData);
64
90
  const base64 = arrayBufferToBase64(int16.buffer as ArrayBuffer);
65
91
  this.onChunk?.(base64);
@@ -69,10 +95,12 @@ export class AudioRecorder {
69
95
  source.connect(this.worklet);
70
96
  this.worklet.connect(this.ctx.destination);
71
97
  this._listening = true;
98
+ console.log('[AudioRecorder] recording started');
72
99
  }
73
100
 
74
101
  stop(): void {
75
102
  if (!this._listening) return;
103
+ console.log('[AudioRecorder] stopping');
76
104
  this.worklet?.disconnect();
77
105
  this.stream?.getTracks().forEach((t) => t.stop());
78
106
  this.ctx?.close().catch(() => {});
@@ -38,21 +38,29 @@ export function useSTT(socket: UglyBotSocket, options: STTOptions = {}) {
38
38
  setError(null);
39
39
  setListening(true);
40
40
 
41
+ const mode = options.mode ?? 'auto';
42
+ console.log(`[STT] start streamId=${streamId} mode=${mode} lang=${options.lang ?? 'auto'}`);
43
+
41
44
  await socket.acquire();
45
+ console.log('[STT] socket acquired');
42
46
 
43
47
  cleanupListeners();
48
+ let chunkCount = 0;
44
49
  unsubsRef.current.push(
45
50
  socket.on('stt:ready', (data) => {
46
51
  if (data.streamId !== streamId) return;
52
+ console.log(`[STT] ready streamId=${streamId}`);
47
53
  readyRef.current = true;
48
54
  }),
49
55
  socket.on('stt:transcript', (data) => {
50
56
  if (data.streamId !== streamId) return;
57
+ console.log(`[STT] transcript isFinal=${data.isFinal} text="${data.text}" (after ${chunkCount} chunks)`);
51
58
  setTranscript(data.text);
52
59
  setIsFinal(data.isFinal);
53
60
  }),
54
61
  socket.on('stt:error', (data) => {
55
62
  if (data.streamId !== streamId) return;
63
+ console.error(`[STT] error streamId=${streamId}: ${data.message}`);
56
64
  setError(data.message);
57
65
  setListening(false);
58
66
  cleanupListeners();
@@ -60,6 +68,7 @@ export function useSTT(socket: UglyBotSocket, options: STTOptions = {}) {
60
68
  }),
61
69
  socket.on('stt:stopped', (data) => {
62
70
  if (data.streamId !== streamId) return;
71
+ console.log(`[STT] stopped streamId=${streamId} (sent ${chunkCount} audio chunks)`);
63
72
  setListening(false);
64
73
  cleanupListeners();
65
74
  socket.release();
@@ -68,30 +77,45 @@ export function useSTT(socket: UglyBotSocket, options: STTOptions = {}) {
68
77
 
69
78
  socket.send('stt:start', {
70
79
  streamId,
71
- mode: options.mode ?? 'auto',
80
+ mode,
72
81
  lang: options.lang,
73
82
  });
74
83
 
75
84
  // Wait for stt:ready (timeout after 5s)
85
+ const readyStart = Date.now();
76
86
  await new Promise<void>((resolve) => {
77
- const startTime = Date.now();
78
87
  const poll = setInterval(() => {
79
- if (readyRef.current || Date.now() - startTime > 5000) {
88
+ if (readyRef.current || Date.now() - readyStart > 5000) {
80
89
  clearInterval(poll);
81
90
  resolve();
82
91
  }
83
92
  }, 50);
84
93
  });
85
94
 
86
- if (cancelledRef.current) return;
95
+ if (!readyRef.current) {
96
+ console.warn(`[STT] ready timeout after ${Date.now() - readyStart}ms — proceeding anyway`);
97
+ } else {
98
+ console.log(`[STT] ready in ${Date.now() - readyStart}ms`);
99
+ }
100
+
101
+ if (cancelledRef.current) {
102
+ console.log('[STT] cancelled before recording started');
103
+ return;
104
+ }
87
105
 
88
106
  if (!recorderRef.current) recorderRef.current = new AudioRecorder();
89
107
  await recorderRef.current.start((audio) => {
108
+ chunkCount++;
109
+ if (chunkCount <= 3 || chunkCount % 50 === 0) {
110
+ console.log(`[STT] audio chunk #${chunkCount} (${audio.length} b64 chars)`);
111
+ }
90
112
  socket.send('stt:audio', { streamId, audio });
91
113
  });
114
+ console.log('[STT] recording started');
92
115
  }, [socket, listening, options.mode, options.lang]);
93
116
 
94
117
  const stop = useCallback(() => {
118
+ console.log(`[STT] stop streamId=${streamIdRef.current}`);
95
119
  cancelledRef.current = true;
96
120
  recorderRef.current?.stop();
97
121
  if (streamIdRef.current) {
@@ -203,6 +203,7 @@ function useTTSAnalyzer() {
203
203
  const ctxRef = useRef<AudioContext | null>(null);
204
204
  const analyzerRef = useRef<AnalyserNode | null>(null);
205
205
  const gainRef = useRef<GainNode | null>(null);
206
+ const nextStartRef = useRef(0);
206
207
  const [analyzer, setAnalyzer] = useState<AnalyserNode | null>(null);
207
208
 
208
209
  const init = useCallback(() => {
@@ -216,6 +217,7 @@ function useTTSAnalyzer() {
216
217
  ctxRef.current = ctx;
217
218
  analyzerRef.current = node;
218
219
  gainRef.current = gain;
220
+ nextStartRef.current = 0;
219
221
  setAnalyzer(node);
220
222
  }, []);
221
223
 
@@ -232,7 +234,10 @@ function useTTSAnalyzer() {
232
234
  const source = ctx.createBufferSource();
233
235
  source.buffer = buffer;
234
236
  source.connect(gain);
235
- source.start();
237
+ const now = ctx.currentTime;
238
+ if (nextStartRef.current < now) nextStartRef.current = now;
239
+ source.start(nextStartRef.current);
240
+ nextStartRef.current += buffer.duration;
236
241
  }, []);
237
242
 
238
243
  const close = useCallback(() => {
@@ -484,7 +489,7 @@ function STTSection({ socket }: { socket: UglyBotSocket }) {
484
489
  let ttsCounter = 0;
485
490
 
486
491
  function TTSSection({ socket }: { socket: UglyBotSocket }) {
487
- const [text, setText] = useState('');
492
+ const [text, setText] = useState('The quick brown fox jumps over the lazy dog. Hello, this is a text to speech test.');
488
493
  const [voice, setVoice] = useState('');
489
494
  const [vizType, setVizType] = useState<VizType>('wave');
490
495
  const [playing, setPlaying] = useState(false);