@memori.ai/memori-react 8.42.0 → 8.44.0

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.
Files changed (164) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +1 -1
  3. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js +1 -1
  4. package/dist/components/Chat/Chat.js +1 -1
  5. package/dist/components/Chat/Chat.js.map +1 -1
  6. package/dist/components/ChatHistoryDrawer/ChatResumeDrawer.css +6 -1
  7. package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
  8. package/dist/components/ChatInputs/ChatInputs.js +2 -2
  9. package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
  10. package/dist/components/IconButton/IconButton.css +144 -0
  11. package/dist/components/IconButton/IconButton.d.ts +9 -0
  12. package/dist/components/IconButton/IconButton.js +36 -0
  13. package/dist/components/IconButton/IconButton.js.map +1 -0
  14. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +1 -0
  15. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  16. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +204 -59
  17. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  18. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +1 -1
  19. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  20. package/dist/components/MemoriArtifactSystem/context/ArtifactContext.d.ts +3 -1
  21. package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js +76 -16
  22. package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
  23. package/dist/components/MemoriArtifactSystem/types/artifact.types.d.ts +11 -0
  24. package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js +18 -13
  25. package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -1
  26. package/dist/components/MemoriArtifactSystem/utils/applyEdits.d.ts +8 -0
  27. package/dist/components/MemoriArtifactSystem/utils/applyEdits.js +117 -0
  28. package/dist/components/MemoriArtifactSystem/utils/applyEdits.js.map +1 -0
  29. package/dist/components/MobileSessionPanel/MobileSessionPanel.css +29 -7
  30. package/dist/components/MobileSessionPanel/MobileSessionPanel.d.ts +3 -0
  31. package/dist/components/MobileSessionPanel/MobileSessionPanel.js +8 -6
  32. package/dist/components/MobileSessionPanel/MobileSessionPanel.js.map +1 -1
  33. package/dist/components/PositionPopover/PositionPopover.d.ts +2 -0
  34. package/dist/components/PositionPopover/PositionPopover.js +19 -11
  35. package/dist/components/PositionPopover/PositionPopover.js.map +1 -1
  36. package/dist/components/UploadButton/UploadButton.d.ts +1 -0
  37. package/dist/components/UploadButton/UploadButton.js +12 -18
  38. package/dist/components/UploadButton/UploadButton.js.map +1 -1
  39. package/dist/components/UploadButton/UploadDocuments/UploadDocuments.d.ts +1 -6
  40. package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js +7 -139
  41. package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
  42. package/dist/components/icons/Print.js +1 -1
  43. package/dist/components/icons/Print.js.map +1 -1
  44. package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js +24 -3
  45. package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
  46. package/dist/components/layouts/WebsiteAssistant/website-assistant.css +137 -55
  47. package/dist/components/layouts/fullpage.css +165 -68
  48. package/dist/helpers/constants.d.ts +1 -0
  49. package/dist/helpers/constants.js +24 -1
  50. package/dist/helpers/constants.js.map +1 -1
  51. package/dist/helpers/convertDocument.d.ts +1 -0
  52. package/dist/helpers/convertDocument.js +24 -0
  53. package/dist/helpers/convertDocument.js.map +1 -0
  54. package/dist/helpers/message.js +3 -0
  55. package/dist/helpers/message.js.map +1 -1
  56. package/dist/helpers/positionPopover.d.ts +1 -1
  57. package/dist/helpers/positionPopover.js +2 -2
  58. package/dist/helpers/positionPopover.js.map +1 -1
  59. package/dist/helpers/tts/muteSpeaker.d.ts +13 -0
  60. package/dist/helpers/tts/muteSpeaker.js +26 -0
  61. package/dist/helpers/tts/muteSpeaker.js.map +1 -0
  62. package/dist/locales/de.json +3 -0
  63. package/dist/locales/en.json +3 -0
  64. package/dist/locales/es.json +3 -0
  65. package/dist/locales/fr.json +3 -0
  66. package/dist/locales/it.json +3 -0
  67. package/dist/version.d.ts +1 -1
  68. package/dist/version.js +1 -1
  69. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +1 -1
  70. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js +1 -1
  71. package/esm/components/Chat/Chat.js +1 -1
  72. package/esm/components/Chat/Chat.js.map +1 -1
  73. package/esm/components/ChatHistoryDrawer/ChatResumeDrawer.css +6 -1
  74. package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
  75. package/esm/components/ChatInputs/ChatInputs.js +2 -2
  76. package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
  77. package/esm/components/IconButton/IconButton.css +144 -0
  78. package/esm/components/IconButton/IconButton.d.ts +9 -0
  79. package/esm/components/IconButton/IconButton.js +33 -0
  80. package/esm/components/IconButton/IconButton.js.map +1 -0
  81. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +1 -0
  82. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  83. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +205 -60
  84. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  85. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +2 -2
  86. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  87. package/esm/components/MemoriArtifactSystem/context/ArtifactContext.d.ts +3 -1
  88. package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js +77 -17
  89. package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
  90. package/esm/components/MemoriArtifactSystem/types/artifact.types.d.ts +11 -0
  91. package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js +18 -13
  92. package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -1
  93. package/esm/components/MemoriArtifactSystem/utils/applyEdits.d.ts +8 -0
  94. package/esm/components/MemoriArtifactSystem/utils/applyEdits.js +112 -0
  95. package/esm/components/MemoriArtifactSystem/utils/applyEdits.js.map +1 -0
  96. package/esm/components/MobileSessionPanel/MobileSessionPanel.css +29 -7
  97. package/esm/components/MobileSessionPanel/MobileSessionPanel.d.ts +3 -0
  98. package/esm/components/MobileSessionPanel/MobileSessionPanel.js +8 -6
  99. package/esm/components/MobileSessionPanel/MobileSessionPanel.js.map +1 -1
  100. package/esm/components/PositionPopover/PositionPopover.d.ts +2 -0
  101. package/esm/components/PositionPopover/PositionPopover.js +20 -12
  102. package/esm/components/PositionPopover/PositionPopover.js.map +1 -1
  103. package/esm/components/UploadButton/UploadButton.d.ts +1 -0
  104. package/esm/components/UploadButton/UploadButton.js +13 -19
  105. package/esm/components/UploadButton/UploadButton.js.map +1 -1
  106. package/esm/components/UploadButton/UploadDocuments/UploadDocuments.d.ts +1 -6
  107. package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js +8 -140
  108. package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
  109. package/esm/components/icons/Print.js +1 -1
  110. package/esm/components/icons/Print.js.map +1 -1
  111. package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js +24 -3
  112. package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
  113. package/esm/components/layouts/WebsiteAssistant/website-assistant.css +137 -55
  114. package/esm/components/layouts/fullpage.css +165 -68
  115. package/esm/helpers/constants.d.ts +1 -0
  116. package/esm/helpers/constants.js +23 -0
  117. package/esm/helpers/constants.js.map +1 -1
  118. package/esm/helpers/convertDocument.d.ts +1 -0
  119. package/esm/helpers/convertDocument.js +20 -0
  120. package/esm/helpers/convertDocument.js.map +1 -0
  121. package/esm/helpers/message.js +3 -0
  122. package/esm/helpers/message.js.map +1 -1
  123. package/esm/helpers/positionPopover.d.ts +1 -1
  124. package/esm/helpers/positionPopover.js +2 -2
  125. package/esm/helpers/positionPopover.js.map +1 -1
  126. package/esm/helpers/tts/muteSpeaker.d.ts +13 -0
  127. package/esm/helpers/tts/muteSpeaker.js +21 -0
  128. package/esm/helpers/tts/muteSpeaker.js.map +1 -0
  129. package/esm/locales/de.json +3 -0
  130. package/esm/locales/en.json +3 -0
  131. package/esm/locales/es.json +3 -0
  132. package/esm/locales/fr.json +3 -0
  133. package/esm/locales/it.json +3 -0
  134. package/esm/version.d.ts +1 -1
  135. package/esm/version.js +1 -1
  136. package/package.json +2 -2
  137. package/src/components/Avatar/AvatarView/AvatarComponent/constants.ts +1 -1
  138. package/src/components/Chat/Chat.tsx +1 -0
  139. package/src/components/ChatInputs/ChatInputs.tsx +3 -0
  140. package/src/components/FilePreview/FilePreview.stories.tsx +0 -3
  141. package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +1 -0
  142. package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +324 -133
  143. package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.tsx +2 -2
  144. package/src/components/MemoriArtifactSystem/context/ArtifactContext.tsx +122 -24
  145. package/src/components/MemoriArtifactSystem/types/artifact.types.ts +20 -1
  146. package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.test.tsx +1 -0
  147. package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.tsx +19 -13
  148. package/src/components/MemoriArtifactSystem/utils/applyEdits.test.ts +85 -0
  149. package/src/components/MemoriArtifactSystem/utils/applyEdits.ts +173 -0
  150. package/src/components/UploadButton/UploadButton.stories.tsx +2 -2
  151. package/src/components/UploadButton/UploadButton.tsx +19 -19
  152. package/src/components/UploadButton/UploadDocuments/UploadDocuments.tsx +13 -187
  153. package/src/components/UploadButton/__snapshots__/UploadButton.test.tsx.snap +2 -2
  154. package/src/components/icons/Print.tsx +6 -2
  155. package/src/helpers/constants.ts +24 -0
  156. package/src/helpers/convertDocument.test.ts +67 -0
  157. package/src/helpers/convertDocument.ts +35 -0
  158. package/src/helpers/message.ts +15 -0
  159. package/src/locales/de.json +3 -0
  160. package/src/locales/en.json +3 -0
  161. package/src/locales/es.json +3 -0
  162. package/src/locales/fr.json +3 -0
  163. package/src/locales/it.json +3 -0
  164. package/src/version.ts +1 -1
