@contentgrowth/llm-service 0.9.8 → 0.9.9

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.
@@ -209,6 +209,7 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
209
209
  onResultRef.current = onResult;
210
210
  onEndRef.current = onEnd;
211
211
  }, [onResult, onEnd]);
212
+ const isStartingRef = (0, import_react2.useRef)(false);
212
213
  (0, import_react2.useEffect)(() => {
213
214
  if (typeof window !== "undefined") {
214
215
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
@@ -219,11 +220,13 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
219
220
  recognition.interimResults = true;
220
221
  recognition.onstart = () => {
221
222
  console.log("[useSpeechRecognition] Native onstart event fired");
223
+ isStartingRef.current = false;
222
224
  setIsListening(true);
223
225
  setError(null);
224
226
  };
225
227
  recognition.onend = () => {
226
228
  console.log("[useSpeechRecognition] Native onend event fired");
229
+ isStartingRef.current = false;
227
230
  if (isSimulatingRef.current) {
228
231
  return;
229
232
  }
@@ -247,6 +250,7 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
247
250
  };
248
251
  recognition.onerror = (event) => {
249
252
  console.error("[useSpeechRecognition] Native onerror event:", event.error);
253
+ isStartingRef.current = false;
250
254
  if (event.error === "not-allowed" && process.env.NODE_ENV === "development") {
251
255
  console.warn("Speech recognition blocked. Simulating input for development...");
252
256
  isSimulatingRef.current = true;
@@ -294,14 +298,27 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
294
298
  console.error("[useSpeechRecognition] Recognition instance missing");
295
299
  return;
296
300
  }
301
+ if (isStartingRef.current) {
302
+ console.warn("[useSpeechRecognition] Already starting - ignoring duplicate call");
303
+ return;
304
+ }
305
+ if (recognitionRef.current.isListening) {
306
+ console.warn("[useSpeechRecognition] Already listening - ignoring");
307
+ }
308
+ if (isListening) {
309
+ console.warn("[useSpeechRecognition] App state says already listening - ignoring");
310
+ return;
311
+ }
297
312
  try {
298
313
  setTranscript("");
314
+ isStartingRef.current = true;
299
315
  recognitionRef.current.start();
300
316
  console.log("[useSpeechRecognition] recognition.start() executed");
301
317
  } catch (error2) {
318
+ isStartingRef.current = false;
302
319
  console.error("[useSpeechRecognition] Failed to start recognition:", error2);
303
320
  }
304
- }, []);
321
+ }, [isListening]);
305
322
  const stop = (0, import_react2.useCallback)(() => {
306
323
  console.log("[useSpeechRecognition] stop() called");
307
324
  if (isSimulatingRef.current) {
@@ -930,58 +947,70 @@ var TapToTalk = ({
930
947
  });
931
948
  const isListening = !!voiceTrigger || nativeSpeech.isListening || customRecorder.isRecording;
932
949
  const isActive = isListening || isTranscribing;
950
+ const processingRef = (0, import_react6.useRef)(false);
933
951
  const toggleVoice = async () => {
934
- console.log("[TapToTalk] toggleVoice called. isActive:", isActive);
935
- const now = Date.now();
936
- if (now - tapCountRef.current.lastTap < 500) {
937
- tapCountRef.current.count++;
938
- } else {
939
- tapCountRef.current.count = 1;
940
- }
941
- tapCountRef.current.lastTap = now;
942
- if (tapCountRef.current.count >= 5) {
943
- setShowDebug((prev) => !prev);
944
- tapCountRef.current.count = 0;
945
- if (isActive) {
946
- console.log("[TapToTalk] Debug trigger force-stop");
947
- if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") nativeSpeech.stop();
948
- else customRecorder.stop();
949
- setVoiceTrigger(null);
950
- }
952
+ if (processingRef.current) {
953
+ console.log("[TapToTalk] toggleVoice ignored - processing");
951
954
  return;
952
955
  }
953
- if (isActive) {
954
- if (isTranscribing && !isListening) {
955
- console.log("[TapToTalk] Ignoring click during transcription");
956
- return;
957
- }
958
- console.log("[TapToTalk] Stopping voice...");
959
- if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") {
960
- nativeSpeech.stop();
956
+ processingRef.current = true;
957
+ console.log("[TapToTalk] toggleVoice called. isActive:", isActive);
958
+ try {
959
+ const now = Date.now();
960
+ if (now - tapCountRef.current.lastTap < 500) {
961
+ tapCountRef.current.count++;
961
962
  } else {
962
- customRecorder.stop();
963
+ tapCountRef.current.count = 1;
963
964
  }
964
- setVoiceTrigger(null);
965
- } else {
966
- console.log("[TapToTalk] Starting voice...");
967
- setErrorMsg(null);
968
- onFocusTarget == null ? void 0 : onFocusTarget();
969
- setVoiceTrigger("click");
970
- if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "custom") {
971
- try {
972
- await customRecorder.start();
973
- } catch (e) {
974
- setErrorMsg("Mic access denied");
965
+ tapCountRef.current.lastTap = now;
966
+ if (tapCountRef.current.count >= 5) {
967
+ setShowDebug((prev) => !prev);
968
+ tapCountRef.current.count = 0;
969
+ if (isActive) {
970
+ console.log("[TapToTalk] Debug trigger force-stop");
971
+ if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") nativeSpeech.stop();
972
+ else customRecorder.stop();
975
973
  setVoiceTrigger(null);
976
974
  }
977
- } else {
978
- if (!nativeSpeech.isSupported) {
979
- setErrorMsg("Speech not supported");
980
- setVoiceTrigger(null);
975
+ return;
976
+ }
977
+ if (isActive) {
978
+ if (isTranscribing && !isListening) {
979
+ console.log("[TapToTalk] Ignoring click during transcription");
981
980
  return;
982
981
  }
983
- nativeSpeech.start();
982
+ console.log("[TapToTalk] Stopping voice...");
983
+ if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") {
984
+ nativeSpeech.stop();
985
+ } else {
986
+ customRecorder.stop();
987
+ }
988
+ setVoiceTrigger(null);
989
+ } else {
990
+ console.log("[TapToTalk] Starting voice...");
991
+ setErrorMsg(null);
992
+ onFocusTarget == null ? void 0 : onFocusTarget();
993
+ setVoiceTrigger("click");
994
+ if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "custom") {
995
+ try {
996
+ await customRecorder.start();
997
+ } catch (e) {
998
+ setErrorMsg("Mic access denied");
999
+ setVoiceTrigger(null);
1000
+ }
1001
+ } else {
1002
+ if (!nativeSpeech.isSupported) {
1003
+ setErrorMsg("Speech not supported");
1004
+ setVoiceTrigger(null);
1005
+ return;
1006
+ }
1007
+ nativeSpeech.start();
1008
+ }
984
1009
  }
1010
+ } finally {
1011
+ setTimeout(() => {
1012
+ processingRef.current = false;
1013
+ }, 300);
985
1014
  }
986
1015
  };
987
1016
  let bgColor = accentColor;