@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.
- package/CHANGELOG.md +52 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js +1 -1
- package/dist/components/Chat/Chat.js +1 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/ChatHistoryDrawer/ChatResumeDrawer.css +6 -1
- package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
- package/dist/components/ChatInputs/ChatInputs.js +2 -2
- package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
- package/dist/components/IconButton/IconButton.css +144 -0
- package/dist/components/IconButton/IconButton.d.ts +9 -0
- package/dist/components/IconButton/IconButton.js +36 -0
- package/dist/components/IconButton/IconButton.js.map +1 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +1 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +204 -59
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/context/ArtifactContext.d.ts +3 -1
- package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js +76 -16
- package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/types/artifact.types.d.ts +11 -0
- package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js +18 -13
- package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/utils/applyEdits.d.ts +8 -0
- package/dist/components/MemoriArtifactSystem/utils/applyEdits.js +117 -0
- package/dist/components/MemoriArtifactSystem/utils/applyEdits.js.map +1 -0
- package/dist/components/MobileSessionPanel/MobileSessionPanel.css +29 -7
- package/dist/components/MobileSessionPanel/MobileSessionPanel.d.ts +3 -0
- package/dist/components/MobileSessionPanel/MobileSessionPanel.js +8 -6
- package/dist/components/MobileSessionPanel/MobileSessionPanel.js.map +1 -1
- package/dist/components/PositionPopover/PositionPopover.d.ts +2 -0
- package/dist/components/PositionPopover/PositionPopover.js +19 -11
- package/dist/components/PositionPopover/PositionPopover.js.map +1 -1
- package/dist/components/UploadButton/UploadButton.d.ts +1 -0
- package/dist/components/UploadButton/UploadButton.js +12 -18
- package/dist/components/UploadButton/UploadButton.js.map +1 -1
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.d.ts +1 -6
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js +7 -139
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/dist/components/icons/Print.js +1 -1
- package/dist/components/icons/Print.js.map +1 -1
- package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js +24 -3
- package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
- package/dist/components/layouts/WebsiteAssistant/website-assistant.css +137 -55
- package/dist/components/layouts/fullpage.css +165 -68
- package/dist/helpers/constants.d.ts +1 -0
- package/dist/helpers/constants.js +24 -1
- package/dist/helpers/constants.js.map +1 -1
- package/dist/helpers/convertDocument.d.ts +1 -0
- package/dist/helpers/convertDocument.js +24 -0
- package/dist/helpers/convertDocument.js.map +1 -0
- package/dist/helpers/message.js +3 -0
- package/dist/helpers/message.js.map +1 -1
- package/dist/helpers/positionPopover.d.ts +1 -1
- package/dist/helpers/positionPopover.js +2 -2
- package/dist/helpers/positionPopover.js.map +1 -1
- package/dist/helpers/tts/muteSpeaker.d.ts +13 -0
- package/dist/helpers/tts/muteSpeaker.js +26 -0
- package/dist/helpers/tts/muteSpeaker.js.map +1 -0
- package/dist/locales/de.json +3 -0
- package/dist/locales/en.json +3 -0
- package/dist/locales/es.json +3 -0
- package/dist/locales/fr.json +3 -0
- package/dist/locales/it.json +3 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js +1 -1
- package/esm/components/Chat/Chat.js +1 -1
- package/esm/components/Chat/Chat.js.map +1 -1
- package/esm/components/ChatHistoryDrawer/ChatResumeDrawer.css +6 -1
- package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
- package/esm/components/ChatInputs/ChatInputs.js +2 -2
- package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
- package/esm/components/IconButton/IconButton.css +144 -0
- package/esm/components/IconButton/IconButton.d.ts +9 -0
- package/esm/components/IconButton/IconButton.js +33 -0
- package/esm/components/IconButton/IconButton.js.map +1 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +1 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +205 -60
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +2 -2
- package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/context/ArtifactContext.d.ts +3 -1
- package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js +77 -17
- package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/types/artifact.types.d.ts +11 -0
- package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js +18 -13
- package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/utils/applyEdits.d.ts +8 -0
- package/esm/components/MemoriArtifactSystem/utils/applyEdits.js +112 -0
- package/esm/components/MemoriArtifactSystem/utils/applyEdits.js.map +1 -0
- package/esm/components/MobileSessionPanel/MobileSessionPanel.css +29 -7
- package/esm/components/MobileSessionPanel/MobileSessionPanel.d.ts +3 -0
- package/esm/components/MobileSessionPanel/MobileSessionPanel.js +8 -6
- package/esm/components/MobileSessionPanel/MobileSessionPanel.js.map +1 -1
- package/esm/components/PositionPopover/PositionPopover.d.ts +2 -0
- package/esm/components/PositionPopover/PositionPopover.js +20 -12
- package/esm/components/PositionPopover/PositionPopover.js.map +1 -1
- package/esm/components/UploadButton/UploadButton.d.ts +1 -0
- package/esm/components/UploadButton/UploadButton.js +13 -19
- package/esm/components/UploadButton/UploadButton.js.map +1 -1
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.d.ts +1 -6
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js +8 -140
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/esm/components/icons/Print.js +1 -1
- package/esm/components/icons/Print.js.map +1 -1
- package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js +24 -3
- package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -1
- package/esm/components/layouts/WebsiteAssistant/website-assistant.css +137 -55
- package/esm/components/layouts/fullpage.css +165 -68
- package/esm/helpers/constants.d.ts +1 -0
- package/esm/helpers/constants.js +23 -0
- package/esm/helpers/constants.js.map +1 -1
- package/esm/helpers/convertDocument.d.ts +1 -0
- package/esm/helpers/convertDocument.js +20 -0
- package/esm/helpers/convertDocument.js.map +1 -0
- package/esm/helpers/message.js +3 -0
- package/esm/helpers/message.js.map +1 -1
- package/esm/helpers/positionPopover.d.ts +1 -1
- package/esm/helpers/positionPopover.js +2 -2
- package/esm/helpers/positionPopover.js.map +1 -1
- package/esm/helpers/tts/muteSpeaker.d.ts +13 -0
- package/esm/helpers/tts/muteSpeaker.js +21 -0
- package/esm/helpers/tts/muteSpeaker.js.map +1 -0
- package/esm/locales/de.json +3 -0
- package/esm/locales/en.json +3 -0
- package/esm/locales/es.json +3 -0
- package/esm/locales/fr.json +3 -0
- package/esm/locales/it.json +3 -0
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/package.json +2 -2
- package/src/components/Avatar/AvatarView/AvatarComponent/constants.ts +1 -1
- package/src/components/Chat/Chat.tsx +1 -0
- package/src/components/ChatInputs/ChatInputs.tsx +3 -0
- package/src/components/FilePreview/FilePreview.stories.tsx +0 -3
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +1 -0
- package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +324 -133
- package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.tsx +2 -2
- package/src/components/MemoriArtifactSystem/context/ArtifactContext.tsx +122 -24
- package/src/components/MemoriArtifactSystem/types/artifact.types.ts +20 -1
- package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.test.tsx +1 -0
- package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.tsx +19 -13
- package/src/components/MemoriArtifactSystem/utils/applyEdits.test.ts +85 -0
- package/src/components/MemoriArtifactSystem/utils/applyEdits.ts +173 -0
- package/src/components/UploadButton/UploadButton.stories.tsx +2 -2
- package/src/components/UploadButton/UploadButton.tsx +19 -19
- package/src/components/UploadButton/UploadDocuments/UploadDocuments.tsx +13 -187
- package/src/components/UploadButton/__snapshots__/UploadButton.test.tsx.snap +2 -2
- package/src/components/icons/Print.tsx +6 -2
- package/src/helpers/constants.ts +24 -0
- package/src/helpers/convertDocument.test.ts +67 -0
- package/src/helpers/convertDocument.ts +35 -0
- package/src/helpers/message.ts +15 -0
- package/src/locales/de.json +3 -0
- package/src/locales/en.json +3 -0
- package/src/locales/es.json +3 -0
- package/src/locales/fr.json +3 -0
- package/src/locales/it.json +3 -0
- 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 {
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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={
|
|
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 {
|
|
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
|
-
|
|
289
|
-
|
|
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,
|
|
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
|
|
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={
|
|
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,.
|
|
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,.
|
|
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
|
-
|
|
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
|
-
|
|
21
|
+
strokeWidth="1"
|
|
18
22
|
fill="none"
|
|
19
23
|
fill-rule="evenodd"
|
|
20
24
|
>
|
package/src/helpers/constants.ts
CHANGED
|
@@ -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
|
+
};
|
package/src/helpers/message.ts
CHANGED
|
@@ -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(':$', ': $')
|
package/src/locales/de.json
CHANGED
|
@@ -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",
|
package/src/locales/en.json
CHANGED
|
@@ -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",
|
package/src/locales/es.json
CHANGED
|
@@ -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",
|
package/src/locales/fr.json
CHANGED
|
@@ -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",
|
package/src/locales/it.json
CHANGED
|
@@ -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.
|
|
2
|
+
export const version = '8.44.0';
|