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