@contentgrowth/llm-service 0.9.92 → 0.9.93

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.
@@ -203,93 +203,32 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
203
203
  const recognitionRef = (0, import_react2.useRef)(null);
204
204
  const isSimulatingRef = (0, import_react2.useRef)(false);
205
205
  const simulationTimeoutRef = (0, import_react2.useRef)(null);
206
+ const languageRef = (0, import_react2.useRef)(language);
207
+ const instanceIdRef = (0, import_react2.useRef)(Math.random().toString(36).slice(2));
208
+ const lastStartAtRef = (0, import_react2.useRef)(null);
209
+ const lastStopAtRef = (0, import_react2.useRef)(null);
206
210
  const onResultRef = (0, import_react2.useRef)(onResult);
207
211
  const onEndRef = (0, import_react2.useRef)(onEnd);
208
212
  (0, import_react2.useEffect)(() => {
209
213
  onResultRef.current = onResult;
210
214
  onEndRef.current = onEnd;
211
215
  }, [onResult, onEnd]);
216
+ (0, import_react2.useEffect)(() => {
217
+ languageRef.current = language;
218
+ if (recognitionRef.current) {
219
+ console.log("[useSpeechRecognition] Updating language to:", language);
220
+ recognitionRef.current.lang = language;
221
+ }
222
+ }, [language]);
212
223
  const isStartingRef = (0, import_react2.useRef)(false);
213
224
  (0, import_react2.useEffect)(() => {
214
- const isMobile = typeof window !== "undefined" && (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || "ontouchstart" in window || navigator.maxTouchPoints > 0);
225
+ var _a;
215
226
  if (typeof window !== "undefined") {
216
227
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
217
- console.log("[useSpeechRecognition] Init - SpeechRecognition available:", !!SpeechRecognition, "isMobile:", isMobile);
218
- if (SpeechRecognition) {
219
- setIsSupported(true);
220
- const recognition = new SpeechRecognition();
221
- recognition.continuous = true;
222
- recognition.interimResults = true;
223
- console.log("[useSpeechRecognition] Created recognition instance. continuous:", recognition.continuous, "interimResults:", recognition.interimResults);
224
- recognition.onstart = () => {
225
- console.log("[useSpeechRecognition] Native onstart event fired. Timestamp:", Date.now());
226
- isStartingRef.current = false;
227
- setIsListening(true);
228
- setError(null);
229
- };
230
- recognition.onend = () => {
231
- console.log("[useSpeechRecognition] Native onend event fired. Timestamp:", Date.now());
232
- isStartingRef.current = false;
233
- if (isSimulatingRef.current) {
234
- console.log("[useSpeechRecognition] onend ignored - simulating");
235
- return;
236
- }
237
- setIsListening(false);
238
- if (onEndRef.current) onEndRef.current();
239
- };
240
- recognition.onresult = (event) => {
241
- console.log("[useSpeechRecognition] onresult event. results count:", event.results.length);
242
- let interimTranscript = "";
243
- let finalTranscript = "";
244
- for (let i = event.results.length - 1; i < event.results.length; ++i) {
245
- const result = event.results[i];
246
- if (result.isFinal) {
247
- finalTranscript += result[0].transcript;
248
- console.log("[useSpeechRecognition] Final transcript:", finalTranscript);
249
- if (onResultRef.current) onResultRef.current(finalTranscript, true);
250
- } else {
251
- interimTranscript += result[0].transcript;
252
- console.log("[useSpeechRecognition] Interim transcript:", interimTranscript);
253
- if (onResultRef.current) onResultRef.current(interimTranscript, false);
254
- }
255
- }
256
- setTranscript((prev) => prev + finalTranscript);
257
- };
258
- recognition.onerror = (event) => {
259
- console.error("[useSpeechRecognition] Native onerror event:", event.error, "Timestamp:", Date.now());
260
- console.error("[useSpeechRecognition] Error details - This could be caused by:");
261
- if (event.error === "aborted") {
262
- console.error("[useSpeechRecognition] - aborted: Recognition was aborted. Common causes: keyboard appeared, focus changed, another recognition started, or page navigation");
263
- } else if (event.error === "not-allowed") {
264
- console.error("[useSpeechRecognition] - not-allowed: Microphone permission denied");
265
- } else if (event.error === "no-speech") {
266
- console.error("[useSpeechRecognition] - no-speech: No speech detected");
267
- } else if (event.error === "network") {
268
- console.error("[useSpeechRecognition] - network: Network error during recognition");
269
- }
270
- isStartingRef.current = false;
271
- if (event.error === "not-allowed" && process.env.NODE_ENV === "development") {
272
- console.warn("Speech recognition blocked. Simulating input for development...");
273
- isSimulatingRef.current = true;
274
- setError(null);
275
- setIsListening(true);
276
- simulationTimeoutRef.current = setTimeout(() => {
277
- const mockText = "This is a simulated voice input for testing.";
278
- setTranscript((prev) => prev + (prev ? " " : "") + mockText);
279
- if (onResultRef.current) onResultRef.current(mockText, true);
280
- isSimulatingRef.current = false;
281
- setIsListening(false);
282
- if (onEndRef.current) onEndRef.current();
283
- simulationTimeoutRef.current = null;
284
- }, 3e3);
285
- return;
286
- }
287
- console.error("Speech recognition error", event.error);
288
- setError(event.error);
289
- setIsListening(false);
290
- };
291
- recognitionRef.current = recognition;
292
- }
228
+ console.log("[useSpeechRecognition] Env - isSecureContext:", window.isSecureContext, "protocol:", (_a = window.location) == null ? void 0 : _a.protocol);
229
+ const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || "ontouchstart" in window || navigator.maxTouchPoints > 0;
230
+ console.log("[useSpeechRecognition] Init check - SpeechRecognition available:", !!SpeechRecognition, "isMobile:", isMobile, "instanceId:", instanceIdRef.current);
231
+ setIsSupported(!!SpeechRecognition);
293
232
  }
294
233
  return () => {
295
234
  console.log("[useSpeechRecognition] Effect cleanup - stopping recognition");
@@ -298,21 +237,149 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
298
237
  simulationTimeoutRef.current = null;
299
238
  }
300
239
  if (recognitionRef.current) {
301
- recognitionRef.current.stop();
240
+ try {
241
+ recognitionRef.current.stop();
242
+ } catch (e) {
243
+ }
244
+ recognitionRef.current = null;
245
+ }
246
+ if (typeof window !== "undefined") {
247
+ const w = window;
248
+ if (w.__llmSpeechRecognitionActiveInstanceId === instanceIdRef.current) {
249
+ console.log("[useSpeechRecognition] Cleanup clearing global active instance lock. instanceId:", instanceIdRef.current);
250
+ w.__llmSpeechRecognitionActiveInstanceId = null;
251
+ }
302
252
  }
303
253
  };
304
254
  }, []);
