@red-hat-developer-hub/backstage-plugin-lightspeed 0.5.7 → 0.6.0
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.
- package/CHANGELOG.md +14 -0
- package/dist/components/Attachment.esm.js +71 -61
- package/dist/components/Attachment.esm.js.map +1 -1
- package/dist/components/AttachmentContext.esm.js +32 -23
- package/dist/components/AttachmentContext.esm.js.map +1 -1
- package/dist/components/DeleteModal.esm.js +24 -15
- package/dist/components/DeleteModal.esm.js.map +1 -1
- package/dist/components/FilePreview.esm.js +16 -13
- package/dist/components/FilePreview.esm.js.map +1 -1
- package/dist/components/LightSpeedChat.esm.js +172 -129
- package/dist/components/LightSpeedChat.esm.js.map +1 -1
- package/dist/components/LightspeedChatBox.esm.js +43 -34
- package/dist/components/LightspeedChatBox.esm.js.map +1 -1
- package/dist/components/LightspeedChatBoxHeader.esm.js +15 -12
- package/dist/components/LightspeedChatBoxHeader.esm.js.map +1 -1
- package/dist/components/LightspeedIcon.esm.js +11 -2
- package/dist/components/LightspeedIcon.esm.js.map +1 -1
- package/dist/components/LightspeedPage.esm.js +32 -26
- package/dist/components/LightspeedPage.esm.js.map +1 -1
- package/dist/components/PermissionRequiredIcon.esm.js +10 -2
- package/dist/components/PermissionRequiredIcon.esm.js.map +1 -1
- package/dist/components/PermissionRequiredState.esm.js +25 -11
- package/dist/components/PermissionRequiredState.esm.js.map +1 -1
- package/dist/components/Trans.esm.js +33 -0
- package/dist/components/Trans.esm.js.map +1 -0
- package/dist/const.esm.js +20 -43
- package/dist/const.esm.js.map +1 -1
- package/dist/hooks/useAutoScroll.esm.js +11 -11
- package/dist/hooks/useAutoScroll.esm.js.map +1 -1
- package/dist/hooks/useBufferedMessages.esm.js +5 -5
- package/dist/hooks/useBufferedMessages.esm.js.map +1 -1
- package/dist/hooks/useConversationMessages.esm.js +8 -8
- package/dist/hooks/useConversationMessages.esm.js.map +1 -1
- package/dist/hooks/useFeedbackActions.esm.js +47 -18
- package/dist/hooks/useFeedbackActions.esm.js.map +1 -1
- package/dist/hooks/useIsMobile.esm.js +3 -3
- package/dist/hooks/useIsMobile.esm.js.map +1 -1
- package/dist/hooks/useLastOpenedConversation.esm.js.map +1 -1
- package/dist/hooks/useTranslation.esm.js +7 -0
- package/dist/hooks/useTranslation.esm.js.map +1 -0
- package/dist/hooks/useWelcomePrompts.esm.js +21 -6
- package/dist/hooks/useWelcomePrompts.esm.js.map +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/translations/de.esm.js +128 -0
- package/dist/translations/de.esm.js.map +1 -0
- package/dist/translations/es.esm.js +128 -0
- package/dist/translations/es.esm.js.map +1 -0
- package/dist/translations/fr.esm.js +128 -0
- package/dist/translations/fr.esm.js.map +1 -0
- package/dist/translations/index.esm.js +14 -0
- package/dist/translations/index.esm.js.map +1 -0
- package/dist/translations/translationRef.esm.js +128 -0
- package/dist/translations/translationRef.esm.js.map +1 -0
- package/dist/types.esm.js.map +1 -1
- package/dist/utils/lightspeed-chatbox-utils.esm.js +24 -21
- package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -1
- package/package.json +12 -12
package/dist/const.esm.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
const TEMP_CONVERSATION_ID = "temp-conversation-id";
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
const createPrompt = (title, message) => {
|
|
5
|
-
return { title, message };
|
|
2
|
+
const createPrompt = (titleKey, messageKey) => {
|
|
3
|
+
return { titleKey, messageKey };
|
|
6
4
|
};
|
|
7
5
|
const supportedFileTypes = {
|
|
8
6
|
"text/plain": [".txt"],
|
|
@@ -12,56 +10,35 @@ const supportedFileTypes = {
|
|
|
12
10
|
};
|
|
13
11
|
const DEFAULT_SAMPLE_PROMPTS = [
|
|
14
12
|
createPrompt(
|
|
15
|
-
"
|
|
16
|
-
"
|
|
13
|
+
"prompts.codeReadability.title",
|
|
14
|
+
"prompts.codeReadability.message"
|
|
17
15
|
),
|
|
16
|
+
createPrompt("prompts.debugging.title", "prompts.debugging.message"),
|
|
18
17
|
createPrompt(
|
|
19
|
-
"
|
|
20
|
-
"
|
|
18
|
+
"prompts.developmentConcept.title",
|
|
19
|
+
"prompts.developmentConcept.message"
|
|
21
20
|
),
|
|
22
21
|
createPrompt(
|
|
23
|
-
"
|
|
24
|
-
"
|
|
22
|
+
"prompts.codeOptimization.title",
|
|
23
|
+
"prompts.codeOptimization.message"
|
|
25
24
|
),
|
|
25
|
+
createPrompt("prompts.documentation.title", "prompts.documentation.message"),
|
|
26
|
+
createPrompt("prompts.gitWorkflows.title", "prompts.gitWorkflows.message"),
|
|
26
27
|
createPrompt(
|
|
27
|
-
"
|
|
28
|
-
"
|
|
28
|
+
"prompts.testingStrategies.title",
|
|
29
|
+
"prompts.testingStrategies.message"
|
|
29
30
|
),
|
|
30
31
|
createPrompt(
|
|
31
|
-
"
|
|
32
|
-
"
|
|
32
|
+
"prompts.sortingAlgorithms.title",
|
|
33
|
+
"prompts.sortingAlgorithms.message"
|
|
33
34
|
),
|
|
34
|
-
createPrompt(
|
|
35
|
-
"Workflows With Git",
|
|
36
|
-
"I want to make changes to code on another branch without loosing my existing work. What is the procedure to do this using Git?"
|
|
37
|
-
),
|
|
38
|
-
createPrompt(
|
|
39
|
-
"Suggest Testing Strategies",
|
|
40
|
-
"Can you recommend some common testing strategies that will make my application robust and error-free?"
|
|
41
|
-
),
|
|
42
|
-
createPrompt(
|
|
43
|
-
"Demystify Sorting Algorithms",
|
|
44
|
-
"Can you explain the difference between a quicksort and a merge sort algorithm, and when to use each?"
|
|
45
|
-
),
|
|
46
|
-
createPrompt(
|
|
47
|
-
"Understand Event-Driven Architecture",
|
|
48
|
-
"Can you explain what event-driven architecture is and when it\u2019s beneficial to use it in software development?"
|
|
49
|
-
)
|
|
35
|
+
createPrompt("prompts.eventDriven.title", "prompts.eventDriven.message")
|
|
50
36
|
];
|
|
51
37
|
const RHDH_SAMPLE_PROMPTS = [
|
|
52
|
-
createPrompt(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
),
|
|
56
|
-
createPrompt(
|
|
57
|
-
"Create An OpenShift Deployment",
|
|
58
|
-
"Can you guide me through creating a new deployment in OpenShift for a containerized application?"
|
|
59
|
-
),
|
|
60
|
-
createPrompt(
|
|
61
|
-
"Getting Started with Red Hat Developer Hub",
|
|
62
|
-
"Can you guide me through the first steps to start using Developer Hub as a developer, like exploring the Software Catalog and adding my service?"
|
|
63
|
-
)
|
|
38
|
+
createPrompt("prompts.tekton.title", "prompts.tekton.message"),
|
|
39
|
+
createPrompt("prompts.openshift.title", "prompts.openshift.message"),
|
|
40
|
+
createPrompt("prompts.rhdh.title", "prompts.rhdh.message")
|
|
64
41
|
];
|
|
65
42
|
|
|
66
|
-
export { DEFAULT_SAMPLE_PROMPTS,
|
|
43
|
+
export { DEFAULT_SAMPLE_PROMPTS, RHDH_SAMPLE_PROMPTS, TEMP_CONVERSATION_ID, supportedFileTypes };
|
|
67
44
|
//# sourceMappingURL=const.esm.js.map
|
package/dist/const.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"const.esm.js","sources":["../src/const.ts"],"sourcesContent":["import { SamplePrompts } from './types';\n\n/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport const TEMP_CONVERSATION_ID = 'temp-conversation-id';\n\
|
|
1
|
+
{"version":3,"file":"const.esm.js","sources":["../src/const.ts"],"sourcesContent":["import { SamplePrompts } from './types';\n\n/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport const TEMP_CONVERSATION_ID = 'temp-conversation-id';\n\n// Translation keys for disclaimers\nexport const FUNCTION_DISCLAIMER_WITHOUT_QUESTION_VALIDATION_KEY =\n 'disclaimer.withoutValidation';\nexport const FUNCTION_DISCLAIMER_KEY = 'disclaimer.withValidation';\n\nconst createPrompt = (titleKey: string, messageKey: string) => {\n return { titleKey, messageKey };\n};\n\nexport const supportedFileTypes = {\n 'text/plain': ['.txt'],\n 'application/json': ['.json'],\n 'application/yaml': ['.yaml', '.yml'],\n 'application/xml': ['.xml'],\n};\n\nexport const DEFAULT_SAMPLE_PROMPTS: SamplePrompts = [\n createPrompt(\n 'prompts.codeReadability.title',\n 'prompts.codeReadability.message',\n ),\n createPrompt('prompts.debugging.title', 'prompts.debugging.message'),\n createPrompt(\n 'prompts.developmentConcept.title',\n 'prompts.developmentConcept.message',\n ),\n createPrompt(\n 'prompts.codeOptimization.title',\n 'prompts.codeOptimization.message',\n ),\n createPrompt('prompts.documentation.title', 'prompts.documentation.message'),\n createPrompt('prompts.gitWorkflows.title', 'prompts.gitWorkflows.message'),\n createPrompt(\n 'prompts.testingStrategies.title',\n 'prompts.testingStrategies.message',\n ),\n createPrompt(\n 'prompts.sortingAlgorithms.title',\n 'prompts.sortingAlgorithms.message',\n ),\n createPrompt('prompts.eventDriven.title', 'prompts.eventDriven.message'),\n];\n\nexport const RHDH_SAMPLE_PROMPTS: SamplePrompts = [\n createPrompt('prompts.tekton.title', 'prompts.tekton.message'),\n createPrompt('prompts.openshift.title', 'prompts.openshift.message'),\n createPrompt('prompts.rhdh.title', 'prompts.rhdh.message'),\n];\n"],"names":[],"mappings":"AAiBO,MAAM,oBAAuB,GAAA;AAOpC,MAAM,YAAA,GAAe,CAAC,QAAA,EAAkB,UAAuB,KAAA;AAC7D,EAAO,OAAA,EAAE,UAAU,UAAW,EAAA;AAChC,CAAA;AAEO,MAAM,kBAAqB,GAAA;AAAA,EAChC,YAAA,EAAc,CAAC,MAAM,CAAA;AAAA,EACrB,kBAAA,EAAoB,CAAC,OAAO,CAAA;AAAA,EAC5B,kBAAA,EAAoB,CAAC,OAAA,EAAS,MAAM,CAAA;AAAA,EACpC,iBAAA,EAAmB,CAAC,MAAM;AAC5B;AAEO,MAAM,sBAAwC,GAAA;AAAA,EACnD,YAAA;AAAA,IACE,+BAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,2BAA2B,2BAA2B,CAAA;AAAA,EACnE,YAAA;AAAA,IACE,kCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA;AAAA,IACE,gCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,+BAA+B,+BAA+B,CAAA;AAAA,EAC3E,YAAA,CAAa,8BAA8B,8BAA8B,CAAA;AAAA,EACzE,YAAA;AAAA,IACE,iCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA;AAAA,IACE,iCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,6BAA6B,6BAA6B;AACzE;AAEO,MAAM,mBAAqC,GAAA;AAAA,EAChD,YAAA,CAAa,wBAAwB,wBAAwB,CAAA;AAAA,EAC7D,YAAA,CAAa,2BAA2B,2BAA2B,CAAA;AAAA,EACnE,YAAA,CAAa,sBAAsB,sBAAsB;AAC3D;;;;"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
3
|
const useAutoScroll = (containerRef, options = {}) => {
|
|
4
4
|
const { deltaUp = 10, deltaDown = 60, delay = 200 } = options;
|
|
5
|
-
const [autoScroll, setAutoScroll] =
|
|
6
|
-
const lastScrollTop =
|
|
7
|
-
const manualScrollInterrupted =
|
|
8
|
-
const debounceTimeout =
|
|
9
|
-
const onScroll =
|
|
5
|
+
const [autoScroll, setAutoScroll] = React.useState(true);
|
|
6
|
+
const lastScrollTop = React.useRef(0);
|
|
7
|
+
const manualScrollInterrupted = React.useRef(false);
|
|
8
|
+
const debounceTimeout = React.useRef(null);
|
|
9
|
+
const onScroll = React.useCallback(() => {
|
|
10
10
|
const container = containerRef.current;
|
|
11
11
|
if (!container) return;
|
|
12
12
|
const currentScrollTop = container.scrollTop;
|
|
@@ -27,7 +27,7 @@ const useAutoScroll = (containerRef, options = {}) => {
|
|
|
27
27
|
}
|
|
28
28
|
lastScrollTop.current = currentScrollTop;
|
|
29
29
|
}, [containerRef, deltaUp, deltaDown, delay]);
|
|
30
|
-
|
|
30
|
+
React.useEffect(() => {
|
|
31
31
|
const container = containerRef.current;
|
|
32
32
|
if (!container) {
|
|
33
33
|
return undefined;
|
|
@@ -38,15 +38,15 @@ const useAutoScroll = (containerRef, options = {}) => {
|
|
|
38
38
|
if (debounceTimeout.current) clearTimeout(debounceTimeout.current);
|
|
39
39
|
};
|
|
40
40
|
}, [onScroll, containerRef]);
|
|
41
|
-
const resumeAutoScroll =
|
|
41
|
+
const resumeAutoScroll = React.useCallback(() => {
|
|
42
42
|
manualScrollInterrupted.current = false;
|
|
43
43
|
setAutoScroll(true);
|
|
44
44
|
}, []);
|
|
45
|
-
const stopAutoScroll =
|
|
45
|
+
const stopAutoScroll = React.useCallback(() => {
|
|
46
46
|
manualScrollInterrupted.current = true;
|
|
47
47
|
setAutoScroll(false);
|
|
48
48
|
}, []);
|
|
49
|
-
const scrollToTop =
|
|
49
|
+
const scrollToTop = React.useCallback(() => {
|
|
50
50
|
stopAutoScroll();
|
|
51
51
|
const container = containerRef.current;
|
|
52
52
|
if (!container) return;
|
|
@@ -55,7 +55,7 @@ const useAutoScroll = (containerRef, options = {}) => {
|
|
|
55
55
|
behavior: "smooth"
|
|
56
56
|
});
|
|
57
57
|
}, [stopAutoScroll, containerRef]);
|
|
58
|
-
const scrollToBottom =
|
|
58
|
+
const scrollToBottom = React.useCallback(() => {
|
|
59
59
|
const container = containerRef.current;
|
|
60
60
|
if (container) {
|
|
61
61
|
container.scrollTo({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAutoScroll.esm.js","sources":["../../src/hooks/useAutoScroll.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\n\ninterface useAutoScrollOptions {\n deltaUp?: number;\n deltaDown?: number;\n delay?: number;\n}\n\nexport const useAutoScroll = (\n containerRef: React.RefObject<HTMLElement>,\n options: useAutoScrollOptions = {},\n) => {\n const { deltaUp = 10, deltaDown = 60, delay = 200 } = options;\n\n const [autoScroll, setAutoScroll] = React.useState(true);\n const lastScrollTop = React.useRef(0);\n const manualScrollInterrupted = React.useRef(false);\n const debounceTimeout = React.useRef<NodeJS.Timeout | null>(null);\n\n const onScroll = React.useCallback(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const currentScrollTop = container.scrollTop;\n const isScrollingDown = currentScrollTop > lastScrollTop.current;\n\n const distanceFromBottom =\n container.scrollHeight - container.scrollTop - container.clientHeight;\n\n const delta = isScrollingDown ? deltaDown : deltaUp;\n const isAtBottom = distanceFromBottom <= delta;\n\n if (debounceTimeout.current) clearTimeout(debounceTimeout.current);\n\n if (isAtBottom && manualScrollInterrupted.current && isScrollingDown) {\n debounceTimeout.current = setTimeout(() => {\n manualScrollInterrupted.current = false;\n setAutoScroll(true);\n }, delay);\n }\n\n if (!isAtBottom && !manualScrollInterrupted.current) {\n manualScrollInterrupted.current = true;\n setAutoScroll(false);\n }\n\n lastScrollTop.current = currentScrollTop;\n }, [containerRef, deltaUp, deltaDown, delay]);\n\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) {\n return undefined;\n }\n\n container.addEventListener('scroll', onScroll, { passive: true });\n return () => {\n container.removeEventListener('scroll', onScroll);\n if (debounceTimeout.current) clearTimeout(debounceTimeout.current);\n };\n }, [onScroll, containerRef]);\n\n const resumeAutoScroll = React.useCallback(() => {\n manualScrollInterrupted.current = false;\n setAutoScroll(true);\n }, []);\n\n const stopAutoScroll = React.useCallback(() => {\n manualScrollInterrupted.current = true;\n setAutoScroll(false);\n }, []);\n\n const scrollToTop = React.useCallback(() => {\n stopAutoScroll();\n const container = containerRef.current;\n if (!container) return;\n\n container.scrollTo({\n top: 0,\n behavior: 'smooth',\n });\n }, [stopAutoScroll, containerRef]);\n\n const scrollToBottom = React.useCallback(() => {\n const container = containerRef.current;\n if (container) {\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'smooth',\n });\n }\n resumeAutoScroll();\n }, [resumeAutoScroll, containerRef]);\n\n return {\n autoScroll,\n resumeAutoScroll,\n stopAutoScroll,\n scrollToBottom,\n scrollToTop,\n };\n};\n"],"names":[
|
|
1
|
+
{"version":3,"file":"useAutoScroll.esm.js","sources":["../../src/hooks/useAutoScroll.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\n\ninterface useAutoScrollOptions {\n deltaUp?: number;\n deltaDown?: number;\n delay?: number;\n}\n\nexport const useAutoScroll = (\n containerRef: React.RefObject<HTMLElement>,\n options: useAutoScrollOptions = {},\n) => {\n const { deltaUp = 10, deltaDown = 60, delay = 200 } = options;\n\n const [autoScroll, setAutoScroll] = React.useState(true);\n const lastScrollTop = React.useRef(0);\n const manualScrollInterrupted = React.useRef(false);\n const debounceTimeout = React.useRef<NodeJS.Timeout | null>(null);\n\n const onScroll = React.useCallback(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const currentScrollTop = container.scrollTop;\n const isScrollingDown = currentScrollTop > lastScrollTop.current;\n\n const distanceFromBottom =\n container.scrollHeight - container.scrollTop - container.clientHeight;\n\n const delta = isScrollingDown ? deltaDown : deltaUp;\n const isAtBottom = distanceFromBottom <= delta;\n\n if (debounceTimeout.current) clearTimeout(debounceTimeout.current);\n\n if (isAtBottom && manualScrollInterrupted.current && isScrollingDown) {\n debounceTimeout.current = setTimeout(() => {\n manualScrollInterrupted.current = false;\n setAutoScroll(true);\n }, delay);\n }\n\n if (!isAtBottom && !manualScrollInterrupted.current) {\n manualScrollInterrupted.current = true;\n setAutoScroll(false);\n }\n\n lastScrollTop.current = currentScrollTop;\n }, [containerRef, deltaUp, deltaDown, delay]);\n\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) {\n return undefined;\n }\n\n container.addEventListener('scroll', onScroll, { passive: true });\n return () => {\n container.removeEventListener('scroll', onScroll);\n if (debounceTimeout.current) clearTimeout(debounceTimeout.current);\n };\n }, [onScroll, containerRef]);\n\n const resumeAutoScroll = React.useCallback(() => {\n manualScrollInterrupted.current = false;\n setAutoScroll(true);\n }, []);\n\n const stopAutoScroll = React.useCallback(() => {\n manualScrollInterrupted.current = true;\n setAutoScroll(false);\n }, []);\n\n const scrollToTop = React.useCallback(() => {\n stopAutoScroll();\n const container = containerRef.current;\n if (!container) return;\n\n container.scrollTo({\n top: 0,\n behavior: 'smooth',\n });\n }, [stopAutoScroll, containerRef]);\n\n const scrollToBottom = React.useCallback(() => {\n const container = containerRef.current;\n if (container) {\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'smooth',\n });\n }\n resumeAutoScroll();\n }, [resumeAutoScroll, containerRef]);\n\n return {\n autoScroll,\n resumeAutoScroll,\n stopAutoScroll,\n scrollToBottom,\n scrollToTop,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
3
|
const useBufferedMessages = (messages, interval = 30) => {
|
|
4
|
-
const [bufferedMessages, setBufferedMessages] =
|
|
5
|
-
const lastUpdateTime =
|
|
6
|
-
const animationFrame =
|
|
7
|
-
|
|
4
|
+
const [bufferedMessages, setBufferedMessages] = React.useState(messages);
|
|
5
|
+
const lastUpdateTime = React.useRef(0);
|
|
6
|
+
const animationFrame = React.useRef(null);
|
|
7
|
+
React.useEffect(() => {
|
|
8
8
|
const now = Date.now();
|
|
9
9
|
const update = () => {
|
|
10
10
|
setBufferedMessages(messages);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBufferedMessages.esm.js","sources":["../../src/hooks/useBufferedMessages.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\n\nexport const useBufferedMessages = <T>(messages: T[], interval = 30): T[] => {\n const [bufferedMessages, setBufferedMessages] = React.useState(messages);\n const lastUpdateTime = React.useRef(0);\n const animationFrame = React.useRef<number | null>(null);\n\n React.useEffect(() => {\n const now = Date.now();\n\n const update = () => {\n setBufferedMessages(messages);\n lastUpdateTime.current = now;\n };\n\n if (now - lastUpdateTime.current > interval) {\n update();\n } else {\n if (animationFrame.current) cancelAnimationFrame(animationFrame.current);\n animationFrame.current = requestAnimationFrame(update);\n }\n\n return () => {\n if (animationFrame.current) cancelAnimationFrame(animationFrame.current);\n };\n }, [messages, interval]);\n\n return bufferedMessages;\n};\n"],"names":[
|
|
1
|
+
{"version":3,"file":"useBufferedMessages.esm.js","sources":["../../src/hooks/useBufferedMessages.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\n\nexport const useBufferedMessages = <T>(messages: T[], interval = 30): T[] => {\n const [bufferedMessages, setBufferedMessages] = React.useState(messages);\n const lastUpdateTime = React.useRef(0);\n const animationFrame = React.useRef<number | null>(null);\n\n React.useEffect(() => {\n const now = Date.now();\n\n const update = () => {\n setBufferedMessages(messages);\n lastUpdateTime.current = now;\n };\n\n if (now - lastUpdateTime.current > interval) {\n update();\n } else {\n if (animationFrame.current) cancelAnimationFrame(animationFrame.current);\n animationFrame.current = requestAnimationFrame(update);\n }\n\n return () => {\n if (animationFrame.current) cancelAnimationFrame(animationFrame.current);\n };\n }, [messages, interval]);\n\n return bufferedMessages;\n};\n"],"names":[],"mappings":";;AAiBO,MAAM,mBAAsB,GAAA,CAAI,QAAe,EAAA,QAAA,GAAW,EAAY,KAAA;AAC3E,EAAA,MAAM,CAAC,gBAAkB,EAAA,mBAAmB,CAAI,GAAA,KAAA,CAAM,SAAS,QAAQ,CAAA;AACvE,EAAM,MAAA,cAAA,GAAiB,KAAM,CAAA,MAAA,CAAO,CAAC,CAAA;AACrC,EAAM,MAAA,cAAA,GAAiB,KAAM,CAAA,MAAA,CAAsB,IAAI,CAAA;AAEvD,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAM,MAAA,GAAA,GAAM,KAAK,GAAI,EAAA;AAErB,IAAA,MAAM,SAAS,MAAM;AACnB,MAAA,mBAAA,CAAoB,QAAQ,CAAA;AAC5B,MAAA,cAAA,CAAe,OAAU,GAAA,GAAA;AAAA,KAC3B;AAEA,IAAI,IAAA,GAAA,GAAM,cAAe,CAAA,OAAA,GAAU,QAAU,EAAA;AAC3C,MAAO,MAAA,EAAA;AAAA,KACF,MAAA;AACL,MAAA,IAAI,cAAe,CAAA,OAAA,EAA8B,oBAAA,CAAA,cAAA,CAAe,OAAO,CAAA;AACvE,MAAe,cAAA,CAAA,OAAA,GAAU,sBAAsB,MAAM,CAAA;AAAA;AAGvD,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,cAAe,CAAA,OAAA,EAA8B,oBAAA,CAAA,cAAA,CAAe,OAAO,CAAA;AAAA,KACzE;AAAA,GACC,EAAA,CAAC,QAAU,EAAA,QAAQ,CAAC,CAAA;AAEvB,EAAO,OAAA,gBAAA;AACT;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { useApi } from '@backstage/core-plugin-api';
|
|
3
3
|
import { useQuery } from '@tanstack/react-query';
|
|
4
4
|
import { lightspeedApiRef } from '../api/api.esm.js';
|
|
@@ -21,15 +21,15 @@ const useFetchConversationMessages = (currentConversation) => {
|
|
|
21
21
|
};
|
|
22
22
|
const useConversationMessages = (conversationId, userName, selectedModel, avatar = userAvatar, onComplete, onStart) => {
|
|
23
23
|
const { mutateAsync: createMessage } = useCreateConversationMessage();
|
|
24
|
-
const scrollToBottomRef =
|
|
25
|
-
const [currentConversation, setCurrentConversation] =
|
|
26
|
-
const [conversations, setConversations] =
|
|
24
|
+
const scrollToBottomRef = React.useRef(null);
|
|
25
|
+
const [currentConversation, setCurrentConversation] = React.useState(conversationId);
|
|
26
|
+
const [conversations, setConversations] = React.useState({
|
|
27
27
|
[currentConversation]: []
|
|
28
28
|
});
|
|
29
|
-
const streamingConversations =
|
|
29
|
+
const streamingConversations = React.useRef({
|
|
30
30
|
[currentConversation]: []
|
|
31
31
|
});
|
|
32
|
-
|
|
32
|
+
React.useEffect(() => {
|
|
33
33
|
if (currentConversation !== conversationId) {
|
|
34
34
|
setCurrentConversation(conversationId);
|
|
35
35
|
setConversations((prev) => {
|
|
@@ -42,7 +42,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
|
|
|
42
42
|
}
|
|
43
43
|
}, [currentConversation, conversationId]);
|
|
44
44
|
const { data: conversationsData = [], ...queryProps } = useFetchConversationMessages(currentConversation);
|
|
45
|
-
|
|
45
|
+
React.useEffect(() => {
|
|
46
46
|
if (!Array.isArray(conversationsData) || conversationsData.length === 0 && conversationId !== TEMP_CONVERSATION_ID)
|
|
47
47
|
return;
|
|
48
48
|
if (conversations) {
|
|
@@ -93,7 +93,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
|
|
|
93
93
|
selectedModel,
|
|
94
94
|
streamingConversations
|
|
95
95
|
]);
|
|
96
|
-
const handleInputPrompt =
|
|
96
|
+
const handleInputPrompt = React.useCallback(
|
|
97
97
|
async (prompt, attachments = []) => {
|
|
98
98
|
let newConversationId = "";
|
|
99
99
|
const conversationTuple = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConversationMessages.esm.js","sources":["../../src/hooks/useConversationMessages.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { useApi } from '@backstage/core-plugin-api';\n\nimport { MessageProps } from '@patternfly/chatbot';\nimport { useQuery } from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\nimport { ScrollContainerHandle } from '../components/LightspeedChatBox';\nimport { TEMP_CONVERSATION_ID } from '../const';\nimport botAvatar from '../images/bot-avatar.svg';\nimport userAvatar from '../images/user-avatar.svg';\nimport { Attachment, ReferencedDocument } from '../types';\nimport {\n createBotMessage,\n createUserMessage,\n getMessageData,\n getTimestamp,\n transformDocumentsToSources,\n} from '../utils/lightspeed-chatbox-utils';\nimport { useCreateConversationMessage } from './useCreateCoversationMessage';\n\n// Fetch all conversation messages\nexport const useFetchConversationMessages = (currentConversation: string) => {\n const lightspeedApi = useApi(lightspeedApiRef);\n return useQuery({\n queryKey: ['conversationMessages', currentConversation],\n queryFn: currentConversation\n ? async () => {\n const response =\n await lightspeedApi.getConversationMessages(currentConversation);\n\n return response;\n }\n : undefined,\n retry: false,\n });\n};\n\ntype Conversations = { [_key: string]: MessageProps[] };\n\n/**\n * Fetches all the messages for given conversation_id\n * @param conversationId\n * @param userName\n * @param selectedModel\n * @param avatar\n *\n */\nexport const useConversationMessages = (\n conversationId: string,\n userName: string | undefined,\n selectedModel: string,\n avatar: string = userAvatar,\n onComplete?: (message: string) => void,\n onStart?: (conversation_id: string) => void,\n) => {\n const { mutateAsync: createMessage } = useCreateConversationMessage();\n const scrollToBottomRef = React.useRef<ScrollContainerHandle>(null);\n\n const [currentConversation, setCurrentConversation] =\n React.useState(conversationId);\n const [conversations, setConversations] = React.useState<Conversations>({\n [currentConversation]: [],\n });\n const streamingConversations = React.useRef<Conversations>({\n [currentConversation]: [],\n });\n\n React.useEffect(() => {\n if (currentConversation !== conversationId) {\n setCurrentConversation(conversationId);\n setConversations(prev => {\n if (prev[conversationId]) return prev;\n\n return {\n ...prev,\n [conversationId]: [],\n };\n });\n }\n }, [currentConversation, conversationId]);\n\n const { data: conversationsData = [], ...queryProps } =\n useFetchConversationMessages(currentConversation);\n\n React.useEffect(() => {\n if (\n !Array.isArray(conversationsData) ||\n (conversationsData.length === 0 &&\n conversationId !== TEMP_CONVERSATION_ID)\n )\n return;\n\n const newConvoIndex: number[] = [];\n\n if (conversations) {\n const _conversations: { [key: string]: any[] } = {\n [currentConversation]: [],\n };\n\n let index = 0;\n for (let i = 0; i < conversationsData.length; i += 2) {\n const userMessage = conversationsData[i];\n const aiMessage = conversationsData[i + 1];\n\n const { content: humanMessage, timestamp: userTimestamp } =\n getMessageData(userMessage);\n const {\n model,\n content: botMessage,\n timestamp: botTimestamp,\n referencedDocuments,\n } = getMessageData(aiMessage);\n\n _conversations[currentConversation].push(\n ...[\n createUserMessage({\n avatar,\n name: userName,\n content: humanMessage,\n timestamp: userTimestamp,\n }),\n createBotMessage({\n avatar: botAvatar,\n isLoading: false,\n name: model ?? selectedModel,\n content: botMessage,\n timestamp: botTimestamp,\n sources: transformDocumentsToSources(referencedDocuments),\n }),\n ],\n );\n\n newConvoIndex.push(index);\n index++;\n }\n\n if (streamingConversations.current[currentConversation]) {\n _conversations[currentConversation].push(\n ...streamingConversations.current[currentConversation],\n );\n }\n\n setConversations(_conversations);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n conversationsData,\n userName,\n avatar,\n currentConversation,\n selectedModel,\n streamingConversations,\n ]);\n\n const handleInputPrompt = React.useCallback(\n async (prompt: string, attachments: Attachment[] = []) => {\n let newConversationId = '';\n\n const conversationTuple = [\n createUserMessage({\n avatar,\n name: userName,\n content: prompt,\n timestamp: getTimestamp(Date.now()) ?? '',\n }),\n createBotMessage({\n avatar: botAvatar,\n isLoading: true,\n name: selectedModel,\n content: '',\n timestamp: '',\n }),\n ];\n\n streamingConversations.current = {\n ...streamingConversations.current,\n [currentConversation]: conversationTuple,\n };\n\n setConversations((prevConv: Conversations) => {\n return {\n ...prevConv,\n [currentConversation]: [\n ...(prevConv?.[currentConversation] ?? []),\n ...conversationTuple,\n ],\n };\n });\n\n setTimeout(() => {\n scrollToBottomRef.current?.scrollToBottom();\n }, 0);\n const finalMessages: string[] = [];\n let buffer = '';\n\n try {\n const reader = await createMessage({\n prompt,\n selectedModel,\n currentConversation,\n attachments,\n });\n\n const decoder = new TextDecoder('utf-8');\n const keepGoing = true;\n\n while (keepGoing) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process all complete messages separated by double newlines\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop()!;\n\n for (const part of parts) {\n const lines = part\n .split('\\n')\n .filter(line => line.startsWith('data:'));\n\n const jsonString = lines\n .map(line => line.trim().slice(5).trim())\n .join('');\n try {\n const { event, data } = JSON.parse(jsonString);\n if (event === 'start') {\n if (currentConversation === TEMP_CONVERSATION_ID) {\n // If the conversation is temp, we need to set the new conversation id\n newConversationId = data?.conversation_id;\n }\n }\n\n if (event === 'token') {\n const content = data?.token || '';\n\n finalMessages.push(content);\n\n // Store streaming message\n const [humanMessage, aiMessage] =\n streamingConversations.current[currentConversation];\n streamingConversations.current[currentConversation] = [\n humanMessage,\n { ...aiMessage, content: aiMessage.content + content },\n ];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += content;\n lastMessage.name =\n data?.response_metadata?.model || selectedModel;\n lastMessage.timestamp = getTimestamp(\n data?.response_metadata?.created_at || Date.now(),\n );\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n\n if (event === 'end') {\n const documents = data?.referenced_documents || [];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n if (documents.length) {\n lastMessage.sources = {\n sources: documents.map((doc: ReferencedDocument) => ({\n title: doc.doc_title,\n link: doc.doc_url,\n body: doc.doc_description,\n })),\n };\n }\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn('Error parsing JSON:', error);\n if (typeof onComplete === 'function') {\n onComplete('Invalid JSON received');\n }\n }\n }\n }\n } catch (e) {\n setConversations(prevConversations => {\n const conversation = prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += e;\n lastMessage.error = {\n title: e.message,\n };\n lastMessage.timestamp = getTimestamp(Date.now());\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n finalMessages.push(`${e}`);\n\n return {\n ...prevConversations,\n [newConversationId.length > 0\n ? newConversationId\n : currentConversation]: updatedConversation,\n };\n });\n }\n // reset current streaming\n streamingConversations.current[currentConversation] = [];\n if (typeof onComplete === 'function') {\n onComplete(finalMessages.join(''));\n }\n // Swap temp conversation messages with new conversation\n\n if (currentConversation === TEMP_CONVERSATION_ID && newConversationId) {\n setConversations(prevConversations => {\n return {\n ...prevConversations,\n [newConversationId]: prevConversations[TEMP_CONVERSATION_ID],\n };\n });\n\n onStart?.(newConversationId);\n\n setConversations(prev => {\n const { temp, ...rest } = prev;\n return rest;\n });\n }\n },\n\n [\n avatar,\n userName,\n onComplete,\n onStart,\n selectedModel,\n createMessage,\n currentConversation,\n ],\n );\n\n return {\n conversationMessages: conversations[currentConversation] ?? [],\n handleInputPrompt,\n conversations,\n scrollToBottomRef,\n ...queryProps,\n };\n};\n"],"names":["React"],"mappings":";;;;;;;;;;AAuCa,MAAA,4BAAA,GAA+B,CAAC,mBAAgC,KAAA;AAC3E,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAA,OAAO,QAAS,CAAA;AAAA,IACd,QAAA,EAAU,CAAC,sBAAA,EAAwB,mBAAmB,CAAA;AAAA,IACtD,OAAA,EAAS,sBACL,YAAY;AACV,MAAA,MAAM,QACJ,GAAA,MAAM,aAAc,CAAA,uBAAA,CAAwB,mBAAmB,CAAA;AAEjE,MAAO,OAAA,QAAA;AAAA,KAET,GAAA,SAAA;AAAA,IACJ,KAAO,EAAA;AAAA,GACR,CAAA;AACH;AAYa,MAAA,uBAAA,GAA0B,CACrC,cACA,EAAA,QAAA,EACA,eACA,MAAiB,GAAA,UAAA,EACjB,YACA,OACG,KAAA;AACH,EAAA,MAAM,EAAE,WAAA,EAAa,aAAc,EAAA,GAAI,4BAA6B,EAAA;AACpE,EAAM,MAAA,iBAAA,GAAoBA,cAAM,CAAA,MAAA,CAA8B,IAAI,CAAA;AAElE,EAAA,MAAM,CAAC,mBAAqB,EAAA,sBAAsB,CAChD,GAAAA,cAAA,CAAM,SAAS,cAAc,CAAA;AAC/B,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIA,eAAM,QAAwB,CAAA;AAAA,IACtE,CAAC,mBAAmB,GAAG;AAAC,GACzB,CAAA;AACD,EAAM,MAAA,sBAAA,GAAyBA,eAAM,MAAsB,CAAA;AAAA,IACzD,CAAC,mBAAmB,GAAG;AAAC,GACzB,CAAA;AAED,EAAAA,cAAA,CAAM,UAAU,MAAM;AACpB,IAAA,IAAI,wBAAwB,cAAgB,EAAA;AAC1C,MAAA,sBAAA,CAAuB,cAAc,CAAA;AACrC,MAAA,gBAAA,CAAiB,CAAQ,IAAA,KAAA;AACvB,QAAI,IAAA,IAAA,CAAK,cAAc,CAAA,EAAU,OAAA,IAAA;AAEjC,QAAO,OAAA;AAAA,UACL,GAAG,IAAA;AAAA,UACH,CAAC,cAAc,GAAG;AAAC,SACrB;AAAA,OACD,CAAA;AAAA;AACH,GACC,EAAA,CAAC,mBAAqB,EAAA,cAAc,CAAC,CAAA;AAExC,EAAM,MAAA,EAAE,MAAM,iBAAoB,GAAA,IAAI,GAAG,UAAA,EACvC,GAAA,4BAAA,CAA6B,mBAAmB,CAAA;AAElD,EAAAA,cAAA,CAAM,UAAU,MAAM;AACpB,IACE,IAAA,CAAC,MAAM,OAAQ,CAAA,iBAAiB,KAC/B,iBAAkB,CAAA,MAAA,KAAW,KAC5B,cAAmB,KAAA,oBAAA;AAErB,MAAA;AAIF,IAAA,IAAI,aAAe,EAAA;AACjB,MAAA,MAAM,cAA2C,GAAA;AAAA,QAC/C,CAAC,mBAAmB,GAAG;AAAC,OAC1B;AAGA,MAAA,KAAA,IAAS,IAAI,CAAG,EAAA,CAAA,GAAI,iBAAkB,CAAA,MAAA,EAAQ,KAAK,CAAG,EAAA;AACpD,QAAM,MAAA,WAAA,GAAc,kBAAkB,CAAC,CAAA;AACvC,QAAM,MAAA,SAAA,GAAY,iBAAkB,CAAA,CAAA,GAAI,CAAC,CAAA;AAEzC,QAAA,MAAM,EAAE,OAAS,EAAA,YAAA,EAAc,WAAW,aAAc,EAAA,GACtD,eAAe,WAAW,CAAA;AAC5B,QAAM,MAAA;AAAA,UACJ,KAAA;AAAA,UACA,OAAS,EAAA,UAAA;AAAA,UACT,SAAW,EAAA,YAAA;AAAA,UACX;AAAA,SACF,GAAI,eAAe,SAAS,CAAA;AAE5B,QAAA,cAAA,CAAe,mBAAmB,CAAE,CAAA,IAAA;AAAA,UAClC,GAAG;AAAA,YACD,iBAAkB,CAAA;AAAA,cAChB,MAAA;AAAA,cACA,IAAM,EAAA,QAAA;AAAA,cACN,OAAS,EAAA,YAAA;AAAA,cACT,SAAW,EAAA;AAAA,aACZ,CAAA;AAAA,YACD,gBAAiB,CAAA;AAAA,cACf,MAAQ,EAAA,SAAA;AAAA,cACR,SAAW,EAAA,KAAA;AAAA,cACX,MAAM,KAAS,IAAA,aAAA;AAAA,cACf,OAAS,EAAA,UAAA;AAAA,cACT,SAAW,EAAA,YAAA;AAAA,cACX,OAAA,EAAS,4BAA4B,mBAAmB;AAAA,aACzD;AAAA;AACH,SACF;AAGA;AAGF,MAAI,IAAA,sBAAA,CAAuB,OAAQ,CAAA,mBAAmB,CAAG,EAAA;AACvD,QAAA,cAAA,CAAe,mBAAmB,CAAE,CAAA,IAAA;AAAA,UAClC,GAAG,sBAAuB,CAAA,OAAA,CAAQ,mBAAmB;AAAA,SACvD;AAAA;AAGF,MAAA,gBAAA,CAAiB,cAAc,CAAA;AAAA;AACjC,GAEC,EAAA;AAAA,IACD,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,mBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,oBAAoBA,cAAM,CAAA,WAAA;AAAA,IAC9B,OAAO,MAAA,EAAgB,WAA4B,GAAA,EAAO,KAAA;AACxD,MAAA,IAAI,iBAAoB,GAAA,EAAA;AAExB,MAAA,MAAM,iBAAoB,GAAA;AAAA,QACxB,iBAAkB,CAAA;AAAA,UAChB,MAAA;AAAA,UACA,IAAM,EAAA,QAAA;AAAA,UACN,OAAS,EAAA,MAAA;AAAA,UACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK,CAAK,IAAA;AAAA,SACxC,CAAA;AAAA,QACD,gBAAiB,CAAA;AAAA,UACf,MAAQ,EAAA,SAAA;AAAA,UACR,SAAW,EAAA,IAAA;AAAA,UACX,IAAM,EAAA,aAAA;AAAA,UACN,OAAS,EAAA,EAAA;AAAA,UACT,SAAW,EAAA;AAAA,SACZ;AAAA,OACH;AAEA,MAAA,sBAAA,CAAuB,OAAU,GAAA;AAAA,QAC/B,GAAG,sBAAuB,CAAA,OAAA;AAAA,QAC1B,CAAC,mBAAmB,GAAG;AAAA,OACzB;AAEA,MAAA,gBAAA,CAAiB,CAAC,QAA4B,KAAA;AAC5C,QAAO,OAAA;AAAA,UACL,GAAG,QAAA;AAAA,UACH,CAAC,mBAAmB,GAAG;AAAA,YACrB,GAAI,QAAA,GAAW,mBAAmB,CAAA,IAAK,EAAC;AAAA,YACxC,GAAG;AAAA;AACL,SACF;AAAA,OACD,CAAA;AAED,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,iBAAA,CAAkB,SAAS,cAAe,EAAA;AAAA,SACzC,CAAC,CAAA;AACJ,MAAA,MAAM,gBAA0B,EAAC;AACjC,MAAA,IAAI,MAAS,GAAA,EAAA;AAEb,MAAI,IAAA;AACF,QAAM,MAAA,MAAA,GAAS,MAAM,aAAc,CAAA;AAAA,UACjC,MAAA;AAAA,UACA,aAAA;AAAA,UACA,mBAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAM,MAAA,OAAA,GAAU,IAAI,WAAA,CAAY,OAAO,CAAA;AACvC,QAAA,MAAM,SAAY,GAAA,IAAA;AAElB,QAAA,OAAO,SAAW,EAAA;AAChB,UAAA,MAAM,EAAE,KAAO,EAAA,IAAA,EAAS,GAAA,MAAM,OAAO,IAAK,EAAA;AAC1C,UAAA,IAAI,IAAM,EAAA;AAEV,UAAA,MAAA,IAAU,QAAQ,MAAO,CAAA,KAAA,EAAO,EAAE,MAAA,EAAQ,MAAM,CAAA;AAGhD,UAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,KAAA,CAAM,MAAM,CAAA;AACjC,UAAA,MAAA,GAAS,MAAM,GAAI,EAAA;AAEnB,UAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,YAAM,MAAA,KAAA,GAAQ,IACX,CAAA,KAAA,CAAM,IAAI,CAAA,CACV,OAAO,CAAQ,IAAA,KAAA,IAAA,CAAK,UAAW,CAAA,OAAO,CAAC,CAAA;AAE1C,YAAA,MAAM,UAAa,GAAA,KAAA,CAChB,GAAI,CAAA,CAAA,IAAA,KAAQ,KAAK,IAAK,EAAA,CAAE,KAAM,CAAA,CAAC,CAAE,CAAA,IAAA,EAAM,CAAA,CACvC,KAAK,EAAE,CAAA;AACV,YAAI,IAAA;AACF,cAAA,MAAM,EAAE,KAAO,EAAA,IAAA,EAAS,GAAA,IAAA,CAAK,MAAM,UAAU,CAAA;AAC7C,cAAA,IAAI,UAAU,OAAS,EAAA;AACrB,gBAAA,IAAI,wBAAwB,oBAAsB,EAAA;AAEhD,kBAAA,iBAAA,GAAoB,IAAM,EAAA,eAAA;AAAA;AAC5B;AAGF,cAAA,IAAI,UAAU,OAAS,EAAA;AACrB,gBAAM,MAAA,OAAA,GAAU,MAAM,KAAS,IAAA,EAAA;AAE/B,gBAAA,aAAA,CAAc,KAAK,OAAO,CAAA;AAG1B,gBAAA,MAAM,CAAC,YAAc,EAAA,SAAS,CAC5B,GAAA,sBAAA,CAAuB,QAAQ,mBAAmB,CAAA;AACpD,gBAAuB,sBAAA,CAAA,OAAA,CAAQ,mBAAmB,CAAI,GAAA;AAAA,kBACpD,YAAA;AAAA,kBACA,EAAE,GAAG,SAAA,EAAW,OAAS,EAAA,SAAA,CAAU,UAAU,OAAQ;AAAA,iBACvD;AAEA,gBAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,kBAAA,MAAM,YACJ,GAAA,iBAAA,CAAkB,mBAAmB,CAAA,IAAK,EAAC;AAE7C,kBAAM,MAAA,gBAAA,GAAmB,aAAa,MAAS,GAAA,CAAA;AAC/C,kBAAA,MAAM,WACJ,GAAA,YAAA,CAAa,MAAW,KAAA,CAAA,GACpB,gBAAiB,CAAA;AAAA,oBACf,OAAS,EAAA,EAAA;AAAA,oBACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK;AAAA,mBACnC,CACD,GAAA,EAAE,GAAG,YAAA,CAAa,gBAAgB,CAAE,EAAA;AAE1C,kBAAA,WAAA,CAAY,SAAY,GAAA,KAAA;AACxB,kBAAA,WAAA,CAAY,OAAW,IAAA,OAAA;AACvB,kBAAY,WAAA,CAAA,IAAA,GACV,IAAM,EAAA,iBAAA,EAAmB,KAAS,IAAA,aAAA;AACpC,kBAAA,WAAA,CAAY,SAAY,GAAA,YAAA;AAAA,oBACtB,IAAM,EAAA,iBAAA,EAAmB,UAAc,IAAA,IAAA,CAAK,GAAI;AAAA,mBAClD;AAEA,kBAAA,MAAM,mBAAsB,GAAA;AAAA,oBAC1B,GAAG,YAAA,CAAa,KAAM,CAAA,CAAA,EAAG,gBAAgB,CAAA;AAAA,oBACzC;AAAA,mBACF;AAEA,kBAAO,OAAA;AAAA,oBACL,GAAG,iBAAA;AAAA,oBACH,CAAC,mBAAmB,GAAG;AAAA,mBACzB;AAAA,iBACD,CAAA;AAAA;AAGH,cAAA,IAAI,UAAU,KAAO,EAAA;AACnB,gBAAM,MAAA,SAAA,GAAY,IAAM,EAAA,oBAAA,IAAwB,EAAC;AAEjD,gBAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,kBAAA,MAAM,YACJ,GAAA,iBAAA,CAAkB,mBAAmB,CAAA,IAAK,EAAC;AAE7C,kBAAM,MAAA,gBAAA,GAAmB,aAAa,MAAS,GAAA,CAAA;AAC/C,kBAAA,MAAM,WACJ,GAAA,YAAA,CAAa,MAAW,KAAA,CAAA,GACpB,gBAAiB,CAAA;AAAA,oBACf,OAAS,EAAA,EAAA;AAAA,oBACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK;AAAA,mBACnC,CACD,GAAA,EAAE,GAAG,YAAA,CAAa,gBAAgB,CAAE,EAAA;AAE1C,kBAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,oBAAA,WAAA,CAAY,OAAU,GAAA;AAAA,sBACpB,OAAS,EAAA,SAAA,CAAU,GAAI,CAAA,CAAC,GAA6B,MAAA;AAAA,wBACnD,OAAO,GAAI,CAAA,SAAA;AAAA,wBACX,MAAM,GAAI,CAAA,OAAA;AAAA,wBACV,MAAM,GAAI,CAAA;AAAA,uBACV,CAAA;AAAA,qBACJ;AAAA;AAGF,kBAAA,MAAM,mBAAsB,GAAA;AAAA,oBAC1B,GAAG,YAAA,CAAa,KAAM,CAAA,CAAA,EAAG,gBAAgB,CAAA;AAAA,oBACzC;AAAA,mBACF;AAEA,kBAAO,OAAA;AAAA,oBACL,GAAG,iBAAA;AAAA,oBACH,CAAC,mBAAmB,GAAG;AAAA,mBACzB;AAAA,iBACD,CAAA;AAAA;AACH,qBACO,KAAO,EAAA;AAEd,cAAQ,OAAA,CAAA,IAAA,CAAK,uBAAuB,KAAK,CAAA;AACzC,cAAI,IAAA,OAAO,eAAe,UAAY,EAAA;AACpC,gBAAA,UAAA,CAAW,uBAAuB,CAAA;AAAA;AACpC;AACF;AACF;AACF,eACO,CAAG,EAAA;AACV,QAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,UAAA,MAAM,YAAe,GAAA,iBAAA,CAAkB,mBAAmB,CAAA,IAAK,EAAC;AAEhE,UAAM,MAAA,gBAAA,GAAmB,aAAa,MAAS,GAAA,CAAA;AAC/C,UAAA,MAAM,WACJ,GAAA,YAAA,CAAa,MAAW,KAAA,CAAA,GACpB,gBAAiB,CAAA;AAAA,YACf,OAAS,EAAA,EAAA;AAAA,YACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK;AAAA,WACnC,CACD,GAAA,EAAE,GAAG,YAAA,CAAa,gBAAgB,CAAE,EAAA;AAE1C,UAAA,WAAA,CAAY,SAAY,GAAA,KAAA;AACxB,UAAA,WAAA,CAAY,OAAW,IAAA,CAAA;AACvB,UAAA,WAAA,CAAY,KAAQ,GAAA;AAAA,YAClB,OAAO,CAAE,CAAA;AAAA,WACX;AACA,UAAA,WAAA,CAAY,SAAY,GAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK,CAAA;AAE/C,UAAA,MAAM,mBAAsB,GAAA;AAAA,YAC1B,GAAG,YAAA,CAAa,KAAM,CAAA,CAAA,EAAG,gBAAgB,CAAA;AAAA,YACzC;AAAA,WACF;AAEA,UAAc,aAAA,CAAA,IAAA,CAAK,CAAG,EAAA,CAAC,CAAE,CAAA,CAAA;AAEzB,UAAO,OAAA;AAAA,YACL,GAAG,iBAAA;AAAA,YACH,CAAC,iBAAkB,CAAA,MAAA,GAAS,CACxB,GAAA,iBAAA,GACA,mBAAmB,GAAG;AAAA,WAC5B;AAAA,SACD,CAAA;AAAA;AAGH,MAAuB,sBAAA,CAAA,OAAA,CAAQ,mBAAmB,CAAA,GAAI,EAAC;AACvD,MAAI,IAAA,OAAO,eAAe,UAAY,EAAA;AACpC,QAAW,UAAA,CAAA,aAAA,CAAc,IAAK,CAAA,EAAE,CAAC,CAAA;AAAA;AAInC,MAAI,IAAA,mBAAA,KAAwB,wBAAwB,iBAAmB,EAAA;AACrE,QAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,UAAO,OAAA;AAAA,YACL,GAAG,iBAAA;AAAA,YACH,CAAC,iBAAiB,GAAG,iBAAA,CAAkB,oBAAoB;AAAA,WAC7D;AAAA,SACD,CAAA;AAED,QAAA,OAAA,GAAU,iBAAiB,CAAA;AAE3B,QAAA,gBAAA,CAAiB,CAAQ,IAAA,KAAA;AACvB,UAAA,MAAM,EAAE,IAAA,EAAM,GAAG,IAAA,EAAS,GAAA,IAAA;AAC1B,UAAO,OAAA,IAAA;AAAA,SACR,CAAA;AAAA;AACH,KACF;AAAA,IAEA;AAAA,MACE,MAAA;AAAA,MACA,QAAA;AAAA,MACA,UAAA;AAAA,MACA,OAAA;AAAA,MACA,aAAA;AAAA,MACA,aAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAO,OAAA;AAAA,IACL,oBAAsB,EAAA,aAAA,CAAc,mBAAmB,CAAA,IAAK,EAAC;AAAA,IAC7D,iBAAA;AAAA,IACA,aAAA;AAAA,IACA,iBAAA;AAAA,IACA,GAAG;AAAA,GACL;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"useConversationMessages.esm.js","sources":["../../src/hooks/useConversationMessages.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { useApi } from '@backstage/core-plugin-api';\n\nimport { MessageProps } from '@patternfly/chatbot';\nimport { useQuery } from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\nimport { ScrollContainerHandle } from '../components/LightspeedChatBox';\nimport { TEMP_CONVERSATION_ID } from '../const';\nimport botAvatar from '../images/bot-avatar.svg';\nimport userAvatar from '../images/user-avatar.svg';\nimport { Attachment, ReferencedDocument } from '../types';\nimport {\n createBotMessage,\n createUserMessage,\n getMessageData,\n getTimestamp,\n transformDocumentsToSources,\n} from '../utils/lightspeed-chatbox-utils';\nimport { useCreateConversationMessage } from './useCreateCoversationMessage';\n\n// Fetch all conversation messages\nexport const useFetchConversationMessages = (currentConversation: string) => {\n const lightspeedApi = useApi(lightspeedApiRef);\n return useQuery({\n queryKey: ['conversationMessages', currentConversation],\n queryFn: currentConversation\n ? async () => {\n const response =\n await lightspeedApi.getConversationMessages(currentConversation);\n\n return response;\n }\n : undefined,\n retry: false,\n });\n};\n\ntype Conversations = { [_key: string]: MessageProps[] };\n\n/**\n * Fetches all the messages for given conversation_id\n * @param conversationId\n * @param userName\n * @param selectedModel\n * @param avatar\n *\n */\nexport const useConversationMessages = (\n conversationId: string,\n userName: string | undefined,\n selectedModel: string,\n avatar: string = userAvatar,\n onComplete?: (message: string) => void,\n onStart?: (conversation_id: string) => void,\n) => {\n const { mutateAsync: createMessage } = useCreateConversationMessage();\n const scrollToBottomRef = React.useRef<ScrollContainerHandle>(null);\n\n const [currentConversation, setCurrentConversation] =\n React.useState(conversationId);\n const [conversations, setConversations] = React.useState<Conversations>({\n [currentConversation]: [],\n });\n const streamingConversations = React.useRef<Conversations>({\n [currentConversation]: [],\n });\n\n React.useEffect(() => {\n if (currentConversation !== conversationId) {\n setCurrentConversation(conversationId);\n setConversations(prev => {\n if (prev[conversationId]) return prev;\n\n return {\n ...prev,\n [conversationId]: [],\n };\n });\n }\n }, [currentConversation, conversationId]);\n\n const { data: conversationsData = [], ...queryProps } =\n useFetchConversationMessages(currentConversation);\n\n React.useEffect(() => {\n if (\n !Array.isArray(conversationsData) ||\n (conversationsData.length === 0 &&\n conversationId !== TEMP_CONVERSATION_ID)\n )\n return;\n\n const newConvoIndex: number[] = [];\n\n if (conversations) {\n const _conversations: { [key: string]: any[] } = {\n [currentConversation]: [],\n };\n\n let index = 0;\n for (let i = 0; i < conversationsData.length; i += 2) {\n const userMessage = conversationsData[i];\n const aiMessage = conversationsData[i + 1];\n\n const { content: humanMessage, timestamp: userTimestamp } =\n getMessageData(userMessage);\n const {\n model,\n content: botMessage,\n timestamp: botTimestamp,\n referencedDocuments,\n } = getMessageData(aiMessage);\n\n _conversations[currentConversation].push(\n ...[\n createUserMessage({\n avatar,\n name: userName,\n content: humanMessage,\n timestamp: userTimestamp,\n }),\n createBotMessage({\n avatar: botAvatar,\n isLoading: false,\n name: model ?? selectedModel,\n content: botMessage,\n timestamp: botTimestamp,\n sources: transformDocumentsToSources(referencedDocuments),\n }),\n ],\n );\n\n newConvoIndex.push(index);\n index++;\n }\n\n if (streamingConversations.current[currentConversation]) {\n _conversations[currentConversation].push(\n ...streamingConversations.current[currentConversation],\n );\n }\n\n setConversations(_conversations);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n conversationsData,\n userName,\n avatar,\n currentConversation,\n selectedModel,\n streamingConversations,\n ]);\n\n const handleInputPrompt = React.useCallback(\n async (prompt: string, attachments: Attachment[] = []) => {\n let newConversationId = '';\n\n const conversationTuple = [\n createUserMessage({\n avatar,\n name: userName,\n content: prompt,\n timestamp: getTimestamp(Date.now()) ?? '',\n }),\n createBotMessage({\n avatar: botAvatar,\n isLoading: true,\n name: selectedModel,\n content: '',\n timestamp: '',\n }),\n ];\n\n streamingConversations.current = {\n ...streamingConversations.current,\n [currentConversation]: conversationTuple,\n };\n\n setConversations((prevConv: Conversations) => {\n return {\n ...prevConv,\n [currentConversation]: [\n ...(prevConv?.[currentConversation] ?? []),\n ...conversationTuple,\n ],\n };\n });\n\n setTimeout(() => {\n scrollToBottomRef.current?.scrollToBottom();\n }, 0);\n const finalMessages: string[] = [];\n let buffer = '';\n\n try {\n const reader = await createMessage({\n prompt,\n selectedModel,\n currentConversation,\n attachments,\n });\n\n const decoder = new TextDecoder('utf-8');\n const keepGoing = true;\n\n while (keepGoing) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process all complete messages separated by double newlines\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop()!;\n\n for (const part of parts) {\n const lines = part\n .split('\\n')\n .filter(line => line.startsWith('data:'));\n\n const jsonString = lines\n .map(line => line.trim().slice(5).trim())\n .join('');\n try {\n const { event, data } = JSON.parse(jsonString);\n if (event === 'start') {\n if (currentConversation === TEMP_CONVERSATION_ID) {\n // If the conversation is temp, we need to set the new conversation id\n newConversationId = data?.conversation_id;\n }\n }\n\n if (event === 'token') {\n const content = data?.token || '';\n\n finalMessages.push(content);\n\n // Store streaming message\n const [humanMessage, aiMessage] =\n streamingConversations.current[currentConversation];\n streamingConversations.current[currentConversation] = [\n humanMessage,\n { ...aiMessage, content: aiMessage.content + content },\n ];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += content;\n lastMessage.name =\n data?.response_metadata?.model || selectedModel;\n lastMessage.timestamp = getTimestamp(\n data?.response_metadata?.created_at || Date.now(),\n );\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n\n if (event === 'end') {\n const documents = data?.referenced_documents || [];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n if (documents.length) {\n lastMessage.sources = {\n sources: documents.map((doc: ReferencedDocument) => ({\n title: doc.doc_title,\n link: doc.doc_url,\n body: doc.doc_description,\n })),\n };\n }\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn('Error parsing JSON:', error);\n if (typeof onComplete === 'function') {\n onComplete('Invalid JSON received');\n }\n }\n }\n }\n } catch (e) {\n setConversations(prevConversations => {\n const conversation = prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += e;\n lastMessage.error = {\n title: e.message,\n };\n lastMessage.timestamp = getTimestamp(Date.now());\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n finalMessages.push(`${e}`);\n\n return {\n ...prevConversations,\n [newConversationId.length > 0\n ? newConversationId\n : currentConversation]: updatedConversation,\n };\n });\n }\n // reset current streaming\n streamingConversations.current[currentConversation] = [];\n if (typeof onComplete === 'function') {\n onComplete(finalMessages.join(''));\n }\n // Swap temp conversation messages with new conversation\n\n if (currentConversation === TEMP_CONVERSATION_ID && newConversationId) {\n setConversations(prevConversations => {\n return {\n ...prevConversations,\n [newConversationId]: prevConversations[TEMP_CONVERSATION_ID],\n };\n });\n\n onStart?.(newConversationId);\n\n setConversations(prev => {\n const { temp, ...rest } = prev;\n return rest;\n });\n }\n },\n\n [\n avatar,\n userName,\n onComplete,\n onStart,\n selectedModel,\n createMessage,\n currentConversation,\n ],\n );\n\n return {\n conversationMessages: conversations[currentConversation] ?? [],\n handleInputPrompt,\n conversations,\n scrollToBottomRef,\n ...queryProps,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import { useRef, useCallback, useEffect
|
|
1
|
+
import { useRef, useMemo, useCallback, useEffect } from 'react';
|
|
2
2
|
import { useCaptureFeedback } from './useCaptureFeedback.esm.js';
|
|
3
3
|
import { useFeedbackState } from './useFeedbackState.esm.js';
|
|
4
4
|
import { useFeedbackStatus } from './useFeedbackStatus.esm.js';
|
|
5
|
+
import { useTranslation } from './useTranslation.esm.js';
|
|
5
6
|
|
|
6
|
-
const quickResponses = {
|
|
7
|
-
positive: [
|
|
8
|
-
{ id: "1", content: "Helpful information" },
|
|
9
|
-
{ id: "2", content: "Easy to understand" },
|
|
10
|
-
{ id: "3", content: "Resolved my issue" }
|
|
11
|
-
],
|
|
12
|
-
negative: [
|
|
13
|
-
{ id: "1", content: `Didn\u2019t answer my question` },
|
|
14
|
-
{ id: "2", content: "Hard to understand" },
|
|
15
|
-
{ id: "3", content: "Not Helpful" }
|
|
16
|
-
]
|
|
17
|
-
};
|
|
18
7
|
const useFeedbackActions = (messages, conversationId, isStreaming) => {
|
|
19
8
|
const copyButtonRef = useRef(null);
|
|
20
9
|
const speakingButtonRef = useRef(null);
|
|
@@ -22,15 +11,43 @@ const useFeedbackActions = (messages, conversationId, isStreaming) => {
|
|
|
22
11
|
const { data: feedbackEnabled } = useFeedbackStatus();
|
|
23
12
|
const { state, ...dispatch } = useFeedbackState();
|
|
24
13
|
const { mutateAsync: captureFeedback } = useCaptureFeedback();
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const createQuickResponses = useMemo(
|
|
16
|
+
() => ({
|
|
17
|
+
positive: [
|
|
18
|
+
{ id: "1", content: t("feedback.quickResponses.positive.helpful") },
|
|
19
|
+
{
|
|
20
|
+
id: "2",
|
|
21
|
+
content: t("feedback.quickResponses.positive.easyToUnderstand")
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "3",
|
|
25
|
+
content: t("feedback.quickResponses.positive.resolvedIssue")
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
negative: [
|
|
29
|
+
{ id: "1", content: t("feedback.quickResponses.negative.didntAnswer") },
|
|
30
|
+
{
|
|
31
|
+
id: "2",
|
|
32
|
+
content: t("feedback.quickResponses.negative.hardToUnderstand")
|
|
33
|
+
},
|
|
34
|
+
{ id: "3", content: t("feedback.quickResponses.negative.notHelpful") }
|
|
35
|
+
]
|
|
36
|
+
}),
|
|
37
|
+
[t]
|
|
38
|
+
);
|
|
25
39
|
const getFeedbackForm = useCallback(
|
|
26
40
|
(messageId, sentiment) => ({
|
|
27
41
|
key: `feedback-${sentiment}`,
|
|
28
42
|
id: `feedback-${sentiment}-${messageId}`,
|
|
29
43
|
hasTextArea: true,
|
|
30
|
-
|
|
44
|
+
title: t("feedback.form.title"),
|
|
45
|
+
textAreaPlaceholder: t("feedback.form.textAreaPlaceholder"),
|
|
46
|
+
submitWord: t("feedback.form.submitWord"),
|
|
47
|
+
quickResponses: createQuickResponses[sentiment],
|
|
31
48
|
onSubmit: (quickResponse = "0", additionalFeedback) => {
|
|
32
49
|
const quickIndex = Number(quickResponse) - 1;
|
|
33
|
-
const quickText = quickResponse !== "0" ?
|
|
50
|
+
const quickText = quickResponse !== "0" ? createQuickResponses[sentiment]?.[quickIndex]?.content : undefined;
|
|
34
51
|
let user_feedback = "";
|
|
35
52
|
if (quickText && additionalFeedback) {
|
|
36
53
|
user_feedback = `${quickText}
|
|
@@ -69,7 +86,14 @@ Additional feedback: ${additionalFeedback}`;
|
|
|
69
86
|
},
|
|
70
87
|
focusOnLoad: true
|
|
71
88
|
}),
|
|
72
|
-
[
|
|
89
|
+
[
|
|
90
|
+
captureFeedback,
|
|
91
|
+
conversationId,
|
|
92
|
+
dispatch,
|
|
93
|
+
messages,
|
|
94
|
+
createQuickResponses,
|
|
95
|
+
t
|
|
96
|
+
]
|
|
73
97
|
);
|
|
74
98
|
const feedbackForms = useCallback(
|
|
75
99
|
(messageId) => ({
|
|
@@ -84,13 +108,15 @@ Additional feedback: ${additionalFeedback}`;
|
|
|
84
108
|
if (!isVisible) return undefined;
|
|
85
109
|
return {
|
|
86
110
|
id: `feebback-completion-${sentiment}-${messageId}`,
|
|
111
|
+
title: t("feedback.completion.title"),
|
|
112
|
+
body: t("feedback.completion.body"),
|
|
87
113
|
onClose: () => {
|
|
88
114
|
dispatch.hideCompletionForm(messageId, sentiment);
|
|
89
115
|
dispatch.resetButtonState(messageId);
|
|
90
116
|
}
|
|
91
117
|
};
|
|
92
118
|
},
|
|
93
|
-
[state, dispatch]
|
|
119
|
+
[state, dispatch, t]
|
|
94
120
|
);
|
|
95
121
|
const scrollToFeedbackForm = useCallback(
|
|
96
122
|
(messageId, sentiment) => {
|
|
@@ -181,13 +207,14 @@ Additional feedback: ${additionalFeedback}`;
|
|
|
181
207
|
scrollToFeedbackForm(messageId, sentiment);
|
|
182
208
|
}
|
|
183
209
|
},
|
|
210
|
+
tooltipContent: selected === "positive" ? t("feedback.tooltips.goodResponse") : t("feedback.tooltips.badResponse"),
|
|
184
211
|
"aria-expanded": sentiment === selected,
|
|
185
212
|
"aria-controls": showFeedbackForm ? `feedback-${sentiment}-${messageId}` : `feebback-completion-${sentiment}-${messageId}`
|
|
186
213
|
});
|
|
187
214
|
const copyAction = {
|
|
188
215
|
isClicked: copied,
|
|
189
216
|
ref: copyButtonRef,
|
|
190
|
-
tooltipContent: copied ? "
|
|
217
|
+
tooltipContent: copied ? t("feedback.tooltips.copied") : t("feedback.tooltips.copy"),
|
|
191
218
|
onClick: async () => {
|
|
192
219
|
await window.navigator.clipboard.writeText(
|
|
193
220
|
message.content
|
|
@@ -205,6 +232,7 @@ Additional feedback: ${additionalFeedback}`;
|
|
|
205
232
|
isClicked: isSpeaking,
|
|
206
233
|
ref: speakingButtonRef,
|
|
207
234
|
id: `listen-${messageId}`,
|
|
235
|
+
tooltipContent: isSpeaking ? t("feedback.tooltips.listening") : t("feedback.tooltips.listen"),
|
|
208
236
|
onClick: () => {
|
|
209
237
|
const isCurrentlySpeaking = state[messageId]?.buttonState?.isSpeaking;
|
|
210
238
|
if (isCurrentlySpeaking) {
|
|
@@ -228,6 +256,7 @@ Additional feedback: ${additionalFeedback}`;
|
|
|
228
256
|
};
|
|
229
257
|
}) : messages;
|
|
230
258
|
}, [
|
|
259
|
+
t,
|
|
231
260
|
conversationId,
|
|
232
261
|
messages,
|
|
233
262
|
state,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFeedbackActions.esm.js","sources":["../../src/hooks/useFeedbackActions.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { MessageProps } from '@patternfly/chatbot';\nimport QuickResponse from '@patternfly/chatbot/dist/cjs/Message/QuickResponse/QuickResponse';\nimport { UserFeedbackProps } from '@patternfly/chatbot/dist/cjs/Message/UserFeedback/UserFeedback';\nimport { UserFeedbackCompleteProps } from '@patternfly/chatbot/dist/cjs/Message/UserFeedback/UserFeedbackComplete';\n\nimport { useCaptureFeedback } from '../hooks/useCaptureFeedback';\nimport { CaptureFeedback } from '../types';\nimport { Sentiment, useFeedbackState } from './useFeedbackState';\nimport { useFeedbackStatus } from './useFeedbackStatus';\n\nconst quickResponses: { [key in Sentiment]: QuickResponse[] } = {\n positive: [\n { id: '1', content: 'Helpful information' },\n { id: '2', content: 'Easy to understand' },\n { id: '3', content: 'Resolved my issue' },\n ],\n negative: [\n { id: '1', content: `Didn’t answer my question` },\n { id: '2', content: 'Hard to understand' },\n { id: '3', content: 'Not Helpful' },\n ],\n};\n\nexport const useFeedbackActions = <T extends MessageProps>(\n messages: T[],\n conversationId: string,\n isStreaming: boolean,\n): T[] => {\n const copyButtonRef = useRef<HTMLButtonElement>(null);\n const speakingButtonRef = useRef<HTMLButtonElement>(null);\n const currentSpeakingIdRef = useRef<string | null>(null);\n\n const { data: feedbackEnabled } = useFeedbackStatus();\n const { state, ...dispatch } = useFeedbackState();\n const { mutateAsync: captureFeedback } = useCaptureFeedback();\n\n const getFeedbackForm = useCallback(\n (messageId: string, sentiment: 'positive' | 'negative') => ({\n key: `feedback-${sentiment}`,\n id: `feedback-${sentiment}-${messageId}`,\n hasTextArea: true,\n quickResponses: quickResponses[sentiment],\n onSubmit: (\n quickResponse: string | undefined = '0',\n additionalFeedback: string | undefined,\n ) => {\n const quickIndex = Number(quickResponse) - 1;\n const quickText =\n quickResponse !== '0'\n ? quickResponses[sentiment]?.[quickIndex]?.content\n : undefined;\n\n let user_feedback = '';\n\n if (quickText && additionalFeedback) {\n user_feedback = `${quickText}\\nAdditional feedback: ${additionalFeedback}`;\n } else if (quickText) {\n user_feedback = quickText;\n } else if (additionalFeedback) {\n user_feedback = additionalFeedback;\n }\n\n const botAnswerId = Number(messageId.split('-').pop());\n const userQuestionId = botAnswerId - 1;\n\n const payload: CaptureFeedback = {\n conversation_id: conversationId,\n user_feedback,\n sentiment: sentiment === 'positive' ? 1 : -1,\n user_question: messages[userQuestionId].content || '',\n llm_response: messages[botAnswerId].content || '',\n };\n\n captureFeedback(payload).then(() => {\n dispatch.hideFeedbackForm(messageId, sentiment);\n dispatch.showCompletionForm(messageId, sentiment);\n dispatch.updateButtonState(messageId, {\n sentiment: sentiment,\n feedbackSubmitted: true,\n });\n\n setTimeout(() => {\n dispatch.hideCompletionForm(messageId, sentiment);\n }, 1000);\n });\n },\n\n // eslint-disable-next-line no-console\n onClose: () => {\n dispatch.hideFeedbackForm(messageId, sentiment);\n dispatch.resetButtonState(messageId);\n dispatch.updateButtonState(messageId, { sentiment: undefined });\n },\n focusOnLoad: true,\n }),\n [captureFeedback, conversationId, dispatch, messages],\n );\n\n const feedbackForms = useCallback(\n (messageId: string): { [key in Sentiment]: UserFeedbackProps } => ({\n positive: getFeedbackForm(messageId, 'positive'),\n negative: getFeedbackForm(messageId, 'negative'),\n }),\n [getFeedbackForm],\n );\n\n const getUserFeedbackComplete = useCallback(\n (\n messageId: string,\n sentiment: Sentiment,\n ): UserFeedbackCompleteProps | undefined => {\n const isVisible = state[messageId]?.completionForm?.[sentiment];\n if (!isVisible) return undefined;\n\n return {\n id: `feebback-completion-${sentiment}-${messageId}`,\n onClose: () => {\n dispatch.hideCompletionForm(messageId, sentiment);\n dispatch.resetButtonState(messageId);\n },\n };\n },\n [state, dispatch],\n );\n\n const scrollToFeedbackForm = useCallback(\n (messageId: string, sentiment: Sentiment) => {\n setTimeout(() => {\n const el = document.getElementById(\n `feedback-${sentiment}-${messageId}`,\n );\n if (el) {\n el.scrollIntoView({ behavior: 'auto', block: 'start' });\n el.focus();\n }\n }, 0);\n },\n [],\n );\n\n const speakMessage = useCallback(\n (messageId: string, content: string) => {\n if (window.speechSynthesis.speaking || window.speechSynthesis.pending) {\n window.speechSynthesis.cancel();\n\n if (\n currentSpeakingIdRef.current &&\n currentSpeakingIdRef.current !== messageId\n ) {\n dispatch.updateButtonState(currentSpeakingIdRef.current, {\n isSpeaking: false,\n });\n }\n }\n\n // Track the current SpeakingId\n currentSpeakingIdRef.current = messageId;\n\n const utterance = new SpeechSynthesisUtterance(content);\n\n utterance.onstart = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: true });\n };\n\n utterance.onend = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n currentSpeakingIdRef.current = null;\n };\n\n utterance.onerror = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n currentSpeakingIdRef.current = null;\n };\n\n window.speechSynthesis.speak(utterance);\n },\n [dispatch],\n );\n\n const cancelSpeaking = useCallback(\n (messageId?: string) => {\n window.speechSynthesis.cancel();\n\n currentSpeakingIdRef.current = null;\n\n if (messageId) {\n // Cancel just this one message\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n } else {\n // Cancel all messages\n Object.keys(state).forEach(id => {\n if (state[id].buttonState?.isSpeaking) {\n dispatch.updateButtonState(id, { isSpeaking: false });\n }\n });\n }\n setTimeout(() => {\n const el = document.getElementById(`listen-${messageId}`);\n if (el) {\n el.blur();\n }\n }, 10);\n },\n [state, dispatch],\n );\n\n useEffect(() => {\n return () => {\n // Stop any ongoing speech when component unmounts\n cancelSpeaking();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [conversationId]);\n\n return useMemo(() => {\n return feedbackEnabled\n ? messages.map((message, index) => {\n if (\n message.role === 'user' ||\n (isStreaming && messages.length - 1 === index)\n )\n return message;\n\n const messageId = `${conversationId}-${message.role}-${index}`;\n const { sentiment, copied, isSpeaking } =\n state[messageId]?.buttonState || {};\n const showFeedbackForm = state[messageId]?.feedbackForm?.[sentiment];\n const userFeedbackForm =\n showFeedbackForm && feedbackForms(messageId)[sentiment];\n\n const userFeedbackComplete = getUserFeedbackComplete(\n messageId,\n sentiment,\n );\n\n const createSentimentAction = (selected: Sentiment) => ({\n isClicked: sentiment === selected,\n onClick: () => {\n if (sentiment !== selected) {\n dispatch.toggleFeedbackForm(messageId, selected);\n dispatch.updateButtonState(messageId, { sentiment: selected });\n scrollToFeedbackForm(messageId, sentiment);\n }\n },\n 'aria-expanded': sentiment === selected,\n 'aria-controls': showFeedbackForm\n ? `feedback-${sentiment}-${messageId}`\n : `feebback-completion-${sentiment}-${messageId}`,\n });\n\n const copyAction = {\n isClicked: copied,\n ref: copyButtonRef,\n tooltipContent: copied ? 'Copied' : null,\n onClick: async () => {\n await window.navigator.clipboard.writeText(\n message.content as string,\n );\n dispatch.updateButtonState(messageId, {\n copied: true,\n });\n\n setTimeout(() => {\n dispatch.updateButtonState(messageId, { copied: false });\n copyButtonRef?.current?.blur();\n }, 1000);\n },\n };\n\n const listenAction = {\n isClicked: isSpeaking,\n ref: speakingButtonRef,\n id: `listen-${messageId}`,\n onClick: () => {\n const isCurrentlySpeaking =\n state[messageId]?.buttonState?.isSpeaking;\n\n if (isCurrentlySpeaking) {\n // Stop if it's already speaking this message\n cancelSpeaking(messageId);\n } else {\n cancelSpeaking();\n speakMessage(messageId, message.content as string);\n }\n },\n };\n\n return {\n ...message,\n userFeedbackForm,\n userFeedbackComplete,\n actions: {\n positive: createSentimentAction('positive'),\n negative: createSentimentAction('negative'),\n copy: copyAction,\n listen: listenAction,\n },\n };\n })\n : messages;\n }, [\n conversationId,\n messages,\n state,\n dispatch,\n isStreaming,\n speakMessage,\n feedbackForms,\n cancelSpeaking,\n feedbackEnabled,\n getUserFeedbackComplete,\n scrollToFeedbackForm,\n ]);\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useFeedbackActions.esm.js","sources":["../../src/hooks/useFeedbackActions.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { MessageProps } from '@patternfly/chatbot';\nimport { UserFeedbackProps } from '@patternfly/chatbot/dist/cjs/Message/UserFeedback/UserFeedback';\nimport { UserFeedbackCompleteProps } from '@patternfly/chatbot/dist/cjs/Message/UserFeedback/UserFeedbackComplete';\n\nimport { useCaptureFeedback } from '../hooks/useCaptureFeedback';\nimport { CaptureFeedback } from '../types';\nimport { Sentiment, useFeedbackState } from './useFeedbackState';\nimport { useFeedbackStatus } from './useFeedbackStatus';\nimport { useTranslation } from './useTranslation';\n\nexport const useFeedbackActions = <T extends MessageProps>(\n messages: T[],\n conversationId: string,\n isStreaming: boolean,\n): T[] => {\n const copyButtonRef = useRef<HTMLButtonElement>(null);\n const speakingButtonRef = useRef<HTMLButtonElement>(null);\n const currentSpeakingIdRef = useRef<string | null>(null);\n\n const { data: feedbackEnabled } = useFeedbackStatus();\n const { state, ...dispatch } = useFeedbackState();\n const { mutateAsync: captureFeedback } = useCaptureFeedback();\n const { t } = useTranslation();\n\n const createQuickResponses = useMemo(\n () => ({\n positive: [\n { id: '1', content: t('feedback.quickResponses.positive.helpful') },\n {\n id: '2',\n content: t('feedback.quickResponses.positive.easyToUnderstand'),\n },\n {\n id: '3',\n content: t('feedback.quickResponses.positive.resolvedIssue'),\n },\n ],\n negative: [\n { id: '1', content: t('feedback.quickResponses.negative.didntAnswer') },\n {\n id: '2',\n content: t('feedback.quickResponses.negative.hardToUnderstand'),\n },\n { id: '3', content: t('feedback.quickResponses.negative.notHelpful') },\n ],\n }),\n [t],\n );\n\n const getFeedbackForm = useCallback(\n (messageId: string, sentiment: 'positive' | 'negative') => ({\n key: `feedback-${sentiment}`,\n id: `feedback-${sentiment}-${messageId}`,\n hasTextArea: true,\n title: t('feedback.form.title'),\n textAreaPlaceholder: t('feedback.form.textAreaPlaceholder'),\n submitWord: t('feedback.form.submitWord'),\n quickResponses: createQuickResponses[sentiment],\n onSubmit: (\n quickResponse: string | undefined = '0',\n additionalFeedback: string | undefined,\n ) => {\n const quickIndex = Number(quickResponse) - 1;\n const quickText =\n quickResponse !== '0'\n ? createQuickResponses[sentiment]?.[quickIndex]?.content\n : undefined;\n\n let user_feedback = '';\n\n if (quickText && additionalFeedback) {\n user_feedback = `${quickText}\\nAdditional feedback: ${additionalFeedback}`;\n } else if (quickText) {\n user_feedback = quickText;\n } else if (additionalFeedback) {\n user_feedback = additionalFeedback;\n }\n\n const botAnswerId = Number(messageId.split('-').pop());\n const userQuestionId = botAnswerId - 1;\n\n const payload: CaptureFeedback = {\n conversation_id: conversationId,\n user_feedback,\n sentiment: sentiment === 'positive' ? 1 : -1,\n user_question: messages[userQuestionId].content || '',\n llm_response: messages[botAnswerId].content || '',\n };\n\n captureFeedback(payload).then(() => {\n dispatch.hideFeedbackForm(messageId, sentiment);\n dispatch.showCompletionForm(messageId, sentiment);\n dispatch.updateButtonState(messageId, {\n sentiment: sentiment,\n feedbackSubmitted: true,\n });\n\n setTimeout(() => {\n dispatch.hideCompletionForm(messageId, sentiment);\n }, 1000);\n });\n },\n\n // eslint-disable-next-line no-console\n onClose: () => {\n dispatch.hideFeedbackForm(messageId, sentiment);\n dispatch.resetButtonState(messageId);\n dispatch.updateButtonState(messageId, { sentiment: undefined });\n },\n focusOnLoad: true,\n }),\n [\n captureFeedback,\n conversationId,\n dispatch,\n messages,\n createQuickResponses,\n t,\n ],\n );\n\n const feedbackForms = useCallback(\n (messageId: string): { [key in Sentiment]: UserFeedbackProps } => ({\n positive: getFeedbackForm(messageId, 'positive'),\n negative: getFeedbackForm(messageId, 'negative'),\n }),\n [getFeedbackForm],\n );\n\n const getUserFeedbackComplete = useCallback(\n (\n messageId: string,\n sentiment: Sentiment,\n ): UserFeedbackCompleteProps | undefined => {\n const isVisible = state[messageId]?.completionForm?.[sentiment];\n if (!isVisible) return undefined;\n\n return {\n id: `feebback-completion-${sentiment}-${messageId}`,\n title: t('feedback.completion.title'),\n body: t('feedback.completion.body'),\n onClose: () => {\n dispatch.hideCompletionForm(messageId, sentiment);\n dispatch.resetButtonState(messageId);\n },\n };\n },\n [state, dispatch, t],\n );\n\n const scrollToFeedbackForm = useCallback(\n (messageId: string, sentiment: Sentiment) => {\n setTimeout(() => {\n const el = document.getElementById(\n `feedback-${sentiment}-${messageId}`,\n );\n if (el) {\n el.scrollIntoView({ behavior: 'auto', block: 'start' });\n el.focus();\n }\n }, 0);\n },\n [],\n );\n\n const speakMessage = useCallback(\n (messageId: string, content: string) => {\n if (window.speechSynthesis.speaking || window.speechSynthesis.pending) {\n window.speechSynthesis.cancel();\n\n if (\n currentSpeakingIdRef.current &&\n currentSpeakingIdRef.current !== messageId\n ) {\n dispatch.updateButtonState(currentSpeakingIdRef.current, {\n isSpeaking: false,\n });\n }\n }\n\n // Track the current SpeakingId\n currentSpeakingIdRef.current = messageId;\n\n const utterance = new SpeechSynthesisUtterance(content);\n\n utterance.onstart = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: true });\n };\n\n utterance.onend = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n currentSpeakingIdRef.current = null;\n };\n\n utterance.onerror = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n currentSpeakingIdRef.current = null;\n };\n\n window.speechSynthesis.speak(utterance);\n },\n [dispatch],\n );\n\n const cancelSpeaking = useCallback(\n (messageId?: string) => {\n window.speechSynthesis.cancel();\n\n currentSpeakingIdRef.current = null;\n\n if (messageId) {\n // Cancel just this one message\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n } else {\n // Cancel all messages\n Object.keys(state).forEach(id => {\n if (state[id].buttonState?.isSpeaking) {\n dispatch.updateButtonState(id, { isSpeaking: false });\n }\n });\n }\n setTimeout(() => {\n const el = document.getElementById(`listen-${messageId}`);\n if (el) {\n el.blur();\n }\n }, 10);\n },\n [state, dispatch],\n );\n\n useEffect(() => {\n return () => {\n // Stop any ongoing speech when component unmounts\n cancelSpeaking();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [conversationId]);\n\n return useMemo(() => {\n return feedbackEnabled\n ? messages.map((message, index) => {\n if (\n message.role === 'user' ||\n (isStreaming && messages.length - 1 === index)\n )\n return message;\n\n const messageId = `${conversationId}-${message.role}-${index}`;\n const { sentiment, copied, isSpeaking } =\n state[messageId]?.buttonState || {};\n const showFeedbackForm = state[messageId]?.feedbackForm?.[sentiment];\n const userFeedbackForm =\n showFeedbackForm && feedbackForms(messageId)[sentiment];\n\n const userFeedbackComplete = getUserFeedbackComplete(\n messageId,\n sentiment,\n );\n\n const createSentimentAction = (selected: Sentiment) => ({\n isClicked: sentiment === selected,\n onClick: () => {\n if (sentiment !== selected) {\n dispatch.toggleFeedbackForm(messageId, selected);\n dispatch.updateButtonState(messageId, { sentiment: selected });\n scrollToFeedbackForm(messageId, sentiment);\n }\n },\n tooltipContent:\n selected === 'positive'\n ? t('feedback.tooltips.goodResponse')\n : t('feedback.tooltips.badResponse'),\n 'aria-expanded': sentiment === selected,\n 'aria-controls': showFeedbackForm\n ? `feedback-${sentiment}-${messageId}`\n : `feebback-completion-${sentiment}-${messageId}`,\n });\n\n const copyAction = {\n isClicked: copied,\n ref: copyButtonRef,\n tooltipContent: copied\n ? t('feedback.tooltips.copied')\n : t('feedback.tooltips.copy'),\n onClick: async () => {\n await window.navigator.clipboard.writeText(\n message.content as string,\n );\n dispatch.updateButtonState(messageId, {\n copied: true,\n });\n\n setTimeout(() => {\n dispatch.updateButtonState(messageId, { copied: false });\n copyButtonRef?.current?.blur();\n }, 1000);\n },\n };\n\n const listenAction = {\n isClicked: isSpeaking,\n ref: speakingButtonRef,\n id: `listen-${messageId}`,\n tooltipContent: isSpeaking\n ? t('feedback.tooltips.listening')\n : t('feedback.tooltips.listen'),\n onClick: () => {\n const isCurrentlySpeaking =\n state[messageId]?.buttonState?.isSpeaking;\n\n if (isCurrentlySpeaking) {\n // Stop if it's already speaking this message\n cancelSpeaking(messageId);\n } else {\n cancelSpeaking();\n speakMessage(messageId, message.content as string);\n }\n },\n };\n\n return {\n ...message,\n userFeedbackForm,\n userFeedbackComplete,\n actions: {\n positive: createSentimentAction('positive'),\n negative: createSentimentAction('negative'),\n copy: copyAction,\n listen: listenAction,\n },\n };\n })\n : messages;\n }, [\n t,\n conversationId,\n messages,\n state,\n dispatch,\n isStreaming,\n speakMessage,\n feedbackForms,\n cancelSpeaking,\n feedbackEnabled,\n getUserFeedbackComplete,\n scrollToFeedbackForm,\n ]);\n};\n"],"names":[],"mappings":"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"}
|