@contentgrowth/llm-service 0.9.91 → 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,76 +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)(() => {
|
|
225
|
+
var _a;
|
|
214
226
|
if (typeof window !== "undefined") {
|
|
215
227
|
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
recognition.interimResults = true;
|
|
221
|
-
recognition.onstart = () => {
|
|
222
|
-
console.log("[useSpeechRecognition] Native onstart event fired");
|
|
223
|
-
isStartingRef.current = false;
|
|
224
|
-
setIsListening(true);
|
|
225
|
-
setError(null);
|
|
226
|
-
};
|
|
227
|
-
recognition.onend = () => {
|
|
228
|
-
console.log("[useSpeechRecognition] Native onend event fired");
|
|
229
|
-
isStartingRef.current = false;
|
|
230
|
-
if (isSimulatingRef.current) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
setIsListening(false);
|
|
234
|
-
if (onEndRef.current) onEndRef.current();
|
|
235
|
-
};
|
|
236
|
-
recognition.onresult = (event) => {
|
|
237
|
-
let interimTranscript = "";
|
|
238
|
-
let finalTranscript = "";
|
|
239
|
-
for (let i = event.results.length - 1; i < event.results.length; ++i) {
|
|
240
|
-
const result = event.results[i];
|
|
241
|
-
if (result.isFinal) {
|
|
242
|
-
finalTranscript += result[0].transcript;
|
|
243
|
-
if (onResultRef.current) onResultRef.current(finalTranscript, true);
|
|
244
|
-
} else {
|
|
245
|
-
interimTranscript += result[0].transcript;
|
|
246
|
-
if (onResultRef.current) onResultRef.current(interimTranscript, false);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
setTranscript((prev) => prev + finalTranscript);
|
|
250
|
-
};
|
|
251
|
-
recognition.onerror = (event) => {
|
|
252
|
-
console.error("[useSpeechRecognition] Native onerror event:", event.error);
|
|
253
|
-
isStartingRef.current = false;
|
|
254
|
-
if (event.error === "not-allowed" && process.env.NODE_ENV === "development") {
|
|
255
|
-
console.warn("Speech recognition blocked. Simulating input for development...");
|
|
256
|
-
isSimulatingRef.current = true;
|
|
257
|
-
setError(null);
|
|
258
|
-
setIsListening(true);
|
|
259
|
-
simulationTimeoutRef.current = setTimeout(() => {
|
|
260
|
-
const mockText = "This is a simulated voice input for testing.";
|
|
261
|
-
setTranscript((prev) => prev + (prev ? " " : "") + mockText);
|
|
262
|
-
if (onResultRef.current) onResultRef.current(mockText, true);
|
|
263
|
-
isSimulatingRef.current = false;
|
|
264
|
-
setIsListening(false);
|
|
265
|
-
if (onEndRef.current) onEndRef.current();
|
|
266
|
-
simulationTimeoutRef.current = null;
|
|
267
|
-
}, 3e3);
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
console.error("Speech recognition error", event.error);
|
|
271
|
-
setError(event.error);
|
|
272
|
-
setIsListening(false);
|
|
273
|
-
};
|
|
274
|
-
recognitionRef.current = recognition;
|
|
275
|
-
}
|
|
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);
|
|
276
232
|
}
|
|
277
233
|
return () => {
|
|
278
234
|
console.log("[useSpeechRecognition] Effect cleanup - stopping recognition");
|
|
@@ -281,49 +237,204 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
|
|
|
281
237
|
simulationTimeoutRef.current = null;
|
|
282
238
|
}
|
|
283
239
|
if (recognitionRef.current) {
|
|
284
|
-
|
|
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
|
+
}
|
|
285
252
|
}
|
|
286
253
|
};
|
|
287
254
|
}, []);
|
|
288
|
-
(0, import_react2.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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;
|
|
292
260
|
}
|
|
293
|
-
|
|
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
|
+
}, []);
|
|
294
378
|
const start = (0, import_react2.useCallback)(() => {
|
|
295
|
-
|
|
379
|
+
var _a;
|
|
380
|
+
const startTimestamp = Date.now();
|
|
381
|
+
console.log("[useSpeechRecognition] start() called. Timestamp:", startTimestamp);
|
|
382
|
+
console.log("[useSpeechRecognition] State check - isListening:", isListening, "isStarting:", isStartingRef.current, "hasExistingInstance:", !!recognitionRef.current);
|
|
383
|
+
if (typeof document !== "undefined") {
|
|
384
|
+
console.log("[useSpeechRecognition] Document hasFocus:", document.hasFocus(), "activeElement:", (_a = document.activeElement) == null ? void 0 : _a.tagName);
|
|
385
|
+
}
|
|
296
386
|
if (isSimulatingRef.current) {
|
|
297
387
|
console.log("[useSpeechRecognition] isSimulating, ignoring start");
|
|
298
388
|
return;
|
|
299
389
|
}
|
|
300
|
-
if (!recognitionRef.current) {
|
|
301
|
-
console.error("[useSpeechRecognition] Recognition instance missing");
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
390
|
if (isStartingRef.current) {
|
|
305
391
|
console.warn("[useSpeechRecognition] Already starting - ignoring duplicate call");
|
|
306
392
|
return;
|
|
307
393
|
}
|
|
308
|
-
if (recognitionRef.current.isListening) {
|
|
309
|
-
console.warn("[useSpeechRecognition] Already listening (native prop) - ignoring");
|
|
310
|
-
}
|
|
311
394
|
if (isListening) {
|
|
312
395
|
console.warn("[useSpeechRecognition] App state says already listening - ignoring");
|
|
313
396
|
return;
|
|
314
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
|
+
}
|
|
315
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;
|
|
316
420
|
setTranscript("");
|
|
317
421
|
isStartingRef.current = true;
|
|
422
|
+
lastStartAtRef.current = Date.now();
|
|
423
|
+
console.log("[useSpeechRecognition] About to call recognition.start(). Timestamp:", Date.now());
|
|
318
424
|
recognitionRef.current.start();
|
|
319
|
-
console.log("[useSpeechRecognition] recognition.start() executed successfully");
|
|
425
|
+
console.log("[useSpeechRecognition] recognition.start() executed successfully. Timestamp:", Date.now());
|
|
320
426
|
} catch (error2) {
|
|
321
427
|
isStartingRef.current = false;
|
|
322
|
-
console.error("[useSpeechRecognition] Failed to start recognition:", error2);
|
|
428
|
+
console.error("[useSpeechRecognition] Failed to start recognition:", (error2 == null ? void 0 : error2.message) || error2);
|
|
429
|
+
if ((error2 == null ? void 0 : error2.name) === "InvalidStateError") {
|
|
430
|
+
console.error("[useSpeechRecognition] InvalidStateError - recognition may already be running");
|
|
431
|
+
}
|
|
432
|
+
setError((error2 == null ? void 0 : error2.message) || "Failed to start speech recognition");
|
|
323
433
|
}
|
|
324
|
-
}, [isListening]);
|
|
434
|
+
}, [isListening, createRecognitionInstance]);
|
|
325
435
|
const stop = (0, import_react2.useCallback)(() => {
|
|
326
436
|
console.log("[useSpeechRecognition] stop() called");
|
|
437
|
+
lastStopAtRef.current = Date.now();
|
|
327
438
|
if (isSimulatingRef.current) {
|
|
328
439
|
if (simulationTimeoutRef.current) {
|
|
329
440
|
clearTimeout(simulationTimeoutRef.current);
|
|
@@ -643,26 +754,47 @@ var ChatInputArea = (0, import_react5.forwardRef)(({
|
|
|
643
754
|
handleSubmit();
|
|
644
755
|
}
|
|
645
756
|
};
|
|
757
|
+
const isMobile = (0, import_react5.useCallback)(() => {
|
|
758
|
+
if (typeof window === "undefined") return false;
|
|
759
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
760
|
+
}, []);
|
|
646
761
|
const startRecording = async (trigger) => {
|
|
647
762
|
var _a2;
|
|
648
|
-
|
|
763
|
+
console.log("[ChatInputArea] startRecording called. trigger:", trigger, "isMobile:", isMobile());
|
|
764
|
+
console.log("[ChatInputArea] Current state - voiceTrigger:", voiceTrigger, "isTranscribing:", isTranscribing);
|
|
765
|
+
if (voiceTrigger || isTranscribing) {
|
|
766
|
+
console.log("[ChatInputArea] startRecording ignored - already active");
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
649
769
|
setVoiceTrigger(trigger);
|
|
650
770
|
setVoiceError(null);
|
|
771
|
+
console.log("[ChatInputArea] Calling voiceConfig.onVoiceStart if exists...");
|
|
651
772
|
(_a2 = voiceConfig == null ? void 0 : voiceConfig.onVoiceStart) == null ? void 0 : _a2.call(voiceConfig);
|
|
652
773
|
if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") {
|
|
774
|
+
console.log("[ChatInputArea] Using native speech recognition");
|
|
653
775
|
if (!nativeSpeech.isSupported) {
|
|
776
|
+
console.error("[ChatInputArea] Native speech not supported");
|
|
654
777
|
alert("Speech recognition is not supported in this browser.");
|
|
655
778
|
setVoiceTrigger(null);
|
|
656
779
|
return;
|
|
657
780
|
}
|
|
781
|
+
console.log("[ChatInputArea] Calling nativeSpeech.start()...");
|
|
658
782
|
nativeSpeech.start();
|
|
783
|
+
console.log("[ChatInputArea] nativeSpeech.start() called");
|
|
659
784
|
} else {
|
|
785
|
+
console.log("[ChatInputArea] Using custom recorder");
|
|
660
786
|
await customRecorder.start();
|
|
787
|
+
console.log("[ChatInputArea] Custom recorder started");
|
|
788
|
+
}
|
|
789
|
+
if (!isMobile()) {
|
|
790
|
+
console.log("[ChatInputArea] Re-focusing textarea (desktop only)");
|
|
791
|
+
setTimeout(() => {
|
|
792
|
+
var _a3;
|
|
793
|
+
return (_a3 = textareaRef.current) == null ? void 0 : _a3.focus();
|
|
794
|
+
}, 0);
|
|
795
|
+
} else {
|
|
796
|
+
console.log("[ChatInputArea] SKIPPING textarea focus on mobile to prevent keyboard conflict");
|
|
661
797
|
}
|
|
662
|
-
setTimeout(() => {
|
|
663
|
-
var _a3;
|
|
664
|
-
return (_a3 = textareaRef.current) == null ? void 0 : _a3.focus();
|
|
665
|
-
}, 0);
|
|
666
798
|
};
|
|
667
799
|
const stopRecording = () => {
|
|
668
800
|
if (!voiceTrigger) return;
|
|
@@ -951,18 +1083,22 @@ var TapToTalk = ({
|
|
|
951
1083
|
const isListening = !!voiceTrigger || nativeSpeech.isListening || customRecorder.isRecording;
|
|
952
1084
|
const isActive = isListening || isTranscribing;
|
|
953
1085
|
const processingRef = (0, import_react6.useRef)(false);
|
|
1086
|
+
const isMobile = (0, import_react6.useCallback)(() => {
|
|
1087
|
+
if (typeof window === "undefined") return false;
|
|
1088
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1089
|
+
}, []);
|
|
954
1090
|
const toggleVoice = async (e) => {
|
|
955
1091
|
if (e) {
|
|
956
1092
|
e.preventDefault();
|
|
957
1093
|
e.stopPropagation();
|
|
958
1094
|
}
|
|
959
|
-
console.
|
|
1095
|
+
console.log("[TapToTalk] toggleVoice called. isMobile:", isMobile());
|
|
960
1096
|
if (processingRef.current) {
|
|
961
1097
|
console.log("[TapToTalk] toggleVoice ignored - processing");
|
|
962
1098
|
return;
|
|
963
1099
|
}
|
|
964
1100
|
processingRef.current = true;
|
|
965
|
-
console.log("[TapToTalk] toggleVoice called. isActive:", isActive);
|
|
1101
|
+
console.log("[TapToTalk] toggleVoice called. isActive:", isActive, "isListening:", isListening, "isTranscribing:", isTranscribing);
|
|
966
1102
|
try {
|
|
967
1103
|
const now = Date.now();
|
|
968
1104
|
if (now - tapCountRef.current.lastTap < 500) {
|
|
@@ -995,29 +1131,39 @@ var TapToTalk = ({
|
|
|
995
1131
|
}
|
|
996
1132
|
setVoiceTrigger(null);
|
|
997
1133
|
} else {
|
|
998
|
-
console.log("[TapToTalk] Starting voice...");
|
|
1134
|
+
console.log("[TapToTalk] Starting voice... mode:", voiceConfig == null ? void 0 : voiceConfig.mode);
|
|
999
1135
|
setErrorMsg(null);
|
|
1000
|
-
if (onFocusTarget) {
|
|
1001
|
-
console.log("[TapToTalk] calling onFocusTarget()
|
|
1136
|
+
if (onFocusTarget && !isMobile()) {
|
|
1137
|
+
console.log("[TapToTalk] calling onFocusTarget() (desktop only)");
|
|
1002
1138
|
onFocusTarget();
|
|
1139
|
+
} else if (onFocusTarget) {
|
|
1140
|
+
console.log("[TapToTalk] SKIPPING onFocusTarget on mobile to prevent keyboard conflict");
|
|
1003
1141
|
} else {
|
|
1004
1142
|
console.log("[TapToTalk] onFocusTarget is undefined");
|
|
1005
1143
|
}
|
|
1006
1144
|
setVoiceTrigger("click");
|
|
1145
|
+
console.log("[TapToTalk] voiceTrigger set to click");
|
|
1007
1146
|
if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "custom") {
|
|
1147
|
+
console.log("[TapToTalk] Starting custom recorder...");
|
|
1008
1148
|
try {
|
|
1009
1149
|
await customRecorder.start();
|
|
1150
|
+
console.log("[TapToTalk] Custom recorder started successfully");
|
|
1010
1151
|
} catch (e2) {
|
|
1152
|
+
console.error("[TapToTalk] Custom recorder failed:", e2);
|
|
1011
1153
|
setErrorMsg("Mic access denied");
|
|
1012
1154
|
setVoiceTrigger(null);
|
|
1013
1155
|
}
|
|
1014
1156
|
} else {
|
|
1157
|
+
console.log("[TapToTalk] Starting native speech recognition...");
|
|
1015
1158
|
if (!nativeSpeech.isSupported) {
|
|
1159
|
+
console.error("[TapToTalk] Native speech not supported");
|
|
1016
1160
|
setErrorMsg("Speech not supported");
|
|
1017
1161
|
setVoiceTrigger(null);
|
|
1018
1162
|
return;
|
|
1019
1163
|
}
|
|
1164
|
+
console.log("[TapToTalk] Calling nativeSpeech.start()...");
|
|
1020
1165
|
nativeSpeech.start();
|
|
1166
|
+
console.log("[TapToTalk] nativeSpeech.start() called");
|
|
1021
1167
|
}
|
|
1022
1168
|
}
|
|
1023
1169
|
} finally {
|