305
- (0, import_react2.useEffect)(() => {
306
- if (recognitionRef.current) {
307
- console.log("[useSpeechRecognition] Updating language to:", language);
308
- recognitionRef.current.lang = language;
255
+ const createRecognitionInstance = (0, import_react2.useCallback)(() => {
256
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
257
+ if (!SpeechRecognition) {
258
+ console.error("[useSpeechRecognition] SpeechRecognition not available");
259
+ return null;
309
260
  }
310
- }, [language]);
261
+ console.log("[useSpeechRecognition] Creating NEW recognition instance within user gesture context. Timestamp:", Date.now());
262
+ const recognition = new SpeechRecognition();
263
+ const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || "ontouchstart" in window || navigator.maxTouchPoints > 0;
264
+ recognition.continuous = !isMobile;
265
+ recognition.interimResults = true;
266
+ recognition.lang = languageRef.current;
267
+ console.log("[useSpeechRecognition] Instance created. continuous:", recognition.continuous, "interimResults:", recognition.interimResults, "lang:", recognition.lang, "isMobile:", isMobile, "instanceId:", instanceIdRef.current);
268
+ recognition.onaudiostart = () => {
269
+ console.log("[useSpeechRecognition] Native onaudiostart. Timestamp:", Date.now(), "instanceId:", instanceIdRef.current);
270
+ };
271
+ recognition.onaudioend = () => {
272
+ console.log("[useSpeechRecognition] Native onaudioend. Timestamp:", Date.now(), "instanceId:", instanceIdRef.current);
273
+ };
274
+ recognition.onsoundstart = () => {
275
+ console.log("[useSpeechRecognition] Native onsoundstart. Timestamp:", Date.now(), "instanceId:", instanceIdRef.current);
276
+ };
277
+ recognition.onsoundend = () => {
278
+ console.log("[useSpeechRecognition] Native onsoundend. Timestamp:", Date.now(), "instanceId:", instanceIdRef.current);
279
+ };
280
+ recognition.onspeechstart = () => {
281
+ console.log("[useSpeechRecognition] Native onspeechstart. Timestamp:", Date.now(), "instanceId:", instanceIdRef.current);
282
+ };
283
+ recognition.onspeechend = () => {
284
+ console.log("[useSpeechRecognition] Native onspeechend. Timestamp:", Date.now(), "instanceId:", instanceIdRef.current);
285
+ };
286
+ recognition.onnomatch = () => {
287
+ console.log("[useSpeechRecognition] Native onnomatch. Timestamp:", Date.now(), "instanceId:", instanceIdRef.current);
288
+ };
289
+ recognition.onstart = () => {
290
+ console.log("[useSpeechRecognition] Native onstart event fired. Timestamp:", Date.now());
291
+ isStartingRef.current = false;
292
+ setIsListening(true);
293
+ setError(null);
294
+ if (typeof window !== "undefined") {
295
+ const w = window;
296
+ w.__llmSpeechRecognitionActiveInstanceId = instanceIdRef.current;
297
+ console.log("[useSpeechRecognition] Set global active instance lock. instanceId:", instanceIdRef.current);
298
+ }
299
+ };
300
+ recognition.onend = () => {
301
+ console.log("[useSpeechRecognition] Native onend event fired. Timestamp:", Date.now());
302
+ isStartingRef.current = false;
303
+ if (isSimulatingRef.current) {
304
+ console.log("[useSpeechRecognition] onend ignored - simulating");
305
+ return;
306
+ }
307
+ setIsListening(false);
308
+ if (onEndRef.current) onEndRef.current();
309
+ if (typeof window !== "undefined") {
310
+ const w = window;
311
+ if (w.__llmSpeechRecognitionActiveInstanceId === instanceIdRef.current) {
312
+ w.__llmSpeechRecognitionActiveInstanceId = null;
313
+ console.log("[useSpeechRecognition] Cleared global active instance lock. instanceId:", instanceIdRef.current);
314
+ }
315
+ }
316
+ };
317
+ recognition.onresult = (event) => {
318
+ console.log("[useSpeechRecognition] onresult event. results count:", event.results.length);
319
+ let interimTranscript = "";
320
+ let finalTranscript = "";
321
+ for (let i = event.results.length - 1; i < event.results.length; ++i) {
322
+ const result = event.results[i];
323
+ if (result.isFinal) {
324
+ finalTranscript += result[0].transcript;
325
+ console.log("[useSpeechRecognition] Final transcript:", finalTranscript);
326
+ if (onResultRef.current) onResultRef.current(finalTranscript, true);
327
+ } else {
328
+ interimTranscript += result[0].transcript;
329
+ console.log("[useSpeechRecognition] Interim transcript:", interimTranscript);
330
+ if (onResultRef.current) onResultRef.current(interimTranscript, false);
331
+ }
332
+ }
333
+ setTranscript((prev) => prev + finalTranscript);
334
+ };
335
+ recognition.onerror = (event) => {
336
+ console.error("[useSpeechRecognition] Native onerror event:", event.error, "Timestamp:", Date.now());
337
+ console.error("[useSpeechRecognition] Error context - lastStartAt:", lastStartAtRef.current, "lastStopAt:", lastStopAtRef.current, "instanceId:", instanceIdRef.current);
338
+ console.error("[useSpeechRecognition] Error details - This could be caused by:");
339
+ if (event.error === "aborted") {
340
+ console.error("[useSpeechRecognition] - aborted: Recognition was aborted. Common causes: keyboard appeared, focus changed, another recognition started, or page navigation");
341
+ } else if (event.error === "not-allowed") {
342
+ console.error("[useSpeechRecognition] - not-allowed: Microphone permission denied");
343
+ } else if (event.error === "no-speech") {
344
+ console.error("[useSpeechRecognition] - no-speech: No speech detected");
345
+ } else if (event.error === "network") {
346
+ console.error("[useSpeechRecognition] - network: Network error during recognition");
347
+ }
348
+ isStartingRef.current = false;
349
+ if (event.error === "not-allowed" && process.env.NODE_ENV === "development") {
350
+ console.warn("Speech recognition blocked. Simulating input for development...");
351
+ isSimulatingRef.current = true;
352
+ setError(null);
353
+ setIsListening(true);
354
+ simulationTimeoutRef.current = setTimeout(() => {
355
+ const mockText = "This is a simulated voice input for testing.";
356
+ setTranscript((prev) => prev + (prev ? " " : "") + mockText);
357
+ if (onResultRef.current) onResultRef.current(mockText, true);
358
+ isSimulatingRef.current = false;
359
+ setIsListening(false);
360
+ if (onEndRef.current) onEndRef.current();
361
+ simulationTimeoutRef.current = null;
362
+ }, 3e3);
363
+ return;
364
+ }
365
+ console.error("Speech recognition error", event.error);
366
+ setError(event.error);
367
+ setIsListening(false);
368
+ if (typeof window !== "undefined") {
369
+ const w = window;
370
+ if (w.__llmSpeechRecognitionActiveInstanceId === instanceIdRef.current) {
371
+ w.__llmSpeechRecognitionActiveInstanceId = null;
372
+ console.log("[useSpeechRecognition] Cleared global active instance lock after error. instanceId:", instanceIdRef.current);
373
+ }
374
+ }
375
+ };
376
+ return recognition;
377
+ }, []);
311
378
  const start = (0, import_react2.useCallback)(() => {
312
379
  var _a;
313
380
  const startTimestamp = Date.now();
314
381
  console.log("[useSpeechRecognition] start() called. Timestamp:", startTimestamp);
315
- console.log("[useSpeechRecognition] State check - isListening:", isListening, "isStarting:", isStartingRef.current, "hasInstance:", !!recognitionRef.current);
382
+ console.log("[useSpeechRecognition] State check - isListening:", isListening, "isStarting:", isStartingRef.current, "hasExistingInstance:", !!recognitionRef.current);
316
383
  if (typeof document !== "undefined") {
317
384
  console.log("[useSpeechRecognition] Document hasFocus:", document.hasFocus(), "activeElement:", (_a = document.activeElement) == null ? void 0 : _a.tagName);
318
385
  }
@@ -320,24 +387,39 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
320
387
  console.log("[useSpeechRecognition] isSimulating, ignoring start");
321
388
  return;
322
389
  }
323
- if (!recognitionRef.current) {
324
- console.error("[useSpeechRecognition] Recognition instance missing");
325
- return;
326
- }
327
390
  if (isStartingRef.current) {
328
391
  console.warn("[useSpeechRecognition] Already starting - ignoring duplicate call");
329
392
  return;
330
393
  }
331
- if (recognitionRef.current.isListening) {
332
- console.warn("[useSpeechRecognition] Already listening (native prop) - ignoring");
333
- }
334
394
  if (isListening) {
335
395
  console.warn("[useSpeechRecognition] App state says already listening - ignoring");
336
396
  return;
337
397
  }
398
+ if (typeof window !== "undefined") {
399
+ const w = window;
400
+ if (w.__llmSpeechRecognitionActiveInstanceId && w.__llmSpeechRecognitionActiveInstanceId !== instanceIdRef.current) {
401
+ console.error("[useSpeechRecognition] Another recognition instance appears active. activeInstanceId:", w.__llmSpeechRecognitionActiveInstanceId, "thisInstanceId:", instanceIdRef.current);
402
+ }
403
+ }
338
404
  try {
405
+ if (recognitionRef.current) {
406
+ console.log("[useSpeechRecognition] Stopping existing instance before creating new one");
407
+ try {
408
+ recognitionRef.current.stop();
409
+ } catch (e) {
410
+ }
411
+ recognitionRef.current = null;
412
+ }
413
+ const recognition = createRecognitionInstance();
414
+ if (!recognition) {
415
+ console.error("[useSpeechRecognition] Failed to create recognition instance");
416
+ setError("Speech recognition not available");
417
+ return;
418
+ }
419
+ recognitionRef.current = recognition;
339
420
  setTranscript("");
340
421
  isStartingRef.current = true;
422
+ lastStartAtRef.current = Date.now();
341
423
  console.log("[useSpeechRecognition] About to call recognition.start(). Timestamp:", Date.now());
342
424
  recognitionRef.current.start();
343
425
  console.log("[useSpeechRecognition] recognition.start() executed successfully. Timestamp:", Date.now());
@@ -347,10 +429,12 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
347
429
  if ((error2 == null ? void 0 : error2.name) === "InvalidStateError") {
348
430
  console.error("[useSpeechRecognition] InvalidStateError - recognition may already be running");
349
431
  }
432
+ setError((error2 == null ? void 0 : error2.message) || "Failed to start speech recognition");
350
433
  }
351
- }, [isListening]);
434
+ }, [isListening, createRecognitionInstance]);
352
435
  const stop = (0, import_react2.useCallback)(() => {
353
436
  console.log("[useSpeechRecognition] stop() called");
437
+ lastStopAtRef.current = Date.now();
354
438
  if (isSimulatingRef.current) {
355
439
  if (simulationTimeoutRef.current) {
356
440
  clearTimeout(simulationTimeoutRef.current);