@apia/ai 4.0.16 → 4.0.17

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.js CHANGED
@@ -1,1045 +1,13 @@
1
- import { jsx, jsxs, Fragment } from '@apia/theme/jsx-runtime';
2
- import { Box, getVariant, useBreakpointIndex, Textarea, Paragraph, Form } from '@apia/theme';
3
- import { useRef, useCallback, useState, createContext, forwardRef, useEffect } from 'react';
4
- import { IconButton, SimpleButton, ApiaUtil, FiltersStore, SortableList, SortableListItem } from '@apia/components';
5
- import { getLabel, noNaN, AudioRecorder, EventEmitter } from '@apia/util';
6
1
  import { makeObservable, observable, action, toJS, makeAutoObservable } from 'mobx';
2
+ import { jsxs, jsx, Fragment } from '@apia/theme/jsx-runtime';
3
+ import { Box, getVariant, Textarea, Paragraph } from '@apia/theme';
7
4
  import { observer } from 'mobx-react-lite';
8
- import { CollectorField, Collector } from '@apia/validations';
9
- import { uniqueId } from '@apia/notifications';
10
- import { FileIcon } from '@apia/icons';
11
5
  import { ApiaApi, makeApiaUrl, parseSuccessfulResponse } from '@apia/api';
6
+ import { FiltersStore, IconButton, ApiaUtil, SortableList, SortableListItem, ChatMessage, SimpleButton } from '@apia/components';
12
7
  import axios from 'axios';