@@ -9,13 +9,17 @@ import UploadDocuments from './UploadDocuments/UploadDocuments';
9
9
  import UploadImages from './UploadImages/UploadImages';
10
10
  import { useTranslation } from 'react-i18next';
11
11
  import memoriApiClient from '@memori.ai/memori-api-client';
12
- import { officeNativeExtensions } from '../../helpers/constants';
12
+ import {
13
+ documentConversionExtensions,
14
+ officeNativeExtensions,
15
+ } from '../../helpers/constants';
13
16
  import Tooltip from '../ui/Tooltip';
14
17
  // Props interface
15
18
  interface UploadManagerProps {
16
19
  authToken?: string;
17
20
  client?: ReturnType<typeof memoriApiClient>;
18
21
  sessionID?: string;
22
+ baseUrl?: string;
19
23
  isMediaAccepted?: boolean;
20
24
  setDocumentPreviewFiles: any;
21
25
  documentPreviewFiles: {
@@ -40,6 +44,7 @@ const UploadButton: React.FC<UploadManagerProps> = ({
40
44
  authToken = '',
41
45
  client,
42
46
  sessionID = '',
47
+ baseUrl = '',
43
48
  isMediaAccepted = false,
44
49
  setDocumentPreviewFiles,
45
50
  documentPreviewFiles,
@@ -101,14 +106,8 @@ const UploadButton: React.FC<UploadManagerProps> = ({
101
106
 
102
107
  // Check if file is a document
103
108
  const isDocumentFile = (file: File): boolean => {
104
- const documentExtensions = [
105
- '.pdf',
106
- '.txt',
107
- '.json',
108
- '.xlsx',
109
- '.csv',
110
- '.md',
111
- '.html',
109
+ const documentExtensions: readonly string[] = [
110
+ ...documentConversionExtensions,
112
111
  ...officeNativeExtensions,
113
112
  ];
114
113
  const fileExt = `.${file.name.split('.').pop()?.toLowerCase()}`;
@@ -453,17 +452,11 @@ ${file.textAssetUrl || ''}
453
452
  // Document validation and error handling
454
453
  const validateDocumentFile = (file: File): boolean => {
455
454
  const fileExt = `.${file.name.split('.').pop()?.toLowerCase()}`;
456
- const ALLOWED_FILE_TYPES = [
457
- '.pdf',
458
- '.txt',
459
- '.json',
460
- '.xlsx',
461
- '.csv',
462
- '.md',
463
- '.html',
455
+ const ALLOWED_FILE_TYPES: readonly string[] = [
456
+ ...documentConversionExtensions,
464
457
  ...officeNativeExtensions,
465
458
  ];
466
- const MAX_FILE_SIZE = 15 * 1024 * 1024; // 15MB
459
+ const MAX_FILE_SIZE = 25 * 1024 * 1024;
467
460
 
468
461
  if (!ALLOWED_FILE_TYPES.includes(fileExt)) {
469
462
  addError({
@@ -578,7 +571,13 @@ ${file.textAssetUrl || ''}
578
571
  <input
579
572
  ref={unifiedInputRef}
580
573
  type="file"
581
- accept={`.jpg,.jpeg,.png,.pdf,.txt,.json,.xlsx,.csv,.md,.html,${officeNativeExtensions.join(',')}`}
574
+ accept={[
575
+ '.jpg',
576
+ '.jpeg',
577
+ '.png',
578
+ ...documentConversionExtensions,
579
+ ...officeNativeExtensions,
580
+ ].join(',')}
582
581
  multiple
583
582
  className="memori--upload-file-input"
584
583
  onChange={handleFileInputChange}
@@ -634,6 +633,7 @@ ${file.textAssetUrl || ''}
634
633
  authToken={authToken}
635
634
  client={client}
636
635
  sessionID={sessionID}
636
+ baseUrl={baseUrl}
637
637
  memoriID={memoriID}
638
638
  maxDocuments={maxDocumentsPerMessage}
639
639
  documentPreviewFiles={documentPreviewFiles}
@@ -5,8 +5,12 @@ import { DocumentIcon } from '../../icons/Document';
5
5
  import Modal from '../../ui/Modal';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import memoriApiClient from '@memori.ai/memori-api-client';
8
- import { officeNativeExtensions } from '../../../helpers/constants';
8
+ import {
9
+ documentConversionExtensions,
10
+ officeNativeExtensions,
11
+ } from '../../../helpers/constants';
9
12
  import { isOfficeNativeFilename } from '../../../helpers/utils';
13
+ import { convertDocument } from '../../../helpers/convertDocument';
10
14
  // Types
11
15
  type PreviewFile = {
12
16
  name: string;
@@ -18,21 +22,6 @@ type PreviewFile = {
18
22
  error?: boolean;
19
23
  };
20
24
 
21
- // Constants
22
- const PDF_JS_VERSION = '3.11.174';
23
- const WORKER_URL = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${PDF_JS_VERSION}/pdf.worker.min.js`;
24
- const PDF_JS_URL = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${PDF_JS_VERSION}/pdf.min.js`;
25
- const XLSX_URL =
26
- 'https://cdn.sheetjs.com/xlsx-0.20.0/package/dist/xlsx.full.min.js';
27
-
28
- // Add type definitions for external libraries
29
- declare global {
30
- interface Window {
31
- pdfjsLib: any;
32
- XLSX: any;
33
- }
34
- }
35
-
36
25
  // Props interface
37
26
  interface UploadDocumentsProps {
38
27
  setDocumentPreviewFiles: (
@@ -47,6 +36,7 @@ interface UploadDocumentsProps {
47
36
  authToken?: string;
48
37
  client?: ReturnType<typeof memoriApiClient>;
49
38
  sessionID?: string;
39
+ baseUrl?: string;
50
40
  memoriID?: string;
51
41
  maxDocuments?: number;
52
42
  documentPreviewFiles: any;
@@ -71,6 +61,7 @@ const UploadDocuments: React.FC<UploadDocumentsProps> = ({
71
61
  authToken = '',
72
62
  client,
73
63
  sessionID = '',
64
+ baseUrl = '',
74
65
  memoriID = '',
75
66
  maxDocuments,
76
67
  documentPreviewFiles,
@@ -123,182 +114,19 @@ const UploadDocuments: React.FC<UploadDocumentsProps> = ({
123
114
  return { valid: true };
124
115
  };
125
116
 
126
- const extractTextFromPDF = async (file: File): Promise<string> => {
127
- try {
128
- // Load PDF.js if not already loaded
129
- if (!window.pdfjsLib) {
130
- await new Promise((resolve, reject) => {
131
- const script = document.createElement('script');
132
- script.src = PDF_JS_URL;
133
- script.onload = () => {
134
- window.pdfjsLib.GlobalWorkerOptions.workerSrc = WORKER_URL;
135
- resolve(true);
136
- };
137
- script.onerror = reject;
138
- document.head.appendChild(script);
139
- });
140
- }
141
-
142
- // Extract text from PDF
143
- const arrayBuffer = await file.arrayBuffer();
144
- const pdf = await window.pdfjsLib.getDocument({ data: arrayBuffer })
145
- .promise;
146
- let text = '';
147
-
148
- // Iterate through each page and extract text
149
- for (let i = 1; i <= pdf.numPages; i++) {
150
- const page = await pdf.getPage(i);
151
- const content = await page.getTextContent();
152
- const pageText = content.items
153
- .filter((item: any) => item.str && typeof item.str === 'string')
154
- .map((item: any) => item.str)
155
- .join(' ');
156
- text += pageText + '\n';
157
- }
158
-
159
- return text;
160
- } catch (error) {
161
- console.error('PDF extraction failed:', error);
162
- throw new Error(
163
- `PDF extraction failed: ${
164
- error instanceof Error ? error.message : 'Unknown error'
165
- }`
166
- );
167
- }
168
- };
169
-
170
- const loadXLSXLibrary = async (): Promise<void> => {
171
- if (window.XLSX) return;
172
-
173
- await new Promise((resolve, reject) => {
174
- const script = document.createElement('script');
175
- script.src = XLSX_URL;
176
- script.onload = resolve;
177
- script.onerror = reject;
178
- document.head.appendChild(script);
179
- });
180
- };
181
-
182
- const readXLSXWorkbook = async (file: File) => {
183
- await loadXLSXLibrary();
184
-
185
- const arrayBuffer = await file.arrayBuffer();
186
- return window.XLSX.read(arrayBuffer, {
187
- type: 'array',
188
- cellFormula: true,
189
- cellNF: true,
190
- cellText: true,
191
- cellDates: true,
192
- });
193
- };
194
-
195
- const formatXLSXWorkbookForDisplay = (workbook: {
196
- SheetNames: string[];
197
- Sheets: Record<string, unknown>;
198
- }): string => {
199
- let text = '';
200
-
201
- for (const sheetName of workbook.SheetNames) {
202
- const worksheet = workbook.Sheets[sheetName];
203
- const data = window.XLSX.utils.sheet_to_json(worksheet, {
204
- header: 1,
205
- raw: false,
206
- });
207
-
208
- const colWidths = data.reduce((widths: number[], row: any[]) => {
209
- row.forEach((cell, i) => {
210
- const cellWidth = (cell || '').toString().length;
211
- widths[i] = Math.max(widths[i] || 0, cellWidth);
212
- });
213
- return widths;
214
- }, []);
215
-
216
- const formattedText = data.map((row: any[]) => {
217
- return row
218
- .map((cell, i) => {
219
- const cellStr = (cell || '').toString();
220
- return cellStr.padEnd(colWidths[i] + 2);
221
- })
222
- .join('|')
223
- .trim();
224
- });
225
-
226
- if (formattedText.length > 0) {
227
- const separator = colWidths
228
- .map((w: number) => '-'.repeat(w + 2))
229
- .join('+');
230
- formattedText.splice(1, 0, separator);
231
- }
232
-
233
- text += `Sheet: ${sheetName}\n${formattedText.join('\n')}\n\n`;
234
- }
235
-
236
- return text;
237
- };
238
-
239
- const formatXLSXWorkbookAsCsv = (workbook: {
240
- SheetNames: string[];
241
- Sheets: Record<string, unknown>;
242
- }): string => {
243
- let text = '';
244
-
245
- for (const sheetName of workbook.SheetNames) {
246
- const worksheet = workbook.Sheets[sheetName];
247
- const csv = window.XLSX.utils.sheet_to_csv(worksheet, { raw: false });
248
- if (csv.trim()) {
249
- text += `Sheet: ${sheetName}\n${csv}\n\n`;
250
- }
251
- }
252
-
253
- return text;
254
- };
255
-
256
- const extractTextFromXLSX = async (
257
- file: File
258
- ): Promise<{ display: string; asset: string }> => {
259
- try {
260
- const workbook = await readXLSXWorkbook(file);
261
- return {
262
- display: formatXLSXWorkbookForDisplay(workbook),
263
- asset: formatXLSXWorkbookAsCsv(workbook),
264
- };
265
- } catch (error) {
266
- console.error('XLSX extraction failed:', error);
267
- throw new Error(
268
- `XLSX extraction failed: ${
269
- error instanceof Error ? error.message : 'Unknown error'
270
- }`
271
- );
272
- }
273
- };
274
-
275
117
  const processDocumentFile = async (
276
118
  file: File
277
119
  ): Promise<{
278
120
  text: string | null;
279
- textForAsset?: string;
280
121
  uploadAsOriginal?: boolean;
281
122
  }> => {
282
123
  if (isOfficeNativeFilename(file.name)) {
283
124
  return { text: null, uploadAsOriginal: true };
284
125
  }
285
126
 
286
- const ext = file.name.split('.').pop()?.toLowerCase() || '';
287
127
  try {
288
- let text: string | null = null;
289
- let textForAsset: string | undefined;
290
-
291
- if (ext === 'pdf') {
292
- text = await extractTextFromPDF(file);
293
- } else if (['txt', 'md', 'json', 'csv', 'html'].includes(ext)) {
294
- text = await file.text();
295
- } else if (ext === 'xlsx') {
296
- const extracted = await extractTextFromXLSX(file);
297
- text = extracted.display;
298
- textForAsset = extracted.asset;
299
- }
300
-
301
- return { text, textForAsset };
128
+ const text = await convertDocument(file, sessionID, baseUrl);
129
+ return { text };
302
130
  } catch (error) {
303
131
  console.error('Document processing failed:', error);
304
132
  throw new Error(
@@ -414,8 +242,7 @@ const UploadDocuments: React.FC<UploadDocumentsProps> = ({
414
242
  const fileId = Math.random().toString(36).substr(2, 9);
415
243
 
416
244
  try {
417
- const { text, textForAsset, uploadAsOriginal } =
418
- await processDocumentFile(file);
245
+ const { text, uploadAsOriginal } = await processDocumentFile(file);
419
246
 
420
247
  if (uploadAsOriginal) {
421
248
  // Office native format: upload the original file as asset, no text extraction
@@ -448,8 +275,7 @@ const UploadDocuments: React.FC<UploadDocumentsProps> = ({
448
275
  });
449
276
  } else if (text) {
450
277
  const baseName = file.name.replace(/\.[^/.]+$/, '') || file.name;
451
- const assetText = textForAsset ?? text;
452
- const textFile = new File([assetText], `${baseName}.txt`, {
278
+ const textFile = new File([text], `${baseName}.txt`, {
453
279
  type: 'text/plain',
454
280
  });
455
281
 
@@ -514,9 +340,9 @@ const UploadDocuments: React.FC<UploadDocumentsProps> = ({
514
340
  <input
515
341
  ref={documentInputRef}
516
342
  type="file"
517
- accept={`.pdf,.txt,.md,.json,.xlsx,.csv,.html,${officeNativeExtensions.join(
343
+ accept={[...documentConversionExtensions, ...officeNativeExtensions].join(
518
344
  ','
519
- )}`}
345
+ )}
520
346
  multiple
521
347
  className="memori--upload-file-input"
522
348
  onChange={handleDocumentUpload}
@@ -6,7 +6,7 @@ exports[`renders UploadButton unchanged 1`] = `
6
6
  class="memori--unified-upload-wrapper"
7
7
  >
8
8
  <input
9
- accept=".jpg,.jpeg,.png,.pdf,.txt,.json,.xlsx,.csv,.md,.html,.doc,.docx,.dotx,.xltx,.potx"
9
+ accept=".jpg,.jpeg,.png,.pdf,.docm,.xlsx,.xlsm,.xls,.ods,.pptx,.pptm,.html,.htm,.xhtml,.csv,.tsv,.txt,.md,.markdown,.json,.xml,.log,.yml,.yaml,.doc,.docx,.dotx,.xltx,.potx"
10
10
  class="memori--upload-file-input"
11
11
  multiple=""
12
12
  style="display: none;"
@@ -52,7 +52,7 @@ exports[`renders UploadButton unchanged 1`] = `
52
52
  class="memori--document-upload-wrapper"
53
53
  >
54
54
  <input
55
- accept=".pdf,.txt,.md,.json,.xlsx,.csv,.html,.doc,.docx,.dotx,.xltx,.potx"
55
+ accept=".pdf,.docm,.xlsx,.xlsm,.xls,.ods,.pptx,.pptm,.html,.htm,.xhtml,.csv,.tsv,.txt,.md,.markdown,.json,.xml,.log,.yml,.yaml,.doc,.docx,.dotx,.xltx,.potx"
56
56
  class="memori--upload-file-input"
57
57
  multiple=""
58
58
  type="file"
@@ -1,5 +1,9 @@
1
1
  import * as React from 'react';
2
- const PrintIcon: React.FC<{ className?: string, title?: string }> = ({ className, title }) => (
2
+
3
+ const PrintIcon: React.FC<{ className?: string; title?: string }> = ({
4
+ className,
5
+ title,
6
+ }) => (
3
7
  <svg
4
8
  {...(!title ? { 'aria-hidden': 'true' } : {})}
5
9
  aria-label={title}
@@ -14,7 +18,7 @@ const PrintIcon: React.FC<{ className?: string, title?: string }> = ({ className
14
18
  <g
15
19
  id="Page-1"
16
20
  stroke="none"
17
- stroke-width="1"
21
+ strokeWidth="1"
18
22
  fill="none"
19
23
  fill-rule="evenodd"
20
24
  >
@@ -52,6 +52,30 @@ export const officeNativeExtensions = [
52
52
  '.potx',
53
53
  ] as const;
54
54
 
55
+ export const documentConversionExtensions = [
56
+ '.pdf',
57
+ '.docm',
58
+ '.xlsx',
59
+ '.xlsm',
60
+ '.xls',
61
+ '.ods',
62
+ '.pptx',
63
+ '.pptm',
64
+ '.html',
65
+ '.htm',
66
+ '.xhtml',
67
+ '.csv',
68
+ '.tsv',
69
+ '.txt',
70
+ '.md',
71
+ '.markdown',
72
+ '.json',
73
+ '.xml',
74
+ '.log',
75
+ '.yml',
76
+ '.yaml',
77
+ ] as const;
78
+
55
79
  export const allowedMediaTypes = [
56
80
  'image/jpeg',
57
81
  'image/png',
@@ -0,0 +1,67 @@
1
+ import { convertDocument } from './convertDocument';
2
+
3
+ describe('convertDocument', () => {
4
+ const fetchMock = jest.fn();
5
+
6
+ beforeEach(() => {
7
+ fetchMock.mockReset();
8
+ globalThis.fetch = fetchMock as unknown as typeof fetch;
9
+ });
10
+
11
+ it('uploads a file through the session-gated endpoint', async () => {
12
+ fetchMock.mockResolvedValue({
13
+ ok: true,
14
+ json: jest.fn().mockResolvedValue({ text: '# Converted document' }),
15
+ });
16
+ const file = new File(['document'], 'contract.pdf', {
17
+ type: 'application/pdf',
18
+ });
19
+
20
+ await expect(
21
+ convertDocument(file, 'session/id', 'https://www.aisuru.com/')
22
+ ).resolves.toBe('# Converted document');
23
+
24
+ expect(fetchMock).toHaveBeenCalledWith(
25
+ 'https://www.aisuru.com/api/convert/session%2Fid',
26
+ expect.objectContaining({
27
+ method: 'POST',
28
+ body: expect.any(FormData),
29
+ })
30
+ );
31
+ const body = fetchMock.mock.calls[0][1].body as FormData;
32
+ expect(body.get('file')).toBe(file);
33
+ expect(fetchMock.mock.calls[0][1].headers).toBeUndefined();
34
+ });
35
+
36
+ it('uses the current origin when baseUrl is omitted', async () => {
37
+ fetchMock.mockResolvedValue({
38
+ ok: true,
39
+ json: jest.fn().mockResolvedValue({ text: 'Converted' }),
40
+ });
41
+
42
+ await convertDocument(new File(['text'], 'notes.txt'), 'session');
43
+
44
+ expect(fetchMock).toHaveBeenCalledWith(
45
+ '/api/convert/session',
46
+ expect.any(Object)
47
+ );
48
+ });
49
+
50
+ it('surfaces conversion API errors', async () => {
51
+ fetchMock.mockResolvedValue({
52
+ ok: false,
53
+ json: jest.fn().mockResolvedValue({ error: 'Formato non supportato' }),
54
+ });
55
+
56
+ await expect(
57
+ convertDocument(new File(['document'], 'contract.pages'), 'session')
58
+ ).rejects.toThrow('Formato non supportato');
59
+ });
60
+
61
+ it('requires a session before uploading', async () => {
62
+ await expect(
63
+ convertDocument(new File(['document'], 'contract.pdf'), '')
64
+ ).rejects.toThrow('Session ID is required');
65
+ expect(fetchMock).not.toHaveBeenCalled();
66
+ });
67
+ });
@@ -0,0 +1,35 @@
1
+ type ConvertDocumentResponse = {
2
+ text?: string;
3
+ error?: string;
4
+ };
5
+
6
+ export const convertDocument = async (
7
+ file: File,
8
+ sessionID: string,
9
+ baseUrl = ''
10
+ ): Promise<string> => {
11
+ if (!sessionID) {
12
+ throw new Error('Session ID is required to convert documents');
13
+ }
14
+
15
+ const body = new FormData();
16
+ body.append('file', file);
17
+
18
+ const origin = baseUrl.replace(/\/+$/, '');
19
+ const response = await fetch(
20
+ `${origin}/api/convert/${encodeURIComponent(sessionID)}`,
21
+ {
22
+ method: 'POST',
23
+ body,
24
+ }
25
+ );
26
+ const payload = (await response
27
+ .json()
28
+ .catch(() => null)) as ConvertDocumentResponse | null;
29
+
30
+ if (!response.ok || !payload?.text) {
31
+ throw new Error(payload?.error || 'Document conversion failed');
32
+ }
33
+
34
+ return payload.text;
35
+ };
@@ -114,6 +114,21 @@ export const renderMsg = (
114
114
  /<output\s+class\s*=\s*["\']memori-artifact["\'][^>]*data-mimetype\s*=\s*["\']([^"']+)["\'][^>]*>([\s\S]*?)(?:<\/output>|$)/gi,
115
115
  ''
116
116
  )
117
+ // Preferred: data-action="update" on memori-artifact
118
+ .replaceAll(
119
+ /<output\s+class\s*=\s*["\']memori-artifact["\'][^>]*data-action\s*=\s*["\']update["\'][^>]*>([\s\S]*?)(?:<\/output>|$)/gi,
120
+ ''
121
+ )
122
+ // data-action may appear before class
123
+ .replaceAll(
124
+ /<output\s+[^>]*data-action\s*=\s*["\']update["\'][^>]*class\s*=\s*["\'][^"']*memori-artifact[^"']*["\'][^>]*>([\s\S]*?)(?:<\/output>|$)/gi,
125
+ ''
126
+ )
127
+ // Legacy class name
128
+ .replaceAll(
129
+ /<output\s+class\s*=\s*["\']memori-artifact-update["\'][^>]*>([\s\S]*?)(?:<\/output>|$)/gi,
130
+ ''
131
+ )
117
132
  .replaceAll(/```markdown([^```]+)```/g, '$1')
118
133
  .replaceAll('($', '( $')
119
134
  .replaceAll(':$', ': $')
@@ -197,6 +197,9 @@
197
197
  "artifact": {
198
198
  "close": "Schließen",
199
199
  "size": "Größe",
200
+ "updated": "aktualisiert",
201
+ "updateFailed": "Update konnte nicht angewendet werden",
202
+ "updateFailedHint": "Der Patch stimmt nicht mit dem aktuellen Inhalt überein. Bitten Sie um ein Neuschreiben des Artifacts.",
200
203
  "generated": "Generiert",
201
204
  "download": "Herunterladen",
202
205
  "print": "Drucken",
@@ -210,6 +210,9 @@
210
210
  "artifact": {
211
211
  "close": "Close",
212
212
  "size": "Size",
213
+ "updated": "updated",
214
+ "updateFailed": "Update could not be applied",
215
+ "updateFailedHint": "The patch did not match the current content. Ask to rewrite the artifact.",
213
216
  "generated": "Generated",
214
217
  "download": "Download",
215
218
  "print": "Print",
@@ -197,6 +197,9 @@
197
197
  "artifact": {
198
198
  "close": "Cerrar",
199
199
  "size": "Tamaño",
200
+ "updated": "actualizado",
201
+ "updateFailed": "No se pudo aplicar la actualización",
202
+ "updateFailedHint": "El parche no coincide con el contenido actual. Pide reescribir el artifact.",
200
203
  "generated": "Generado",
201
204
  "download": "Descargar",
202
205
  "print": "Imprimir",
@@ -196,6 +196,9 @@
196
196
  "artifact": {
197
197
  "close": "Fermer",
198
198
  "size": "Taille",
199
+ "updated": "mis à jour",
200
+ "updateFailed": "Mise à jour non appliquée",
201
+ "updateFailedHint": "Le correctif ne correspond pas au contenu actuel. Demandez de réécrire l'artifact.",
199
202
  "generated": "Généré",
200
203
  "download": "Télécharger",
201
204
  "print": "Imprimer",
@@ -212,6 +212,9 @@
212
212
  "artifact": {
213
213
  "close": "Chiudi",
214
214
  "size": "Dimensione",
215
+ "updated": "aggiornato",
216
+ "updateFailed": "Aggiornamento non applicato",
217
+ "updateFailedHint": "Il patch non corrisponde al contenuto attuale. Chiedi di riscrivere l'artifact.",
215
218
  "generated": "Generato",
216
219
  "download": "Scarica",
217
220
  "print": "Stampa",
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const version = '8.42.0';
2
+ export const version = '8.44.0';