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