13
-
14
- const AutoscrollContainer = ({ children }) => {
15
- const observer = useRef(null);
16
- const unsuscribe = useRef(null);
17
- const isFullScrolled = useRef(false);
18
- const hasInited = useRef(false);
19
- const ref = useCallback((el) => {
20
- if (!el)
21
- return;
22
- if (!hasInited.current) {
23
- hasInited.current = true;
24
- el.scrollTo({
25
- top: el.getBoundingClientRect().height,
26
- behavior: "auto"
27
- });
28
- isFullScrolled.current = true;
29
- }
30
- observer.current?.disconnect();
31
- unsuscribe.current?.();
32
- observer.current = new MutationObserver(([mutation]) => {
33
- if (mutation && mutation.target instanceof HTMLElement) {
34
- if (isFullScrolled.current && el.scrollTop !== el.scrollHeight - el.offsetHeight) {
35
- el.scrollTo({
36
- top: el.scrollHeight,
37
- behavior: "smooth"
38
- });
39
- }
40
- }
41
- });
42
- observer.current.observe(el, { childList: true, subtree: true });
43
- const handleScroll = (ev) => {
44
- if (ev.target === el && el instanceof HTMLElement) {
45
- setTimeout(() => {
46
- isFullScrolled.current = Math.abs(el.scrollTop - (el.scrollHeight - el.offsetHeight)) < 150;
47
- }, 100);
48
- }
49
- };
50
- el.addEventListener("scroll", handleScroll);
51
- unsuscribe.current = () => {
52
- el.removeEventListener("scroll", handleScroll);
53
- };
54
- }, []);
55
- return /* @__PURE__ */ jsx(
56
- Box,
57
- {
58
- ...getVariant("layout.common.components.autoscrollContainer"),
59
- className: "autoscrollContainer",
60
- ref,
61
- children
62
- }
63
- );
64
- };
65
-
66
- function isImageFile(file) {
67
- const IMAGE_EXTENSIONS = [
68
- "jpg",
69
- "jpeg",
70
- "png",
71
- "gif",
72
- "bmp",
73
- "webp",
74
- "tiff",
75
- "svg",
76
- "jfif"
77
- ];
78
- return IMAGE_EXTENSIONS.includes(file.name.split(".").pop());
79
- }
80
- function getImageOcrMaker(lang) {
81
- return new class ImageOcrMaker {
82
- async processFile(file, onProgress) {
83
- const tesseract = await import('tesseract.js');
84
- const worker = await tesseract.createWorker(lang, 1, {
85
- logger(arg) {
86
- onProgress?.(arg.progress * 100);
87
- }
88
- });
89
- const result = (await worker.recognize(file)).data.text;
90
- return [result];
91
- }
92
- willProcessFile(file) {
93
- return isImageFile(file);
94
- }
95
- }();
96
- }
97
-
98
- function isPdfFile(file) {
99
- const IMAGE_EXTENSIONS = ["pdf"];
100
- return IMAGE_EXTENSIONS.includes(file.name.split(".").pop());
101
- }
102
- function getPdfReader() {
103
- return new class PdfReader {
104
- async processFile(file, onProgress) {
105
- onProgress?.(0);
106
- const { getDocument, GlobalWorkerOptions } = await import('pdfjs-dist');
107
- async function getPdfTextFromArrayBuffer(buffer) {
108
- GlobalWorkerOptions.workerSrc = "../includes/pdf.worker.min.js";
109
- const pdf = await getDocument({ data: buffer }).promise;
110
- const pages = [];
111
- for (let i = 1; i <= pdf.numPages; i++) {
112
- const page = await pdf.getPage(i);
113
- const textContent = await page.getTextContent();
114
- pages.push(
115
- textContent.items.map((item) => item.str).join(" ")
116
- );
117
- }
118
- return pages;
119
- }
120
- return new Promise((resolve) => {
121
- const reader = new FileReader();
122
- reader.onload = async function(event) {
123
- if (!event.target?.result) {
124
- alert("Error al leer el archivo.");
125
- return;
126
- }
127
- const buffer = event.target.result;
128
- const text = await getPdfTextFromArrayBuffer(buffer);
129
- onProgress?.(100);
130
- resolve(text);
131
- };
132
- reader.readAsArrayBuffer(file);
133
- });
134
- }
135
- willProcessFile(file) {
136
- return isPdfFile(file);
137
- }
138
- }();
139
- }
140
-
141
- class WrongFormatError extends Error {
142
- constructor(fileName) {
143
- super(`File format not supported: ${fileName}`);
144
- }
145
- }
146
- function useHandleFileUpload({
147
- onContent
148
- }) {
149
- const [progress, setProgress] = useState(100);
150
- const handleFileUpload = useCallback(
151
- async (ev) => {
152
- setProgress(0);
153
- const imageProcessor = getImageOcrMaker("spa");
154
- const pdfProcessor = getPdfReader();
155
- await (async () => {
156
- const obtainedText = [];
157
- const files = ev.target.files;
158
- const filesLength = ev.target.files?.length ?? 0;
159
- if (files) {
160
- for (let i = 0; i < filesLength; i++) {
161
- const file = files[i];
162
- if (!isImageFile(file) && !isPdfFile(file)) {
163
- setProgress(100);
164
- throw new WrongFormatError(file.name);
165
- }
166
- const handleProgress = (progress2) => {
167
- setProgress(
168
- i / filesLength * 100 + 1 / filesLength * 100 * (progress2 / 100)
169
- );
170
- };
171
- let result = "";
172
- if (imageProcessor.willProcessFile(file)) {
173
- try {
174
- result = (await imageProcessor.processFile(file, handleProgress))[0];
175
- } catch (e) {
176
- console.error(e);
177
- }
178
- } else if (pdfProcessor.willProcessFile(file)) {
179
- result = (await pdfProcessor.processFile(file, handleProgress)).join("\n\n");
180
- }
181
- if (result) {
182
- obtainedText.push(result);
183
- }
184
- setProgress((i + 1) / filesLength * 100);
185
- }
186
- }
187
- onContent(obtainedText);
188
- })();
189
- ev.target.value = "";
190
- },
191
- [onContent]
192
- );
193
- return { progress, handleFileUpload };
194
- }
195
-
196
- var __defProp$c = Object.defineProperty;
197
- var __defNormalProp$c = (obj, key, value) => key in obj ? __defProp$c(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
198
- var __publicField$c = (obj, key, value) => {
199
- __defNormalProp$c(obj, typeof key !== "symbol" ? key + "" : key, value);
200
- return value;
201
- };
202
- let maxId = 0;
203
- class ChatMessage {
204
- constructor(message = "", messageType = "user", attachments = [], reference = null) {
205
- this.message = message;
206
- this.messageType = messageType;
207
- this.attachments = attachments;
208
- this.reference = reference;
209
- __publicField$c(this, "id");
210
- __publicField$c(this, "clone", () => new ChatMessage(
211
- this.message,
212
- this.messageType,
213
- [...this.attachments],
214
- this.reference
215
- ));
216
- __publicField$c(this, "Component", observer(({ className }) => {
217
- return /* @__PURE__ */ jsxs(
218
- Box,
219
- {
220
- as: "pre",
221
- className: `history_message ${className || ""} ${this.messageType}`,
222
- children: [
223
- /* @__PURE__ */ jsx(
224
- Box,
225
- {
226
- className: "history_message__content",
227
- ...typeof this.message === "string" ? { dangerouslySetInnerHTML: { __html: this.message } } : { children: this.message }
228
- }
229
- ),
230
- this.attachments.length > 0 && /* @__PURE__ */ jsx(Box, { className: "history_message__attachments", children: this.attachments.map((x) => {
231
- const a = x;
232
- return /* @__PURE__ */ jsx(a.Component, {}, x.id);
233
- }) }),
234
- this.reference && /* @__PURE__ */ jsx(Box, { className: "history_message__references", children: this.reference })
235
- ]
236
- },
237
- this.id
238
- );
239
- }));
240
- this.id = maxId++;
241
- if (messageType === "response")
242
- this.messageType = "system";
243
- if (typeof message === "string")
244
- this.message = this.parseMessage(message);
245
- makeObservable(this, {
246
- attachments: observable,
247
- message: observable,
248
- messageType: observable,
249
- reference: observable
250
- });
251
- }
252
- parseMessage(message) {
253
- let result = message;
254
- result = result.replaceAll("[strong]", "<strong>");
255
- result = result.replaceAll("[/strong]", "</strong>");
256
- return result;
257
- }
258
- removeAttachment(idx) {
259
- this.attachments = this.attachments.filter((_, i) => i !== idx);
260
- }
261
- }
262
-
263
- var __defProp$b = Object.defineProperty;
264
- var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
265
- var __publicField$b = (obj, key, value) => {
266
- __defNormalProp$b(obj, typeof key !== "symbol" ? key + "" : key, value);
267
- return value;
268
- };
269
- class AIContent extends CollectorField {
270
- constructor(content) {
271
- super(uniqueId(), "");
272
- __publicField$b(this, "type", "aiContent");
273
- __publicField$b(this, "content");
274
- __publicField$b(this, "Component", () => {
275
- return /* @__PURE__ */ jsx(Box, { variant: "layout.common.components.aiMessage.textBox", children: /* @__PURE__ */ jsx(Box, { variant: "layout.common.components.aiMessage.textSnippet", children: this.content }) });
276
- });
277
- this.content = content;
278
- }
279
- }
280
-
281
- const AIFileContentAllowedExtensions = {
282
- svg: "svg",
283
- png: "png",
284
- jpg: "jpg",
285
- jpeg: "jpeg",
286
- txt: "txt",
287
- doc: "doc",
288
- pdf: "pdf",
289
- docx: "docx",
290
- csv: "csv",
291
- xlsx: "xlsx",
292
- xls: "xls",
293
- mp3: "mp3",
294
- wav: "wav"
295
- };
296
- var FileType = /* @__PURE__ */ ((FileType2) => {
297
- FileType2["DOCUMENT"] = "DOCUMENT";
298
- FileType2["IMAGE"] = "IMAGE";
299
- FileType2["AUDIO"] = "AUDIO";
300
- FileType2["SHEET"] = "SHEET";
301
- return FileType2;
302
- })(FileType || {});
303
- var AIMessageRole = /* @__PURE__ */ ((AIMessageRole2) => {
304
- AIMessageRole2["USER"] = "USER";
305
- AIMessageRole2["SYSTEM"] = "SYSTEM";
306
- return AIMessageRole2;
307
- })(AIMessageRole || {});
308
-
309
- var __defProp$a = Object.defineProperty;
310
- var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
311
- var __publicField$a = (obj, key, value) => {
312
- __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
313
- return value;
314
- };
315
- const _AIFileContent = class _AIFileContent extends AIContent {
316
- constructor(props) {
317
- if (props.needsControlExtension === null || props.needsControlExtension === void 0) {
318
- props.needsControlExtension = true;
319
- }
320
- const extension = _AIFileContent.getExtensionFromFileName(props.name);
321
- super();
322
- __publicField$a(this, "type");
323
- __publicField$a(this, "value");
324
- __publicField$a(this, "name");
325
- __publicField$a(this, "extension");
326
- __publicField$a(this, "__file");
327
- __publicField$a(this, "__error");
328
- __publicField$a(this, "onClose");
329
- __publicField$a(this, "overrideSize");
330
- __publicField$a(this, "id", uniqueId());
331
- __publicField$a(this, "inferContent", () => {
332
- return `You must collect information contained in this ${this.type} as help to build your tool choice.`;
333
- });
334
- __publicField$a(this, "inferExtension", (extension) => {
335
- switch (extension) {
336
- case AIFileContentAllowedExtensions.jpg:
337
- case AIFileContentAllowedExtensions.jpeg:
338
- case AIFileContentAllowedExtensions.png:
339
- case AIFileContentAllowedExtensions.svg:
340
- return FileType.IMAGE;
341
- case AIFileContentAllowedExtensions.txt:
342
- case AIFileContentAllowedExtensions.doc:
343
- case AIFileContentAllowedExtensions.pdf:
344
- case AIFileContentAllowedExtensions.docx:
345
- return FileType.DOCUMENT;
346
- case AIFileContentAllowedExtensions.csv:
347
- case AIFileContentAllowedExtensions.xlsx:
348
- case AIFileContentAllowedExtensions.xls:
349
- return FileType.SHEET;
350
- case AIFileContentAllowedExtensions.mp3:
351
- case AIFileContentAllowedExtensions.wav:
352
- return FileType.AUDIO;
353
- default:
354
- this.__throwError(
355
- new Error(_AIFileContent.__getExtensionErrorMessage(extension)),
356
- this.__error?.fileExtension
357
- );
358
- }
359
- });
360
- // COMPONENT METHODS
361
- __publicField$a(this, "Component", () => {
362
- const closeButton = this.onClose ? /* @__PURE__ */ jsx(
363
- IconButton,
364
- {
365
- className: "file_close_button",
366
- size: "Md",
367
- icon: "Close",
368
- onClick: this.onClose,
369
- title: getLabel("lblDeleteItem").title
370
- }
371
- ) : null;
372
- return /* @__PURE__ */ jsxs(
373
- Box,
374
- {
375
- className: "file_box",
376
- sx: {
377
- ...this.overrideSize ? {
378
- ...this.overrideSize,
379
- img: {
380
- width: `${this.overrideSize.width - 20}px`,
381
- height: `${this.overrideSize.height - 61}px`
382
- }
383
- } : {}
384
- },
385
- variant: "layout.common.components.aiMessage.fileBox",
386
- children: [
387
- closeButton && closeButton,
388
- FileType.IMAGE === this.type ? /* @__PURE__ */ jsx("img", { src: URL.createObjectURL(this.file), alt: this.name }) : /* @__PURE__ */ jsx(FileIcon, { iconSize: "lg", docName: this.name }),
389
- /* @__PURE__ */ jsx(
390
- Box,
391
- {
392
- as: "p",
393
- variant: "layout.common.components.aiMessage.fileName",
394
- title: this.name,
395
- children: this.name
396
- }
397
- )
398
- ]
399
- }
400
- );
401
- });
402
- this.__error = props.error;
403
- if (props.needsControlExtension && !_AIFileContent.isValidExtension(extension))
404
- this.__throwError(
405
- new Error(_AIFileContent.__getExtensionErrorMessage(extension)),
406
- this.__error?.fileExtension
407
- );
408
- this.value = props.value;
409
- this.extension = extension;
410
- this.type = this.inferExtension(this.extension);
411
- this.name = props.name;
412
- this.__file = props.f;
413
- this.content = this.inferContent();
414
- this.onClose = props.onClose;
415
- }
416
- setOnClose(callback) {
417
- this.onClose = callback;
418
- return this;
419
- }
420
- // PUBLIC METHODS
421
- setOverrideSize(overrideSize) {
422
- this.overrideSize = overrideSize;
423
- return this;
424
- }
425
- get file() {
426
- if (!this.__file)
427
- throw new Error("File is undefined");
428
- return this.__file;
429
- }
430
- static getExtensionFromFileName(fileName) {
431
- return fileName.split(".").pop();
432
- }
433
- // PRIVATE METHODS
434
- static __getExtensionErrorMessage(extension) {
435
- return `extension "${extension}" is not included into valid types:
436
- ${Object.keys(AIFileContentAllowedExtensions)}`;
437
- }
438
- __throwError(e, callback) {
439
- callback && callback();
440
- throw e;
441
- }
442
- getId() {
443
- return this.id;
444
- }
445
- };
446
- // STATIC METHODS
447
- __publicField$a(_AIFileContent, "isValidExtension", (extension) => {
448
- return Object.values(
449
- AIFileContentAllowedExtensions
450
- ).includes(extension);
451
- });
452
- __publicField$a(_AIFileContent, "blobToBase64", async (blob) => {
453
- return await ((blob2) => new Promise((resolve, reject) => {
454
- const reader = new FileReader();
455
- reader.onloadend = () => {
456
- const base64String = reader.result;
457
- resolve(base64String);
458
- };
459
- reader.onerror = reject;
460
- reader.readAsDataURL(blob2);
461
- }))(blob);
462
- });
463
- __publicField$a(_AIFileContent, "fromFile", async (props) => {
464
- const fileUrl = await ((f) => new Promise((resolve, reject) => {
465
- const reader = new FileReader();
466
- reader.readAsDataURL(f);
467
- reader.onload = () => resolve(reader.result);
468
- reader.onerror = () => reject();
469
- }))(props.f);
470
- return new _AIFileContent({
471
- value: fileUrl,
472
- name: props.f.name,
473
- f: props.f,
474
- error: props.error,
475
- needsControlExtension: props.needsControlExtension
476
- });
477
- });
478
- let AIFileContent = _AIFileContent;
479
-
480
- var __defProp$9 = Object.defineProperty;
481
- var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
482
- var __publicField$9 = (obj, key, value) => {
483
- __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
484
- return value;
485
- };
486
- class AIMessageAttachments {
487
- constructor(role, content, close) {
488
- this.close = close;
489
- __publicField$9(this, "role");
490
- __publicField$9(this, "content");
491
- __publicField$9(this, "id", uniqueId());
492
- __publicField$9(this, "customDescription", false);
493
- __publicField$9(this, "addDescription", async () => {
494
- const collector = new Collector();
495
- const collected = await collector.add(this.content).add(
496
- new collector.fields.textarea(
497
- "addCommentTextArea",
498
- getLabel("lblAiAddImageCo").text.replace(".", ""),
499
- {
500
- initialValue: this.content instanceof AIFileContent && this.content.content !== this.content.inferContent() ? this.content.content : ""
501
- }
502
- )
503
- ).show({
504
- title: getLabel("btnAddComment").text
505
- }).catch((e) => {
506
- throw e;
507
- });
508
- if (collected?.addCommentTextArea) {
509
- this.content.content = collected.addCommentTextArea;
510
- this.customDescription = true;
511
- } else {
512
- if (this.content instanceof AIFileContent)
513
- this.content.content = this.content.inferContent();
514
- this.customDescription = false;
515
- }
516
- });
517
- __publicField$9(this, "Component", (props) => /* @__PURE__ */ jsxs(Box, { ...getVariant("layout.common.components.aiMessage"), children: [
518
- props.closeButton ? /* @__PURE__ */ jsx(
519
- IconButton,
520
- {
521
- className: "closeButton",
522
- size: "Md",
523
- icon: "Close",
524
- onClick: this.close,
525
- title: getLabel("lblDeleteItem").title
526
- }
527
- ) : /* @__PURE__ */ jsx(Fragment, {}),
528
- props?.canAddDescription ? /* @__PURE__ */ jsx(
529
- IconButton,
530
- {
531
- className: "descriptionButton",
532
- size: "Md",
533
- icon: "Magic",
534
- onClick: this.addDescription
535
- }
536
- ) : /* @__PURE__ */ jsx(Fragment, {}),
537
- /* @__PURE__ */ jsx(this.content.Component, {})
538
- ] }));
539
- this.role = role;
540
- this.content = content;
541
- }
542
- getId() {
543
- return this.id;
544
- }
545
- }
546
-
547
- const handleFileUploadAsMessage = async (fileInputElement, chatController) => {
548
- if (fileInputElement.files) {
549
- [...fileInputElement.files].forEach(async (f) => {
550
- const m = new AIMessageAttachments(
551
- AIMessageRole.USER,
552
- await AIFileContent.fromFile(f, {
553
- fileExtension: () => chatController.messages.add(
554
- new ChatMessage(
555
- getLabel("msgAiIncorrectFileExtensionError", {
556
- text: {
557
- TOK1: `[${Object.keys(AIFileContentAllowedExtensions).join(", ")}]`
558
- }
559
- }).text,
560
- "error"
561
- )
562
- )
563
- }),
564
- () => chatController.attachments.drop(m)
565
- );
566
- chatController.attachments.add(m);
567
- });
568
- }
569
- };
570
-
571
- const makeTextarea = (chatController) => {
572
- const NewTextarea = observer(
573
- ({
574
- hideDeleteButton,
575
- isLoading: outIsLoading,
576
- onSubmit,
577
- preventAppendUserMessages
578
- }) => {
579
- const [isLoading, setIsLoading] = useState(false);
580
- const breakpoint = useBreakpointIndex();
581
- const submit = useCallback(() => {
582
- if (preventAppendUserMessages !== true)
583
- chatController.messages.add(chatController.state.current);
584
- chatController.history.add(chatController.state.current);
585
- onSubmit(chatController.state.current).finally(() => {
586
- setIsLoading(false);
587
- chatController.state.current = new ChatMessage();
588
- });
589
- }, [onSubmit, preventAppendUserMessages]);
590
- const handleSubmit = useCallback(
591
- (ev) => {
592
- ev.preventDefault();
593
- if (chatController.state.current.message || chatController.attachments.size() > 0) {
594
- setIsLoading(true);
595
- submit();
596
- }
597
- const textarea = document.getElementById(
598
- `GPTMessage${chatController.id}`
599
- );
600
- textarea.focus();
601
- },
602
- [submit]
603
- );
604
- const onKeyDown = useCallback((ev) => {
605
- if (ev.target.readOnly)
606
- return;
607
- if (ev.code === "Enter" && !ev.shiftKey) {
608
- ev.preventDefault();
609
- ev.target.closest("form")?.querySelector('button[type="submit"]')?.click();
610
- }
611
- }, []);
612
- const { progress, handleFileUpload } = useHandleFileUpload({
613
- onContent(content) {
614
- document.getElementById(
615
- `GPTMessage${chatController.id}`
616
- ).value = content.join("\n\n");
617
- }
618
- });
619
- const actualIsLoading = isLoading || progress !== 100 || outIsLoading;
620
- const [dragging, setDragging] = useState(false);
621
- const handleDragLeave = (ev) => {
622
- ev.preventDefault();
623
- setDragging(false);
624
- };
625
- const handleDrop = (ev) => {
626
- ev.preventDefault();
627
- setDragging(false);
628
- const fileElement = document.getElementById(
629
- `gptUploadFile__${chatController.id}`
630
- );
631
- fileElement.files = ev.dataTransfer.files;
632
- const event = new Event("change", { bubbles: true });
633
- fileElement.dispatchEvent(event);
634
- };
635
- const handleDragOver = (ev) => {
636
- ev.preventDefault();
637
- };
638
- const handleDragEnter = (ev) => {
639
- ev.preventDefault();
640
- setDragging(true);
641
- };
642
- const additionalButtons = [];
643
- additionalButtons.push({
644
- key: "prev",
645
- children: /* @__PURE__ */ jsx(
646
- SimpleButton,
647
- {
648
- title: getLabel("btnAiPrevious").title,
649
- variant: "outline",
650
- type: "button",
651
- onClick: chatController.history.previous,
652
- size: "sm",
653
- children: getLabel("btnAiPrevious").text
654
- }
655
- )
656
- });
657
- additionalButtons.push({
658
- key: "next",
659
- children: /* @__PURE__ */ jsx(
660
- SimpleButton,
661
- {
662
- title: getLabel("btnAiNext").title,
663
- variant: "outline",
664
- type: "button",
665
- onClick: chatController.history.next,
666
- size: "sm",
667
- children: getLabel("btnAiNext").text
668
- }
669
- )
670
- });
671
- if (!hideDeleteButton) {
672
- additionalButtons.push({
673
- key: "delete",
674
- children: /* @__PURE__ */ jsx(
675
- SimpleButton,
676
- {
677
- title: getLabel("btnAiDelete").title,
678
- variant: "outline",
679
- type: "button",
680
- onClick: () => {
681
- chatController.state.current.message = "";
682
- chatController.attachments.dropAll();
683
- chatController.currentHistoryIndex = -1;
684
- },
685
- size: "sm",
686
- children: getLabel("btnAiDelete").text
687
- }
688
- )
689
- });
690
- additionalButtons.push({
691
- key: "deleteMessages",
692
- children: /* @__PURE__ */ jsx(
693
- SimpleButton,
694
- {
695
- title: getLabel("btnAiDeleteMessages").title,
696
- variant: "outline",
697
- type: "button",
698
- onClick: () => chatController.messages.clear(),
699
- size: "sm",
700
- children: getLabel("btnAiDeleteMessages").text
701
- }
702
- )
703
- });
704
- }
705
- const isPhone = breakpoint < 4;
706
- let iconButton = /* @__PURE__ */ jsx(Fragment, {});
707
- if (isPhone) {
708
- iconButton = /* @__PURE__ */ jsx(
709
- IconButton,
710
- {
711
- ...getVariant("layout.ai.execution.formsAssistant.settingsButton"),
712
- iconSize: "Md",
713
- size: "Lg",
714
- icon: "Ellipsis",
715
- isLoading: actualIsLoading,
716
- onClick: () => {
717
- const util = ApiaUtil.instance;
718
- const items = [];
719
- items.push(...additionalButtons);
720
- if (items.length > 0)
721
- util.menu.open({
722
- menuProps: {
723
- anchorPoint: { x: util.mouse.x, y: util.mouse.y }
724
- },
725
- items
726
- });
727
- }
728
- }
729
- );
730
- }
731
- return /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", width: "100%" }, children: [
732
- /* @__PURE__ */ jsx(
733
- Box,
734
- {
735
- sx: {
736
- flexWrap: "wrap",
737
- display: "flex",
738
- maxHeight: "280px",
739
- overflowY: "auto",
740
- paddingTop: "6px",
741
- paddingBottom: "6px"
742
- },
743
- children: chatController.attachments.getComponents()
744
- }
745
- ),
746
- /* @__PURE__ */ jsxs(
747
- "form",
748
- {
749
- onDrop: handleDrop,
750
- onDragOver: handleDragOver,
751
- onDragEnter: handleDragEnter,
752
- onDragLeave: handleDragLeave,
753
- onSubmit: handleSubmit,
754
- className: "gpt__form",
755
- action: "",
756
- children: [
757
- dragging ? /* @__PURE__ */ jsx(
758
- Box,
759
- {
760
- sx: {
761
- height: "150px",
762
- border: "3px dashed #aaa",
763
- width: "100%",
764
- display: "flex",
765
- alignItems: "center",
766
- justifyContent: "center"
767
- },
768
- children: getLabel("msgAiDragAndDrop").text
769
- }
770
- ) : /* @__PURE__ */ jsx(
771
- Textarea,
772
- {
773
- onKeyDown,
774
- id: `GPTMessage${chatController.id}`,
775
- readOnly: actualIsLoading,
776
- value: chatController.state.current.message,
777
- onChange: (ev) => {
778
- chatController.state.current.message = ev.target.value;
779
- if (!chatController.state.current.message && chatController.attachments.size() < 1)
780
- chatController.currentHistoryIndex = -1;
781
- }
782
- }
783
- ),
784
- /* @__PURE__ */ jsxs(Box, { className: "gpt__buttonsContainer", children: [
785
- /* @__PURE__ */ jsx(Box, { sx: { display: "none" }, children: /* @__PURE__ */ jsx(
786
- "input",
787
- {
788
- type: "file",
789
- className: "gptUploadFile",
790
- multiple: true,
791
- id: `gptUploadFile__${chatController.id}`,
792
- onChange: (ev) => {
793
- if (1 == noNaN("a"))
794
- handleFileUpload(ev).catch((e) => {
795
- if (e instanceof WrongFormatError) {
796
- setIsLoading(false);
797
- chatController.messages.add(
798
- new ChatMessage(
799
- getLabel("msgAiFileExtensionError").text,
800
- "error"
801
- )
802
- );
803
- } else {
804
- throw e;
805
- }
806
- });
807
- else {
808
- handleFileUploadAsMessage(ev.target, chatController);
809
- }
810
- ev.target.value = "";
811
- }
812
- }
813
- ) }),
814
- /* @__PURE__ */ jsx(
815
- IconButton,
816
- {
817
- variant: "icon-outline",
818
- onClick: () => !chatController.audioRecorder.state.recording ? chatController.audioRecorder.start() : chatController.audioRecorder.stop(),
819
- disabled: actualIsLoading && !chatController.audioRecorder.state.recording,
820
- sx: {
821
- color: chatController.audioRecorder.state.recording ? "red" : void 0
822
- },
823
- icon: chatController.audioRecorder.state.recording ? "Stop" : "Microphone",
824
- id: "transcribeAudio",
825
- size: "Lg",
826
- title: getLabel("lblAiRecordAudio").text
827
- }
828
- ),
829
- /* @__PURE__ */ jsx(
830
- IconButton,
831
- {
832
- title: getLabel("btnUploadFile").text,
833
- icon: "File",
834
- variant: "icon-outline",
835
- disabled: actualIsLoading,
836
- onClick: () => {
837
- document.getElementById(
838
- `gptUploadFile__${chatController.id}`
839
- ).click();
840
- },
841
- size: "Lg"
842
- }
843
- ),
844
- isPhone ? iconButton : /* @__PURE__ */ jsxs(Fragment, { children: [
845
- ...additionalButtons.map(
846
- (x) => x.children
847
- )
848
- ] }),
849
- /* @__PURE__ */ jsx(
850
- SimpleButton,
851
- {
852
- title: getLabel("btnAiSend").title,
853
- isLoading: actualIsLoading,
854
- type: "submit",
855
- size: "sm",
856
- children: getLabel("btnAiSend").text
857
- }
858
- )
859
- ] })
860
- ]
861
- }
862
- )
863
- ] });
864
- }
865
- );
866
- NewTextarea.displayName = "";
867
- return NewTextarea;
868
- };
869
-
870
- var __defProp$8 = Object.defineProperty;
871
- var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
872
- var __publicField$8 = (obj, key, value) => {
873
- __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
874
- return value;
875
- };
876
- var __accessCheck = (obj, member, msg) => {
877
- if (!member.has(obj))
878
- throw TypeError("Cannot " + msg);
879
- };
880
- var __privateGet = (obj, member, getter) => {
881
- __accessCheck(obj, member, "read from private field");
882
- return getter ? getter.call(obj) : member.get(obj);
883
- };
884
- var __privateAdd = (obj, member, value) => {
885
- if (member.has(obj))
886
- throw TypeError("Cannot add the same private member more than once");
887
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
888
- };
889
- var __privateSet = (obj, member, value, setter) => {
890
- __accessCheck(obj, member, "write to private field");
891
- setter ? setter.call(obj, value) : member.set(obj, value);
892
- return value;
893
- };
894
- var _promptsHistory, _internalAudioRecorder;
895
- class ChatController {
896
- constructor(id, welcomeMessage) {
897
- this.id = id;
898
- __publicField$8(this, "state", {
899
- current: new ChatMessage(),
900
- messages: []
901
- });
902
- __publicField$8(this, "components", {
903
- MessageHistory: observer(() => {
904
- return /* @__PURE__ */ jsx(
905
- Box,
906
- {
907
- ...getVariant("layout.common.components.chat"),
908
- className: "history",
909
- children: /* @__PURE__ */ jsx(AutoscrollContainer, { children: this.state.messages.map((current) => /* @__PURE__ */ jsx(current.Component, {}, current.id)) })
910
- }
911
- );
912
- }),
913
- Textarea: makeTextarea(this)
914
- });
915
- __privateAdd(this, _promptsHistory, []);
916
- __publicField$8(this, "currentHistoryIndex", -1);
917
- __privateAdd(this, _internalAudioRecorder, new AudioRecorder());
918
- __publicField$8(this, "audioRecorder", {
919
- start: () => __privateGet(this, _internalAudioRecorder).start().then(async (blob) => {
920
- const m = new AIMessageAttachments(
921
- AIMessageRole.USER,
922
- new AIFileContent({
923
- value: await AIFileContent.blobToBase64(blob),
924
- name: `userRecord_${this.audioRecorder.record++}.wav`
925
- }),
926
- () => this.attachments.drop(m)
927
- );
928
- this.attachments.add(m);
929
- }),
930
- stop: async () => {
931
- __privateGet(this, _internalAudioRecorder).stop();
932
- },
933
- record: 0,
934
- state: __privateGet(this, _internalAudioRecorder).state
935
- });
936
- __publicField$8(this, "history", {
937
- add: (message) => {
938
- this.currentHistoryIndex = -1;
939
- if (message === __privateGet(this, _promptsHistory)[__privateGet(this, _promptsHistory).length]) {
940
- return;
941
- }
942
- __privateSet(this, _promptsHistory, [
943
- message,
944
- ...__privateGet(this, _promptsHistory).slice(
945
- Math.max(0, __privateGet(this, _promptsHistory).length - 10)
946
- )
947
- ]);
948
- },
949
- next: () => {
950
- let message = new ChatMessage();
951
- if (__privateGet(this, _promptsHistory)[this.currentHistoryIndex - 1])
952
- message = __privateGet(this, _promptsHistory)[--this.currentHistoryIndex].clone();
953
- else {
954
- this.currentHistoryIndex = -1;
955
- }
956
- this.history.updateState(message);
957
- },
958
- previous: () => {
959
- if (__privateGet(this, _promptsHistory)[this.currentHistoryIndex + 1]) {
960
- this.history.updateState(
961
- __privateGet(this, _promptsHistory)[++this.currentHistoryIndex].clone()
962
- );
963
- }
964
- },
965
- updateState: (message) => {
966
- if (message)
967
- this.state.current = message;
968
- else
969
- this.state.current = new ChatMessage();
970
- },
971
- size: () => this.state.messages.length
972
- });
973
- __publicField$8(this, "messages", {
974
- add: (message, idx) => {
975
- if (idx !== void 0 && idx !== null) {
976
- this.state.messages.splice(idx, 0, message);
977
- } else {
978
- this.state.messages.push(message);
979
- }
980
- },
981
- clear: () => {
982
- this.state.messages = [];
983
- }
984
- });
985
- __publicField$8(this, "attachments", {
986
- add: (...aiMessage) => {
987
- this.state.current.attachments.push(
988
- ...aiMessage
989
- );
990
- },
991
- dropAll: () => void (this.state.current.attachments = []),
992
- drop: (el) => {
993
- const e = el;
994
- this.state.current.attachments = this.state.current.attachments.filter(
995
- (c) => c !== e
996
- );
997
- if (!this.state.current.message && this.attachments.size() < 1)
998
- this.currentHistoryIndex = -1;
999
- },
1000
- getComponents: () => this.state.current.attachments.map((x) => {
1001
- const c = x;
1002
- return /* @__PURE__ */ jsx(c.Component, { closeButton: true, canAddDescription: true }, x.id);
1003
- }),
1004
- get: () => this.state.current.attachments,
1005
- size: () => this.state.current.attachments.length
1006
- });
1007
- if (welcomeMessage) {
1008
- this.state.messages.splice(
1009
- 0,
1010
- 0,
1011
- new ChatMessage(welcomeMessage, "system")
1012
- );
1013
- }
1014
- makeObservable(this, { state: observable });
1015
- }
1016
- }
1017
- _promptsHistory = new WeakMap();
1018
- _internalAudioRecorder = new WeakMap();
1019
-
1020
- class MultipleChoiceMessage extends ChatMessage {
1021
- constructor(question, options, Renderer) {
1022
- super(
1023
- Renderer ? /* @__PURE__ */ jsxs(Box, { className: "multipleChoiceMessage customRenderer", children: [
1024
- /* @__PURE__ */ jsx(Paragraph, { children: question }),
1025
- options.map((item) => /* @__PURE__ */ jsx(Renderer, { item }, item.url))
1026
- ] }) : /* @__PURE__ */ jsxs(Box, { className: "multipleChoiceMessage", children: [
1027
- /* @__PURE__ */ jsx(Paragraph, { children: question }),
1028
- /* @__PURE__ */ jsx(Box, { as: "ul", children: options.map((current) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
1029
- SimpleButton,
1030
- {
1031
- className: "multipleChoice__option",
1032
- onClick: () => {
1033
- ApiaUtil.instance.tabs.openTab(current.label, current.url);
1034
- },
1035
- children: current.label
1036
- }
1037
- ) }, current.label)) })
1038
- ] }),
1039
- "multipleChoice"
1040
- );
1041
- }
1042
- }
8
+ import { AudioRecorder, EventEmitter } from '@apia/util';
9
+ import { createContext } from 'react';
10
+ import { uniqueId } from '@apia/notifications';
1043
11
 
