@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.
|
@@ -429,6 +429,42 @@ var ChatInputArea = (0, import_react5.forwardRef)(({
|
|
|
429
429
|
const [isTranscribing, setIsTranscribing] = (0, import_react5.useState)(false);
|
|
430
430
|
const [voiceError, setVoiceError] = (0, import_react5.useState)(null);
|
|
431
431
|
const [isFocused, setIsFocused] = (0, import_react5.useState)(false);
|
|
432
|
+
const [showDebug, setShowDebug] = (0, import_react5.useState)(false);
|
|
433
|
+
const [logs, setLogs] = (0, import_react5.useState)([]);
|
|
434
|
+
const tapCountRef = (0, import_react5.useRef)({ count: 0, lastTap: 0 });
|
|
435
|
+
(0, import_react5.useEffect)(() => {
|
|
436
|
+
const originalLog = console.log;
|
|
437
|
+
const originalWarn = console.warn;
|
|
438
|
+
const originalError = console.error;
|
|
439
|
+
const addLog = (type, args) => {
|
|
440
|
+
try {
|
|
441
|
+
const msg = args.map((arg) => {
|
|
442
|
+
if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
|
|
443
|
+
if (typeof arg === "object") return JSON.stringify(arg);
|
|
444
|
+
return String(arg);
|
|
445
|
+
}).join(" ");
|
|
446
|
+
setLogs((prev) => [`[${type}] ${msg}`, ...prev].slice(0, 50));
|
|
447
|
+
} catch (e) {
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
console.log = (...args) => {
|
|
451
|
+
originalLog(...args);
|
|
452
|
+
addLog("LOG", args);
|
|
453
|
+
};
|
|
454
|
+
console.warn = (...args) => {
|
|
455
|
+
originalWarn(...args);
|
|
456
|
+
addLog("WRN", args);
|
|
457
|
+
};
|
|
458
|
+
console.error = (...args) => {
|
|
459
|
+
originalError(...args);
|
|
460
|
+
addLog("ERR", args);
|
|
461
|
+
};
|
|
462
|
+
return () => {
|
|
463
|
+
console.log = originalLog;
|
|
464
|
+
console.warn = originalWarn;
|
|
465
|
+
console.error = originalError;
|
|
466
|
+
};
|
|
467
|
+
}, []);
|
|
432
468
|
const textareaRef = (0, import_react5.useRef)(null);
|
|
433
469
|
const measurementRef = (0, import_react5.useRef)(null);
|
|
434
470
|
const pendingSelectionRef = (0, import_react5.useRef)(null);
|
|
@@ -498,6 +534,12 @@ var ChatInputArea = (0, import_react5.forwardRef)(({
|
|
|
498
534
|
(_b2 = (_a2 = voiceConfigRef.current) == null ? void 0 : _a2.onVoiceEnd) == null ? void 0 : _b2.call(_a2);
|
|
499
535
|
}, []);
|
|
500
536
|
const nativeSpeech = useSpeechRecognition(handleVoiceResult, handleVoiceEnd, voiceConfig == null ? void 0 : voiceConfig.language);
|
|
537
|
+
(0, import_react5.useEffect)(() => {
|
|
538
|
+
if (nativeSpeech.error) {
|
|
539
|
+
setVoiceError(nativeSpeech.error);
|
|
540
|
+
console.error("[ChatInputArea] Native Speech Error:", nativeSpeech.error);
|
|
541
|
+
}
|
|
542
|
+
}, [nativeSpeech.error]);
|
|
501
543
|
const customRecorder = useAudioRecorder(async (blob) => {
|
|
502
544
|
var _a2, _b2, _c2;
|
|
503
545
|
setVoiceTrigger(null);
|
|
@@ -611,20 +653,40 @@ var ChatInputArea = (0, import_react5.forwardRef)(({
|
|
|
611
653
|
if (!showInputForm) {
|
|
612
654
|
return null;
|
|
613
655
|
}
|
|
614
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col w-full", children: [
|
|
656
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col w-full relative", children: [
|
|
657
|
+
showDebug && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("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: [
|
|
658
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between items-center bg-gray-800 p-1 mb-1", children: [
|
|
659
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Debug Logs" }),
|
|
660
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { onClick: () => setShowDebug(false), className: "text-white hover:text-red-400", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_outline.XMarkIcon, { className: "w-4 h-4" }) })
|
|
661
|
+
] }),
|
|
662
|
+
logs.map((log, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "mb-0.5 border-b border-gray-700/50 pb-0.5 break-all", children: log }, i)),
|
|
663
|
+
logs.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: "No logs yet..." })
|
|
664
|
+
] }),
|
|
615
665
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
616
666
|
voiceConfig && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
617
667
|
"button",
|
|
618
668
|
{
|
|
619
669
|
type: "button",
|
|
620
670
|
onClick: () => {
|
|
671
|
+
const now = Date.now();
|
|
672
|
+
if (now - tapCountRef.current.lastTap < 500) {
|
|
673
|
+
tapCountRef.current.count++;
|
|
674
|
+
} else {
|
|
675
|
+
tapCountRef.current.count = 1;
|
|
676
|
+
}
|
|
677
|
+
tapCountRef.current.lastTap = now;
|
|
678
|
+
if (tapCountRef.current.count >= 5) {
|
|
679
|
+
setShowDebug((prev) => !prev);
|
|
680
|
+
tapCountRef.current.count = 0;
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
621
683
|
if (voiceTrigger) {
|
|
622
684
|
stopRecording();
|
|
623
685
|
} else if (!isTranscribing) {
|
|
624
686
|
startRecording("click");
|
|
625
687
|
}
|
|
626
688
|
},
|
|
627
|
-
className: `mb-1 p-2 rounded-full transition-all duration-300 flex-shrink-0 border ${
|
|
689
|
+
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" : ""}`,
|
|
628
690
|
disabled: isTranscribing,
|
|
629
691
|
title: isTranscribing ? "Transcribing..." : voiceTrigger ? "Stop Recording" : "Start Voice Input",
|
|
630
692
|
children: isTranscribing ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "animate-spin w-5 h-5 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { className: "w-5 h-5 text-white", viewBox: "0 0 24 24", children: [
|
|
@@ -727,16 +789,16 @@ var ChatInputArea = (0, import_react5.forwardRef)(({
|
|
|
727
789
|
)
|
|
728
790
|
] }),
|
|
729
791
|
inputHint && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-sm text-red-500 bg-red-50 py-1 px-4 rounded-lg mt-1", children: inputHint }),
|
|
730
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ml-[46px] mb-2 mt-0.5 min-h-[0.75rem]", style: { marginLeft: "48px" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: `text-[10px] leading-tight transition-all duration-200 ${voiceError ? "text-red-500" :
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ml-[46px] mb-2 mt-0.5 min-h-[0.75rem]", style: { marginLeft: "48px" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "flex items-center gap-1 font-semibold italic", children: [
|
|
731
793
|
"Error: ",
|
|
732
794
|
voiceError
|
|
733
|
-
] }) : 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...") }) })
|
|
795
|
+
] }) : 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...") }) })
|
|
734
796
|
] });
|
|
735
797
|
});
|
|
736
798
|
ChatInputArea.displayName = "ChatInputArea";
|
|
737
799
|
|
|
738
800
|
// src/ui/react/components/TapToTalk.tsx
|
|
739
|
-
var import_react6 = require("react");
|
|
801
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
740
802
|
var import_outline2 = require("@heroicons/react/24/outline");
|
|
741
803
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
742
804
|
var TapToTalk = ({
|
|
@@ -754,6 +816,42 @@ var TapToTalk = ({
|
|
|
754
816
|
const [isTranscribing, setIsTranscribing] = (0, import_react6.useState)(false);
|
|
755
817
|
const [voiceTrigger, setVoiceTrigger] = (0, import_react6.useState)(null);
|
|
756
818
|
const [errorMsg, setErrorMsg] = (0, import_react6.useState)(null);
|
|
819
|
+
const [showDebug, setShowDebug] = (0, import_react6.useState)(false);
|
|
820
|
+
const [logs, setLogs] = (0, import_react6.useState)([]);
|
|
821
|
+
const tapCountRef = (0, import_react6.useRef)({ count: 0, lastTap: 0 });
|
|
822
|
+
import_react6.default.useEffect(() => {
|
|
823
|
+
const originalLog = console.log;
|
|
824
|
+
const originalWarn = console.warn;
|
|
825
|
+
const originalError = console.error;
|
|
826
|
+
const addLog = (type, args) => {
|
|
827
|
+
try {
|
|
828
|
+
const msg = args.map((arg) => {
|
|
829
|
+
if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
|
|
830
|
+
if (typeof arg === "object") return JSON.stringify(arg);
|
|
831
|
+
return String(arg);
|
|
832
|
+
}).join(" ");
|
|
833
|
+
setLogs((prev) => [`[${type}] ${msg}`, ...prev].slice(0, 50));
|
|
834
|
+
} catch (e) {
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
console.log = (...args) => {
|
|
838
|
+
originalLog(...args);
|
|
839
|
+
addLog("LOG", args);
|
|
840
|
+
};
|
|
841
|
+
console.warn = (...args) => {
|
|
842
|
+
originalWarn(...args);
|
|
843
|
+
addLog("WRN", args);
|
|
844
|
+
};
|
|
845
|
+
console.error = (...args) => {
|
|
846
|
+
originalError(...args);
|
|
847
|
+
addLog("ERR", args);
|
|
848
|
+
};
|
|
849
|
+
return () => {
|
|
850
|
+
console.log = originalLog;
|
|
851
|
+
console.warn = originalWarn;
|
|
852
|
+
console.error = originalError;
|
|
853
|
+
};
|
|
854
|
+
}, []);
|
|
757
855
|
const handleVoiceResult = (0, import_react6.useCallback)((text, isFinal) => {
|
|
758
856
|
if (isFinal) {
|
|
759
857
|
onResult(text);
|
|
@@ -765,6 +863,12 @@ var TapToTalk = ({
|
|
|
765
863
|
setVoiceTrigger(null);
|
|
766
864
|
}, []);
|
|
767
865
|
const nativeSpeech = useSpeechRecognition(handleVoiceResult, handleVoiceEnd, voiceConfig == null ? void 0 : voiceConfig.language);
|
|
866
|
+
import_react6.default.useEffect(() => {
|
|
867
|
+
if (nativeSpeech.error) {
|
|
868
|
+
setErrorMsg(nativeSpeech.error);
|
|
869
|
+
console.error("[TapToTalk] Native Speech Error:", nativeSpeech.error);
|
|
870
|
+
}
|
|
871
|
+
}, [nativeSpeech.error]);
|
|
768
872
|
const customRecorder = useAudioRecorder(async (blob) => {
|
|
769
873
|
setVoiceTrigger(null);
|
|
770
874
|
setIsTranscribing(true);
|
|
@@ -793,6 +897,18 @@ var TapToTalk = ({
|
|
|
793
897
|
const isListening = !!voiceTrigger || nativeSpeech.isListening || customRecorder.isRecording;
|
|
794
898
|
const isActive = isListening || isTranscribing;
|
|
795
899
|
const toggleVoice = async () => {
|
|
900
|
+
const now = Date.now();
|
|
901
|
+
if (now - tapCountRef.current.lastTap < 500) {
|
|
902
|
+
tapCountRef.current.count++;
|
|
903
|
+
} else {
|
|
904
|
+
tapCountRef.current.count = 1;
|
|
905
|
+
}
|
|
906
|
+
tapCountRef.current.lastTap = now;
|
|
907
|
+
if (tapCountRef.current.count >= 5) {
|
|
908
|
+
setShowDebug((prev) => !prev);
|
|
909
|
+
tapCountRef.current.count = 0;
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
796
912
|
if (isActive) {
|
|
797
913
|
if (isTranscribing && !isListening) return;
|
|
798
914
|
if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") {
|
|
@@ -830,30 +946,43 @@ var TapToTalk = ({
|
|
|
830
946
|
label = "Listening ... Tap to stop";
|
|
831
947
|
Icon = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_outline2.MicrophoneIcon, { className: "h-5 w-5 animate-pulse" });
|
|
832
948
|
} else if (isTranscribing) {
|
|
833
|
-
bgColor = "bg-
|
|
949
|
+
bgColor = "bg-indigo-600";
|
|
834
950
|
label = "Transcribing ...";
|
|
835
951
|
Icon = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("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: [
|
|
836
952
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
837
953
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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" })
|
|
838
954
|
] });
|
|
839
955
|
}
|
|
840
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
841
|
-
"
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
956
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col w-full relative", children: [
|
|
957
|
+
showDebug && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("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: [
|
|
958
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex justify-between items-center bg-gray-800 p-1 mb-1", children: [
|
|
959
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Debug Logs" }),
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: (e) => {
|
|
961
|
+
e.stopPropagation();
|
|
962
|
+
setShowDebug(false);
|
|
963
|
+
}, className: "text-white hover:text-red-400", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_outline2.XMarkIcon, { className: "w-4 h-4" }) })
|
|
964
|
+
] }),
|
|
965
|
+
logs.map((log, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mb-0.5 border-b border-gray-700/50 pb-0.5 break-all", children: log }, i)),
|
|
966
|
+
logs.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: "No logs yet..." })
|
|
967
|
+
] }),
|
|
968
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
969
|
+
"button",
|
|
970
|
+
{
|
|
971
|
+
onClick: toggleVoice,
|
|
972
|
+
disabled: disabled || isTranscribing && !isListening,
|
|
973
|
+
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]
|
|
846
974
|
${bgColor} text-white
|
|
847
975
|
${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
|
|
848
976
|
${className}`,
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
977
|
+
title: label,
|
|
978
|
+
children: [
|
|
979
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex items-center justify-center shrink-0", children: Icon }),
|
|
980
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", children: label }),
|
|
981
|
+
errorMsg && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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 })
|
|
982
|
+
]
|
|
983
|
+
}
|
|
984
|
+
)
|
|
985
|
+
] });
|
|
857
986
|
};
|
|
858
987
|
|
|
859
988
|
// src/ui/react/components/ChatMessageList.tsx
|