@openk9ui/openk9-chatbot 3.0.1
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/README.md +50 -0
- package/dist/SingleMessage-Dyc7W2JZ.js +13738 -0
- package/dist/assets/Chatbot.css +107 -0
- package/dist/components/Chatbot.js +399 -0
- package/dist/components/LanguageContext.js +53 -0
- package/dist/components/Search.js +91 -0
- package/dist/components/SingleMessage.js +9 -0
- package/dist/components/Translate.js +69 -0
- package/dist/components/client.js +119 -0
- package/dist/components/styled.js +21 -0
- package/dist/components/useFocusTrap.js +95 -0
- package/dist/components/useGenerateResponse.js +271 -0
- package/dist/components/useLanguage.js +12 -0
- package/dist/lib/components/Chatbot.js +168 -0
- package/dist/lib/components/LanguageContext.js +63 -0
- package/dist/lib/components/Search.js +56 -0
- package/dist/lib/components/SingleMessage.js +385 -0
- package/dist/lib/components/Translate.js +71 -0
- package/dist/lib/components/client.js +170 -0
- package/dist/lib/components/styled.js +14 -0
- package/dist/lib/components/useFocusTrap.js +85 -0
- package/dist/lib/components/useGenerateResponse.js +310 -0
- package/dist/lib/components/useLanguage.js +16 -0
- package/dist/lib/main.js +8 -0
- package/dist/main.js +4 -0
- package/dist/src/theme.js +52 -0
- package/dist/types/lib/components/Chatbot.d.ts +26 -0
- package/dist/types/lib/components/LanguageContext.d.ts +12 -0
- package/dist/types/lib/components/Search.d.ts +9 -0
- package/dist/types/lib/components/SingleMessage.d.ts +19 -0
- package/dist/types/lib/components/Translate.d.ts +5 -0
- package/dist/types/lib/components/client.d.ts +91 -0
- package/dist/types/lib/components/styled.d.ts +13 -0
- package/dist/types/lib/components/useFocusTrap.d.ts +5 -0
- package/dist/types/lib/components/useGenerateResponse.d.ts +33 -0
- package/dist/types/lib/components/useLanguage.d.ts +4 -0
- package/dist/types/lib/main.d.ts +2 -0
- package/dist/types/src/theme.d.ts +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React__default from "react";
|
|
2
|
+
const OpenK9ClientContext = React__default.createContext(
|
|
3
|
+
null
|
|
4
|
+
/* must break app if not provided */
|
|
5
|
+
);
|
|
6
|
+
function Client() {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
function OpenK9Client({
|
|
10
|
+
callbackAuthorization
|
|
11
|
+
}) {
|
|
12
|
+
async function authFetch(route, init = {}) {
|
|
13
|
+
const authorization = callbackAuthorization && callbackAuthorization();
|
|
14
|
+
const headers = {
|
|
15
|
+
...init.headers,
|
|
16
|
+
...authorization ? { authorization } : {}
|
|
17
|
+
};
|
|
18
|
+
return fetch(route, {
|
|
19
|
+
...init,
|
|
20
|
+
headers
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
// authInit: keycloakInit,
|
|
25
|
+
// async authenticate() {
|
|
26
|
+
// await keycloak.login();
|
|
27
|
+
// },
|
|
28
|
+
// async deauthenticate() {
|
|
29
|
+
// await keycloak.logout();
|
|
30
|
+
// },
|
|
31
|
+
// async getUserProfile(): Promise<{ name?: string } | undefined | null> {
|
|
32
|
+
// if (!keycloak.authenticated) {
|
|
33
|
+
// throw new Error("User is not authenticated");
|
|
34
|
+
// }
|
|
35
|
+
// try {
|
|
36
|
+
// const userInfo = await keycloak.loadUserInfo();
|
|
37
|
+
// return userInfo as { name: string };
|
|
38
|
+
// } catch (error) {
|
|
39
|
+
// throw error;
|
|
40
|
+
// }
|
|
41
|
+
// },
|
|
42
|
+
async getInitialMessages(chatId) {
|
|
43
|
+
const response = await authFetch(`/api/rag/chat/${chatId}`);
|
|
44
|
+
if (!response.ok) throw new Error("Network response was not ok");
|
|
45
|
+
const data = await response.json();
|
|
46
|
+
return data || [];
|
|
47
|
+
},
|
|
48
|
+
// async getUserInfo(): Promise<getUserInfo> {
|
|
49
|
+
// const response = await fetch(`/api/datasource/buckets/current`);
|
|
50
|
+
// if (!response.ok) throw new Error("Network response was not ok");
|
|
51
|
+
// const data = await response.json();
|
|
52
|
+
// return data;
|
|
53
|
+
// },
|
|
54
|
+
async getHistoryChat(searchQuery) {
|
|
55
|
+
console.log("Calling getHistoryChat with URL:", "/api/rag/user-chats");
|
|
56
|
+
const response = await authFetch(`/api/rag/user-chats`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: {
|
|
59
|
+
accept: "application/json",
|
|
60
|
+
"Content-Type": "application/json"
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify(searchQuery)
|
|
63
|
+
});
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
console.error("Response not ok:", response.status, response.statusText);
|
|
66
|
+
throw new Error("Network response was not ok");
|
|
67
|
+
}
|
|
68
|
+
const result = await response.json();
|
|
69
|
+
return result;
|
|
70
|
+
},
|
|
71
|
+
async GenerateResponse({
|
|
72
|
+
url,
|
|
73
|
+
searchQuery,
|
|
74
|
+
controller
|
|
75
|
+
}) {
|
|
76
|
+
const response = await authFetch(url, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: {
|
|
79
|
+
accept: "application/json",
|
|
80
|
+
"Content-Type": "application/json"
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify(searchQuery),
|
|
83
|
+
signal: controller.signal
|
|
84
|
+
});
|
|
85
|
+
return response;
|
|
86
|
+
}
|
|
87
|
+
// async deleteChat(chatId: string) {
|
|
88
|
+
// const response = await authFetch(`/api/rag/chat/${chatId}`, {
|
|
89
|
+
// method: "DELETE",
|
|
90
|
+
// headers: {
|
|
91
|
+
// accept: "application/json"
|
|
92
|
+
// }
|
|
93
|
+
// });
|
|
94
|
+
// if (!response.ok) {
|
|
95
|
+
// throw new Error("Errore durante l'eliminazione della chat");
|
|
96
|
+
// }
|
|
97
|
+
// return response;
|
|
98
|
+
// },
|
|
99
|
+
// async renameChat(chatId: string, newTitle: string) {
|
|
100
|
+
// const response = await authFetch(`/api/rag/chat/${chatId}`, {
|
|
101
|
+
// method: "PATCH",
|
|
102
|
+
// headers: {
|
|
103
|
+
// accept: "application/json",
|
|
104
|
+
// "Content-Type": "application/json",
|
|
105
|
+
// },
|
|
106
|
+
// body: JSON.stringify({ newTitle })
|
|
107
|
+
// });
|
|
108
|
+
// if (!response.ok) {
|
|
109
|
+
// throw new Error("Errore durante la rinomina della chat");
|
|
110
|
+
// }
|
|
111
|
+
// return response;
|
|
112
|
+
// }
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
OpenK9Client,
|
|
117
|
+
OpenK9ClientContext,
|
|
118
|
+
Client as default
|
|
119
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
const ParagraphTime = styled.p`
|
|
3
|
+
color: ${(props) => props.$color};
|
|
4
|
+
margin: 0px;
|
|
5
|
+
align-self: end;
|
|
6
|
+
font-size: 10px;
|
|
7
|
+
font-weight: 500;
|
|
8
|
+
line-height: 11.72px;
|
|
9
|
+
`;
|
|
10
|
+
const ParagraphMessage = styled.p`
|
|
11
|
+
color:${(props) => props.$color};
|
|
12
|
+
margin: 0px;
|
|
13
|
+
fontSize: "12px",
|
|
14
|
+
fontWeight: "400",
|
|
15
|
+
lineHeight: "18.25px",
|
|
16
|
+
textAlign: "left",
|
|
17
|
+
`;
|
|
18
|
+
export {
|
|
19
|
+
ParagraphMessage,
|
|
20
|
+
ParagraphTime
|
|
21
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useRef, useCallback, useEffect } from "react";
|
|
2
|
+
function convertToIntOrFallback(stringToConvert) {
|
|
3
|
+
const parsed = parseInt(stringToConvert ?? "");
|
|
4
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
5
|
+
}
|
|
6
|
+
function getTabIndexOfNode(targetNode) {
|
|
7
|
+
return convertToIntOrFallback(targetNode.getAttribute("tabindex"));
|
|
8
|
+
}
|
|
9
|
+
function sanitizeTabIndexInput(tabIndex, highestPositiveTabIndex) {
|
|
10
|
+
if (tabIndex < 0) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`Unable to sort given input. A negative value is not part of the tab order: ${tabIndex}`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return tabIndex === 0 ? highestPositiveTabIndex + 1 : tabIndex;
|
|
16
|
+
}
|
|
17
|
+
function sortByTabIndex(firstNode, secondNode) {
|
|
18
|
+
const tabIndexes = [firstNode, secondNode].map(
|
|
19
|
+
(node) => getTabIndexOfNode(node)
|
|
20
|
+
);
|
|
21
|
+
return tabIndexes.map(
|
|
22
|
+
(tabIndexValue) => sanitizeTabIndexInput(tabIndexValue, Math.max(...tabIndexes))
|
|
23
|
+
).reduce((previousValue, currentValue) => previousValue - currentValue);
|
|
24
|
+
}
|
|
25
|
+
const focusableElementsSelector = "a[href], area[href], input:not([disabled]):not([type=hidden]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]";
|
|
26
|
+
const TAB_KEY = 9;
|
|
27
|
+
function useFocusTrap(isActive) {
|
|
28
|
+
const trapRef = useRef(null);
|
|
29
|
+
const selectNextFocusableElem = useCallback(
|
|
30
|
+
(sortedFocusableElems, currentIndex, shiftKeyPressed = false, skipCount = 0) => {
|
|
31
|
+
if (skipCount > sortedFocusableElems.length) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const backwards = !!shiftKeyPressed;
|
|
35
|
+
const maxIndex = sortedFocusableElems.length - 1;
|
|
36
|
+
if (currentIndex === void 0) {
|
|
37
|
+
currentIndex = sortedFocusableElems.indexOf(document.activeElement) ?? 0;
|
|
38
|
+
}
|
|
39
|
+
let nextIndex = backwards ? currentIndex - 1 : currentIndex + 1;
|
|
40
|
+
if (nextIndex > maxIndex) {
|
|
41
|
+
nextIndex = 0;
|
|
42
|
+
}
|
|
43
|
+
if (nextIndex < 0) {
|
|
44
|
+
nextIndex = maxIndex;
|
|
45
|
+
}
|
|
46
|
+
const newFocusElem = sortedFocusableElems[nextIndex];
|
|
47
|
+
newFocusElem.focus();
|
|
48
|
+
if (document.activeElement !== newFocusElem) {
|
|
49
|
+
selectNextFocusableElem(
|
|
50
|
+
sortedFocusableElems,
|
|
51
|
+
nextIndex,
|
|
52
|
+
shiftKeyPressed,
|
|
53
|
+
skipCount + 1
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
[]
|
|
58
|
+
);
|
|
59
|
+
const trapper = useCallback(
|
|
60
|
+
(evt) => {
|
|
61
|
+
const trapRefElem = trapRef.current;
|
|
62
|
+
if (trapRefElem !== null) {
|
|
63
|
+
if (evt.which === TAB_KEY || evt.key === "Tab") {
|
|
64
|
+
evt.preventDefault();
|
|
65
|
+
const shiftKeyPressed = !!evt.shiftKey;
|
|
66
|
+
let focusableElems = Array.from(
|
|
67
|
+
trapRefElem.querySelectorAll(focusableElementsSelector)
|
|
68
|
+
).filter(
|
|
69
|
+
(focusableElement) => getTabIndexOfNode(focusableElement) >= 0
|
|
70
|
+
);
|
|
71
|
+
focusableElems = focusableElems.sort(sortByTabIndex);
|
|
72
|
+
selectNextFocusableElem(focusableElems, void 0, shiftKeyPressed);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
[selectNextFocusableElem]
|
|
77
|
+
);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (isActive) {
|
|
80
|
+
window.addEventListener("keydown", trapper);
|
|
81
|
+
}
|
|
82
|
+
return () => {
|
|
83
|
+
if (isActive) {
|
|
84
|
+
window.removeEventListener("keydown", trapper);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}, [isActive, trapper]);
|
|
88
|
+
return [trapRef];
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
convertToIntOrFallback,
|
|
92
|
+
getTabIndexOfNode,
|
|
93
|
+
sortByTabIndex,
|
|
94
|
+
useFocusTrap
|
|
95
|
+
};
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import React__default, { useState, useCallback } from "react";
|
|
2
|
+
import { useLanguage } from "./useLanguage.js";
|
|
3
|
+
import { OpenK9Client } from "./client.js";
|
|
4
|
+
const byteToHex = [];
|
|
5
|
+
for (let i = 0; i < 256; ++i) {
|
|
6
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
|
7
|
+
}
|
|
8
|
+
function unsafeStringify(arr, offset = 0) {
|
|
9
|
+
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
let getRandomValues;
|
|
12
|
+
const rnds8 = new Uint8Array(16);
|
|
13
|
+
function rng() {
|
|
14
|
+
if (!getRandomValues) {
|
|
15
|
+
if (typeof crypto === "undefined" || !crypto.getRandomValues) {
|
|
16
|
+
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
|
|
17
|
+
}
|
|
18
|
+
getRandomValues = crypto.getRandomValues.bind(crypto);
|
|
19
|
+
}
|
|
20
|
+
return getRandomValues(rnds8);
|
|
21
|
+
}
|
|
22
|
+
const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
23
|
+
const native = { randomUUID };
|
|
24
|
+
function v4(options, buf, offset) {
|
|
25
|
+
var _a;
|
|
26
|
+
if (native.randomUUID && true && !options) {
|
|
27
|
+
return native.randomUUID();
|
|
28
|
+
}
|
|
29
|
+
options = options || {};
|
|
30
|
+
const rnds = options.random ?? ((_a = options.rng) == null ? void 0 : _a.call(options)) ?? rng();
|
|
31
|
+
if (rnds.length < 16) {
|
|
32
|
+
throw new Error("Random bytes length must be >= 16");
|
|
33
|
+
}
|
|
34
|
+
rnds[6] = rnds[6] & 15 | 64;
|
|
35
|
+
rnds[8] = rnds[8] & 63 | 128;
|
|
36
|
+
return unsafeStringify(rnds);
|
|
37
|
+
}
|
|
38
|
+
const useGenerateResponse = ({
|
|
39
|
+
initialMessages,
|
|
40
|
+
tenant,
|
|
41
|
+
callbackAuthorization
|
|
42
|
+
}) => {
|
|
43
|
+
const { language } = useLanguage();
|
|
44
|
+
const [messages, setMessages] = useState(initialMessages);
|
|
45
|
+
const [abortControllers, setAbortControllers] = useState(/* @__PURE__ */ new Map());
|
|
46
|
+
const [isChatting, setIsChatting] = useState(false);
|
|
47
|
+
const [isLoading, setIsLoading] = useState(null);
|
|
48
|
+
const client = React__default.useMemo(
|
|
49
|
+
() => OpenK9Client({ callbackAuthorization }),
|
|
50
|
+
[callbackAuthorization]
|
|
51
|
+
);
|
|
52
|
+
const generateResponse = useCallback(
|
|
53
|
+
async (query) => {
|
|
54
|
+
var _a, _b;
|
|
55
|
+
const id = v4();
|
|
56
|
+
setIsLoading({ id, isLoading: true });
|
|
57
|
+
const timestamp = "" + Date.now();
|
|
58
|
+
const nonLoggedUserId = `anonymous_${v4()}_${timestamp}`;
|
|
59
|
+
const chatHistory = messages.map((msg) => ({
|
|
60
|
+
question: msg.question,
|
|
61
|
+
answer: msg.answer,
|
|
62
|
+
title: "",
|
|
63
|
+
sources: msg.sources || [],
|
|
64
|
+
chat_id: nonLoggedUserId,
|
|
65
|
+
//keycloak.authenticated ? chatId : nonLoggedUserId,
|
|
66
|
+
timestamp: msg.timestamp || "",
|
|
67
|
+
chat_sequence_number: msg.chat_sequence_number
|
|
68
|
+
}));
|
|
69
|
+
setMessages((prevMessages) => {
|
|
70
|
+
var _a2;
|
|
71
|
+
const chat_sequence_number = (((_a2 = prevMessages[prevMessages.length - 1]) == null ? void 0 : _a2.chat_sequence_number) || 0) + 1;
|
|
72
|
+
const newMessage = {
|
|
73
|
+
id,
|
|
74
|
+
question: query,
|
|
75
|
+
answer: "",
|
|
76
|
+
sendTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
77
|
+
status: "CHUNK",
|
|
78
|
+
sources: [],
|
|
79
|
+
chat_sequence_number,
|
|
80
|
+
timestamp
|
|
81
|
+
};
|
|
82
|
+
return [...prevMessages, newMessage];
|
|
83
|
+
});
|
|
84
|
+
setIsChatting(true);
|
|
85
|
+
const controller = new AbortController();
|
|
86
|
+
setAbortControllers((prev) => new Map(prev).set(id, controller));
|
|
87
|
+
const url = `${tenant}/api/rag/chat-tool`;
|
|
88
|
+
const searchQuery = (
|
|
89
|
+
// keycloak.authenticated ? {
|
|
90
|
+
// searchText: query,
|
|
91
|
+
// chatId,
|
|
92
|
+
// chatSequenceNumber: messages[messages.length - 1]?.chat_sequence_number + 1 || 1,
|
|
93
|
+
// timestamp,
|
|
94
|
+
// // language,
|
|
95
|
+
// } :
|
|
96
|
+
{
|
|
97
|
+
searchText: query,
|
|
98
|
+
chatSequenceNumber: ((_a = messages[messages.length - 1]) == null ? void 0 : _a.chat_sequence_number) + 1 || 1,
|
|
99
|
+
timestamp,
|
|
100
|
+
chatHistory
|
|
101
|
+
// language,
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
try {
|
|
105
|
+
const response = await client.GenerateResponse({
|
|
106
|
+
controller,
|
|
107
|
+
searchQuery,
|
|
108
|
+
url
|
|
109
|
+
});
|
|
110
|
+
if (response.ok) {
|
|
111
|
+
const reader = (_b = response.body) == null ? void 0 : _b.getReader();
|
|
112
|
+
const decoder = new TextDecoder("utf-8");
|
|
113
|
+
let done = false;
|
|
114
|
+
let buffer = "";
|
|
115
|
+
while (!done && reader) {
|
|
116
|
+
const { value, done: readerDone } = await reader.read();
|
|
117
|
+
done = readerDone;
|
|
118
|
+
buffer += decoder.decode(value, { stream: true });
|
|
119
|
+
let boundaryIndex;
|
|
120
|
+
while ((boundaryIndex = buffer.indexOf("\n")) !== -1) {
|
|
121
|
+
const chunkStr = buffer.slice(0, boundaryIndex);
|
|
122
|
+
buffer = buffer.slice(boundaryIndex + 1);
|
|
123
|
+
if (chunkStr.trim().startsWith("data: ")) {
|
|
124
|
+
const dataStr = chunkStr.trim().slice(6);
|
|
125
|
+
try {
|
|
126
|
+
const data = JSON.parse(dataStr);
|
|
127
|
+
switch (data.type) {
|
|
128
|
+
case "CHUNK":
|
|
129
|
+
setMessages(
|
|
130
|
+
(prev) => prev.map(
|
|
131
|
+
(msg) => msg.id === id ? {
|
|
132
|
+
...msg,
|
|
133
|
+
answer: msg.answer + data.chunk
|
|
134
|
+
} : msg
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
break;
|
|
138
|
+
case "DOCUMENT":
|
|
139
|
+
setMessages(
|
|
140
|
+
(prev) => prev.map(
|
|
141
|
+
(msg) => msg.id === id ? {
|
|
142
|
+
...msg,
|
|
143
|
+
sources: [...(msg == null ? void 0 : msg.sources) ?? [], data.chunk]
|
|
144
|
+
} : msg
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
break;
|
|
148
|
+
case "START":
|
|
149
|
+
setIsLoading(null);
|
|
150
|
+
break;
|
|
151
|
+
case "ERROR":
|
|
152
|
+
setMessages(
|
|
153
|
+
(prev) => prev.map(
|
|
154
|
+
(msg) => msg.id === id ? {
|
|
155
|
+
...msg,
|
|
156
|
+
answer: data.chunk,
|
|
157
|
+
status: "ERROR"
|
|
158
|
+
} : msg
|
|
159
|
+
)
|
|
160
|
+
);
|
|
161
|
+
setIsChatting(false);
|
|
162
|
+
break;
|
|
163
|
+
case "END":
|
|
164
|
+
setMessages(
|
|
165
|
+
(prev) => prev.map(
|
|
166
|
+
(msg) => msg.id === id ? {
|
|
167
|
+
...msg,
|
|
168
|
+
status: "END"
|
|
169
|
+
} : msg
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
setIsChatting(false);
|
|
173
|
+
break;
|
|
174
|
+
default:
|
|
175
|
+
console.warn(
|
|
176
|
+
"Tipo di chunk non riconosciuto:",
|
|
177
|
+
data.type
|
|
178
|
+
);
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
} catch (e) {
|
|
182
|
+
console.error("Errore nel parsing del JSON", e);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
console.error("Errore nel generare la risposta");
|
|
189
|
+
setMessages(
|
|
190
|
+
(prev) => prev.map(
|
|
191
|
+
(msg) => msg.id === id ? {
|
|
192
|
+
...msg,
|
|
193
|
+
status: "ERROR",
|
|
194
|
+
answer: (response == null ? void 0 : response.statusText) || "Error"
|
|
195
|
+
} : msg
|
|
196
|
+
)
|
|
197
|
+
);
|
|
198
|
+
setIsChatting(false);
|
|
199
|
+
}
|
|
200
|
+
setIsChatting(false);
|
|
201
|
+
setIsLoading(null);
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error("Errore durante la richiesta", error);
|
|
204
|
+
setIsChatting(false);
|
|
205
|
+
}
|
|
206
|
+
setAbortControllers((prev) => {
|
|
207
|
+
const updated = new Map(prev);
|
|
208
|
+
updated.delete(id);
|
|
209
|
+
return updated;
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
[messages, client, tenant, language]
|
|
213
|
+
//loading, userInfo,
|
|
214
|
+
);
|
|
215
|
+
const cancelResponse = (id) => {
|
|
216
|
+
const controller = abortControllers.get(id);
|
|
217
|
+
if (controller) {
|
|
218
|
+
controller.abort();
|
|
219
|
+
setIsLoading(null);
|
|
220
|
+
setMessages(
|
|
221
|
+
(prev) => prev.map(
|
|
222
|
+
(msg) => msg.id === id ? {
|
|
223
|
+
...msg,
|
|
224
|
+
status: "END",
|
|
225
|
+
answer: "La risposta è stata annullata"
|
|
226
|
+
} : msg
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
setAbortControllers((prev) => {
|
|
230
|
+
const updated = new Map(prev);
|
|
231
|
+
updated.delete(id);
|
|
232
|
+
return updated;
|
|
233
|
+
});
|
|
234
|
+
setIsChatting(abortControllers.size > 0);
|
|
235
|
+
} else {
|
|
236
|
+
console.warn(`No AbortController found for id: ${id}`);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const cancelAllResponses = () => {
|
|
240
|
+
abortControllers.forEach((controller) => {
|
|
241
|
+
controller.abort();
|
|
242
|
+
});
|
|
243
|
+
setMessages(
|
|
244
|
+
(prev) => prev.map(
|
|
245
|
+
(msg) => msg.status === "CHUNK" ? {
|
|
246
|
+
...msg,
|
|
247
|
+
status: "END",
|
|
248
|
+
answer: msg.answer + "... La risposta è stata annullata"
|
|
249
|
+
} : msg
|
|
250
|
+
)
|
|
251
|
+
);
|
|
252
|
+
setAbortControllers(/* @__PURE__ */ new Map());
|
|
253
|
+
setIsChatting(false);
|
|
254
|
+
setIsLoading(null);
|
|
255
|
+
};
|
|
256
|
+
const resetMessage = () => {
|
|
257
|
+
setMessages([]);
|
|
258
|
+
};
|
|
259
|
+
return {
|
|
260
|
+
messages,
|
|
261
|
+
generateResponse,
|
|
262
|
+
cancelResponse,
|
|
263
|
+
cancelAllResponses,
|
|
264
|
+
isChatting,
|
|
265
|
+
isLoading,
|
|
266
|
+
resetMessage
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
export {
|
|
270
|
+
useGenerateResponse as default
|
|
271
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import LanguageContext from "./LanguageContext.js";
|
|
3
|
+
const useLanguage = () => {
|
|
4
|
+
const context = useContext(LanguageContext);
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error("useLanguage must used to LanguageProvider");
|
|
7
|
+
}
|
|
8
|
+
return context;
|
|
9
|
+
};
|
|
10
|
+
export {
|
|
11
|
+
useLanguage
|
|
12
|
+
};
|