aizek-chatbot 1.0.16 → 1.0.21

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.mjs DELETED
@@ -1,932 +0,0 @@
1
- import { useRef, useState, useEffect } from "react";
2
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
- import ReactMarkdown from "react-markdown";
4
- import remarkGfm from "remark-gfm";
5
- import Anthropic from "@anthropic-ai/sdk";
6
- import { Client } from "@modelcontextprotocol/sdk/client";
7
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
8
- import "./index.css";
9
-
10
- // src/services/chat-widget-api.ts
11
- var API_BASE_URL = "https://api-alpha.aizek.ai";
12
- var fetchChatWidgetSettings = async (clientId) => {
13
- try {
14
- const response = await fetch(`${API_BASE_URL}/ChatWidgetSettings/GetByClientId?client_id=${clientId}`, {
15
- method: "GET",
16
- headers: {
17
- "Content-Type": "application/json",
18
- },
19
- });
20
- if (!response.ok) {
21
- throw new Error(`HTTP error! status: ${response.status}`);
22
- }
23
- const data = await response.json();
24
- return data;
25
- } catch (error) {
26
- console.error("Error fetching chat widget settings:", error);
27
- throw error;
28
- }
29
- };
30
-
31
- // src/utils/cx.ts
32
- function validateHeaders(headers, authConfig, opts = {}) {
33
- const { caseSensitive = false, allowExtra = false } = opts;
34
- const normalize = (s) => (caseSensitive ? s : s.toLowerCase());
35
- const headerEntries = Object.entries(headers).map(([k, v]) => [normalize(k), v.trim()]);
36
- const authEntries = Object.entries(authConfig).map(([k, v]) => [normalize(k), v.trim()]);
37
- const headerKeys = headerEntries.map(([k]) => k);
38
- const authKeys = authEntries.map(([k]) => k);
39
- const requiredSet = new Set(authKeys);
40
- const missingKeys = authKeys.filter((k) => !headerKeys.includes(k));
41
- const extraKeys = headerKeys.filter((k) => !requiredSet.has(k));
42
- const hasAllRequired = missingKeys.length === 0;
43
- const hasExtraKeys = extraKeys.length > 0 && !allowExtra;
44
- const emptyValueKeys = authKeys.filter((k) => {
45
- const val = headerEntries.find(([key]) => key === k)?.[1];
46
- return !val || val.length === 0;
47
- });
48
- const isValid = hasAllRequired && !hasExtraKeys && emptyValueKeys.length === 0;
49
- return { isValid, missingKeys, extraKeys, emptyValueKeys };
50
- }
51
-
52
- // src/store/static.ts
53
- var defaultConfig = {
54
- auth_config: {
55
- header: "",
56
- },
57
- chat_widget_settings: {
58
- welcome_message: "Merhaba! Size nas\u0131l yard\u0131mc\u0131 olabilirim?",
59
- button_background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
60
- placeholder: "Mesaj\u0131n\u0131z\u0131 yaz\u0131n...",
61
- button_position: "bottom-left",
62
- button_size: "medium",
63
- chat_width: "400px",
64
- chat_height: "600px",
65
- show_typing_indicator: true,
66
- initial_open: true,
67
- header_background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
68
- company_logo: "",
69
- company_name: "Aizek",
70
- api_source_id: 0,
71
- chat_widget_settings_id: 0,
72
- created_at: "",
73
- updated_at: "",
74
- },
75
- mcp_url: "",
76
- openai_key: "",
77
- };
78
- var GENERATIVE_UI_SYSTEM_PROMPT = `
79
- You can generate interactive UI components as part of your responses.
80
- When users need to:
81
- - Provide multiple pieces of information \u2192 Generate a FORM
82
- - Make a choice between options \u2192 Generate BUTTONS
83
- - View structured data \u2192 Generate a TABLE or LIST
84
- - See entity details \u2192 Generate a CARD
85
-
86
- For each component type, include JSON in this format:
87
-
88
- \`\`\`ui-component
89
- {
90
- "version": "1.0",
91
- "title": string,
92
- "description"?: string,
93
- "components": Array<{
94
- id: string,
95
- type:
96
- | "text"
97
- | "input"
98
- | "button"
99
- | "select"
100
- | "card"
101
- | "list"
102
- | "image"
103
- | "link"
104
- | "table"
105
- | "form",
106
- label?: string,
107
- fieldType?: "text" | "number" | "date" | "textarea",
108
- requiredField?: boolean,
109
- placeholder?: string,
110
- options?: string[],
111
- columns?: string[],
112
- rows?: string[][],
113
- url?: string,
114
- fieldName?: string
115
- buttonType?: click | submit
116
- }>
117
- }
118
- \`\`\`
119
-
120
-
121
-
122
-
123
-
124
- Always provide both a conversational text response AND appropriate UI components.
125
-
126
- `;
127
- var HeaderAlert = ({ headerValidation, showAlert, setShowAlert }) => {
128
- if (!headerValidation || !showAlert) return null;
129
- const { isValid, missingKeys, extraKeys, emptyValueKeys } = headerValidation;
130
- if (isValid && missingKeys.length === 0 && extraKeys.length === 0 && emptyValueKeys.length === 0) {
131
- return null;
132
- }
133
- const hasErrors = missingKeys.length > 0 || emptyValueKeys.length > 0;
134
- const hasWarnings = extraKeys.length > 0;
135
- const alertType = hasErrors ? "error" : "warning";
136
- const getAlertIcon = () => {
137
- if (hasErrors) {
138
- return /* @__PURE__ */ jsx("svg", {
139
- width: "20",
140
- height: "20",
141
- viewBox: "0 0 24 24",
142
- fill: "currentColor",
143
- children: /* @__PURE__ */ 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" }),
144
- });
145
- }
146
- return /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" }) });
147
- };
148
- return /* @__PURE__ */ jsx(Fragment, {
149
- children: /* @__PURE__ */ jsxs("div", {
150
- className: `alert-container ${alertType}`,
151
- children: [
152
- /* @__PURE__ */ jsx("div", { className: "alert-icon-container", children: getAlertIcon() }),
153
- /* @__PURE__ */ jsxs("div", {
154
- className: "alert-content",
155
- children: [
156
- /* @__PURE__ */ jsx("h4", { className: "alert-title", children: hasErrors ? "Header Do\u011Frulama Hatas\u0131" : "Header Uyar\u0131s\u0131" }),
157
- /* @__PURE__ */ jsx("p", {
158
- className: "alert-message",
159
- children:
160
- hasErrors && hasWarnings
161
- ? "Header yap\u0131land\u0131rman\u0131zda hatalar ve uyar\u0131lar bulundu."
162
- : hasErrors
163
- ? "Header yap\u0131land\u0131rman\u0131zda hatalar bulundu."
164
- : "Header yap\u0131land\u0131rman\u0131zda fazla anahtarlar bulundu.",
165
- }),
166
- missingKeys.length > 0 &&
167
- /* @__PURE__ */ jsxs("div", {
168
- children: [
169
- /* @__PURE__ */ jsx("strong", { children: "Eksik Header'lar:" }),
170
- /* @__PURE__ */ jsx("ul", {
171
- className: "alert-list",
172
- children: missingKeys.map((key, index) => /* @__PURE__ */ jsxs("li", { className: "alert-list-item", children: [/* @__PURE__ */ jsx("span", { children: "\u2022" }), /* @__PURE__ */ jsx("code", { children: key })] }, index)),
173
- }),
174
- ],
175
- }),
176
- emptyValueKeys.length > 0 &&
177
- /* @__PURE__ */ jsxs("div", {
178
- children: [
179
- /* @__PURE__ */ jsx("strong", { children: "Bo\u015F De\u011Ferli Header'lar:" }),
180
- /* @__PURE__ */ jsx("ul", {
181
- className: "alert-list",
182
- children: emptyValueKeys.map((key, index) =>
183
- /* @__PURE__ */ jsxs(
184
- "li",
185
- { className: "alert-list-item", children: [/* @__PURE__ */ jsx("span", { children: "\u2022" }), /* @__PURE__ */ jsx("code", { children: key }), /* @__PURE__ */ jsx("span", { children: "(de\u011Fer bo\u015F olamaz)" })] },
186
- index
187
- )
188
- ),
189
- }),
190
- ],
191
- }),
192
- extraKeys.length > 0 &&
193
- /* @__PURE__ */ jsxs("div", {
194
- children: [
195
- /* @__PURE__ */ jsx("strong", { children: "Fazla Header'lar:" }),
196
- /* @__PURE__ */ jsx("ul", {
197
- className: "alert-list",
198
- children: extraKeys.map((key, index) => /* @__PURE__ */ jsxs("li", { className: "alert-list-item", children: [/* @__PURE__ */ jsx("span", { children: "\u2022" }), /* @__PURE__ */ jsx("code", { children: key })] }, index)),
199
- }),
200
- ],
201
- }),
202
- ],
203
- }),
204
- /* @__PURE__ */ jsx("button", {
205
- onClick: () => setShowAlert(false),
206
- className: "alert-close-button",
207
- "aria-label": "Uyar\u0131y\u0131 kapat",
208
- children: /* @__PURE__ */ jsx("svg", {
209
- width: "16",
210
- height: "16",
211
- viewBox: "0 0 24 24",
212
- fill: "currentColor",
213
- children: /* @__PURE__ */ 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" }),
214
- }),
215
- }),
216
- ],
217
- }),
218
- });
219
- };
220
- var LoadingSpinner = () => {
221
- return /* @__PURE__ */ jsx("div", { className: "loading-spinner" });
222
- };
223
- var ChatInput = ({ isLoading, placeholder, handleSendMessage }) => {
224
- const [message, setMessage] = useState("");
225
- const textareaRef = useRef(null);
226
- const handleSubmit = (e) => {
227
- e.preventDefault();
228
- if (message.trim() && !isLoading) {
229
- handleSendMessage(message.trim());
230
- setMessage("");
231
- if (textareaRef.current) {
232
- textareaRef.current.style.height = "auto";
233
- }
234
- }
235
- };
236
- const handleKeyDown = (e) => {
237
- if (e.key === "Enter" && !e.shiftKey) {
238
- e.preventDefault();
239
- handleSubmit(e);
240
- }
241
- };
242
- const handleInputChange = (e) => {
243
- setMessage(e.target.value);
244
- const textarea = e.target;
245
- textarea.style.height = "auto";
246
- textarea.style.height = Math.min(textarea.scrollHeight, 120) + "px";
247
- };
248
- return /* @__PURE__ */ jsxs("form", {
249
- onSubmit: handleSubmit,
250
- className: "input-container",
251
- children: [
252
- /* @__PURE__ */ jsx("textarea", {
253
- ref: textareaRef,
254
- value: message,
255
- onChange: handleInputChange,
256
- onKeyDown: handleKeyDown,
257
- placeholder,
258
- disabled: isLoading,
259
- className: "textarea",
260
- }),
261
- /* @__PURE__ */ jsx("button", {
262
- type: "submit",
263
- disabled: isLoading || !message.trim(),
264
- className: "send-button",
265
- children: isLoading
266
- ? /* @__PURE__ */ jsx(LoadingSpinner, {})
267
- : /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) }),
268
- }),
269
- ],
270
- });
271
- };
272
- var GenericUIRenderer = ({ uiData, onInteraction }) => {
273
- const containerRef = useRef(null);
274
- if (!uiData || !uiData.components) return null;
275
- const collectFormValues = () => {
276
- if (!containerRef.current) return {};
277
- const formData = {};
278
- const inputs = containerRef.current.querySelectorAll("input, textarea, select");
279
- inputs.forEach((element) => {
280
- const name = element.getAttribute("name");
281
- if (name) {
282
- if (element instanceof HTMLInputElement && element.type === "checkbox") {
283
- formData[name] = element.checked;
284
- } else if (element instanceof HTMLInputElement && element.type === "radio") {
285
- if (element.checked) {
286
- formData[name] = element.value;
287
- }
288
- } else {
289
- formData[name] = element.value;
290
- }
291
- }
292
- });
293
- return formData;
294
- };
295
- const renderComponent = (comp) => {
296
- switch (comp.type) {
297
- case "text":
298
- return /* @__PURE__ */ jsx("p", { className: "gen-ui-text", children: comp.value ?? comp.label }, comp.id);
299
- case "input":
300
- return /* @__PURE__ */ jsxs(
301
- "div",
302
- {
303
- className: "gen-ui-input-wrapper",
304
- children: [
305
- comp.label && /* @__PURE__ */ jsx("label", { className: "gen-ui-input-label", children: comp.label }),
306
- comp.fieldType === "textarea"
307
- ? /* @__PURE__ */ jsx("textarea", {
308
- name: comp.id,
309
- placeholder: comp.placeholder,
310
- className: "gen-ui-textarea",
311
- })
312
- : /* @__PURE__ */ jsx("input", {
313
- name: comp.id,
314
- type: comp.fieldType || "text",
315
- placeholder: comp.placeholder,
316
- className: "gen-ui-input",
317
- }),
318
- ],
319
- },
320
- comp.id
321
- );
322
- case "select":
323
- return /* @__PURE__ */ jsxs(
324
- "div",
325
- {
326
- className: "gen-ui-select-wrapper",
327
- children: [
328
- comp.label && /* @__PURE__ */ jsx("label", { className: "gen-ui-select-label", children: comp.label }),
329
- /* @__PURE__ */ jsx("select", { name: comp.id, className: "gen-ui-select", children: comp.options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt)) }),
330
- ],
331
- },
332
- comp.id
333
- );
334
- case "button":
335
- return /* @__PURE__ */ jsx(
336
- "button",
337
- {
338
- onClick: () => {
339
- const formValues = collectFormValues();
340
- onInteraction({
341
- action: comp.label,
342
- buttonId: comp.buttonType,
343
- formData: formValues,
344
- });
345
- },
346
- className: "gen-ui-button",
347
- children: comp.label,
348
- },
349
- comp.id
350
- );
351
- case "card":
352
- return /* @__PURE__ */ jsxs(
353
- "div",
354
- { className: "gen-ui-card", children: [comp.label && /* @__PURE__ */ jsx("h2", { className: "gen-ui-card-title", children: comp.label }), comp.value && /* @__PURE__ */ jsx("p", { className: "gen-ui-card-content", children: comp.value })] },
355
- comp.id
356
- );
357
- case "list":
358
- return /* @__PURE__ */ jsx("ul", { className: "gen-ui-list", children: comp.items?.map((item) => /* @__PURE__ */ jsx("li", { className: "gen-ui-list-item", children: item.label ?? String(item.value ?? "") }, item.id)) }, comp.id);
359
- case "image":
360
- return /* @__PURE__ */ jsx(
361
- "img",
362
- {
363
- src: comp.url,
364
- alt: comp.label || "",
365
- className: "gen-ui-image",
366
- },
367
- comp.id
368
- );
369
- case "link":
370
- return /* @__PURE__ */ jsx(
371
- "a",
372
- {
373
- href: comp.url,
374
- className: "gen-ui-link",
375
- children: comp.label || comp.url,
376
- },
377
- comp.id
378
- );
379
- case "table":
380
- return /* @__PURE__ */ jsx(
381
- "div",
382
- {
383
- className: "gen-ui-table-wrapper",
384
- children: /* @__PURE__ */ jsxs("table", {
385
- className: "gen-ui-table",
386
- children: [
387
- comp.columns &&
388
- /* @__PURE__ */ jsx("thead", { className: "gen-ui-table-header", children: /* @__PURE__ */ jsx("tr", { children: comp.columns.map((col) => /* @__PURE__ */ jsx("th", { className: "gen-ui-table-th", children: col }, col)) }) }),
389
- comp.rows &&
390
- /* @__PURE__ */ jsx("tbody", {
391
- className: "gen-ui-table-body",
392
- children: comp.rows.map((row, ridx) => /* @__PURE__ */ jsx("tr", { children: row.map((cell, cidx) => /* @__PURE__ */ jsx("td", { className: "gen-ui-table-td", children: cell }, cidx)) }, ridx)),
393
- }),
394
- ],
395
- }),
396
- },
397
- comp.id
398
- );
399
- case "form":
400
- return /* @__PURE__ */ jsx("form", { className: "gen-ui-form", children: comp.items?.map((field) => renderComponent(field)) }, comp.id);
401
- default:
402
- return null;
403
- }
404
- };
405
- return /* @__PURE__ */ jsxs("div", {
406
- className: "generative-ui-container",
407
- ref: containerRef,
408
- children: [
409
- (uiData.title || uiData.description) &&
410
- /* @__PURE__ */ jsxs("div", {
411
- className: "generative-ui-header",
412
- children: [uiData.title && /* @__PURE__ */ jsx("h1", { className: "generative-ui-title", children: uiData.title }), uiData.description && /* @__PURE__ */ jsx("p", { className: "generative-ui-description", children: uiData.description })],
413
- }),
414
- uiData.components.map((comp) => renderComponent(comp)),
415
- ],
416
- });
417
- };
418
- var MessageBubble = ({ message, onAction }) => {
419
- console.log("MESSAGE", message);
420
- const isUser = message.role === "user";
421
- const approval = message.role === "approval";
422
- if (approval) {
423
- return /* @__PURE__ */ jsx(Fragment, {});
424
- }
425
- return /* @__PURE__ */ jsxs("div", {
426
- className: `message-container ${isUser ? "user" : "assistant"}`,
427
- children: [
428
- /* @__PURE__ */ jsx("div", {
429
- className: `message-bubble ${isUser ? "user" : "assistant"}`,
430
- children: isUser
431
- ? message.text && /* @__PURE__ */ jsx("div", { className: "markdown-content", children: message.text })
432
- : /* @__PURE__ */ jsxs(Fragment, {
433
- children: [
434
- message.text && /* @__PURE__ */ jsx("div", { className: "markdown-content", children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: message.text }) }),
435
- message.ui &&
436
- /* @__PURE__ */ jsx(GenericUIRenderer, {
437
- uiData: message.ui,
438
- onInteraction: (event) => {
439
- console.log("event", event);
440
- if (event.buttonId === "submit") {
441
- onAction(JSON.stringify(event.formData), true);
442
- } else {
443
- onAction(event.action, true);
444
- }
445
- },
446
- }),
447
- ],
448
- }),
449
- }),
450
- /* @__PURE__ */ jsx("div", {
451
- className: `message-time ${isUser ? "user" : "assistant"}`,
452
- children: message.timestamp.toLocaleTimeString("tr-TR", {
453
- hour: "2-digit",
454
- minute: "2-digit",
455
- }),
456
- }),
457
- ],
458
- });
459
- };
460
- var TypingDots = () => {
461
- const [dots, setDots] = useState("");
462
- useEffect(() => {
463
- const interval = setInterval(() => {
464
- setDots((prev) => {
465
- if (prev === "...") return "";
466
- return prev + ".";
467
- });
468
- }, 500);
469
- return () => clearInterval(interval);
470
- }, []);
471
- return /* @__PURE__ */ jsx("div", {
472
- className: "message-container assistant",
473
- children: /* @__PURE__ */ jsx("div", { className: "message-bubble assistant", children: /* @__PURE__ */ jsx("div", { className: "message-typing-indicator", children: /* @__PURE__ */ jsx("span", { children: dots }) }) }),
474
- });
475
- };
476
-
477
- // src/utils/chatbot.ts
478
- var extractUIJsonFromText = (text) => {
479
- const regex = /```ui-component([\s\S]*?)```/g;
480
- let cleaned = text;
481
- let match;
482
- let uiData = null;
483
- while ((match = regex.exec(text)) !== null) {
484
- const block = match[1].trim();
485
- try {
486
- const parsed = JSON.parse(block);
487
- if (parsed && parsed.components && Array.isArray(parsed.components)) {
488
- parsed.components = parsed.components.map((comp, index) => {
489
- if (!comp.id || typeof comp.id !== "string" || !comp.id.trim()) {
490
- comp.id = `ui-comp-${index}-${Date.now()}`;
491
- }
492
- if (comp.type === "button") {
493
- if (!comp.buttonType) {
494
- comp.buttonType = "click";
495
- }
496
- }
497
- if (comp.type === "input") {
498
- if (!comp.fieldType) {
499
- comp.fieldType = "text";
500
- }
501
- }
502
- if (comp.type === "select") {
503
- if (comp.options && Array.isArray(comp.options)) {
504
- const firstOption = comp.options[0];
505
- if (typeof firstOption === "object" && firstOption !== null) {
506
- if ("label" in firstOption || "value" in firstOption) {
507
- comp.options = comp.options.map((opt) => opt.label || opt.value || String(opt));
508
- }
509
- }
510
- }
511
- }
512
- if (comp.type === "table") {
513
- if (comp.columns && Array.isArray(comp.columns)) {
514
- const firstCol = comp.columns[0];
515
- if (typeof firstCol === "object" && firstCol !== null) {
516
- comp.columns = comp.columns.map((col) => col.label || col.id || String(col));
517
- }
518
- }
519
- if (comp.rows && Array.isArray(comp.rows)) {
520
- const firstRow = comp.rows[0];
521
- if (typeof firstRow === "object" && !Array.isArray(firstRow)) {
522
- comp.rows = comp.rows.map((row) => {
523
- if (Array.isArray(row)) return row;
524
- return Object.values(row).map((val) => {
525
- if (typeof val === "object" && val !== null) {
526
- if (val.type === "image" && val.src) return val.src;
527
- if (val.value !== void 0) return String(val.value);
528
- }
529
- return String(val || "");
530
- });
531
- });
532
- }
533
- }
534
- }
535
- if (comp.type === "form" && comp.items && Array.isArray(comp.items)) {
536
- comp.items = comp.items.map((field, fieldIndex) => {
537
- if (!field.id || !field.id.trim()) {
538
- field.id = `field-${fieldIndex}-${Date.now()}`;
539
- }
540
- if (field.optional !== void 0) {
541
- field.requiredField = !field.optional;
542
- delete field.optional;
543
- }
544
- if (field.required !== void 0) {
545
- field.requiredField = field.required;
546
- delete field.required;
547
- }
548
- if (field.type === "input" && !field.fieldType) {
549
- field.fieldType = "text";
550
- }
551
- if (field.type === "select" && field.options && Array.isArray(field.options)) {
552
- const firstOpt = field.options[0];
553
- if (typeof firstOpt === "object" && firstOpt !== null) {
554
- field.options = field.options.map((opt) => opt.label || opt.value || String(opt));
555
- }
556
- }
557
- return field;
558
- });
559
- }
560
- if (comp.type === "list" && comp.items && Array.isArray(comp.items)) {
561
- comp.items = comp.items.map((item, itemIndex) => {
562
- if (typeof item === "string") {
563
- return {
564
- id: `list-item-${itemIndex}-${Date.now()}`,
565
- type: "text",
566
- value: item,
567
- label: item,
568
- };
569
- }
570
- if (!item.id || !item.id.trim()) {
571
- item.id = `list-item-${itemIndex}-${Date.now()}`;
572
- }
573
- return item;
574
- });
575
- }
576
- return comp;
577
- });
578
- uiData = parsed;
579
- }
580
- cleaned = cleaned.replace(match[0], "").trim();
581
- break;
582
- } catch (e) {
583
- console.error("Invalid ui-component JSON:", e, block);
584
- }
585
- }
586
- return {
587
- cleanedText: cleaned,
588
- uiData,
589
- };
590
- };
591
- var historyMessages = (history, currentUserText) => {
592
- const claudeHistory = history
593
- .filter((m) => m.role === "user" || m.role === "assistant")
594
- .map((m) => ({
595
- role: m.role,
596
- content: m.text ?? JSON.stringify(m.ui ?? ""),
597
- }));
598
- claudeHistory.push({
599
- role: "user",
600
- content: currentUserText,
601
- });
602
- return claudeHistory;
603
- };
604
- var generateId = () => Date.now().toString() + Math.random().toString(36).substr(2, 9);
605
- var normalizeHeaders = (headers) => {
606
- const result = {};
607
- for (const [key, value] of Object.entries(headers)) {
608
- if (!value) continue;
609
- if (key.toLowerCase() === "cookie") {
610
- result["x-cookie"] = value;
611
- } else {
612
- result[key] = value;
613
- }
614
- }
615
- return result;
616
- };
617
- var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, onMessage, onToolCall }) => {
618
- const messagesEndRef = useRef(null);
619
- const [config, setConfig] = useState(defaultConfig);
620
- const [anthropic, setAnthropic] = useState();
621
- const [messages, setMessages] = useState([]);
622
- const [isLoading, setIsLoading] = useState(false);
623
- const [mcpClient, setMcpClient] = useState();
624
- const [isConfigLoading, setIsConfigLoading] = useState(true);
625
- const [isOpen, setIsOpen] = useState(false);
626
- const [headerValidation, setHeaderValidation] = useState(null);
627
- const [showAlert, setShowAlert] = useState(true);
628
- const { button_background, button_position, button_size, chat_height, chat_width, company_logo, company_name, header_background, initial_open, placeholder, show_typing_indicator, welcome_message } = config.chat_widget_settings;
629
- useEffect(() => {
630
- onMounted?.();
631
- }, []);
632
- useEffect(() => {
633
- if (!isConfigLoading && mcpClient && anthropic && config) {
634
- onReady?.({
635
- config,
636
- });
637
- }
638
- }, [isConfigLoading, mcpClient, anthropic, config]);
639
- useEffect(() => {
640
- const loadConfig = async () => {
641
- try {
642
- setIsConfigLoading(true);
643
- const apiResponse = await fetchChatWidgetSettings(clientId);
644
- if (apiResponse.success) {
645
- const anthropic2 = new Anthropic({
646
- apiKey: apiResponse.data.openai_key,
647
- dangerouslyAllowBrowser: true,
648
- });
649
- const mcpClient2 = new Client({
650
- name: "mcp-client-cli",
651
- version: "1.0.0",
652
- });
653
- const transport = new SSEClientTransport(new URL("", apiResponse.data.mcp_url), {
654
- eventSourceInit: {
655
- fetch: (url, init) => {
656
- if (headers) {
657
- const dynamicHeaders = normalizeHeaders(headers);
658
- return fetch(url, {
659
- headers: {
660
- ...(init?.headers ?? {}),
661
- ...dynamicHeaders,
662
- },
663
- });
664
- } else {
665
- return fetch(url, {
666
- headers: {
667
- ...(init?.headers ?? {}),
668
- },
669
- });
670
- }
671
- },
672
- },
673
- });
674
- await mcpClient2.connect(transport);
675
- setMcpClient(mcpClient2);
676
- setAnthropic(anthropic2);
677
- if (headers && apiResponse.data.auth_config) {
678
- const validationResult = validateHeaders(headers, apiResponse.data.auth_config, {
679
- allowExtra: false,
680
- caseSensitive: true,
681
- });
682
- setHeaderValidation(validationResult);
683
- }
684
- if (!apiResponse.data.chat_widget_settings) {
685
- setConfig({
686
- auth_config: apiResponse.data.auth_config,
687
- mcp_url: apiResponse.data.mcp_url,
688
- openai_key: apiResponse.data.openai_key,
689
- chat_widget_settings: {
690
- api_source_id: 0,
691
- chat_widget_settings_id: 0,
692
- created_at: "",
693
- updated_at: "",
694
- button_background: defaultConfig.chat_widget_settings.button_background,
695
- button_position: defaultConfig.chat_widget_settings.button_position,
696
- button_size: defaultConfig.chat_widget_settings.button_size,
697
- chat_height: defaultConfig.chat_widget_settings.chat_height,
698
- chat_width: defaultConfig.chat_widget_settings.chat_width,
699
- company_logo: defaultConfig.chat_widget_settings.company_logo,
700
- company_name: defaultConfig.chat_widget_settings.company_name,
701
- header_background: defaultConfig.chat_widget_settings.header_background,
702
- initial_open: defaultConfig.chat_widget_settings.initial_open,
703
- placeholder: defaultConfig.chat_widget_settings.placeholder,
704
- show_typing_indicator: defaultConfig.chat_widget_settings.show_typing_indicator,
705
- welcome_message: defaultConfig.chat_widget_settings.welcome_message,
706
- },
707
- });
708
- } else {
709
- setConfig(apiResponse.data);
710
- }
711
- }
712
- } catch (error) {
713
- console.error("Failed to load chat widget config:", error);
714
- } finally {
715
- setIsConfigLoading(false);
716
- }
717
- };
718
- loadConfig();
719
- }, []);
720
- useEffect(() => {
721
- setIsOpen(initial_open);
722
- const newIsOpen = !isOpen;
723
- setIsOpen(newIsOpen);
724
- if (newIsOpen) onOpen?.();
725
- else onClose?.();
726
- }, [initial_open]);
727
- useEffect(() => {
728
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
729
- }, [messages]);
730
- if (isConfigLoading || !mcpClient || !anthropic) {
731
- return /* @__PURE__ */ jsx("button", {
732
- className: `floating-button ${button_position} button-sizes ${button_size}`,
733
- style: { background: button_background },
734
- children: /* @__PURE__ */ jsx("div", { className: "loading-spinner" }),
735
- });
736
- }
737
- const addMessage = (payload) => {
738
- const newMessage = {
739
- id: generateId(),
740
- text: payload.text,
741
- ui: payload.ui,
742
- role: payload.role,
743
- timestamp: /* @__PURE__ */ new Date(),
744
- };
745
- onMessage?.(newMessage);
746
- setMessages((prev) => [...prev, newMessage]);
747
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
748
- return newMessage;
749
- };
750
- const sendMessage = async (message, approval) => {
751
- if (!message.trim() || isLoading) return;
752
- const newMessage = {
753
- id: generateId(),
754
- text: message,
755
- ui: void 0,
756
- role: approval ? "approval" : "user",
757
- timestamp: /* @__PURE__ */ new Date(),
758
- };
759
- setMessages((prev) => [...prev, newMessage]);
760
- setIsLoading(true);
761
- const toolsResult = await mcpClient.listTools();
762
- const tools = toolsResult.tools.map((tool) => ({ name: tool.name, description: tool.description, input_schema: tool.inputSchema }));
763
- try {
764
- const historyForContext = historyMessages([...messages, newMessage], message);
765
- const response = await anthropic.beta.messages.create({
766
- model: "claude-sonnet-4-5",
767
- betas: ["structured-outputs-2025-11-13"],
768
- max_tokens: 5e3,
769
- messages: historyForContext,
770
- tools,
771
- system: [
772
- {
773
- type: "text",
774
- text: GENERATIVE_UI_SYSTEM_PROMPT,
775
- cache_control: {
776
- type: "ephemeral",
777
- ttl: "1h",
778
- },
779
- },
780
- ],
781
- });
782
- for (const content of response.content) {
783
- if (content.type === "tool_use") {
784
- const toolCall = await mcpClient.callTool({ name: content.name, arguments: content.input });
785
- onToolCall?.({ name: content.name, args: content.input, result: toolCall });
786
- const toolMessagesForContext = historyMessages([...messages, newMessage], JSON.stringify(toolCall.structuredContent));
787
- const finalResponse = await anthropic.beta.messages.create({
788
- model: "claude-sonnet-4-5",
789
- max_tokens: 1024,
790
- betas: ["structured-outputs-2025-11-13"],
791
- messages: toolMessagesForContext,
792
- tools,
793
- system: [
794
- {
795
- type: "text",
796
- text: GENERATIVE_UI_SYSTEM_PROMPT,
797
- cache_control: {
798
- type: "ephemeral",
799
- ttl: "1h",
800
- },
801
- },
802
- ],
803
- });
804
- const textBlock = finalResponse.content.find((x) => x.type === "text");
805
- const { cleanedText, uiData } = extractUIJsonFromText(textBlock?.text ?? "");
806
- addMessage({ ui: uiData, text: cleanedText || void 0, role: "assistant" });
807
- } else if (content.type === "text") {
808
- const { cleanedText, uiData } = extractUIJsonFromText(content?.text);
809
- addMessage({ ui: uiData, text: cleanedText || void 0, role: "assistant" });
810
- }
811
- }
812
- setIsLoading(false);
813
- } catch (error) {
814
- console.error("Error sending message:", error);
815
- addMessage({
816
- text: "\xDCzg\xFCn\xFCm, bir hata olu\u015Ftu. L\xFCtfen tekrar deneyin.",
817
- role: "assistant",
818
- });
819
- setIsLoading(false);
820
- }
821
- };
822
- const toggleChat = () => {
823
- const newIsOpen = !isOpen;
824
- setIsOpen(newIsOpen);
825
- if (newIsOpen) onOpen?.();
826
- else onClose?.();
827
- };
828
- return /* @__PURE__ */ jsxs(Fragment, {
829
- children: [
830
- isOpen &&
831
- /* @__PURE__ */ jsx("div", {
832
- className: `overlay floating-chat-overlay ${isOpen ? "is-open" : ""}`,
833
- onClick: toggleChat,
834
- }),
835
- /* @__PURE__ */ jsx("div", {
836
- className: `chat-container ${button_position} ${isOpen ? "is-open" : ""}`,
837
- style: { width: chat_width, height: chat_height },
838
- children: /* @__PURE__ */ jsxs("div", {
839
- className: "chatbot-container",
840
- children: [
841
- /* @__PURE__ */ jsxs("div", {
842
- className: "header",
843
- style: { background: header_background },
844
- children: [
845
- /* @__PURE__ */ jsx("div", {
846
- className: "logo-container",
847
- children: company_logo
848
- ? company_logo.startsWith("http") || company_logo.startsWith("data:")
849
- ? /* @__PURE__ */ jsx("img", {
850
- src: company_logo,
851
- alt: "Company Logo",
852
- className: "logo-image",
853
- })
854
- : /* @__PURE__ */ jsx("span", { className: "logo-text", children: company_logo })
855
- : "\u{1F916}",
856
- }),
857
- /* @__PURE__ */ jsxs("div", {
858
- children: [/* @__PURE__ */ jsx("h3", { className: "company-name", children: company_name }), /* @__PURE__ */ jsx("p", { className: "status-text", children: isLoading ? "Yaz\u0131yor..." : "\xC7evrimi\xE7i" })],
859
- }),
860
- ],
861
- }),
862
- /* @__PURE__ */ jsxs("div", {
863
- className: "messages-container",
864
- children: [
865
- /* @__PURE__ */ jsx(HeaderAlert, {
866
- headerValidation,
867
- setShowAlert,
868
- showAlert,
869
- }),
870
- messages.length === 0
871
- ? /* @__PURE__ */ jsxs("div", {
872
- className: "empty-state",
873
- children: [
874
- /* @__PURE__ */ jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
875
- /* @__PURE__ */ jsx("h4", { className: "empty-state-title", children: welcome_message }),
876
- /* @__PURE__ */ jsx("p", { className: "empty-state-description", children: "A\u015Fa\u011F\u0131daki alana mesaj\u0131n\u0131z\u0131 yazarak ba\u015Flayabilirsiniz." }),
877
- ],
878
- })
879
- : /* @__PURE__ */ jsxs(Fragment, {
880
- children: [
881
- messages.map((message) =>
882
- /* @__PURE__ */ jsx(
883
- MessageBubble,
884
- {
885
- message,
886
- onAction: sendMessage,
887
- },
888
- message.id
889
- )
890
- ),
891
- show_typing_indicator && isLoading && /* @__PURE__ */ jsx(TypingDots, {}),
892
- ],
893
- }),
894
- /* @__PURE__ */ jsx("div", { ref: messagesEndRef }),
895
- ],
896
- }),
897
- /* @__PURE__ */ jsx(ChatInput, {
898
- handleSendMessage: sendMessage,
899
- isLoading,
900
- placeholder,
901
- }),
902
- ],
903
- }),
904
- }),
905
- /* @__PURE__ */ jsx("button", {
906
- onClick: toggleChat,
907
- className: `floating-button ${button_position} button-sizes ${button_size} ${isOpen ? "is-open" : ""}`,
908
- style: { background: button_background },
909
- "aria-label": isOpen ? "Chati kapat" : "Chati a\xE7",
910
- children: isOpen
911
- ? /* @__PURE__ */ jsx("svg", {
912
- width: "24",
913
- height: "24",
914
- viewBox: "0 0 24 24",
915
- fill: "currentColor",
916
- children: /* @__PURE__ */ 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" }),
917
- })
918
- : /* @__PURE__ */ jsx("svg", {
919
- width: "24",
920
- height: "24",
921
- viewBox: "0 0 24 24",
922
- fill: "currentColor",
923
- children: /* @__PURE__ */ 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" }),
924
- }),
925
- }),
926
- ],
927
- });
928
- };
929
-
930
- export { AizekChatBot };
931
- //# sourceMappingURL=index.mjs.map
932
- //# sourceMappingURL=index.mjs.map