aizek-chatbot 1.0.30 → 1.0.32
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/dist/index.cjs +905 -891
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +42 -13
- package/dist/index.d.ts +42 -13
- package/dist/index.mjs +907 -893
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -12,12 +12,42 @@ var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
|
12
12
|
var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
|
|
13
13
|
var sanitizeHtml__default = /*#__PURE__*/_interopDefault(sanitizeHtml);
|
|
14
14
|
|
|
15
|
-
// src/
|
|
16
|
-
var
|
|
15
|
+
// src/constants/index.ts
|
|
16
|
+
var PROXY_BASE_URL = "http://localhost:3001/api";
|
|
17
|
+
var DEVICE_STORAGE_KEY = "aizek_device_id_v1";
|
|
18
|
+
var ACTIVE_SESSION_STORAGE_KEY = "aizek_active_session_v1";
|
|
17
19
|
var MAX_SESSIONS = 3;
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
var SESSION_TITLE_MAX_LENGTH = 46;
|
|
21
|
+
|
|
22
|
+
// src/utils/device.ts
|
|
23
|
+
function getOrCreateDeviceId() {
|
|
24
|
+
if (typeof window === "undefined") return "";
|
|
25
|
+
const existing = localStorage.getItem(DEVICE_STORAGE_KEY);
|
|
26
|
+
if (existing) return existing;
|
|
27
|
+
const id = crypto.randomUUID();
|
|
28
|
+
localStorage.setItem(DEVICE_STORAGE_KEY, id);
|
|
29
|
+
return id;
|
|
30
|
+
}
|
|
31
|
+
function getActiveSessionId() {
|
|
32
|
+
if (typeof window === "undefined") return null;
|
|
33
|
+
return localStorage.getItem(ACTIVE_SESSION_STORAGE_KEY);
|
|
34
|
+
}
|
|
35
|
+
function setActiveSessionId(id) {
|
|
36
|
+
if (typeof window === "undefined") return;
|
|
37
|
+
if (!id) localStorage.removeItem(ACTIVE_SESSION_STORAGE_KEY);
|
|
38
|
+
else localStorage.setItem(ACTIVE_SESSION_STORAGE_KEY, id);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/utils/headers.ts
|
|
42
|
+
function buildRequestHeaders(deviceId, alternateHeaders, sessionId) {
|
|
43
|
+
const headers = {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
"x-device-id": deviceId,
|
|
46
|
+
"x-alternate": JSON.stringify(alternateHeaders)
|
|
47
|
+
};
|
|
48
|
+
if (sessionId) headers["x-session-id"] = sessionId;
|
|
49
|
+
return headers;
|
|
50
|
+
}
|
|
21
51
|
function validateHeaders(headers, authConfig, opts = {}) {
|
|
22
52
|
if (headers && (!authConfig || Object.keys(authConfig).length === 0)) {
|
|
23
53
|
return {
|
|
@@ -30,82 +60,558 @@ function validateHeaders(headers, authConfig, opts = {}) {
|
|
|
30
60
|
}
|
|
31
61
|
const { caseSensitive = false, allowExtra = false } = opts;
|
|
32
62
|
const normalize = (s) => caseSensitive ? s : s.toLowerCase();
|
|
33
|
-
const headerEntries = Object.entries(headers).map(([k, v]) => [
|
|
34
|
-
|
|
63
|
+
const headerEntries = Object.entries(headers).map(([k, v]) => [
|
|
64
|
+
normalize(k),
|
|
65
|
+
v.trim()
|
|
66
|
+
]);
|
|
67
|
+
const authEntries = Object.entries(authConfig).map(([k, v]) => [
|
|
68
|
+
normalize(k),
|
|
69
|
+
v.trim()
|
|
70
|
+
]);
|
|
35
71
|
const headerKeys = headerEntries.map(([k]) => k);
|
|
36
72
|
const authKeys = authEntries.map(([k]) => k);
|
|
37
73
|
const requiredSet = new Set(authKeys);
|
|
38
74
|
const missingKeys = authKeys.filter((k) => !headerKeys.includes(k));
|
|
39
75
|
const extraKeys = headerKeys.filter((k) => !requiredSet.has(k));
|
|
40
|
-
const hasAllRequired = missingKeys.length === 0;
|
|
41
|
-
const hasExtraKeys = extraKeys.length > 0 && !allowExtra;
|
|
42
76
|
const emptyValueKeys = authKeys.filter((k) => {
|
|
43
77
|
const val = headerEntries.find(([key]) => key === k)?.[1];
|
|
44
78
|
return !val || val.length === 0;
|
|
45
79
|
});
|
|
80
|
+
const hasAllRequired = missingKeys.length === 0;
|
|
81
|
+
const hasExtraKeys = extraKeys.length > 0 && !allowExtra;
|
|
46
82
|
const isValid = hasAllRequired && !hasExtraKeys && emptyValueKeys.length === 0;
|
|
47
83
|
return { isValid, missingKeys, extraKeys, emptyValueKeys };
|
|
48
84
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
85
|
+
|
|
86
|
+
// src/utils/message.ts
|
|
87
|
+
function extractTextFromContent(content) {
|
|
88
|
+
if (typeof content === "string") return content;
|
|
89
|
+
if (Array.isArray(content)) {
|
|
90
|
+
return content.filter((item) => item.type === "text" && typeof item.text === "string").map((item) => item.text).join("\n");
|
|
91
|
+
}
|
|
92
|
+
return "";
|
|
56
93
|
}
|
|
57
|
-
function
|
|
58
|
-
|
|
94
|
+
function normalizeComponent(component, index) {
|
|
95
|
+
const normalized = { ...component };
|
|
96
|
+
if (!normalized.id?.trim()) {
|
|
97
|
+
normalized.id = `ui-comp-${index}-${Date.now()}`;
|
|
98
|
+
}
|
|
99
|
+
if (normalized.type === "button" && !normalized.buttonType) {
|
|
100
|
+
normalized.buttonType = "click";
|
|
101
|
+
}
|
|
102
|
+
if (normalized.type === "input" && !normalized.fieldType) {
|
|
103
|
+
normalized.fieldType = "text";
|
|
104
|
+
}
|
|
105
|
+
if (normalized.type === "select" && Array.isArray(normalized.options)) {
|
|
106
|
+
normalized.options = normalizeStringArray(normalized.options);
|
|
107
|
+
}
|
|
108
|
+
if (normalized.type === "table") {
|
|
109
|
+
normalized.columns = normalizeTableColumns(normalized.columns);
|
|
110
|
+
normalized.rows = normalizeTableRows(normalized.rows);
|
|
111
|
+
}
|
|
112
|
+
if (normalized.type === "form" && Array.isArray(normalized.items)) {
|
|
113
|
+
normalized.items = normalized.items.map(normalizeFormField);
|
|
114
|
+
}
|
|
115
|
+
if (normalized.type === "list" && Array.isArray(normalized.items)) {
|
|
116
|
+
normalized.items = normalized.items.map(normalizeListItem);
|
|
117
|
+
}
|
|
118
|
+
return normalized;
|
|
59
119
|
}
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
120
|
+
function normalizeStringArray(items) {
|
|
121
|
+
return items.map(
|
|
122
|
+
(item) => typeof item === "object" && item !== null ? item.label ?? item.value ?? String(item) : String(item)
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
function normalizeTableColumns(columns) {
|
|
126
|
+
if (!Array.isArray(columns)) return columns;
|
|
127
|
+
return columns.map(
|
|
128
|
+
(col) => typeof col === "object" && col !== null ? col.label ?? col.id ?? String(col) : String(col)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
function normalizeTableRows(rows) {
|
|
132
|
+
if (!Array.isArray(rows)) return rows;
|
|
133
|
+
return rows.map((row) => {
|
|
134
|
+
if (Array.isArray(row)) {
|
|
135
|
+
return row.map((cell) => String(cell ?? ""));
|
|
136
|
+
}
|
|
137
|
+
return Object.values(row).map((val) => {
|
|
138
|
+
if (typeof val === "object" && val !== null && val.type === "image") {
|
|
139
|
+
return val.src;
|
|
140
|
+
}
|
|
141
|
+
const record = val;
|
|
142
|
+
return String(record?.value ?? val ?? "");
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function normalizeFormField(field, fieldIndex) {
|
|
147
|
+
const normalized = { ...field };
|
|
148
|
+
if (!normalized.id?.trim()) {
|
|
149
|
+
normalized.id = `field-${fieldIndex}-${Date.now()}`;
|
|
150
|
+
}
|
|
151
|
+
const raw = field;
|
|
152
|
+
if ("optional" in raw) {
|
|
153
|
+
normalized.requiredField = !raw.optional;
|
|
154
|
+
}
|
|
155
|
+
if ("required" in raw) {
|
|
156
|
+
normalized.requiredField = !!raw.required;
|
|
157
|
+
}
|
|
158
|
+
if (normalized.type === "input" && !normalized.fieldType) {
|
|
159
|
+
normalized.fieldType = "text";
|
|
160
|
+
}
|
|
161
|
+
if (normalized.type === "select" && Array.isArray(normalized.options)) {
|
|
162
|
+
normalized.options = normalizeStringArray(normalized.options);
|
|
163
|
+
}
|
|
164
|
+
return normalized;
|
|
165
|
+
}
|
|
166
|
+
function normalizeListItem(item, itemIndex) {
|
|
167
|
+
if (typeof item === "string") {
|
|
168
|
+
return {
|
|
169
|
+
id: `list-item-${itemIndex}-${Date.now()}`,
|
|
170
|
+
type: "text",
|
|
171
|
+
label: item,
|
|
172
|
+
value: item
|
|
173
|
+
};
|
|
68
174
|
}
|
|
175
|
+
const comp = item;
|
|
176
|
+
if (!comp.id?.trim()) {
|
|
177
|
+
comp.id = `list-item-${itemIndex}-${Date.now()}`;
|
|
178
|
+
}
|
|
179
|
+
return comp;
|
|
69
180
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
181
|
+
function extractUIJsonFromText(text) {
|
|
182
|
+
const UI_COMPONENT_REGEX = /```ui-component\s*([\s\S]*?)```/g;
|
|
183
|
+
const matches = Array.from(text.matchAll(UI_COMPONENT_REGEX));
|
|
184
|
+
if (matches.length === 0) {
|
|
185
|
+
return { cleanedText: text.trim(), uiData: null };
|
|
186
|
+
}
|
|
187
|
+
let cleanedText = text;
|
|
188
|
+
let mergedUIData = null;
|
|
189
|
+
for (const match of matches) {
|
|
190
|
+
const fullBlock = match[0];
|
|
191
|
+
const jsonBlock = match[1]?.trim();
|
|
192
|
+
cleanedText = cleanedText.replace(fullBlock, "").trim();
|
|
193
|
+
try {
|
|
194
|
+
const parsed = JSON.parse(jsonBlock);
|
|
195
|
+
if (parsed && Array.isArray(parsed.components)) {
|
|
196
|
+
parsed.components = parsed.components.map(normalizeComponent);
|
|
197
|
+
if (!mergedUIData) {
|
|
198
|
+
mergedUIData = parsed;
|
|
199
|
+
} else {
|
|
200
|
+
mergedUIData.components = [
|
|
201
|
+
...mergedUIData.components,
|
|
202
|
+
...parsed.components
|
|
203
|
+
];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} catch (err) {
|
|
207
|
+
console.error("Invalid ui-component JSON:", err, jsonBlock);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
cleanedText = cleanedText.replace(/\n{3,}/g, "\n\n").trim();
|
|
211
|
+
return { cleanedText, uiData: mergedUIData };
|
|
72
212
|
}
|
|
73
|
-
function
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
213
|
+
function parseRawMessages(rawMessages) {
|
|
214
|
+
const result = [];
|
|
215
|
+
for (const msg of rawMessages) {
|
|
216
|
+
const textContent = extractTextFromContent(msg.content);
|
|
217
|
+
let cleanText = textContent;
|
|
218
|
+
let uiData = null;
|
|
219
|
+
if (textContent) {
|
|
220
|
+
const extracted = extractUIJsonFromText(textContent);
|
|
221
|
+
cleanText = extracted.cleanedText;
|
|
222
|
+
uiData = extracted.uiData;
|
|
223
|
+
}
|
|
224
|
+
if (cleanText.trim() || uiData) {
|
|
225
|
+
result.push({
|
|
226
|
+
text: cleanText.trim() || void 0,
|
|
227
|
+
ui: uiData ?? void 0,
|
|
228
|
+
role: msg.role === "user" ? "user" : "assistant",
|
|
229
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
230
|
+
});
|
|
231
|
+
}
|
|
81
232
|
}
|
|
82
|
-
return
|
|
233
|
+
return result;
|
|
83
234
|
}
|
|
84
|
-
|
|
85
|
-
|
|
235
|
+
|
|
236
|
+
// src/services/chat-api.ts
|
|
237
|
+
async function fetchWidgetConfig(clientId, headers) {
|
|
238
|
+
const deviceId = getOrCreateDeviceId();
|
|
239
|
+
const response = await fetch(
|
|
240
|
+
`${PROXY_BASE_URL}/aizek-connect?clientId=${clientId}`,
|
|
241
|
+
{
|
|
242
|
+
method: "POST",
|
|
243
|
+
headers: buildRequestHeaders(deviceId, headers)
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
return response.json();
|
|
86
247
|
}
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
248
|
+
async function createSession(clientId, headers) {
|
|
249
|
+
const deviceId = getOrCreateDeviceId();
|
|
250
|
+
const response = await fetch(
|
|
251
|
+
`${PROXY_BASE_URL}/aizek-sessions/new?clientId=${clientId}`,
|
|
252
|
+
{
|
|
253
|
+
method: "POST",
|
|
254
|
+
headers: buildRequestHeaders(deviceId, headers)
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
return response.json();
|
|
258
|
+
}
|
|
259
|
+
async function sendChatMessage(clientId, sessionId, message, headers) {
|
|
260
|
+
const deviceId = getOrCreateDeviceId();
|
|
261
|
+
return fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: buildRequestHeaders(deviceId, headers, sessionId),
|
|
264
|
+
body: JSON.stringify({ message })
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
async function fetchMessageHistory(sessionId, headers) {
|
|
268
|
+
const deviceId = getOrCreateDeviceId();
|
|
269
|
+
const response = await fetch(`${PROXY_BASE_URL}/aizek-messages`, {
|
|
270
|
+
method: "GET",
|
|
271
|
+
headers: buildRequestHeaders(deviceId, headers, sessionId)
|
|
272
|
+
});
|
|
273
|
+
const data = await response.json();
|
|
274
|
+
if (!data.success)
|
|
275
|
+
throw new Error(data.message || "Failed to fetch messages");
|
|
276
|
+
return parseRawMessages(data.data?.messages ?? []);
|
|
90
277
|
}
|
|
91
|
-
function
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
278
|
+
async function fetchSessionTitle(sessionId, headers) {
|
|
279
|
+
const deviceId = getOrCreateDeviceId();
|
|
280
|
+
const res = await fetch(`${PROXY_BASE_URL}/aizek-last-message`, {
|
|
281
|
+
method: "GET",
|
|
282
|
+
headers: buildRequestHeaders(deviceId, headers, sessionId)
|
|
283
|
+
});
|
|
284
|
+
const json = await res.json();
|
|
285
|
+
if (!json?.success) return null;
|
|
286
|
+
const last = json.data?.lastMessage;
|
|
287
|
+
if (!last) return null;
|
|
288
|
+
const textContent = extractTextFromContent(last.content);
|
|
289
|
+
if (!textContent.trim()) return null;
|
|
290
|
+
const { cleanedText } = extractUIJsonFromText(textContent);
|
|
291
|
+
const firstLine = (cleanedText.split("\n").find((l) => l.trim()) || "").trim();
|
|
292
|
+
const title = firstLine || cleanedText;
|
|
293
|
+
if (!title) return null;
|
|
294
|
+
return title.length > SESSION_TITLE_MAX_LENGTH ? `${title.slice(0, SESSION_TITLE_MAX_LENGTH).trim()}\u2026` : title;
|
|
96
295
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
296
|
+
|
|
297
|
+
// src/hooks/use-chat-session.ts
|
|
298
|
+
function useChatSession({
|
|
299
|
+
clientId,
|
|
300
|
+
headers,
|
|
301
|
+
onReady,
|
|
302
|
+
onToolCall
|
|
303
|
+
}) {
|
|
304
|
+
const [config, setConfig] = react.useState();
|
|
305
|
+
const [messages, setMessages] = react.useState([]);
|
|
306
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
307
|
+
const [isConfigLoading, setIsConfigLoading] = react.useState(true);
|
|
308
|
+
const [sessions, setSessions] = react.useState([]);
|
|
309
|
+
const [activeSession, setActiveSession] = react.useState(null);
|
|
310
|
+
const [headerValidation, setHeaderValidation] = react.useState(null);
|
|
311
|
+
const [sessionTitleById, setSessionTitleById] = react.useState({});
|
|
312
|
+
const messagesEndRef = react.useRef(null);
|
|
313
|
+
const loadConfig = react.useCallback(async () => {
|
|
314
|
+
try {
|
|
315
|
+
setIsConfigLoading(true);
|
|
316
|
+
const localActive = getActiveSessionId();
|
|
317
|
+
const data = await fetchWidgetConfig(clientId, headers);
|
|
318
|
+
if (!data.success) return;
|
|
319
|
+
setConfig(data.data);
|
|
320
|
+
const serverSessions = data.data.sessions ?? [];
|
|
321
|
+
setSessions(serverSessions);
|
|
322
|
+
if (serverSessions.length === 0) {
|
|
323
|
+
setActiveSession(null);
|
|
324
|
+
setActiveSessionId(null);
|
|
325
|
+
} else {
|
|
326
|
+
const nextActive = (localActive && serverSessions.includes(localActive) ? localActive : null) ?? serverSessions[0] ?? null;
|
|
327
|
+
setActiveSession(nextActive);
|
|
328
|
+
setActiveSessionId(nextActive);
|
|
329
|
+
}
|
|
330
|
+
if (headers) {
|
|
331
|
+
const validationResult = validateHeaders(
|
|
332
|
+
headers,
|
|
333
|
+
data.data.auth_config,
|
|
334
|
+
{ allowExtra: false, caseSensitive: true }
|
|
335
|
+
);
|
|
336
|
+
setHeaderValidation(validationResult);
|
|
337
|
+
}
|
|
338
|
+
onReady?.({ config: { ...data.data } });
|
|
339
|
+
} catch (error) {
|
|
340
|
+
console.error("Failed to load chat widget config:", error);
|
|
341
|
+
} finally {
|
|
342
|
+
setIsConfigLoading(false);
|
|
343
|
+
}
|
|
344
|
+
}, [clientId]);
|
|
345
|
+
const createNewSession = react.useCallback(async () => {
|
|
346
|
+
if (sessions.length >= MAX_SESSIONS) {
|
|
347
|
+
throw new Error(`You can open up to ${MAX_SESSIONS} sessions.`);
|
|
348
|
+
}
|
|
349
|
+
const data = await createSession(clientId, headers);
|
|
350
|
+
if (!data.success) throw new Error(data.message || "Session create failed");
|
|
351
|
+
const sid = data.data.sessionId;
|
|
352
|
+
const updatedSessions = data.data.sessions ?? [sid];
|
|
353
|
+
setSessions(updatedSessions);
|
|
354
|
+
setActiveSession(sid);
|
|
355
|
+
setActiveSessionId(sid);
|
|
356
|
+
setMessages([]);
|
|
357
|
+
return sid;
|
|
358
|
+
}, [clientId, headers, sessions.length]);
|
|
359
|
+
const handleStreamResponse = react.useCallback(
|
|
360
|
+
async (response, onFinish) => {
|
|
361
|
+
if (!response.body) {
|
|
362
|
+
throw new Error("Streaming not supported (no response body)");
|
|
363
|
+
}
|
|
364
|
+
const reader = response.body.getReader();
|
|
365
|
+
const decoder = new TextDecoder();
|
|
366
|
+
let text = "";
|
|
367
|
+
let buffer = "";
|
|
368
|
+
try {
|
|
369
|
+
while (true) {
|
|
370
|
+
const { value, done } = await reader.read();
|
|
371
|
+
if (done) break;
|
|
372
|
+
buffer += decoder.decode(value, { stream: true });
|
|
373
|
+
const chunks = buffer.split("\n\n");
|
|
374
|
+
buffer = chunks.pop() ?? "";
|
|
375
|
+
for (const rawChunk of chunks) {
|
|
376
|
+
const line = rawChunk.split("\n").find((l) => l.startsWith("data:"));
|
|
377
|
+
if (!line) continue;
|
|
378
|
+
const jsonStr = line.replace(/^data:\s*/, "").trim();
|
|
379
|
+
if (!jsonStr) continue;
|
|
380
|
+
try {
|
|
381
|
+
const event = JSON.parse(jsonStr);
|
|
382
|
+
if (event.type === "response.output_text.delta" && event.delta) {
|
|
383
|
+
setIsLoading(false);
|
|
384
|
+
text += event.delta;
|
|
385
|
+
setMessages((prev) => {
|
|
386
|
+
const lastMsg = prev[prev.length - 1];
|
|
387
|
+
if (lastMsg?.role === "assistant") {
|
|
388
|
+
return [...prev.slice(0, -1), { ...lastMsg, text }];
|
|
389
|
+
}
|
|
390
|
+
return [
|
|
391
|
+
...prev,
|
|
392
|
+
{ text, role: "assistant", timestamp: /* @__PURE__ */ new Date() }
|
|
393
|
+
];
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
if (event.type === "response.output_item.done" && event.item.type === "mcp_call") {
|
|
397
|
+
onToolCall?.({
|
|
398
|
+
name: event.item.name,
|
|
399
|
+
args: JSON.parse(event.item.arguments),
|
|
400
|
+
result: JSON.parse(event.item.output)
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
} catch (e) {
|
|
404
|
+
console.error("Error parsing stream event", e);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
} finally {
|
|
409
|
+
onFinish?.();
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
[onToolCall]
|
|
413
|
+
);
|
|
414
|
+
const sendMessage = react.useCallback(
|
|
415
|
+
async (message, approval) => {
|
|
416
|
+
if (!message.trim() || isLoading) return;
|
|
417
|
+
setIsLoading(true);
|
|
418
|
+
setMessages((prev) => [
|
|
419
|
+
...prev,
|
|
420
|
+
{
|
|
421
|
+
text: message,
|
|
422
|
+
ui: void 0,
|
|
423
|
+
role: approval ? "approval" : "user",
|
|
424
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
425
|
+
}
|
|
426
|
+
]);
|
|
427
|
+
try {
|
|
428
|
+
let sid = activeSession;
|
|
429
|
+
if (!sid) sid = await createNewSession();
|
|
430
|
+
let response = await sendChatMessage(clientId, sid, message, headers);
|
|
431
|
+
if (response.status === 401) {
|
|
432
|
+
console.log("Session expired, renewing...");
|
|
433
|
+
const filtered = sessions.filter((s) => s !== sid);
|
|
434
|
+
setSessions(filtered);
|
|
435
|
+
setActiveSession(null);
|
|
436
|
+
setActiveSessionId(null);
|
|
437
|
+
const newSid = await createNewSession();
|
|
438
|
+
response = await sendChatMessage(clientId, newSid, message, headers);
|
|
439
|
+
}
|
|
440
|
+
if (!response.ok) throw new Error(`HTTP error ${response.status}`);
|
|
441
|
+
await handleStreamResponse(response);
|
|
442
|
+
} catch (error) {
|
|
443
|
+
console.error("Error sending message:", error);
|
|
444
|
+
setMessages((prev) => {
|
|
445
|
+
const last = prev[prev.length - 1];
|
|
446
|
+
const errorMessage = {
|
|
447
|
+
text: "Sorry, something went wrong. Please try again.",
|
|
448
|
+
role: "assistant",
|
|
449
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
450
|
+
};
|
|
451
|
+
if (last?.role === "assistant" && !last.text) {
|
|
452
|
+
return [...prev.slice(0, -1), errorMessage];
|
|
453
|
+
}
|
|
454
|
+
return [...prev, errorMessage];
|
|
455
|
+
});
|
|
456
|
+
} finally {
|
|
457
|
+
setIsLoading(false);
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
[
|
|
461
|
+
activeSession,
|
|
462
|
+
clientId,
|
|
463
|
+
createNewSession,
|
|
464
|
+
handleStreamResponse,
|
|
465
|
+
headers,
|
|
466
|
+
isLoading,
|
|
467
|
+
sessions
|
|
468
|
+
]
|
|
469
|
+
);
|
|
470
|
+
const selectSession = react.useCallback((sid) => {
|
|
471
|
+
setActiveSession(sid);
|
|
472
|
+
setActiveSessionId(sid);
|
|
473
|
+
}, []);
|
|
474
|
+
const getSessionTitle = react.useCallback(
|
|
475
|
+
(sid) => sessionTitleById[sid] ?? "New conversation",
|
|
476
|
+
[sessionTitleById]
|
|
477
|
+
);
|
|
478
|
+
react.useEffect(() => {
|
|
479
|
+
loadConfig();
|
|
480
|
+
}, [loadConfig]);
|
|
481
|
+
react.useEffect(() => {
|
|
482
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
483
|
+
}, [messages]);
|
|
484
|
+
react.useEffect(() => {
|
|
485
|
+
if (activeSession && !isConfigLoading) {
|
|
486
|
+
fetchMessageHistory(activeSession, headers).then(setMessages).catch(
|
|
487
|
+
(error) => console.error("Failed to load message history:", error)
|
|
488
|
+
);
|
|
489
|
+
} else if (!activeSession) {
|
|
490
|
+
setMessages([]);
|
|
491
|
+
}
|
|
492
|
+
}, [activeSession, isConfigLoading]);
|
|
493
|
+
react.useEffect(() => {
|
|
494
|
+
if (!sessions.length) return;
|
|
495
|
+
const missing = sessions.filter((sid) => !sessionTitleById[sid]);
|
|
496
|
+
if (!missing.length) return;
|
|
497
|
+
let cancelled = false;
|
|
498
|
+
(async () => {
|
|
499
|
+
for (const sid of missing) {
|
|
500
|
+
if (cancelled) return;
|
|
501
|
+
const title = await fetchSessionTitle(sid, headers);
|
|
502
|
+
if (cancelled || !title) continue;
|
|
503
|
+
setSessionTitleById(
|
|
504
|
+
(prev) => prev[sid] ? prev : { ...prev, [sid]: title }
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
})();
|
|
508
|
+
return () => {
|
|
509
|
+
cancelled = true;
|
|
510
|
+
};
|
|
511
|
+
}, [sessions]);
|
|
512
|
+
return {
|
|
513
|
+
config,
|
|
514
|
+
messages,
|
|
515
|
+
isLoading,
|
|
516
|
+
isConfigLoading,
|
|
517
|
+
sessions,
|
|
518
|
+
activeSessionId: activeSession,
|
|
519
|
+
headerValidation,
|
|
520
|
+
sessionTitleById,
|
|
521
|
+
createNewSession,
|
|
522
|
+
sendMessage,
|
|
523
|
+
selectSession,
|
|
524
|
+
getSessionTitle
|
|
525
|
+
};
|
|
107
526
|
}
|
|
108
|
-
var
|
|
527
|
+
var IconClose = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) });
|
|
528
|
+
var IconChat = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4l4 4 4-4h4c1.1 0-2 .9-2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z" }) });
|
|
529
|
+
var IconBack = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 18l-6-6 6-6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
530
|
+
var IconBubble = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3c-4.418 0-8 3.134-8 7 0 2.382 1.362 4.486 3.5 5.737V21l4.07-2.13c.14.008.283.013.43.013 4.418 0 8-3.134 8-7s-3.582-7-8-7z", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }) });
|
|
531
|
+
var IconInfo = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
|
|
532
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 17v-6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
533
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 8h.01", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }),
|
|
534
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" })
|
|
535
|
+
] });
|
|
536
|
+
var IconTrash = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
|
|
537
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 6h18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
538
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 6V4h8v2", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }),
|
|
539
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l1 16h10l1-16", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" })
|
|
540
|
+
] });
|
|
541
|
+
var HomePanel = ({
|
|
542
|
+
companyName,
|
|
543
|
+
isLoading,
|
|
544
|
+
sessionsCount,
|
|
545
|
+
onNewSession,
|
|
546
|
+
onViewConversations
|
|
547
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-panel", children: [
|
|
548
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Welcome" }),
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "panel-title", children: companyName }),
|
|
550
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "panel-subtitle", children: "Ask anything. We keep your history and respond instantly." }),
|
|
551
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-actions", children: [
|
|
552
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
553
|
+
"button",
|
|
554
|
+
{
|
|
555
|
+
className: "primary-button",
|
|
556
|
+
onClick: onNewSession,
|
|
557
|
+
disabled: isLoading || sessionsCount >= MAX_SESSIONS,
|
|
558
|
+
children: "Start a new conversation"
|
|
559
|
+
}
|
|
560
|
+
),
|
|
561
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "ghost-button", onClick: onViewConversations, children: "View conversations" })
|
|
562
|
+
] })
|
|
563
|
+
] });
|
|
564
|
+
var ConversationListPanel = ({
|
|
565
|
+
sessions,
|
|
566
|
+
activeSessionId,
|
|
567
|
+
getSessionTitle,
|
|
568
|
+
onNewSession,
|
|
569
|
+
onSelectSession
|
|
570
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-list", children: [
|
|
571
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "list-header", children: [
|
|
572
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
573
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Conversations" }),
|
|
574
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "panel-title", children: "Inbox" })
|
|
575
|
+
] }),
|
|
576
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
577
|
+
"button",
|
|
578
|
+
{
|
|
579
|
+
className: "session-new-button",
|
|
580
|
+
onClick: onNewSession,
|
|
581
|
+
disabled: sessions.length >= MAX_SESSIONS,
|
|
582
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "+ New" })
|
|
583
|
+
}
|
|
584
|
+
)
|
|
585
|
+
] }),
|
|
586
|
+
sessions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-list", children: [
|
|
587
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
|
|
588
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "empty-state-title", children: "No conversations yet" }),
|
|
589
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-description", children: "Start a new conversation to see it appear here." })
|
|
590
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "conversation-items", children: sessions.map((sid) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
591
|
+
"button",
|
|
592
|
+
{
|
|
593
|
+
className: `conversation-item ${sid === activeSessionId ? "active" : ""}`,
|
|
594
|
+
onClick: () => onSelectSession(sid),
|
|
595
|
+
children: [
|
|
596
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-meta", children: [
|
|
597
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "conversation-title", children: getSessionTitle(sid) }),
|
|
598
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "conversation-sub", children: [
|
|
599
|
+
"Session ID: ",
|
|
600
|
+
sid.slice(0, 8),
|
|
601
|
+
"..."
|
|
602
|
+
] })
|
|
603
|
+
] }),
|
|
604
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "conversation-pill", children: "Open" })
|
|
605
|
+
]
|
|
606
|
+
},
|
|
607
|
+
sid
|
|
608
|
+
)) })
|
|
609
|
+
] });
|
|
610
|
+
var HeaderAlert = ({
|
|
611
|
+
headerValidation,
|
|
612
|
+
showAlert,
|
|
613
|
+
setShowAlert
|
|
614
|
+
}) => {
|
|
109
615
|
if (!headerValidation || !showAlert) return null;
|
|
110
616
|
const { isValid, missingKeys, extraKeys, emptyValueKeys, warning } = headerValidation;
|
|
111
617
|
if (isValid && missingKeys.length === 0 && extraKeys.length === 0 && emptyValueKeys.length === 0 && !warning) {
|
|
@@ -114,14 +620,14 @@ var HeaderAlert = ({ headerValidation, showAlert, setShowAlert }) => {
|
|
|
114
620
|
const hasErrors = missingKeys.length > 0 || emptyValueKeys.length > 0;
|
|
115
621
|
const hasWarnings = extraKeys.length > 0 || !!warning;
|
|
116
622
|
const alertType = hasErrors ? "error" : "warning";
|
|
117
|
-
const
|
|
623
|
+
const renderAlertIcon = () => {
|
|
118
624
|
if (hasErrors) {
|
|
119
625
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" }) });
|
|
120
626
|
}
|
|
121
627
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" }) });
|
|
122
628
|
};
|
|
123
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
124
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "alert-icon-container", children:
|
|
629
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `alert-container ${alertType}`, children: [
|
|
630
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "alert-icon-container", children: renderAlertIcon() }),
|
|
125
631
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "alert-content", children: [
|
|
126
632
|
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "alert-title", children: hasErrors ? "Header Do\u011Frulama Hatas\u0131" : "Header Uyar\u0131s\u0131" }),
|
|
127
633
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "alert-message", children: hasErrors && hasWarnings ? "Header yap\u0131land\u0131rman\u0131zda hatalar ve uyar\u0131lar bulundu." : hasErrors ? "Header yap\u0131land\u0131rman\u0131zda hatalar bulundu." : "Header yap\u0131land\u0131rman\u0131zda fazla anahtarlar bulundu." }),
|
|
@@ -161,18 +667,22 @@ var HeaderAlert = ({ headerValidation, showAlert, setShowAlert }) => {
|
|
|
161
667
|
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) })
|
|
162
668
|
}
|
|
163
669
|
)
|
|
164
|
-
] })
|
|
670
|
+
] });
|
|
165
671
|
};
|
|
166
672
|
var LoadingSpinner = () => {
|
|
167
673
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loading-spinner" });
|
|
168
674
|
};
|
|
169
|
-
var ChatInput = ({
|
|
675
|
+
var ChatInput = ({
|
|
676
|
+
isLoading,
|
|
677
|
+
placeholder,
|
|
678
|
+
onSendMessage
|
|
679
|
+
}) => {
|
|
170
680
|
const [message, setMessage] = react.useState("");
|
|
171
681
|
const textareaRef = react.useRef(null);
|
|
172
682
|
const handleSubmit = (e) => {
|
|
173
683
|
e.preventDefault();
|
|
174
684
|
if (message.trim() && !isLoading) {
|
|
175
|
-
|
|
685
|
+
onSendMessage(message.trim());
|
|
176
686
|
setMessage("");
|
|
177
687
|
if (textareaRef.current) {
|
|
178
688
|
textareaRef.current.style.height = "auto";
|
|
@@ -215,109 +725,130 @@ var ChatInput = ({ isLoading, placeholder, handleSendMessage }) => {
|
|
|
215
725
|
)
|
|
216
726
|
] });
|
|
217
727
|
};
|
|
218
|
-
var
|
|
728
|
+
var GenUIText = ({ component }) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: "gen-ui-text", children: component.value ?? component.label }, component.id);
|
|
729
|
+
var GenUIInput = ({ component }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gen-ui-input-wrapper", children: [
|
|
730
|
+
component.label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "gen-ui-input-label", children: component.label }),
|
|
731
|
+
component.fieldType === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
732
|
+
"textarea",
|
|
733
|
+
{
|
|
734
|
+
name: component.id,
|
|
735
|
+
placeholder: component.placeholder,
|
|
736
|
+
className: "gen-ui-textarea"
|
|
737
|
+
}
|
|
738
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
739
|
+
"input",
|
|
740
|
+
{
|
|
741
|
+
name: component.id,
|
|
742
|
+
type: component.fieldType || "text",
|
|
743
|
+
placeholder: component.placeholder,
|
|
744
|
+
className: "gen-ui-input"
|
|
745
|
+
}
|
|
746
|
+
)
|
|
747
|
+
] }, component.id);
|
|
748
|
+
var GenUISelect = ({ component }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gen-ui-select-wrapper", children: [
|
|
749
|
+
component.label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "gen-ui-select-label", children: component.label }),
|
|
750
|
+
/* @__PURE__ */ jsxRuntime.jsx("select", { name: component.id, className: "gen-ui-select", children: component.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: opt }, opt)) })
|
|
751
|
+
] }, component.id);
|
|
752
|
+
var GenUIButton = ({
|
|
753
|
+
component,
|
|
754
|
+
onInteraction,
|
|
755
|
+
collectFormValues
|
|
756
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
757
|
+
"button",
|
|
758
|
+
{
|
|
759
|
+
onClick: () => {
|
|
760
|
+
const formValues = collectFormValues();
|
|
761
|
+
onInteraction({
|
|
762
|
+
action: component.label ?? "",
|
|
763
|
+
buttonId: component.buttonType,
|
|
764
|
+
formData: formValues
|
|
765
|
+
});
|
|
766
|
+
},
|
|
767
|
+
className: "gen-ui-button",
|
|
768
|
+
children: component.label
|
|
769
|
+
},
|
|
770
|
+
component.id
|
|
771
|
+
);
|
|
772
|
+
var GenUICard = ({ component }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gen-ui-card", children: [
|
|
773
|
+
component.label && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "gen-ui-card-title", children: component.label }),
|
|
774
|
+
component.value && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "gen-ui-card-content", children: component.value })
|
|
775
|
+
] }, component.id);
|
|
776
|
+
var GenUIList = ({ component }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "gen-ui-list", children: component.items?.map((item) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "gen-ui-list-item", children: item.label ?? String(item.value ?? "") }, item.id)) }, component.id);
|
|
777
|
+
var GenUIImage = ({ component }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
778
|
+
"img",
|
|
779
|
+
{
|
|
780
|
+
src: component.url,
|
|
781
|
+
alt: component.label || "",
|
|
782
|
+
className: "gen-ui-image"
|
|
783
|
+
},
|
|
784
|
+
component.id
|
|
785
|
+
);
|
|
786
|
+
var GenUILink = ({ component }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
787
|
+
"a",
|
|
788
|
+
{
|
|
789
|
+
href: component.url,
|
|
790
|
+
className: "gen-ui-link",
|
|
791
|
+
children: component.label || component.url
|
|
792
|
+
},
|
|
793
|
+
component.id
|
|
794
|
+
);
|
|
795
|
+
var GenUITable = ({ component }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "gen-ui-table-wrapper", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "gen-ui-table", children: [
|
|
796
|
+
component.columns && /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "gen-ui-table-header", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: component.columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "gen-ui-table-th", children: col }, col)) }) }),
|
|
797
|
+
component.rows && /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "gen-ui-table-body", children: component.rows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx("tr", { children: row.map((cell, cellIndex) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "gen-ui-table-td", children: cell }, cellIndex)) }, rowIndex)) })
|
|
798
|
+
] }) }, component.id);
|
|
799
|
+
var GenericUIRenderer = ({
|
|
800
|
+
uiData,
|
|
801
|
+
onInteraction
|
|
802
|
+
}) => {
|
|
219
803
|
const containerRef = react.useRef(null);
|
|
220
|
-
if (!uiData
|
|
804
|
+
if (!uiData?.components) return null;
|
|
221
805
|
const collectFormValues = () => {
|
|
222
806
|
if (!containerRef.current) return {};
|
|
223
807
|
const formData = {};
|
|
224
808
|
const inputs = containerRef.current.querySelectorAll("input, textarea, select");
|
|
225
809
|
inputs.forEach((element) => {
|
|
226
810
|
const name = element.getAttribute("name");
|
|
227
|
-
if (name)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
} else {
|
|
235
|
-
formData[name] = element.value;
|
|
236
|
-
}
|
|
811
|
+
if (!name) return;
|
|
812
|
+
if (element instanceof HTMLInputElement && element.type === "checkbox") {
|
|
813
|
+
formData[name] = element.checked;
|
|
814
|
+
} else if (element instanceof HTMLInputElement && element.type === "radio") {
|
|
815
|
+
if (element.checked) formData[name] = element.value;
|
|
816
|
+
} else {
|
|
817
|
+
formData[name] = element.value;
|
|
237
818
|
}
|
|
238
819
|
});
|
|
239
820
|
return formData;
|
|
240
821
|
};
|
|
241
|
-
const renderComponent = (
|
|
242
|
-
switch (
|
|
822
|
+
const renderComponent = (component) => {
|
|
823
|
+
switch (component.type) {
|
|
243
824
|
case "text":
|
|
244
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
825
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUIText, { component }, component.id);
|
|
245
826
|
case "input":
|
|
246
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
247
|
-
comp.label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "gen-ui-input-label", children: comp.label }),
|
|
248
|
-
comp.fieldType === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
249
|
-
"textarea",
|
|
250
|
-
{
|
|
251
|
-
name: comp.id,
|
|
252
|
-
placeholder: comp.placeholder,
|
|
253
|
-
className: "gen-ui-textarea"
|
|
254
|
-
}
|
|
255
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
256
|
-
"input",
|
|
257
|
-
{
|
|
258
|
-
name: comp.id,
|
|
259
|
-
type: comp.fieldType || "text",
|
|
260
|
-
placeholder: comp.placeholder,
|
|
261
|
-
className: "gen-ui-input"
|
|
262
|
-
}
|
|
263
|
-
)
|
|
264
|
-
] }, comp.id);
|
|
827
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUIInput, { component }, component.id);
|
|
265
828
|
case "select":
|
|
266
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
267
|
-
comp.label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "gen-ui-select-label", children: comp.label }),
|
|
268
|
-
/* @__PURE__ */ jsxRuntime.jsx("select", { name: comp.id, className: "gen-ui-select", children: comp.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: opt }, opt)) })
|
|
269
|
-
] }, comp.id);
|
|
829
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUISelect, { component }, component.id);
|
|
270
830
|
case "button":
|
|
271
831
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
272
|
-
|
|
832
|
+
GenUIButton,
|
|
273
833
|
{
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
action: comp.label,
|
|
278
|
-
buttonId: comp.buttonType,
|
|
279
|
-
formData: formValues
|
|
280
|
-
});
|
|
281
|
-
},
|
|
282
|
-
className: "gen-ui-button",
|
|
283
|
-
children: comp.label
|
|
834
|
+
component,
|
|
835
|
+
onInteraction,
|
|
836
|
+
collectFormValues
|
|
284
837
|
},
|
|
285
|
-
|
|
838
|
+
component.id
|
|
286
839
|
);
|
|
287
840
|
case "card":
|
|
288
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
289
|
-
comp.label && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "gen-ui-card-title", children: comp.label }),
|
|
290
|
-
comp.value && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "gen-ui-card-content", children: comp.value })
|
|
291
|
-
] }, comp.id);
|
|
841
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUICard, { component }, component.id);
|
|
292
842
|
case "list":
|
|
293
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
843
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUIList, { component }, component.id);
|
|
294
844
|
case "image":
|
|
295
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
296
|
-
"img",
|
|
297
|
-
{
|
|
298
|
-
src: comp.url,
|
|
299
|
-
alt: comp.label || "",
|
|
300
|
-
className: "gen-ui-image"
|
|
301
|
-
},
|
|
302
|
-
comp.id
|
|
303
|
-
);
|
|
845
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUIImage, { component }, component.id);
|
|
304
846
|
case "link":
|
|
305
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
306
|
-
"a",
|
|
307
|
-
{
|
|
308
|
-
href: comp.url,
|
|
309
|
-
className: "gen-ui-link",
|
|
310
|
-
children: comp.label || comp.url
|
|
311
|
-
},
|
|
312
|
-
comp.id
|
|
313
|
-
);
|
|
847
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUILink, { component }, component.id);
|
|
314
848
|
case "table":
|
|
315
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
316
|
-
comp.columns && /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "gen-ui-table-header", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: comp.columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "gen-ui-table-th", children: col }, col)) }) }),
|
|
317
|
-
comp.rows && /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "gen-ui-table-body", children: comp.rows.map((row, ridx) => /* @__PURE__ */ jsxRuntime.jsx("tr", { children: row.map((cell, cidx) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "gen-ui-table-td", children: cell }, cidx)) }, ridx)) })
|
|
318
|
-
] }) }, comp.id);
|
|
849
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUITable, { component }, component.id);
|
|
319
850
|
case "form":
|
|
320
|
-
return /* @__PURE__ */ jsxRuntime.jsx("form", { className: "gen-ui-form", children:
|
|
851
|
+
return /* @__PURE__ */ jsxRuntime.jsx("form", { className: "gen-ui-form", children: component.items?.map((field) => renderComponent(field)) }, component.id);
|
|
321
852
|
default:
|
|
322
853
|
return null;
|
|
323
854
|
}
|
|
@@ -331,12 +862,8 @@ var GenericUIRenderer = ({ uiData, onInteraction }) => {
|
|
|
331
862
|
] });
|
|
332
863
|
};
|
|
333
864
|
var MessageBubble = ({ message, onAction }) => {
|
|
334
|
-
console.log("MESSAGE", message);
|
|
335
865
|
const isUser = message.role === "user";
|
|
336
|
-
|
|
337
|
-
if (approval) {
|
|
338
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
339
|
-
}
|
|
866
|
+
if (message.role === "approval") return null;
|
|
340
867
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `message-container ${isUser ? "user" : "assistant"}`, children: [
|
|
341
868
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `message-bubble ${isUser ? "user" : "assistant"}`, children: isUser ? message.text && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "markdown-content", children: message.text }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
342
869
|
message.text && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "markdown-content", children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown__default.default, { remarkPlugins: [remarkGfm__default.default], children: message.text }) }),
|
|
@@ -345,7 +872,6 @@ var MessageBubble = ({ message, onAction }) => {
|
|
|
345
872
|
{
|
|
346
873
|
uiData: message.ui,
|
|
347
874
|
onInteraction: (event) => {
|
|
348
|
-
console.log("event", event);
|
|
349
875
|
if (event.buttonId === "submit") {
|
|
350
876
|
onAction(JSON.stringify(event.formData), true);
|
|
351
877
|
} else {
|
|
@@ -374,277 +900,137 @@ var TypingDots = () => {
|
|
|
374
900
|
}, []);
|
|
375
901
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "message-container assistant", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "message-bubble assistant", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "message-typing-indicator", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: dots }) }) }) });
|
|
376
902
|
};
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const firstOption = comp.options[0];
|
|
406
|
-
if (typeof firstOption === "object" && firstOption !== null) {
|
|
407
|
-
if ("label" in firstOption || "value" in firstOption) {
|
|
408
|
-
comp.options = comp.options.map(
|
|
409
|
-
(opt) => opt.label || opt.value || String(opt)
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
if (comp.type === "table") {
|
|
416
|
-
if (comp.columns && Array.isArray(comp.columns)) {
|
|
417
|
-
const firstCol = comp.columns[0];
|
|
418
|
-
if (typeof firstCol === "object" && firstCol !== null) {
|
|
419
|
-
comp.columns = comp.columns.map(
|
|
420
|
-
(col) => col.label || col.id || String(col)
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
if (comp.rows && Array.isArray(comp.rows)) {
|
|
425
|
-
const firstRow = comp.rows[0];
|
|
426
|
-
if (typeof firstRow === "object" && !Array.isArray(firstRow)) {
|
|
427
|
-
comp.rows = comp.rows.map((row) => {
|
|
428
|
-
if (Array.isArray(row)) return row;
|
|
429
|
-
return Object.values(row).map((val) => {
|
|
430
|
-
if (typeof val === "object" && val !== null) {
|
|
431
|
-
if (val.type === "image" && val.src) return val.src;
|
|
432
|
-
if (val.value !== void 0) return String(val.value);
|
|
433
|
-
}
|
|
434
|
-
return String(val || "");
|
|
435
|
-
});
|
|
436
|
-
});
|
|
437
|
-
}
|
|
903
|
+
var ConversationDetailPanel = ({
|
|
904
|
+
activeSessionId,
|
|
905
|
+
isLoading,
|
|
906
|
+
messages,
|
|
907
|
+
headerValidation,
|
|
908
|
+
showAlert,
|
|
909
|
+
setShowAlert,
|
|
910
|
+
sanitizedWelcome,
|
|
911
|
+
messagesEndRef,
|
|
912
|
+
config,
|
|
913
|
+
getSessionTitle,
|
|
914
|
+
onBack,
|
|
915
|
+
onInfo,
|
|
916
|
+
onSendMessage,
|
|
917
|
+
placeholder
|
|
918
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-detail", children: [
|
|
919
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header", children: [
|
|
920
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-header-left", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "icon-button", onClick: onBack, "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx(IconBack, {}) }) }),
|
|
921
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-center", children: [
|
|
922
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(IconBubble, {}) }),
|
|
923
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title", children: [
|
|
924
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title-row", children: [
|
|
925
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { className: "detail-title-text", children: activeSessionId ? getSessionTitle(activeSessionId) : "Chat" }),
|
|
926
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
927
|
+
"span",
|
|
928
|
+
{
|
|
929
|
+
className: `status-dot ${isLoading ? "typing" : "online"}`,
|
|
930
|
+
"aria-hidden": "true"
|
|
438
931
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
return field;
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
if (comp.type === "list" && comp.items && Array.isArray(comp.items)) {
|
|
468
|
-
comp.items = comp.items.map((item, itemIndex) => {
|
|
469
|
-
if (typeof item === "string") {
|
|
470
|
-
return {
|
|
471
|
-
id: `list-item-${itemIndex}-${Date.now()}`,
|
|
472
|
-
type: "text",
|
|
473
|
-
value: item,
|
|
474
|
-
label: item
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
if (!item.id || !item.id.trim()) {
|
|
478
|
-
item.id = `list-item-${itemIndex}-${Date.now()}`;
|
|
479
|
-
}
|
|
480
|
-
return item;
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
return comp;
|
|
484
|
-
});
|
|
485
|
-
uiData = parsed;
|
|
932
|
+
)
|
|
933
|
+
] }),
|
|
934
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "detail-subtitle", children: isLoading ? "Typing..." : "Online" })
|
|
935
|
+
] })
|
|
936
|
+
] }),
|
|
937
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-right", children: [
|
|
938
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "icon-button", onClick: onInfo, "aria-label": "Bilgi", children: /* @__PURE__ */ jsxRuntime.jsx(IconInfo, {}) }),
|
|
939
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
940
|
+
"button",
|
|
941
|
+
{
|
|
942
|
+
className: "icon-button danger",
|
|
943
|
+
disabled: !activeSessionId,
|
|
944
|
+
"aria-label": "End conversation",
|
|
945
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(IconTrash, {})
|
|
946
|
+
}
|
|
947
|
+
)
|
|
948
|
+
] })
|
|
949
|
+
] }),
|
|
950
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "messages-container", children: [
|
|
951
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
952
|
+
HeaderAlert,
|
|
953
|
+
{
|
|
954
|
+
headerValidation,
|
|
955
|
+
setShowAlert,
|
|
956
|
+
showAlert
|
|
486
957
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
958
|
+
),
|
|
959
|
+
messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: sanitizedWelcome } }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
960
|
+
messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
961
|
+
MessageBubble,
|
|
962
|
+
{
|
|
963
|
+
message,
|
|
964
|
+
onAction: onSendMessage
|
|
965
|
+
},
|
|
966
|
+
index
|
|
967
|
+
)),
|
|
968
|
+
config?.widget_config.show_typing_indicator && isLoading && /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {})
|
|
969
|
+
] }),
|
|
970
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
|
|
971
|
+
] }),
|
|
972
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
973
|
+
ChatInput,
|
|
974
|
+
{
|
|
975
|
+
onSendMessage,
|
|
976
|
+
isLoading,
|
|
977
|
+
placeholder
|
|
491
978
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
979
|
+
)
|
|
980
|
+
] });
|
|
981
|
+
var InfoPanel = ({
|
|
982
|
+
companyName,
|
|
983
|
+
isLoading,
|
|
984
|
+
sessionsCount
|
|
985
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "info-panel", children: [
|
|
986
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Info" }),
|
|
987
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "panel-title", children: "Widget Details" }),
|
|
988
|
+
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "info-list", children: [
|
|
989
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
990
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Company" }),
|
|
991
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: companyName })
|
|
992
|
+
] }),
|
|
993
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
994
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Status" }),
|
|
995
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: isLoading ? "Typing..." : "Online" })
|
|
996
|
+
] }),
|
|
997
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
998
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Conversations" }),
|
|
999
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: sessionsCount })
|
|
1000
|
+
] })
|
|
1001
|
+
] })
|
|
1002
|
+
] });
|
|
1003
|
+
var AizekChatBot = ({
|
|
1004
|
+
clientId,
|
|
1005
|
+
headers,
|
|
1006
|
+
onMounted,
|
|
1007
|
+
onReady,
|
|
1008
|
+
onOpen,
|
|
1009
|
+
onClose,
|
|
1010
|
+
onMessage,
|
|
1011
|
+
onToolCall,
|
|
1012
|
+
onDisconnect
|
|
1013
|
+
}) => {
|
|
499
1014
|
const messagesEndRef = react.useRef(null);
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
1015
|
+
const {
|
|
1016
|
+
config,
|
|
1017
|
+
messages,
|
|
1018
|
+
isLoading,
|
|
1019
|
+
isConfigLoading,
|
|
1020
|
+
sessions,
|
|
1021
|
+
activeSessionId,
|
|
1022
|
+
headerValidation,
|
|
1023
|
+
createNewSession,
|
|
1024
|
+
sendMessage,
|
|
1025
|
+
selectSession,
|
|
1026
|
+
getSessionTitle
|
|
1027
|
+
} = useChatSession({ clientId, headers, onReady, onToolCall, onDisconnect });
|
|
504
1028
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
505
|
-
const [headerValidation, setHeaderValidation] = react.useState(null);
|
|
506
1029
|
const [showAlert, setShowAlert] = react.useState(true);
|
|
507
|
-
const [sessions, setSessions] = react.useState([]);
|
|
508
|
-
const [activeSessionId, setActiveSessionIdState] = react.useState(null);
|
|
509
1030
|
const [activeTab, setActiveTab] = react.useState("home");
|
|
510
1031
|
const [messageView, setMessageView] = react.useState("list");
|
|
511
|
-
const [sessionTitleById, setSessionTitleById] = react.useState({});
|
|
512
|
-
const PROXY_BASE_URL = "https://proxy.aizek.ai/api";
|
|
513
|
-
const createNewSession = async () => {
|
|
514
|
-
const deviceId = getOrCreateDeviceId();
|
|
515
|
-
if (sessions.length >= MAX_SESSIONS) {
|
|
516
|
-
throw new Error(`You can open up to ${MAX_SESSIONS} sessions.`);
|
|
517
|
-
}
|
|
518
|
-
const res = await fetch(`${PROXY_BASE_URL}/aizek-sessions/new?clientId=${clientId}`, {
|
|
519
|
-
method: "POST",
|
|
520
|
-
headers: {
|
|
521
|
-
"Content-Type": "application/json",
|
|
522
|
-
"x-device-id": deviceId,
|
|
523
|
-
"x-alternate": JSON.stringify(headers)
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
const data = await res.json();
|
|
527
|
-
if (!data.success) throw new Error(data.message || "session create failed");
|
|
528
|
-
const sid = data.data.sessionId;
|
|
529
|
-
const updatedSessions = data.data.sessions ?? [sid];
|
|
530
|
-
upsertSessionsFromServer(updatedSessions, setSessions);
|
|
531
|
-
setActiveSessionIdState(sid);
|
|
532
|
-
setActiveSessionId(sid);
|
|
533
|
-
setActiveTab("messages");
|
|
534
|
-
setMessageView("detail");
|
|
535
|
-
touchSession(sid);
|
|
536
|
-
setMessages([]);
|
|
537
|
-
return sid;
|
|
538
|
-
};
|
|
539
|
-
const loadConfig = async () => {
|
|
540
|
-
try {
|
|
541
|
-
setIsConfigLoading(true);
|
|
542
|
-
const deviceId = getOrCreateDeviceId();
|
|
543
|
-
purgeExpiredLocalSessions(setActiveSessionIdState);
|
|
544
|
-
const localActive = getActiveSessionId();
|
|
545
|
-
const response = await fetch(`${PROXY_BASE_URL}/aizek-connect?clientId=${clientId}`, {
|
|
546
|
-
method: "POST",
|
|
547
|
-
headers: {
|
|
548
|
-
"Content-Type": "application/json",
|
|
549
|
-
"x-device-id": deviceId,
|
|
550
|
-
"x-alternate": JSON.stringify(headers)
|
|
551
|
-
}
|
|
552
|
-
});
|
|
553
|
-
const data = await response.json();
|
|
554
|
-
if (!data.success) {
|
|
555
|
-
setIsOpen(false);
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
setIsOpen(!!data.data.widget_config.initial_open);
|
|
559
|
-
setConfig(data.data);
|
|
560
|
-
const serverSessions = data.data.sessions ?? [];
|
|
561
|
-
const merged = upsertSessionsFromServer(serverSessions, setSessions);
|
|
562
|
-
if (merged.length === 0) {
|
|
563
|
-
const newSid = await createNewSession();
|
|
564
|
-
setActiveSessionIdState(newSid);
|
|
565
|
-
setActiveSessionId(newSid);
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
const mergedIds = merged.map((s) => s.sessionId);
|
|
569
|
-
const nextActive = (localActive && mergedIds.includes(localActive) ? localActive : null) ?? mergedIds[0] ?? null;
|
|
570
|
-
setActiveSessionIdState(nextActive);
|
|
571
|
-
setActiveSessionId(nextActive);
|
|
572
|
-
if (headers) {
|
|
573
|
-
const validationResult = validateHeaders(headers, data.data.auth_config, {
|
|
574
|
-
allowExtra: false,
|
|
575
|
-
caseSensitive: true
|
|
576
|
-
});
|
|
577
|
-
setHeaderValidation(validationResult);
|
|
578
|
-
}
|
|
579
|
-
onReady?.({ config: { ...data.data } });
|
|
580
|
-
} catch (error) {
|
|
581
|
-
console.error("Failed to load chat widget config:", error);
|
|
582
|
-
} finally {
|
|
583
|
-
setIsConfigLoading(false);
|
|
584
|
-
}
|
|
585
|
-
};
|
|
586
|
-
const getHistoryMessageBySessionId = async (sid) => {
|
|
587
|
-
try {
|
|
588
|
-
const deviceId = getOrCreateDeviceId();
|
|
589
|
-
const response = await fetch(`${PROXY_BASE_URL}/aizek-messages`, {
|
|
590
|
-
method: "GET",
|
|
591
|
-
headers: {
|
|
592
|
-
"Content-Type": "application/json",
|
|
593
|
-
"x-device-id": deviceId,
|
|
594
|
-
"x-session-id": sid,
|
|
595
|
-
"x-alternate": JSON.stringify(headers)
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
const data = await response.json();
|
|
599
|
-
if (!data.success) {
|
|
600
|
-
throw new Error(data.message || "Failed to fetch messages");
|
|
601
|
-
}
|
|
602
|
-
const historyMessages = [];
|
|
603
|
-
if (data.data?.messages && Array.isArray(data.data.messages)) {
|
|
604
|
-
for (const msg of data.data.messages) {
|
|
605
|
-
let textContent = "";
|
|
606
|
-
let uiData = null;
|
|
607
|
-
if (typeof msg.content === "string") {
|
|
608
|
-
textContent = msg.content;
|
|
609
|
-
} else if (Array.isArray(msg.content)) {
|
|
610
|
-
const textParts = [];
|
|
611
|
-
for (const item of msg.content) {
|
|
612
|
-
if (item.type === "text" && item.text) {
|
|
613
|
-
textParts.push(item.text);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
textContent = textParts.join("\n");
|
|
617
|
-
}
|
|
618
|
-
if (textContent) {
|
|
619
|
-
const extracted = extractUIJsonFromText(textContent);
|
|
620
|
-
textContent = extracted.cleanedText;
|
|
621
|
-
uiData = extracted.uiData;
|
|
622
|
-
}
|
|
623
|
-
if (textContent.trim() || uiData) {
|
|
624
|
-
historyMessages.push({
|
|
625
|
-
text: textContent.trim() || void 0,
|
|
626
|
-
ui: uiData,
|
|
627
|
-
role: msg.role === "user" ? "user" : msg.role === "assistant" ? "assistant" : "user",
|
|
628
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
return historyMessages;
|
|
634
|
-
} catch (error) {
|
|
635
|
-
console.error("Error fetching message history:", error);
|
|
636
|
-
return [];
|
|
637
|
-
}
|
|
638
|
-
};
|
|
639
1032
|
react.useEffect(() => {
|
|
640
1033
|
onMounted?.();
|
|
641
|
-
loadConfig();
|
|
642
|
-
}, []);
|
|
643
|
-
react.useEffect(() => {
|
|
644
|
-
const t = setInterval(() => {
|
|
645
|
-
purgeExpiredLocalSessions(setActiveSessionIdState);
|
|
646
|
-
}, 1e3);
|
|
647
|
-
return () => clearInterval(t);
|
|
648
1034
|
}, []);
|
|
649
1035
|
react.useEffect(() => {
|
|
650
1036
|
if (typeof config?.widget_config.initial_open === "boolean") {
|
|
@@ -657,519 +1043,147 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
|
|
|
657
1043
|
react.useEffect(() => {
|
|
658
1044
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
659
1045
|
}, [messages]);
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}).catch((error) => {
|
|
665
|
-
console.error("Failed to load message history:", error);
|
|
666
|
-
});
|
|
667
|
-
} else if (!activeSessionId) {
|
|
668
|
-
setMessages([]);
|
|
669
|
-
}
|
|
670
|
-
}, [activeSessionId, isConfigLoading]);
|
|
671
|
-
react.useEffect(() => {
|
|
672
|
-
if (!sessions.length) return;
|
|
673
|
-
const missing = sessions.filter((sid) => !sessionTitleById[sid]);
|
|
674
|
-
if (!missing.length) return;
|
|
675
|
-
let cancelled = false;
|
|
676
|
-
(async () => {
|
|
677
|
-
for (const sid of missing) {
|
|
678
|
-
if (cancelled) return;
|
|
679
|
-
const title = await fetchLastMessageTitle(sid);
|
|
680
|
-
if (cancelled) return;
|
|
681
|
-
if (!title) continue;
|
|
682
|
-
setSessionTitleById((prev) => prev[sid] ? prev : { ...prev, [sid]: title });
|
|
683
|
-
}
|
|
684
|
-
})();
|
|
685
|
-
return () => {
|
|
686
|
-
cancelled = true;
|
|
687
|
-
};
|
|
688
|
-
}, [sessions]);
|
|
689
|
-
const addMessage = (payload) => {
|
|
690
|
-
const newMessage = {
|
|
691
|
-
text: payload.text,
|
|
692
|
-
ui: payload.ui,
|
|
693
|
-
role: payload.role,
|
|
694
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
695
|
-
};
|
|
696
|
-
onMessage?.(newMessage);
|
|
697
|
-
setMessages((prev) => [...prev, newMessage]);
|
|
698
|
-
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
699
|
-
return newMessage;
|
|
700
|
-
};
|
|
701
|
-
const sendMessage = async (message, approval) => {
|
|
702
|
-
if (!message.trim() || isLoading) return;
|
|
703
|
-
setMessages((prev) => [
|
|
704
|
-
...prev,
|
|
705
|
-
{ text: message, ui: void 0, role: approval ? "approval" : "user", timestamp: /* @__PURE__ */ new Date() }
|
|
706
|
-
]);
|
|
707
|
-
setIsLoading(true);
|
|
708
|
-
try {
|
|
709
|
-
const deviceId = getOrCreateDeviceId();
|
|
710
|
-
purgeExpiredLocalSessions(setActiveSessionIdState);
|
|
711
|
-
let sid = activeSessionId;
|
|
712
|
-
if (!sid) sid = await createNewSession();
|
|
713
|
-
const response = await fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
|
|
714
|
-
method: "POST",
|
|
715
|
-
headers: {
|
|
716
|
-
"Content-Type": "application/json",
|
|
717
|
-
"x-device-id": deviceId,
|
|
718
|
-
"x-session-id": sid,
|
|
719
|
-
"x-alternate": JSON.stringify(headers)
|
|
720
|
-
},
|
|
721
|
-
body: JSON.stringify({ message })
|
|
722
|
-
});
|
|
723
|
-
if (response.status === 401) {
|
|
724
|
-
const local = readStoredSessions().filter((s) => s.sessionId !== sid);
|
|
725
|
-
writeStoredSessions(local);
|
|
726
|
-
setSessions(local.map((x) => x.sessionId));
|
|
727
|
-
setActiveSessionId(null);
|
|
728
|
-
setActiveSessionIdState(null);
|
|
729
|
-
const newSid = await createNewSession();
|
|
730
|
-
const retry = await fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
|
|
731
|
-
method: "POST",
|
|
732
|
-
headers: {
|
|
733
|
-
"Content-Type": "application/json",
|
|
734
|
-
"x-device-id": deviceId,
|
|
735
|
-
"x-session-id": newSid,
|
|
736
|
-
"x-alternate": JSON.stringify(headers)
|
|
737
|
-
},
|
|
738
|
-
body: JSON.stringify({ message })
|
|
739
|
-
});
|
|
740
|
-
if (!retry.ok) throw new Error(`HTTP error ${retry.status}`);
|
|
741
|
-
const retryJson = await retry.json();
|
|
742
|
-
const text = JSON.stringify(retryJson.data);
|
|
743
|
-
const { cleanedText, uiData } = extractUIJsonFromText(text);
|
|
744
|
-
addMessage({ text: cleanedText, ui: uiData, role: "assistant" });
|
|
745
|
-
touchSession(newSid);
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
if (!response.ok) {
|
|
749
|
-
throw new Error(`HTTP error ${response.status}`);
|
|
750
|
-
}
|
|
751
|
-
if (!response.body) {
|
|
752
|
-
throw new Error("Streaming desteklenmiyor (response.body yok)");
|
|
753
|
-
}
|
|
754
|
-
const reader = response.body.getReader();
|
|
755
|
-
const decoder = new TextDecoder();
|
|
756
|
-
let buffer = "";
|
|
757
|
-
while (true) {
|
|
758
|
-
const { value, done } = await reader.read();
|
|
759
|
-
if (done) break;
|
|
760
|
-
buffer += decoder.decode(value, { stream: true });
|
|
761
|
-
const chunks = buffer.split("\n\n");
|
|
762
|
-
buffer = chunks.pop() ?? "";
|
|
763
|
-
for (const rawChunk of chunks) {
|
|
764
|
-
const line = rawChunk.split("\n").find((l) => l.startsWith("data:"));
|
|
765
|
-
if (!line) continue;
|
|
766
|
-
const jsonStr = line.replace(/^data:\s*/, "").trim();
|
|
767
|
-
if (!jsonStr) continue;
|
|
768
|
-
const event = JSON.parse(jsonStr);
|
|
769
|
-
if (event.type === "assistant_text" && event.content) {
|
|
770
|
-
const { cleanedText, uiData } = extractUIJsonFromText(event.content);
|
|
771
|
-
addMessage({
|
|
772
|
-
text: cleanedText,
|
|
773
|
-
ui: uiData,
|
|
774
|
-
role: "assistant"
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
if (event.type === "assistant_tool_result" && event.content) {
|
|
778
|
-
const toolInfoParsed = JSON.parse(event.content);
|
|
779
|
-
onToolCall?.(toolInfoParsed);
|
|
780
|
-
}
|
|
781
|
-
if (event.type === "error" && event.content) {
|
|
782
|
-
const { cleanedText, uiData } = extractUIJsonFromText(event.content);
|
|
783
|
-
addMessage({
|
|
784
|
-
text: cleanedText,
|
|
785
|
-
ui: uiData,
|
|
786
|
-
role: "assistant"
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
touchSession(sid);
|
|
792
|
-
} catch (error) {
|
|
793
|
-
console.error("Error sending message:", error);
|
|
794
|
-
addMessage({ text: "Sorry, something went wrong. Please try again.", role: "assistant" });
|
|
795
|
-
} finally {
|
|
796
|
-
setIsLoading(false);
|
|
797
|
-
}
|
|
1046
|
+
const toggleChat = () => {
|
|
1047
|
+
const next = !isOpen;
|
|
1048
|
+
setIsOpen(next);
|
|
1049
|
+
next ? onOpen?.() : onClose?.();
|
|
798
1050
|
};
|
|
799
|
-
const
|
|
1051
|
+
const handleCreateSession = async () => {
|
|
800
1052
|
try {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
await fetch(`${PROXY_BASE_URL}/aizek-disconnect?clientId=${clientId}`, {
|
|
805
|
-
method: "POST",
|
|
806
|
-
headers: {
|
|
807
|
-
"Content-Type": "application/json",
|
|
808
|
-
"x-device-id": deviceId,
|
|
809
|
-
"x-session-id": sid,
|
|
810
|
-
"x-alternate": JSON.stringify(headers)
|
|
811
|
-
},
|
|
812
|
-
body: JSON.stringify({ sessionId: sid })
|
|
813
|
-
});
|
|
814
|
-
const nextStored = readStoredSessions().filter((s) => s.sessionId !== sid);
|
|
815
|
-
writeStoredSessions(nextStored);
|
|
816
|
-
const nextSessions = nextStored.map((x) => x.sessionId);
|
|
817
|
-
setSessions(nextSessions);
|
|
818
|
-
const nextActive = nextSessions[0] ?? null;
|
|
819
|
-
setActiveSessionIdState(nextActive);
|
|
820
|
-
setActiveSessionId(nextActive);
|
|
821
|
-
setMessages([]);
|
|
822
|
-
onDisconnect?.();
|
|
1053
|
+
await createNewSession();
|
|
1054
|
+
setActiveTab("messages");
|
|
1055
|
+
setMessageView("detail");
|
|
823
1056
|
} catch (e) {
|
|
824
1057
|
console.error(e);
|
|
825
1058
|
}
|
|
826
1059
|
};
|
|
827
1060
|
const handleSelectSession = (sid) => {
|
|
828
|
-
|
|
829
|
-
setActiveSessionId(sid);
|
|
1061
|
+
selectSession(sid);
|
|
830
1062
|
setActiveTab("messages");
|
|
831
1063
|
setMessageView("detail");
|
|
832
1064
|
};
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
return "New conversation";
|
|
836
|
-
};
|
|
837
|
-
const fetchLastMessageTitle = async (sid) => {
|
|
838
|
-
try {
|
|
839
|
-
const deviceId = getOrCreateDeviceId();
|
|
840
|
-
const res = await fetch(`${PROXY_BASE_URL}/aizek-last-message`, {
|
|
841
|
-
method: "GET",
|
|
842
|
-
headers: {
|
|
843
|
-
"Content-Type": "application/json",
|
|
844
|
-
"x-device-id": deviceId,
|
|
845
|
-
"x-session-id": sid,
|
|
846
|
-
"x-alternate": JSON.stringify(headers)
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
const json = await res.json();
|
|
850
|
-
if (!json?.success) return null;
|
|
851
|
-
const last = json?.data?.lastMessage;
|
|
852
|
-
if (!last) return null;
|
|
853
|
-
let textContent = "";
|
|
854
|
-
if (typeof last.content === "string") {
|
|
855
|
-
textContent = last.content;
|
|
856
|
-
} else if (Array.isArray(last.content)) {
|
|
857
|
-
const parts = [];
|
|
858
|
-
for (const item of last.content) {
|
|
859
|
-
if (item?.type === "text" && typeof item.text === "string") parts.push(item.text);
|
|
860
|
-
}
|
|
861
|
-
textContent = parts.join("\n");
|
|
862
|
-
}
|
|
863
|
-
if (!textContent.trim()) return null;
|
|
864
|
-
const extracted = extractUIJsonFromText(textContent);
|
|
865
|
-
const cleaned = (extracted.cleanedText || "").trim();
|
|
866
|
-
const firstLine = (cleaned.split("\n").find((l) => l.trim()) || "").trim();
|
|
867
|
-
const title = firstLine || cleaned;
|
|
868
|
-
if (!title) return null;
|
|
869
|
-
const compact = title.length > 46 ? `${title.slice(0, 46).trim()}\u2026` : title;
|
|
870
|
-
return compact;
|
|
871
|
-
} catch (e) {
|
|
872
|
-
console.error("Failed to fetch last message title:", e);
|
|
873
|
-
return null;
|
|
874
|
-
}
|
|
875
|
-
};
|
|
876
|
-
const toggleChat = () => {
|
|
877
|
-
const newIsOpen = !isOpen;
|
|
878
|
-
setIsOpen(newIsOpen);
|
|
879
|
-
if (newIsOpen) onOpen?.();
|
|
880
|
-
else onClose?.();
|
|
881
|
-
};
|
|
882
|
-
const clean = sanitizeHtml__default.default(config?.widget_config.welcome_message ?? "", {
|
|
883
|
-
allowedTags: ["b", "i", "em", "strong", "a", "p", "br"],
|
|
884
|
-
allowedAttributes: {
|
|
885
|
-
a: ["href", "target", "rel"]
|
|
886
|
-
}
|
|
887
|
-
});
|
|
888
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: isConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
889
|
-
"button",
|
|
1065
|
+
const sanitizedWelcome = sanitizeHtml__default.default(
|
|
1066
|
+
config?.widget_config.welcome_message ?? "",
|
|
890
1067
|
{
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
"aria-label": "Loading",
|
|
894
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loading-spinner" })
|
|
1068
|
+
allowedTags: ["b", "i", "em", "strong", "a", "p", "br"],
|
|
1069
|
+
allowedAttributes: { a: ["href", "target", "rel"] }
|
|
895
1070
|
}
|
|
896
|
-
)
|
|
897
|
-
|
|
1071
|
+
);
|
|
1072
|
+
if (isConfigLoading) {
|
|
1073
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1074
|
+
"button",
|
|
1075
|
+
{
|
|
1076
|
+
className: "floating-button bottom-right button-sizes medium loading-state",
|
|
1077
|
+
style: { background: "#4f46e5" },
|
|
1078
|
+
"aria-label": "Loading",
|
|
1079
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loading-spinner" })
|
|
1080
|
+
}
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1084
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1085
|
+
"div",
|
|
1086
|
+
{
|
|
1087
|
+
className: `overlay floating-chat-overlay ${isOpen ? "is-open" : ""}`,
|
|
1088
|
+
onClick: toggleChat
|
|
1089
|
+
}
|
|
1090
|
+
),
|
|
898
1091
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
899
1092
|
"div",
|
|
900
1093
|
{
|
|
901
1094
|
className: `chat-container ${config?.widget_config.button_position} ${isOpen ? "is-open" : ""}`,
|
|
902
|
-
style: {
|
|
1095
|
+
style: {
|
|
1096
|
+
width: config?.widget_config.chat_width,
|
|
1097
|
+
height: config?.widget_config.chat_height
|
|
1098
|
+
},
|
|
903
1099
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatbot-container", children: [
|
|
904
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
activeTab === "home" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-panel", children: [
|
|
913
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Welcome" }),
|
|
914
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "panel-title", children: config?.widget_config.company_name }),
|
|
915
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "panel-subtitle", children: "Ask anything. We keep your history and respond instantly." }),
|
|
916
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-actions", children: [
|
|
917
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
918
|
-
"button",
|
|
919
|
-
{
|
|
920
|
-
className: "primary-button",
|
|
921
|
-
onClick: async () => {
|
|
922
|
-
try {
|
|
923
|
-
await createNewSession();
|
|
924
|
-
} catch (e) {
|
|
925
|
-
console.error(e);
|
|
926
|
-
}
|
|
927
|
-
},
|
|
928
|
-
disabled: isLoading || sessions.length >= MAX_SESSIONS,
|
|
929
|
-
children: "Start a new conversation"
|
|
930
|
-
}
|
|
931
|
-
),
|
|
932
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
933
|
-
"button",
|
|
1100
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1101
|
+
"div",
|
|
1102
|
+
{
|
|
1103
|
+
className: "header",
|
|
1104
|
+
style: { background: config?.widget_config.header_background },
|
|
1105
|
+
children: [
|
|
1106
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "logo-container", children: config?.widget_config.company_logo ? config.widget_config.company_logo.startsWith("http") || config.widget_config.company_logo.startsWith("data:") ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1107
|
+
"img",
|
|
934
1108
|
{
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
setMessageView("list");
|
|
939
|
-
},
|
|
940
|
-
children: "View conversations"
|
|
1109
|
+
src: config.widget_config.company_logo,
|
|
1110
|
+
alt: "Company Logo",
|
|
1111
|
+
className: "logo-image"
|
|
941
1112
|
}
|
|
942
|
-
)
|
|
943
|
-
] })
|
|
944
|
-
] }),
|
|
945
|
-
activeTab === "messages" && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: messageView === "list" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-list", children: [
|
|
946
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "list-header", children: [
|
|
1113
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "logo-text", children: config.widget_config.company_logo }) : "\u{1F916}" }),
|
|
947
1114
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
948
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
949
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
950
|
-
] }),
|
|
951
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
952
|
-
"button",
|
|
953
|
-
{
|
|
954
|
-
className: "session-new-button",
|
|
955
|
-
onClick: async () => {
|
|
956
|
-
try {
|
|
957
|
-
await createNewSession();
|
|
958
|
-
} catch (e) {
|
|
959
|
-
console.error(e);
|
|
960
|
-
}
|
|
961
|
-
},
|
|
962
|
-
disabled: sessions.length >= MAX_SESSIONS,
|
|
963
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "+ New" })
|
|
964
|
-
}
|
|
965
|
-
)
|
|
966
|
-
] }),
|
|
967
|
-
sessions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-list", children: [
|
|
968
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
|
|
969
|
-
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "empty-state-title", children: "No conversations yet" }),
|
|
970
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-description", children: "Start a new conversation to see it appear here." })
|
|
971
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "conversation-items", children: sessions.map((sid) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
972
|
-
"button",
|
|
973
|
-
{
|
|
974
|
-
className: `conversation-item ${sid === activeSessionId ? "active" : ""}`,
|
|
975
|
-
onClick: () => handleSelectSession(sid),
|
|
976
|
-
children: [
|
|
977
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-meta", children: [
|
|
978
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "conversation-title", children: getSessionTitle(sid) }),
|
|
979
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "conversation-sub", children: [
|
|
980
|
-
"Session ID: ",
|
|
981
|
-
sid.slice(0, 8),
|
|
982
|
-
"..."
|
|
983
|
-
] })
|
|
984
|
-
] }),
|
|
985
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "conversation-pill", children: "Open" })
|
|
986
|
-
]
|
|
987
|
-
},
|
|
988
|
-
sid
|
|
989
|
-
)) })
|
|
990
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-detail", children: [
|
|
991
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header", children: [
|
|
992
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-header-left", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "icon-button", onClick: () => setMessageView("list"), "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
993
|
-
"path",
|
|
994
|
-
{
|
|
995
|
-
d: "M15 18l-6-6 6-6",
|
|
996
|
-
stroke: "currentColor",
|
|
997
|
-
strokeWidth: "2",
|
|
998
|
-
strokeLinecap: "round",
|
|
999
|
-
strokeLinejoin: "round"
|
|
1000
|
-
}
|
|
1001
|
-
) }) }) }),
|
|
1002
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-center", children: [
|
|
1003
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1004
|
-
"path",
|
|
1005
|
-
{
|
|
1006
|
-
d: "M12 3c-4.418 0-8 3.134-8 7 0 2.382 1.362 4.486 3.5 5.737V21l4.07-2.13c.14.008.283.013.43.013 4.418 0 8-3.134 8-7s-3.582-7-8-7z",
|
|
1007
|
-
stroke: "currentColor",
|
|
1008
|
-
strokeWidth: "2",
|
|
1009
|
-
strokeLinejoin: "round"
|
|
1010
|
-
}
|
|
1011
|
-
) }) }),
|
|
1012
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title", children: [
|
|
1013
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title-row", children: [
|
|
1014
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { className: "detail-title-text", children: activeSessionId ? getSessionTitle(activeSessionId) : "Chat" }),
|
|
1015
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `status-dot ${isLoading ? "typing" : "online"}`, "aria-hidden": "true" })
|
|
1016
|
-
] }),
|
|
1017
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "detail-subtitle", children: isLoading ? "Yaz\u0131yor\u2026" : "Online" })
|
|
1018
|
-
] })
|
|
1019
|
-
] }),
|
|
1020
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-right", children: [
|
|
1021
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1022
|
-
"button",
|
|
1023
|
-
{
|
|
1024
|
-
className: "icon-button",
|
|
1025
|
-
onClick: () => {
|
|
1026
|
-
setActiveTab("info");
|
|
1027
|
-
setMessageView("list");
|
|
1028
|
-
},
|
|
1029
|
-
"aria-label": "Bilgi",
|
|
1030
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
|
|
1031
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1032
|
-
"path",
|
|
1033
|
-
{
|
|
1034
|
-
d: "M12 17v-6",
|
|
1035
|
-
stroke: "currentColor",
|
|
1036
|
-
strokeWidth: "2",
|
|
1037
|
-
strokeLinecap: "round"
|
|
1038
|
-
}
|
|
1039
|
-
),
|
|
1040
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1041
|
-
"path",
|
|
1042
|
-
{
|
|
1043
|
-
d: "M12 8h.01",
|
|
1044
|
-
stroke: "currentColor",
|
|
1045
|
-
strokeWidth: "2.5",
|
|
1046
|
-
strokeLinecap: "round"
|
|
1047
|
-
}
|
|
1048
|
-
),
|
|
1049
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1050
|
-
"circle",
|
|
1051
|
-
{
|
|
1052
|
-
cx: "12",
|
|
1053
|
-
cy: "12",
|
|
1054
|
-
r: "9",
|
|
1055
|
-
stroke: "currentColor",
|
|
1056
|
-
strokeWidth: "2"
|
|
1057
|
-
}
|
|
1058
|
-
)
|
|
1059
|
-
] })
|
|
1060
|
-
}
|
|
1061
|
-
),
|
|
1062
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1063
|
-
"button",
|
|
1064
|
-
{
|
|
1065
|
-
className: "icon-button danger",
|
|
1066
|
-
onClick: disconnectActiveSession,
|
|
1067
|
-
disabled: !activeSessionId,
|
|
1068
|
-
"aria-label": "End conversation",
|
|
1069
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
|
|
1070
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1071
|
-
"path",
|
|
1072
|
-
{
|
|
1073
|
-
d: "M3 6h18",
|
|
1074
|
-
stroke: "currentColor",
|
|
1075
|
-
strokeWidth: "2",
|
|
1076
|
-
strokeLinecap: "round"
|
|
1077
|
-
}
|
|
1078
|
-
),
|
|
1079
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1080
|
-
"path",
|
|
1081
|
-
{
|
|
1082
|
-
d: "M8 6V4h8v2",
|
|
1083
|
-
stroke: "currentColor",
|
|
1084
|
-
strokeWidth: "2",
|
|
1085
|
-
strokeLinejoin: "round"
|
|
1086
|
-
}
|
|
1087
|
-
),
|
|
1088
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1089
|
-
"path",
|
|
1090
|
-
{
|
|
1091
|
-
d: "M6 6l1 16h10l1-16",
|
|
1092
|
-
stroke: "currentColor",
|
|
1093
|
-
strokeWidth: "2",
|
|
1094
|
-
strokeLinejoin: "round"
|
|
1095
|
-
}
|
|
1096
|
-
)
|
|
1097
|
-
] })
|
|
1098
|
-
}
|
|
1099
|
-
)
|
|
1100
|
-
] })
|
|
1101
|
-
] }),
|
|
1102
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "messages-container", children: [
|
|
1103
|
-
/* @__PURE__ */ jsxRuntime.jsx(HeaderAlert, { headerValidation, setShowAlert, showAlert }),
|
|
1104
|
-
messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: clean } }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1105
|
-
messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { message, onAction: sendMessage }, index)),
|
|
1106
|
-
config?.widget_config.show_typing_indicator && isLoading && /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {})
|
|
1107
|
-
] }),
|
|
1108
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
|
|
1109
|
-
] }),
|
|
1110
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1111
|
-
ChatInput,
|
|
1112
|
-
{
|
|
1113
|
-
handleSendMessage: sendMessage,
|
|
1114
|
-
isLoading,
|
|
1115
|
-
placeholder: config?.widget_config.placeholder ?? ""
|
|
1116
|
-
}
|
|
1117
|
-
)
|
|
1118
|
-
] }) }),
|
|
1119
|
-
activeTab === "info" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "info-panel", children: [
|
|
1120
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Info" }),
|
|
1121
|
-
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "panel-title", children: "Widget Details" }),
|
|
1122
|
-
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "info-list", children: [
|
|
1123
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
1124
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Company" }),
|
|
1125
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: config?.widget_config.company_name })
|
|
1126
|
-
] }),
|
|
1127
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
1128
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Status" }),
|
|
1129
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: isLoading ? "Typing..." : "Online" })
|
|
1130
|
-
] }),
|
|
1131
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
1132
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Conversations" }),
|
|
1133
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: sessions.length })
|
|
1115
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "company-name", children: config?.widget_config.company_name }),
|
|
1116
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "status-text", children: isLoading ? "Typing..." : "Online" })
|
|
1134
1117
|
] })
|
|
1135
|
-
]
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
1139
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1140
|
-
|
|
1118
|
+
]
|
|
1119
|
+
}
|
|
1120
|
+
),
|
|
1121
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chat-content", children: [
|
|
1122
|
+
activeTab === "home" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1123
|
+
HomePanel,
|
|
1141
1124
|
{
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1125
|
+
companyName: config?.widget_config.company_name ?? "",
|
|
1126
|
+
isLoading,
|
|
1127
|
+
sessionsCount: sessions.length,
|
|
1128
|
+
onNewSession: handleCreateSession,
|
|
1129
|
+
onViewConversations: () => {
|
|
1130
|
+
setActiveTab("messages");
|
|
1145
1131
|
setMessageView("list");
|
|
1146
|
-
}
|
|
1147
|
-
children: "Home"
|
|
1132
|
+
}
|
|
1148
1133
|
}
|
|
1149
1134
|
),
|
|
1150
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1151
|
-
|
|
1135
|
+
activeTab === "messages" && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: messageView === "list" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1136
|
+
ConversationListPanel,
|
|
1152
1137
|
{
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
children: "Messages"
|
|
1138
|
+
sessions,
|
|
1139
|
+
activeSessionId,
|
|
1140
|
+
getSessionTitle,
|
|
1141
|
+
onNewSession: handleCreateSession,
|
|
1142
|
+
onSelectSession: handleSelectSession
|
|
1159
1143
|
}
|
|
1160
|
-
)
|
|
1161
|
-
|
|
1162
|
-
"button",
|
|
1144
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1145
|
+
ConversationDetailPanel,
|
|
1163
1146
|
{
|
|
1164
|
-
|
|
1165
|
-
|
|
1147
|
+
activeSessionId,
|
|
1148
|
+
isLoading,
|
|
1149
|
+
messages,
|
|
1150
|
+
headerValidation,
|
|
1151
|
+
showAlert,
|
|
1152
|
+
setShowAlert,
|
|
1153
|
+
sanitizedWelcome,
|
|
1154
|
+
messagesEndRef,
|
|
1155
|
+
config,
|
|
1156
|
+
getSessionTitle,
|
|
1157
|
+
onBack: () => setMessageView("list"),
|
|
1158
|
+
onInfo: () => {
|
|
1166
1159
|
setActiveTab("info");
|
|
1167
1160
|
setMessageView("list");
|
|
1168
1161
|
},
|
|
1169
|
-
|
|
1162
|
+
onSendMessage: sendMessage,
|
|
1163
|
+
placeholder: config?.widget_config.placeholder ?? ""
|
|
1164
|
+
}
|
|
1165
|
+
) }),
|
|
1166
|
+
activeTab === "info" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1167
|
+
InfoPanel,
|
|
1168
|
+
{
|
|
1169
|
+
companyName: config?.widget_config.company_name ?? "",
|
|
1170
|
+
isLoading,
|
|
1171
|
+
sessionsCount: sessions.length
|
|
1170
1172
|
}
|
|
1171
1173
|
)
|
|
1172
|
-
] })
|
|
1174
|
+
] }),
|
|
1175
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bottom-nav", children: ["home", "messages", "info"].map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1176
|
+
"button",
|
|
1177
|
+
{
|
|
1178
|
+
className: `nav-button ${activeTab === tab ? "active" : ""}`,
|
|
1179
|
+
onClick: () => {
|
|
1180
|
+
setActiveTab(tab);
|
|
1181
|
+
setMessageView("list");
|
|
1182
|
+
},
|
|
1183
|
+
children: tab.charAt(0).toUpperCase() + tab.slice(1)
|
|
1184
|
+
},
|
|
1185
|
+
tab
|
|
1186
|
+
)) })
|
|
1173
1187
|
] })
|
|
1174
1188
|
}
|
|
1175
1189
|
),
|
|
@@ -1179,10 +1193,10 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
|
|
|
1179
1193
|
onClick: toggleChat,
|
|
1180
1194
|
className: `floating-button ${config?.widget_config.button_position} button-sizes ${config?.widget_config.button_size} ${isOpen ? "is-open" : ""}`,
|
|
1181
1195
|
style: { background: config?.widget_config.button_background },
|
|
1182
|
-
children: isOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1196
|
+
children: isOpen ? /* @__PURE__ */ jsxRuntime.jsx(IconClose, {}) : /* @__PURE__ */ jsxRuntime.jsx(IconChat, {})
|
|
1183
1197
|
}
|
|
1184
1198
|
)
|
|
1185
|
-
] })
|
|
1199
|
+
] });
|
|
1186
1200
|
};
|
|
1187
1201
|
|
|
1188
1202
|
exports.AizekChatBot = AizekChatBot;
|