@contentgrowth/llm-service 0.9.3 → 0.9.4

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.
@@ -149,7 +149,7 @@ function ChatHeader({
149
149
 
150
150
  // src/ui/react/components/ChatInputArea.tsx
151
151
  import { useState as useState3, useRef as useRef3, useImperativeHandle, forwardRef, useEffect as useEffect3, useCallback as useCallback3, useLayoutEffect } from "react";
152
- import { MicrophoneIcon, StopIcon, PaperAirplaneIcon } from "@heroicons/react/24/outline";
152
+ import { MicrophoneIcon, StopIcon, PaperAirplaneIcon, XMarkIcon } from "@heroicons/react/24/outline";
153
153
 
154
154
  // src/ui/react/hooks/useSpeechRecognition.ts
155
155
  import { useState, useEffect, useCallback, useRef } from "react";
@@ -387,6 +387,42 @@ var ChatInputArea = forwardRef(({
387
387
  const [isTranscribing, setIsTranscribing] = useState3(false);
388
388
  const [voiceError, setVoiceError] = useState3(null);
389
389
  const [isFocused, setIsFocused] = useState3(false);
390
+ const [showDebug, setShowDebug] = useState3(false);
391
+ const [logs, setLogs] = useState3([]);
392
+ const tapCountRef = useRef3({ count: 0, lastTap: 0 });
393
+ useEffect3(() => {
394
+ const originalLog = console.log;
395
+ const originalWarn = console.warn;
396
+ const originalError = console.error;
397
+ const addLog = (type, args) => {
398
+ try {
399
+ const msg = args.map((arg) => {
400
+ if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
401
+ if (typeof arg === "object") return JSON.stringify(arg);
402
+ return String(arg);
403
+ }).join(" ");
404
+ setLogs((prev) => [`[${type}] ${msg}`, ...prev].slice(0, 50));
405
+ } catch (e) {
406
+ }
407
+ };
408
+ console.log = (...args) => {
409
+ originalLog(...args);
410
+ addLog("LOG", args);
411
+ };
412
+ console.warn = (...args) => {
413
+ originalWarn(...args);
414
+ addLog("WRN", args);
415
+ };
416
+ console.error = (...args) => {
417
+ originalError(...args);
418
+ addLog("ERR", args);
419
+ };
420
+ return () => {
421
+ console.log = originalLog;
422
+ console.warn = originalWarn;
423
+ console.error = originalError;
424
+ };
425
+ }, []);
390
426
  const textareaRef = useRef3(null);
391
427
  const measurementRef = useRef3(null);
392
428
  const pendingSelectionRef = useRef3(null);
@@ -456,6 +492,12 @@ var ChatInputArea = forwardRef(({
456
492
  (_b2 = (_a2 = voiceConfigRef.current) == null ? void 0 : _a2.onVoiceEnd) == null ? void 0 : _b2.call(_a2);
457
493
  }, []);
458
494
  const nativeSpeech = useSpeechRecognition(handleVoiceResult, handleVoiceEnd, voiceConfig == null ? void 0 : voiceConfig.language);
495
+ useEffect3(() => {
496
+ if (nativeSpeech.error) {
497
+ setVoiceError(nativeSpeech.error);
498
+ console.error("[ChatInputArea] Native Speech Error:", nativeSpeech.error);
499
+ }
500
+ }, [nativeSpeech.error]);
459
501
  const customRecorder = useAudioRecorder(async (blob) => {
460
502
  var _a2, _b2, _c2;
461
503
  setVoiceTrigger(null);
@@ -569,20 +611,40 @@ var ChatInputArea = forwardRef(({
569
611
  if (!showInputForm) {
570
612
  return null;
571
613
  }
572
- return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col w-full", children: [
614
+ return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col w-full relative", children: [
615
+ showDebug && /* @__PURE__ */ jsxs3("div", { className: "absolute bottom-full left-0 right-0 mb-2 p-2 bg-black/80 text-green-400 text-xs font-mono h-48 overflow-y-auto rounded z-50 pointer-events-auto", children: [
616
+ /* @__PURE__ */ jsxs3("div", { className: "flex justify-between items-center bg-gray-800 p-1 mb-1", children: [
617
+ /* @__PURE__ */ jsx5("span", { children: "Debug Logs" }),
618
+ /* @__PURE__ */ jsx5("button", { onClick: () => setShowDebug(false), className: "text-white hover:text-red-400", children: /* @__PURE__ */ jsx5(XMarkIcon, { className: "w-4 h-4" }) })
619
+ ] }),
620
+ logs.map((log, i) => /* @__PURE__ */ jsx5("div", { className: "mb-0.5 border-b border-gray-700/50 pb-0.5 break-all", children: log }, i)),
621
+ logs.length === 0 && /* @__PURE__ */ jsx5("div", { children: "No logs yet..." })
622
+ ] }),
573
623
  /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
574
624
  voiceConfig && /* @__PURE__ */ jsx5(
575
625
  "button",
576
626
  {
577
627
  type: "button",
578
628
  onClick: () => {
629
+ const now = Date.now();
630
+ if (now - tapCountRef.current.lastTap < 500) {
631
+ tapCountRef.current.count++;
632
+ } else {
633
+ tapCountRef.current.count = 1;
634
+ }
635
+ tapCountRef.current.lastTap = now;
636
+ if (tapCountRef.current.count >= 5) {
637
+ setShowDebug((prev) => !prev);
638
+ tapCountRef.current.count = 0;
639
+ return;
640
+ }
579
641
  if (voiceTrigger) {
580
642
  stopRecording();
581
643
  } else if (!isTranscribing) {
582
644
  startRecording("click");
583
645
  }
584
646
  },
585
- className: `mb-1 p-2 rounded-full transition-all duration-300 flex-shrink-0 border ${voiceTrigger || isTranscribing ? "text-white border-orange-400 bg-orange-500 scale-110 shadow-lg" : "text-gray-500 border-gray-300 bg-white hover:text-gray-700 hover:bg-gray-100"} ${voiceTrigger ? "animate-pulse" : ""} ${isTranscribing ? "cursor-wait" : ""}`,
647
+ className: `mb-1 p-2 rounded-full transition-all duration-300 flex-shrink-0 border ${isTranscribing ? "text-white border-indigo-500 bg-indigo-600 scale-110 shadow-lg" : voiceTrigger ? "text-white border-orange-400 bg-orange-500 scale-110 shadow-lg" : "text-gray-500 border-gray-300 bg-white hover:text-gray-700 hover:bg-gray-100"} ${voiceTrigger ? "animate-pulse" : ""} ${isTranscribing ? "cursor-wait" : ""}`,
586
648
  disabled: isTranscribing,
587
649
  title: isTranscribing ? "Transcribing..." : voiceTrigger ? "Stop Recording" : "Start Voice Input",
588
650
  children: isTranscribing ? /* @__PURE__ */ jsx5("div", { className: "animate-spin w-5 h-5 flex items-center justify-center", children: /* @__PURE__ */ jsxs3("svg", { className: "w-5 h-5 text-white", viewBox: "0 0 24 24", children: [
@@ -685,17 +747,17 @@ var ChatInputArea = forwardRef(({
685
747
  )
686
748
  ] }),
687
749
  inputHint && /* @__PURE__ */ jsx5("div", { className: "text-sm text-red-500 bg-red-50 py-1 px-4 rounded-lg mt-1", children: inputHint }),
688
- /* @__PURE__ */ jsx5("div", { className: "ml-[46px] mb-2 mt-0.5 min-h-[0.75rem]", style: { marginLeft: "48px" }, children: /* @__PURE__ */ jsx5("p", { className: `text-[10px] leading-tight transition-all duration-200 ${voiceError ? "text-red-500" : voiceTrigger || isTranscribing ? "text-orange-600 font-medium" : "text-gray-400"}`, children: voiceError ? /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-1 font-semibold italic", children: [
750
+ /* @__PURE__ */ jsx5("div", { className: "ml-[46px] mb-2 mt-0.5 min-h-[0.75rem]", style: { marginLeft: "48px" }, children: /* @__PURE__ */ jsx5("p", { className: `text-[10px] leading-tight transition-all duration-200 ${voiceError ? "text-red-500" : isTranscribing ? "text-indigo-600 font-bold" : voiceTrigger ? "text-orange-600 font-medium" : "text-gray-400"}`, children: voiceError ? /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-1 font-semibold italic", children: [
689
751
  "Error: ",
690
752
  voiceError
691
- ] }) : isTranscribing ? "Transcribing, please wait..." : voiceTrigger ? "Listening... tap mic icon again to stop" : hintText || (voiceConfig ? "Type in text or tap mic icon to talk" : "Type your message...") }) })
753
+ ] }) : isTranscribing ? "Transcribing... please wait" : voiceTrigger ? "Transcribing, please wait..." : voiceTrigger ? "Listening... tap mic icon again to stop" : hintText || (voiceConfig ? "Type in text or tap mic icon to talk" : "Type your message...") }) })
692
754
  ] });
693
755
  });
694
756
  ChatInputArea.displayName = "ChatInputArea";
695
757
 
696
758
  // src/ui/react/components/TapToTalk.tsx
697
- import { useState as useState4, useCallback as useCallback4 } from "react";
698
- import { MicrophoneIcon as MicrophoneIcon2 } from "@heroicons/react/24/outline";
759
+ import React3, { useState as useState4, useCallback as useCallback4, useRef as useRef4 } from "react";
760
+ import { MicrophoneIcon as MicrophoneIcon2, XMarkIcon as XMarkIcon2 } from "@heroicons/react/24/outline";
699
761
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
700
762
  var TapToTalk = ({
701
763
  onResult,
@@ -712,6 +774,42 @@ var TapToTalk = ({
712
774
  const [isTranscribing, setIsTranscribing] = useState4(false);
713
775
  const [voiceTrigger, setVoiceTrigger] = useState4(null);
714
776
  const [errorMsg, setErrorMsg] = useState4(null);
777
+ const [showDebug, setShowDebug] = useState4(false);
778
+ const [logs, setLogs] = useState4([]);
779
+ const tapCountRef = useRef4({ count: 0, lastTap: 0 });
780
+ React3.useEffect(() => {
781
+ const originalLog = console.log;
782
+ const originalWarn = console.warn;
783
+ const originalError = console.error;
784
+ const addLog = (type, args) => {
785
+ try {
786
+ const msg = args.map((arg) => {
787
+ if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
788
+ if (typeof arg === "object") return JSON.stringify(arg);
789
+ return String(arg);
790
+ }).join(" ");
791
+ setLogs((prev) => [`[${type}] ${msg}`, ...prev].slice(0, 50));
792
+ } catch (e) {
793
+ }
794
+ };
795
+ console.log = (...args) => {
796
+ originalLog(...args);
797
+ addLog("LOG", args);
798
+ };
799
+ console.warn = (...args) => {
800
+ originalWarn(...args);
801
+ addLog("WRN", args);
802
+ };
803
+ console.error = (...args) => {
804
+ originalError(...args);
805
+ addLog("ERR", args);
806
+ };
807
+ return () => {
808
+ console.log = originalLog;
809
+ console.warn = originalWarn;
810
+ console.error = originalError;
811
+ };
812
+ }, []);
715
813
  const handleVoiceResult = useCallback4((text, isFinal) => {
716
814
  if (isFinal) {
717
815
  onResult(text);
@@ -723,6 +821,12 @@ var TapToTalk = ({
723
821
  setVoiceTrigger(null);
724
822
  }, []);
725
823
  const nativeSpeech = useSpeechRecognition(handleVoiceResult, handleVoiceEnd, voiceConfig == null ? void 0 : voiceConfig.language);
824
+ React3.useEffect(() => {
825
+ if (nativeSpeech.error) {
826
+ setErrorMsg(nativeSpeech.error);
827
+ console.error("[TapToTalk] Native Speech Error:", nativeSpeech.error);
828
+ }
829
+ }, [nativeSpeech.error]);
726
830
  const customRecorder = useAudioRecorder(async (blob) => {
727
831
  setVoiceTrigger(null);
728
832
  setIsTranscribing(true);
@@ -751,6 +855,18 @@ var TapToTalk = ({
751
855
  const isListening = !!voiceTrigger || nativeSpeech.isListening || customRecorder.isRecording;
752
856
  const isActive = isListening || isTranscribing;
753
857
  const toggleVoice = async () => {
858
+ const now = Date.now();
859
+ if (now - tapCountRef.current.lastTap < 500) {
860
+ tapCountRef.current.count++;
861
+ } else {
862
+ tapCountRef.current.count = 1;
863
+ }
864
+ tapCountRef.current.lastTap = now;
865
+ if (tapCountRef.current.count >= 5) {
866
+ setShowDebug((prev) => !prev);
867
+ tapCountRef.current.count = 0;
868
+ return;
869
+ }
754
870
  if (isActive) {
755
871
  if (isTranscribing && !isListening) return;
756
872
  if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") {
@@ -788,30 +904,43 @@ var TapToTalk = ({
788
904
  label = "Listening ... Tap to stop";
789
905
  Icon = /* @__PURE__ */ jsx6(MicrophoneIcon2, { className: "h-5 w-5 animate-pulse" });
790
906
  } else if (isTranscribing) {
791
- bgColor = "bg-orange-500";
907
+ bgColor = "bg-indigo-600";
792
908
  label = "Transcribing ...";
793
909
  Icon = /* @__PURE__ */ jsxs4("svg", { className: "animate-spin h-5 w-5 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
794
910
  /* @__PURE__ */ jsx6("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
795
911
  /* @__PURE__ */ jsx6("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
796
912
  ] });
797
913
  }
798
- return /* @__PURE__ */ jsxs4(
799
- "button",
800
- {
801
- onClick: toggleVoice,
802
- disabled: disabled || isTranscribing && !isListening,
803
- className: `flex items-center justify-center gap-3 px-6 py-3 rounded-xl transition-all duration-300 w-full font-medium shadow-md active:scale-[0.98]
914
+ return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col w-full relative", children: [
915
+ showDebug && /* @__PURE__ */ jsxs4("div", { className: "absolute bottom-full left-0 right-0 mb-2 p-2 bg-black/80 text-green-400 text-xs font-mono h-48 overflow-y-auto rounded z-50 pointer-events-auto", children: [
916
+ /* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-center bg-gray-800 p-1 mb-1", children: [
917
+ /* @__PURE__ */ jsx6("span", { children: "Debug Logs" }),
918
+ /* @__PURE__ */ jsx6("button", { onClick: (e) => {
919
+ e.stopPropagation();
920
+ setShowDebug(false);
921
+ }, className: "text-white hover:text-red-400", children: /* @__PURE__ */ jsx6(XMarkIcon2, { className: "w-4 h-4" }) })
922
+ ] }),
923
+ logs.map((log, i) => /* @__PURE__ */ jsx6("div", { className: "mb-0.5 border-b border-gray-700/50 pb-0.5 break-all", children: log }, i)),
924
+ logs.length === 0 && /* @__PURE__ */ jsx6("div", { children: "No logs yet..." })
925
+ ] }),
926
+ /* @__PURE__ */ jsxs4(
927
+ "button",
928
+ {
929
+ onClick: toggleVoice,
930
+ disabled: disabled || isTranscribing && !isListening,
931
+ className: `flex items-center justify-center gap-3 px-6 py-3 rounded-xl transition-all duration-300 w-full font-medium shadow-md active:scale-[0.98]
804
932
  ${bgColor} text-white
805
933
  ${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
806
934
  ${className}`,
807
- title: label,
808
- children: [
809
- /* @__PURE__ */ jsx6("div", { className: "flex items-center justify-center shrink-0", children: Icon }),
810
- /* @__PURE__ */ jsx6("span", { className: "truncate", children: label }),
811
- errorMsg && /* @__PURE__ */ jsx6("span", { className: "text-[10px] bg-white/20 px-1.5 py-0.5 rounded text-red-100 animate-in fade-in slide-in-from-right-1", children: errorMsg })
812
- ]
813
- }
814
- );
935
+ title: label,
936
+ children: [
937
+ /* @__PURE__ */ jsx6("div", { className: "flex items-center justify-center shrink-0", children: Icon }),
938
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children: label }),
939
+ errorMsg && /* @__PURE__ */ jsx6("span", { className: "text-[10px] bg-white/20 px-1.5 py-0.5 rounded text-red-100 animate-in fade-in slide-in-from-right-1", children: errorMsg })
940
+ ]
941
+ }
942
+ )
943
+ ] });
815
944
  };
816
945
 
817
946
  // src/ui/react/components/ChatMessageList.tsx