UNPKG

@memori.ai/memori-react

Version:

[![npm version](https://img.shields.io/github/package-json/v/memori-ai/memori-react)](https://www.npmjs.com/package/@memori.ai/memori-react) ![Tests](https://github.com/memori-ai/memori-react/workflows/CI/badge.svg?branch=main) ![TypeScript Support](https

231 lines 11.6 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import React, { useState, useRef, useEffect } from 'react'; import cx from 'classnames'; import Spin from '../../ui/Spin'; import { DocumentIcon } from '../../icons/Document'; import Modal from '../../ui/Modal'; import { MAX_DOCUMENT_CONTENT_LENGTH } from '../../../helpers/constants'; const PDF_JS_VERSION = '3.11.174'; const WORKER_URL = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${PDF_JS_VERSION}/pdf.worker.min.js`; const PDF_JS_URL = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${PDF_JS_VERSION}/pdf.min.js`; const XLSX_URL = 'https://cdn.sheetjs.com/xlsx-0.20.0/package/dist/xlsx.full.min.js'; const UploadDocuments = ({ setDocumentPreviewFiles, maxDocuments, documentPreviewFiles, onLoadingChange, onDocumentError, onValidateFile, onValidatePayloadSize, }) => { const [isLoading, setIsLoading] = useState(false); const [selectedFile, setSelectedFile] = useState(null); const documentInputRef = useRef(null); useEffect(() => { if (onLoadingChange) { onLoadingChange(isLoading); } }, [isLoading, onLoadingChange]); const validateDocumentFile = (file) => { if (onValidateFile) { return onValidateFile(file); } return true; }; const validatePayloadSize = (newDocuments) => { if (onValidatePayloadSize) { return onValidatePayloadSize(newDocuments); } return true; }; const extractTextFromPDF = async (file) => { console.log('Extracting text from PDF:', file.name); try { if (!window.pdfjsLib) { console.log('Loading PDF.js library...'); await new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = PDF_JS_URL; script.onload = () => { window.pdfjsLib.GlobalWorkerOptions.workerSrc = WORKER_URL; console.log('PDF.js loaded successfully'); resolve(true); }; script.onerror = reject; document.head.appendChild(script); }); } const arrayBuffer = await file.arrayBuffer(); const pdf = await window.pdfjsLib.getDocument({ data: arrayBuffer }).promise; console.log('PDF loaded, pages:', pdf.numPages); let text = ''; for (let i = 1; i <= pdf.numPages; i++) { console.log('Processing page', i); const page = await pdf.getPage(i); const content = await page.getTextContent(); const pageText = content.items .filter((item) => item.str && typeof item.str === 'string') .map((item) => item.str) .join(' '); text += pageText + '\n'; } console.log('PDF text extraction complete'); return text; } catch (error) { console.error('PDF extraction failed:', error); throw new Error(`PDF extraction failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } }; const extractTextFromXLSX = async (file) => { console.log('Extracting text from XLSX:', file.name); try { if (!window.XLSX) { console.log('Loading XLSX library...'); await new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = XLSX_URL; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); console.log('XLSX library loaded successfully'); } const arrayBuffer = await file.arrayBuffer(); const workbook = window.XLSX.read(arrayBuffer, { type: 'array', cellFormula: true, cellNF: true, cellText: true, cellDates: true, }); console.log('XLSX workbook loaded, sheets:', workbook.SheetNames); let text = ''; for (const sheetName of workbook.SheetNames) { console.log('Processing sheet:', sheetName); const worksheet = workbook.Sheets[sheetName]; const data = window.XLSX.utils.sheet_to_json(worksheet, { header: 1, raw: false }); const colWidths = data.reduce((widths, row) => { row.forEach((cell, i) => { const cellWidth = (cell || '').toString().length; widths[i] = Math.max(widths[i] || 0, cellWidth); }); return widths; }, []); const formattedText = data.map((row) => { return row .map((cell, i) => { const cellStr = (cell || '').toString(); return cellStr.padEnd(colWidths[i] + 2); }) .join('|') .trim(); }); if (formattedText.length > 0) { const separator = colWidths .map((w) => '-'.repeat(w + 2)) .join('+'); formattedText.splice(1, 0, separator); } text += `Sheet: ${sheetName}\n${formattedText.join('\n')}\n\n`; } console.log('XLSX text extraction complete'); return text; } catch (error) { console.error('XLSX extraction failed:', error); throw new Error(`XLSX extraction failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } }; const processDocumentFile = async (file) => { var _a; console.log('Processing document file:', file.name); const fileExt = ((_a = file.name.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || ''; try { let text = null; if (fileExt === 'pdf') { text = await extractTextFromPDF(file); } else if (['txt', 'md', 'json', 'csv'].includes(fileExt)) { text = await file.text(); } else if (fileExt === 'xlsx') { text = await extractTextFromXLSX(file); } if (text && text.length > MAX_DOCUMENT_CONTENT_LENGTH) { console.warn('Document content exceeds length limit:', text.length, '>', MAX_DOCUMENT_CONTENT_LENGTH); onDocumentError === null || onDocumentError === void 0 ? void 0 : onDocumentError({ message: `File "${file.name}" content exceeds ${MAX_DOCUMENT_CONTENT_LENGTH} characters and was truncated`, severity: 'warning', }); text = text.substring(0, MAX_DOCUMENT_CONTENT_LENGTH) + "\n\n[Content truncated due to size limits]"; } console.log('Document processing complete'); return text; } catch (error) { console.error('Document processing failed:', error); throw new Error(`Failed to process "${file.name}": ${error instanceof Error ? error.message : 'Unknown error'}`); } }; const handleDocumentUpload = async (e) => { console.log('Document upload started'); const files = Array.from(e.target.files || []); if (files.length === 0) return; setIsLoading(true); const processedFiles = []; for (const file of files) { console.log('Processing file:', file.name); if (!validateDocumentFile(file)) { continue; } const fileId = Math.random().toString(36).substr(2, 9); try { const text = await processDocumentFile(file); if (text) { processedFiles.push({ name: file.name, id: fileId, content: text, mimeType: file.type, }); } } catch (error) { console.error('File processing error:', error); onDocumentError === null || onDocumentError === void 0 ? void 0 : onDocumentError({ message: `${error instanceof Error ? error.message : 'Unknown error'}`, severity: 'error', }); } } if (processedFiles.length > 0) { console.log('Successfully processed files:', processedFiles.length); if (!validatePayloadSize(processedFiles)) { setIsLoading(false); if (documentInputRef.current) { documentInputRef.current.value = ''; } return; } const existingDocuments = documentPreviewFiles.filter((file) => file.type === 'document'); const existingImages = documentPreviewFiles.filter((file) => file.type === 'image'); console.log('existingDocuments', existingDocuments); console.log('processedFiles', processedFiles); console.log('existingImages', existingImages); setDocumentPreviewFiles([ ...existingDocuments, ...processedFiles.map(file => ({ ...file, type: 'document' })), ]); } console.log('Document upload complete'); setIsLoading(false); if (documentInputRef.current) { documentInputRef.current.value = ''; } }; return (_jsxs("div", { className: "memori--document-upload-wrapper", children: [_jsx("input", { ref: documentInputRef, type: "file", accept: ".pdf,.txt,.md,.json,.xlsx,.csv", className: "memori--upload-file-input", onChange: handleDocumentUpload }), _jsx("button", { className: cx('memori-button', 'memori-button--circle', 'memori-button--icon-only', 'memori-share-button--button', 'memori--conversation-button', 'memori--document-upload-button', { 'memori--error': false }), onClick: () => { var _a; return (_a = documentInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: isLoading || (maxDocuments && documentPreviewFiles.filter((file) => file.type !== 'image').length >= maxDocuments) || false, title: "Upload documents", children: isLoading ? (_jsx(Spin, { spinning: true, className: "memori--upload-icon" })) : (_jsx(React.Fragment, { children: _jsx(DocumentIcon, { className: "memori--upload-icon" }) })) }), _jsx(Modal, { width: "80%", widthMd: "80%", open: !!selectedFile, className: "memori--modal-preview-file", onClose: () => setSelectedFile(null), closable: true, title: selectedFile === null || selectedFile === void 0 ? void 0 : selectedFile.name, children: _jsx("div", { className: "memori--preview-content", style: { maxHeight: '70vh', overflowY: 'auto', textAlign: 'center', whiteSpace: 'pre-wrap' }, children: selectedFile === null || selectedFile === void 0 ? void 0 : selectedFile.content }) })] })); }; export default UploadDocuments; //# sourceMappingURL=UploadDocuments.js.map