1044
12
  const Component = observer(
1045
13
  (props) => {
@@ -1050,16 +18,16 @@ const Component = observer(
1050
18
  }
1051
19
  );
1052
20
 
1053
- var __defProp$7 = Object.defineProperty;
1054
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1055
- var __publicField$7 = (obj, key, value) => {
1056
- __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+ var __defProp$4 = Object.defineProperty;
22
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
23
+ var __publicField$4 = (obj, key, value) => {
24
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
1057
25
  return value;
1058
26
  };
1059
27
  class SemanticSearchReference {
1060
28
  constructor(props) {
1061
- __publicField$7(this, "state", { title: "", body: "", link: "" });
1062
- __publicField$7(this, "Component", () => /* @__PURE__ */ jsxs(Fragment, { children: [
29
+ __publicField$4(this, "state", { title: "", body: "", link: "" });
30
+ __publicField$4(this, "Component", () => /* @__PURE__ */ jsxs(Fragment, { children: [
1063
31
  "(",
1064
32
  /* @__PURE__ */ jsx(Component, { instance: this }),
1065
33
  ")"
@@ -1069,15 +37,15 @@ class SemanticSearchReference {
1069
37
  }
1070
38
  }
1071
39
 
1072
- var __defProp$6 = Object.defineProperty;
1073
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1074
- var __publicField$6 = (obj, key, value) => {
1075
- __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
40
+ var __defProp$3 = Object.defineProperty;
41
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
42
+ var __publicField$3 = (obj, key, value) => {
43
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
1076
44
  return value;
1077
45
  };
1078
46
  const _SearchController = class _SearchController {
1079
47
  constructor() {
1080
- __publicField$6(this, "state", { queryString: "", results: [], isLoading: false, disabled: false });
48
+ __publicField$3(this, "state", { queryString: "", results: [], isLoading: false, disabled: false });
1081
49
  makeObservable(this, { state: observable });
1082
50
  }
1083
51
  async search(selectedId) {
@@ -1115,676 +83,8 @@ const _SearchController = class _SearchController {
1115
83
  _SearchController.instance.state.disabled = false;
1116
84
  }
1117
85
  };
1118
- __publicField$6(_SearchController, "instance", new _SearchController());
86
+ __publicField$3(_SearchController, "instance", new _SearchController());
1119
87
  let SearchController = _SearchController;
1120
- var SearchController$1 = SearchController;
1121
-
1122
- const FileAttachment = observer(
1123
- ({
1124
- attachment,
1125
- onRemove
1126
- }) => {
1127
- return /* @__PURE__ */ jsxs(Box, { className: "file_box", children: [
1128
- /* @__PURE__ */ jsx(FileIcon, { className: "file_box__icon", docName: attachment.name }),
1129
- /* @__PURE__ */ jsx(Box, { className: "file_box__name", title: attachment.name, children: attachment.name }),
1130
- onRemove && /* @__PURE__ */ jsx(
1131
- IconButton,
1132
- {
1133
- icon: "Close",
1134
- className: "file_box__remove",
1135
- onClick: onRemove,
1136
- variant: "icon-only"
1137
- }
1138
- )
1139
- ] });
1140
- }
1141
- );
1142
-
1143
- const Attachments = observer(
1144
- ({
1145
- attachments,
1146
- onRemove
1147
- }) => {
1148
- if (!attachments.length)
1149
- return null;
1150
- return /* @__PURE__ */ jsx(
1151
- Box,
1152
- {
1153
- className: "attachments",
1154
- ...getVariant("layout.common.chat.attachments"),
1155
- children: attachments.map((x) => /* @__PURE__ */ jsx(
1156
- FileAttachment,
1157
- {
1158
- attachment: x,
1159
- onRemove: onRemove ? () => onRemove(x) : void 0
1160
- },
1161
- x.id
1162
- ))
1163
- }
1164
- );
1165
- }
1166
- );
1167
-
1168
- const Message = observer(
1169
- ({
1170
- className,
1171
- type,
1172
- id,
1173
- message,
1174
- attachments,
1175
- reference
1176
- }) => {
1177
- return /* @__PURE__ */ jsxs(
1178
- Box,
1179
- {
1180
- as: "pre",
1181
- className: `history_message ${className || ""} ${type}`,
1182
- children: [
1183
- /* @__PURE__ */ jsx(
1184
- Box,
1185
- {
1186
- className: "history_message__content",
1187
- ...typeof message === "string" ? { dangerouslySetInnerHTML: { __html: message } } : { children: message }
1188
- }
1189
- ),
1190
- attachments.length > 0 && /* @__PURE__ */ jsx(Attachments, { attachments }),
1191
- reference && /* @__PURE__ */ jsx(Box, { className: "history_message__references", children: reference })
1192
- ]
1193
- },
1194
- id
1195
- );
1196
- }
1197
- );
1198
-
1199
- const History = observer(({ messages }) => {
1200
- let currentType = "";
1201
- return /* @__PURE__ */ jsx(AutoscrollContainer, { children: /* @__PURE__ */ jsx(
1202
- Box,
1203
- {
1204
- ...getVariant("layout.common.chat.history"),
1205
- className: "chat_history",
1206
- children: messages.map((current, i) => {
1207
- let first = false;
1208
- let last = false;
1209
- if (currentType !== current.messageType) {
1210
- currentType = current.messageType;
1211
- first = true;
1212
- }
1213
- if (i === messages.length - 1 || messages[i + 1].messageType !== current.messageType) {
1214
- last = true;
1215
- }
1216
- return /* @__PURE__ */ jsx(
1217
- Message,
1218
- {
1219
- className: first ? "first" : last ? "last" : void 0,
1220
- type: current.messageType,
1221
- id: String(current.id),
1222
- attachments: current.attachments,
1223
- reference: current.reference,
1224
- message: current.message
1225
- }
1226
- );
1227
- })
1228
- }
1229
- ) });
1230
- });
1231
-
1232
- function getBase64FromFile(f) {
1233
- return ((f2) => new Promise((resolve, reject) => {
1234
- const reader = new FileReader();
1235
- reader.readAsDataURL(f2);
1236
- reader.onload = () => resolve(reader.result);
1237
- reader.onerror = () => reject();
1238
- }))(f);
1239
- }
1240
- function getBase64FromBlob(b) {
1241
- return ((blob) => new Promise((resolve, reject) => {
1242
- const reader = new FileReader();
1243
- reader.onloadend = () => {
1244
- const base64String = reader.result;
1245
- resolve(base64String);
1246
- };
1247
- reader.onerror = reject;
1248
- reader.readAsDataURL(blob);
1249
- }))(b);
1250
- }
1251
-
1252
- const TextArea = observer(
1253
- ({
1254
- isLoading,
1255
- isRecording,
1256
- onSubmit,
1257
- onChange,
1258
- onClearHistory,
1259
- onClearAttachments,
1260
- onClearMessage,
1261
- onAttach,
1262
- onRecord,
1263
- onVideoRecord,
1264
- onPrev,
1265
- onNext,
1266
- hideDeleteButton,
1267
- value,
1268
- id
1269
- }) => {
1270
- const fileInputRef = useRef(null);
1271
- const searchControlsRef = useRef(null);
1272
- const recordButton = /* @__PURE__ */ jsx(
1273
- IconButton,
1274
- {
1275
- variant: "icon-only",
1276
- onClick: onRecord,
1277
- disabled: isLoading && !isRecording,
1278
- sx: {
1279
- color: isRecording ? "red" : void 0
1280
- },
1281
- icon: isRecording ? "Stop" : "Microphone",
1282
- id: "transcribeAudio",
1283
- iconSize: "Sm",
1284
- title: getLabel("lblAiRecordAudio").text
1285
- }
1286
- );
1287
- const handleAttachments = async (ev) => {
1288
- if (ev.target.files) {
1289
- for await (const f of ev.target.files) {
1290
- const base64 = await getBase64FromFile(f);
1291
- onAttach({
1292
- value: base64,
1293
- name: f.name,
1294
- id: f.name
1295
- });
1296
- }
1297
- }
1298
- };
1299
- const iconsList = [
1300
- {
1301
- icon: "ArrowLeft",
1302
- children: getLabel("btnAiPrevious").text,
1303
- title: getLabel("btnAiPrevious").text,
1304
- onClick: onPrev,
1305
- key: "0"
1306
- },
1307
- {
1308
- icon: "ArrowRight",
1309
- children: getLabel("btnAiNext").text,
1310
- title: getLabel("btnAiNext").text,
1311
- onClick: onNext,
1312
- key: "1"
1313
- },
1314
- {
1315
- children: getLabel("btnUpload").text,
1316
- title: getLabel("btnUpload").text,
1317
- icon: "File",
1318
- onClick: () => fileInputRef.current?.click(),
1319
- key: "2"
1320
- },
1321
- {
1322
- title: getLabel("lblOpenCamera").text,
1323
- children: getLabel("lblOpenCamera").text,
1324
- icon: "Camera",
1325
- onClick: onVideoRecord,
1326
- key: "3"
1327
- },
1328
- {
1329
- title: getLabel("lblAiRecordAudio").text,
1330
- children: getLabel("lblAiRecordAudio").text,
1331
- key: "4",
1332
- onClick: (event) => onRecord(event),
1333
- icon: isRecording ? "Stop" : "Microphone"
1334
- },
1335
- ...hideDeleteButton ? [] : [
1336
- {
1337
- icon: "Trash",
1338
- onClick: onClearHistory,
1339
- key: "5",
1340
- children: getLabel("btnAiDeleteMessages").text,
1341
- title: getLabel("btnAiDeleteMessages").text
1342
- },
1343
- {
1344
- icon: "Erase",
1345
- title: getLabel("btnAiDelete").text,
1346
- children: getLabel("btnAiDelete").text,
1347
- onClick: () => {
1348
- onClearMessage();
1349
- onClearAttachments();
1350
- },
1351
- key: "6"
1352
- }
1353
- ]
1354
- ];
1355
- return /* @__PURE__ */ jsxs(
1356
- Form,
1357
- {
1358
- id,
1359
- onSubmit: (ev) => {
1360
- ev.preventDefault();
1361
- onSubmit();
1362
- },
1363
- className: "search_controls",
1364
- ...getVariant("layout.common.chat.form"),
1365
- children: [
1366
- /* @__PURE__ */ jsx(
1367
- Textarea,
1368
- {
1369
- ref: searchControlsRef,
1370
- "aria-label": (
1371
- /** TODO: Crear etiqueta para búsqueda */
1372
- "Frase de b\xFAsqueda"
1373
- ),
1374
- value,
1375
- className: "searchTextArea",
1376
- onChange: (ev) => onChange(ev.target.value),
1377
- onKeyDown: (ev) => {
1378
- if (ev.code === "Enter" && !ev.shiftKey) {
1379
- ev.preventDefault();
1380
- ev.target.closest("form").querySelector('[type="submit"]').click();
1381
- }
1382
- }
1383
- }
1384
- ),
1385
- isRecording && recordButton,
1386
- /* @__PURE__ */ jsx(
1387
- "input",
1388
- {
1389
- ref: fileInputRef,
1390
- id: "invisible__attach__file",
1391
- type: "file",
1392
- multiple: true,
1393
- onChange: handleAttachments,
1394
- sx: { display: "none" }
1395
- }
1396
- ),
1397
- /* @__PURE__ */ jsx(
1398
- IconButton,
1399
- {
1400
- disabled: isLoading,
1401
- icon: "Ellipsis",
1402
- variant: "icon-only",
1403
- iconSize: "Sm",
1404
- onClick: (ev) => {
1405
- ApiaUtil.instance.menu.open({
1406
- menuProps: {
1407
- anchorPoint: { x: ev.clientX, y: ev.clientY }
1408
- },
1409
- items: iconsList
1410
- });
1411
- }
1412
- }
1413
- ),
1414
- /* @__PURE__ */ jsx(
1415
- IconButton,
1416
- {
1417
- className: "SearchButton",
1418
- isLoading,
1419
- icon: "ArrowRight",
1420
- variant: "icon-only",
1421
- iconSize: "Sm",
1422
- title: getLabel("btnBus").title,
1423
- type: "submit"
1424
- }
1425
- )
1426
- ]
1427
- }
1428
- );
1429
- }
1430
- );
1431
-
1432
- var __defProp$5 = Object.defineProperty;
1433
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1434
- var __publicField$5 = (obj, key, value) => {
1435
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
1436
- return value;
1437
- };
1438
- class CameraController {
1439
- constructor() {
1440
- __publicField$5(this, "state", {
1441
- videoStream: null,
1442
- isOpen: false
1443
- });
1444
- __publicField$5(this, "currentCapture", null);
1445
- __publicField$5(this, "videoElement");
1446
- __publicField$5(this, "Component", () => {
1447
- return /* @__PURE__ */ jsx(
1448
- "video",
1449
- {
1450
- ref: (el) => {
1451
- if (el) {
1452
- el.srcObject = this.videoElement.srcObject;
1453
- el.autoplay = true;
1454
- el.playsInline = true;
1455
- }
1456
- },
1457
- style: { width: "100%", height: "auto" }
1458
- }
1459
- );
1460
- });
1461
- makeObservable(this, {
1462
- state: observable,
1463
- openCamera: action,
1464
- closeCamera: action
1465
- });
1466
- this.videoElement = document.createElement("video");
1467
- this.videoElement.autoplay = true;
1468
- this.videoElement.playsInline = true;
1469
- }
1470
- async openCamera() {
1471
- try {
1472
- const stream = await navigator.mediaDevices.getUserMedia({ video: true });
1473
- this.state.videoStream = stream;
1474
- this.videoElement.srcObject = stream;
1475
- this.state.isOpen = true;
1476
- ApiaUtil.instance.modals.open({
1477
- children: /* @__PURE__ */ jsx(this.Component, {}),
1478
- onConfirm: () => {
1479
- this.closeCamera();
1480
- },
1481
- onClose: () => {
1482
- this.state.isOpen = false;
1483
- this.closeCamera();
1484
- }
1485
- });
1486
- } catch (error) {
1487
- console.error("Error while accessing the camera:", error);
1488
- this.state.isOpen = false;
1489
- this.closeCamera();
1490
- }
1491
- }
1492
- async closeCamera() {
1493
- if (!this.videoElement.srcObject)
1494
- return null;
1495
- const canvas = document.createElement("canvas");
1496
- canvas.width = this.videoElement.videoWidth;
1497
- canvas.height = this.videoElement.videoHeight;
1498
- const ctx = canvas.getContext("2d");
1499
- if (ctx)
1500
- ctx.drawImage(this.videoElement, 0, 0, canvas.width, canvas.height);
1501
- this.currentCapture = await new Promise((resolve) => {
1502
- canvas.toBlob((blob) => {
1503
- if (blob) {
1504
- const file = new File([blob], "captured_image.jpg", {
1505
- type: "image/jpeg"
1506
- });
1507
- resolve(file);
1508
- } else {
1509
- resolve(null);
1510
- }
1511
- }, "image/jpeg");
1512
- }).finally(() => {
1513
- this.state.videoStream?.getTracks().forEach((track) => track.stop());
1514
- this.state.videoStream = null;
1515
- this.videoElement.srcObject = null;
1516
- this.state.isOpen = false;
1517
- });
1518
- }
1519
- pop() {
1520
- const returnFile = this.currentCapture;
1521
- this.currentCapture = null;
1522
- return returnFile;
1523
- }
1524
- }
1525
-
1526
- var __defProp$4 = Object.defineProperty;
1527
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1528
- var __publicField$4 = (obj, key, value) => {
1529
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
1530
- return value;
1531
- };
1532
- class ChatController2 {
1533
- constructor(props, onMessageSubmit, id, onMessageResponse) {
1534
- this.onMessageSubmit = onMessageSubmit;
1535
- this.id = id;
1536
- this.onMessageResponse = onMessageResponse;
1537
- __publicField$4(this, "currentIndex", 0);
1538
- __publicField$4(this, "state", {
1539
- isVisible: false,
1540
- isLoading: false,
1541
- canRecord: true,
1542
- canAttach: true,
1543
- canAddSystemMessage: true,
1544
- canAddUserMessage: true,
1545
- canShowSystemMessage: true,
1546
- canShowUserMessage: true,
1547
- hideDeleteButton: false,
1548
- maxAttachmentsSize: 100,
1549
- messages: [],
1550
- currentMessage: new ChatMessage("", "user")
1551
- });
1552
- __publicField$4(this, "internalAudioRecorder", new AudioRecorder());
1553
- __publicField$4(this, "internalCameraRecorder", new CameraController());
1554
- __publicField$4(this, "maxId", 0);
1555
- __publicField$4(this, "audioRecorder", {
1556
- start: () => {
1557
- this.internalAudioRecorder.start().then(async (blob) => {
1558
- this.state.currentMessage.attachments.push({
1559
- id: String(this.maxId++),
1560
- name: `userRecord_${this.audioRecorder.record++}.wav`,
1561
- value: await getBase64FromBlob(blob)
1562
- });
1563
- });
1564
- },
1565
- stop: async () => {
1566
- this.internalAudioRecorder.stop();
1567
- },
1568
- record: 0,
1569
- state: this.internalAudioRecorder.state
1570
- });
1571
- __publicField$4(this, "History", observer(() => /* @__PURE__ */ jsx(History, { messages: this.state.messages })));
1572
- __publicField$4(this, "Attachments", observer(() => /* @__PURE__ */ jsx(
1573
- Attachments,
1574
- {
1575
- attachments: this.state.currentMessage.attachments,
1576
- onRemove: (a) => {
1577
- this.removeAttachment(a);
1578
- }
1579
- }
1580
- )));
1581
- __publicField$4(this, "TextArea", observer(() => /* @__PURE__ */ jsx(
1582
- TextArea,
1583
- {
1584
- id: this.id,
1585
- value: this.state.currentMessage.message,
1586
- isLoading: this.state.isLoading,
1587
- isRecording: this.internalAudioRecorder.state.recording,
1588
- onChange: (ev) => {
1589
- this.state.currentMessage.message = ev;
1590
- },
1591
- onSubmit: async () => {
1592
- if (this.state.currentMessage.message || this.state.currentMessage.attachments.length > 0) {
1593
- this.state.isLoading = true;
1594
- if (this.state.canAddUserMessage) {
1595
- this.addMessage(this.state.currentMessage);
1596
- }
1597
- const response = await this.onMessageSubmit({
1598
- message: this.state.currentMessage
1599
- });
1600
- if (this.onMessageResponse) {
1601
- await this.onMessageResponse(response);
1602
- }
1603
- this.state.isLoading = false;
1604
- if (this.state.canAddSystemMessage && response.responseMessage) {
1605
- this.addMessage(response.responseMessage);
1606
- }
1607
- this.state.currentMessage = new ChatMessage("", "user");
1608
- }
1609
- },
1610
- onClearHistory: () => {
1611
- this.clearHistory();
1612
- },
1613
- onClearAttachments: () => {
1614
- this.state.currentMessage.attachments = [];
1615
- },
1616
- onClearMessage: () => {
1617
- this.clearMessage();
1618
- },
1619
- onAttach: async (ev) => {
1620
- this.state.currentMessage.attachments.push({
1621
- ...ev,
1622
- id: String(this.maxId++)
1623
- });
1624
- },
1625
- onRecord: () => {
1626
- !this.internalAudioRecorder.state.recording ? this.audioRecorder.start() : this.audioRecorder.stop();
1627
- },
1628
- onVideoRecord: async () => {
1629
- !this.internalCameraRecorder.state.isOpen && await this.internalCameraRecorder.openCamera();
1630
- await new Promise((resolve, _) => {
1631
- const checkCapture = async () => {
1632
- if (!this.internalCameraRecorder.state.isOpen) {
1633
- const capture = this.internalCameraRecorder.pop();
1634
- if (capture) {
1635
- this.state.currentMessage.attachments.push({
1636
- id: String(this.maxId++),
1637
- name: capture.name,
1638
- value: await getBase64FromFile(capture)
1639
- });
1640
- return resolve();
1641
- }
1642
- } else {
1643
- requestAnimationFrame(checkCapture);
1644
- }
1645
- };
1646
- checkCapture();
1647
- });
1648
- },
1649
- onPrev: () => {
1650
- this.prevMessage();
1651
- },
1652
- onNext: () => {
1653
- this.nextMessage();
1654
- },
1655
- hideDeleteButton: this.state.hideDeleteButton,
1656
- attachments: []
1657
- }
1658
- )));
1659
- __publicField$4(this, "Renderer", () => /* @__PURE__ */ jsxs(
1660
- Box,
1661
- {
1662
- ...getVariant("layout.common.chat.controller"),
1663
- className: "chat_controller",
1664
- children: [
1665
- /* @__PURE__ */ jsx(this.History, {}),
1666
- /* @__PURE__ */ jsx(this.Attachments, {}),
1667
- /* @__PURE__ */ jsx(this.TextArea, {})
1668
- ]
1669
- }
1670
- ));
1671
- this.state = Object.assign({}, this.state, props);
1672
- makeObservable(this, { state: observable });
1673
- }
1674
- removeMessage(idx) {
1675
- this.state.messages = this.state.messages.filter((_, i) => i !== idx);
1676
- }
1677
- addMessage(message) {
1678
- this.state.messages.push(message);
1679
- }
1680
- clearHistory() {
1681
- this.state.messages = [];
1682
- }
1683
- clearMessage() {
1684
- this.state.currentMessage = new ChatMessage("", "user");
1685
- }
1686
- removeAttachment(attachment) {
1687
- this.state.currentMessage.attachments = this.state.currentMessage.attachments.filter((x) => x !== attachment);
1688
- }
1689
- isValidToShow(message) {
1690
- return message && (message.messageType === "system" && this.state.canShowSystemMessage || message.messageType === "user" && this.state.canShowUserMessage);
1691
- }
1692
- nextMessage() {
1693
- let newCurrentMessage = void 0;
1694
- let i = this.currentIndex;
1695
- const n = this.state.messages.length;
1696
- if (n === 0) {
1697
- return;
1698
- }
1699
- while (!newCurrentMessage) {
1700
- if (i === -1 || i === n - 1) {
1701
- newCurrentMessage = this.state.messages[0];
1702
- i = 0;
1703
- } else if (i < n - 1) {
1704
- newCurrentMessage = this.state.messages[i + 1];
1705
- i++;
1706
- }
1707
- if (this.isValidToShow(newCurrentMessage)) {
1708
- this.state.currentMessage = newCurrentMessage.clone();
1709
- break;
1710
- } else {
1711
- newCurrentMessage = void 0;
1712
- }
1713
- if (i === this.currentIndex) {
1714
- break;
1715
- }
1716
- }
1717
- this.currentIndex = i;
1718
- }
1719
- prevMessage() {
1720
- let newCurrentMessage = void 0;
1721
- let i = this.currentIndex;
1722
- const n = this.state.messages.length;
1723
- if (n === 0) {
1724
- return;
1725
- }
1726
- while (!newCurrentMessage) {
1727
- if (i === -1 || i === 0) {
1728
- newCurrentMessage = this.state.messages[n - 1];
1729
- i = n - 1;
1730
- } else if (i > 0) {
1731
- newCurrentMessage = this.state.messages[i - 1];
1732
- i--;
1733
- }
1734
- if (this.isValidToShow(newCurrentMessage)) {
1735
- this.state.currentMessage = newCurrentMessage.clone();
1736
- break;
1737
- } else {
1738
- newCurrentMessage = void 0;
1739
- }
1740
- if (i === this.currentIndex) {
1741
- break;
1742
- }
1743
- }
1744
- this.currentIndex = i;
1745
- }
1746
- }
1747
-
1748
- var __defProp$3 = Object.defineProperty;
1749
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1750
- var __publicField$3 = (obj, key, value) => {
1751
- __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
1752
- return value;
1753
- };
1754
- class FloatingChatController extends ChatController2 {
1755
- constructor(props, onMessageSubmit, id, onMessageResponse) {
1756
- super(props, onMessageSubmit, id, onMessageResponse);
1757
- __publicField$3(this, "Window", observer(() => {
1758
- return /* @__PURE__ */ jsx(
1759
- IconButton,
1760
- {
1761
- icon: "Magic",
1762
- size: "Md",
1763
- variant: "icon-outline",
1764
- onClick: () => {
1765
- this.state.isVisible = true;
1766
- this.open();
1767
- }
1768
- }
1769
- );
1770
- }));
1771
- makeObservable({ open: action });
1772
- }
1773
- open() {
1774
- ApiaUtil.instance.modals.open({
1775
- variant: "layout.common.chat.assistant.floatingAssistant",
1776
- defaultPosition: {
1777
- bottom: "10px",
1778
- right: "50px"
1779
- },
1780
- draggable: true,
1781
- children: /* @__PURE__ */ jsx(this.Renderer, {}),
1782
- onClose: () => {
1783
- this.state.isVisible = false;
1784
- }
1785
- });
1786
- }
1787
- }
1788
88
 
1789
89
  var __defProp$2 = Object.defineProperty;
1790
90
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -2015,8 +315,8 @@ class ResponseStream extends EventEmitter {
2015
315
  __publicField$1(this, "buffer", "");
2016
316
  __publicField$1(this, "isRunning", false);
2017
317
  __publicField$1(this, "locked", false);
2018
- __publicField$1(this, "maxCompletionTime", 2);
2019
- // s
318
+ __publicField$1(this, "maxCompletionTime", 150);
319
+ // ms
2020
320
  __publicField$1(this, "minPartSize", 2);
2021
321
  __publicField$1(this, "partSize", 2);
2022
322
  __publicField$1(this, "timing", 5);
@@ -2027,7 +327,7 @@ class ResponseStream extends EventEmitter {
2027
327
  const totalSize = this.buffer.length + this.waiting.reduce((a, b) => a + b.length, 0);
2028
328
  this.partSize = Math.max(
2029
329
  this.minPartSize,
2030
- totalSize * this.timing / (this.maxCompletionTime * 1e3)
330
+ totalSize * (this.timing / this.maxCompletionTime)
2031
331
  );
2032
332
  }
2033
333
  emit(_, data) {
@@ -2266,81 +566,29 @@ const ViewRendererContext = createContext(
2266
566
  {}
2267
567
  );
2268
568
 
2269
- const WindowDragger = forwardRef((props, outerRef) => {
2270
- const isDragging = useRef(false);
2271
- const initialPosition = useRef({ mousex: 0, mousey: 0, boxx: 0, boxy: 0 });
2272
- const ref = useRef(null);
2273
- useEffect(() => {
2274
- const handleMouseMove = (ev) => {
2275
- if (isDragging.current && ref.current) {
2276
- const newx = ev.clientX;
2277
- const newy = ev.clientY;
2278
- const difx = newx - initialPosition.current.mousex;
2279
- const dify = newy - initialPosition.current.mousey;
2280
- ref.current.style.left = `${initialPosition.current.boxx + difx}px`;
2281
- ref.current.style.top = `${initialPosition.current.boxy + dify}px`;
2282
- ref.current.style.bottom = "auto";
2283
- ref.current.style.right = "auto";
2284
- ref.current.style.zIndex = "1200";
2285
- }
2286
- };
2287
- const handleMouseUp = () => {
2288
- isDragging.current = false;
2289
- };
2290
- const handleWindowResize = () => {
2291
- if (ref.current) {
2292
- const bounding = ref.current.getBoundingClientRect();
2293
- if (window.innerWidth < bounding.left + bounding.width) {
2294
- const newx = window.innerWidth - bounding.width;
2295
- ref.current.style.left = `${newx}px`;
2296
- }
2297
- if (window.innerHeight < bounding.top + bounding.height) {
2298
- const newy = window.innerHeight - bounding.height;
2299
- ref.current.style.top = `${newy}px`;
2300
- }
2301
- }
2302
- };
2303
- document.addEventListener("mousemove", handleMouseMove);
2304
- document.addEventListener("mouseup", handleMouseUp);
2305
- window.addEventListener("resize", handleWindowResize);
2306
- return () => {
2307
- document.removeEventListener("mousemove", handleMouseMove);
2308
- document.removeEventListener("mouseup", handleMouseUp);
2309
- window.removeEventListener("resize", handleWindowResize);
2310
- };
2311
- }, []);
2312
- return /* @__PURE__ */ jsx(
2313
- Box,
2314
- {
2315
- ref,
2316
- className: "windowDragger",
2317
- onMouseDown: (ev) => {
2318
- if (ev.target instanceof Element && (ev.target.nodeName === "TEXTAREA" || ev.target.classList.contains("history__message")))
2319
- return;
2320
- const target = ev.target.closest?.(
2321
- ".windowDragger"
2322
- );
2323
- if (target) {
2324
- const bounding = target.getBoundingClientRect();
2325
- isDragging.current = true;
2326
- initialPosition.current = {
2327
- mousex: ev.clientX,
2328
- mousey: ev.clientY,
2329
- boxx: bounding.left,
2330
- boxy: bounding.top
2331
- };
2332
- }
2333
- },
2334
- sx: {
2335
- position: "fixed",
2336
- bottom: "260px",
2337
- right: "10px",
2338
- ...props.style
2339
- },
2340
- children: props.children
2341
- }
2342
- );
2343
- });
569
+ class MultipleChoiceMessage extends ChatMessage {
570
+ constructor(question, options, Renderer) {
571
+ super(
572
+ Renderer ? /* @__PURE__ */ jsxs(Box, { className: "multipleChoiceMessage customRenderer", children: [
573
+ /* @__PURE__ */ jsx(Paragraph, { children: question }),
574
+ options.map((item) => /* @__PURE__ */ jsx(Renderer, { item }, item.url))
575
+ ] }) : /* @__PURE__ */ jsxs(Box, { className: "multipleChoiceMessage", children: [
576
+ /* @__PURE__ */ jsx(Paragraph, { children: question }),
577
+ /* @__PURE__ */ jsx(Box, { as: "ul", children: options.map((current) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
578
+ SimpleButton,
579
+ {
580
+ className: "multipleChoice__option",
581
+ onClick: () => {
582
+ ApiaUtil.instance.tabs.openTab(current.label, current.url);
583
+ },
584
+ children: current.label
585
+ }
586
+ ) }, current.label)) })
587
+ ] }),
588
+ "multipleChoice"
589
+ );
590
+ }
591
+ }
2344
592
 
2345
- export { AIFileContent, AIMessageAttachments, AutoscrollContainer, ChatController, ChatController2, ChatMessage, DashboardsRoutinesGeneration, FloatingChatController, MultipleChoiceMessage, ResponseStream, RoutinesGeneration, SearchController$1 as SearchController, SemanticSearchReference as SemanticSearchResult, ViewRendererContext, WindowDragger, getImageFromDisk, getImagesFromDisk, getImagesWithDescription };
593
+ export { DashboardsRoutinesGeneration, MultipleChoiceMessage, ResponseStream, RoutinesGeneration, SearchController, SemanticSearchReference as SemanticSearchResult, ViewRendererContext, getImageFromDisk, getImagesFromDisk, getImagesWithDescription };
2346
594
  //# sourceMappingURL=index.js.map