import { excelMimeTypes, QueryKeys } from 'librechat-data-provider'; import type { QueryClient } from '@tanstack/react-query'; import type { TFile } from 'librechat-data-provider'; import SheetPaths from '~/components/svg/Files/SheetPaths'; import TextPaths from '~/components/svg/Files/TextPaths'; import FilePaths from '~/components/svg/Files/FilePaths'; import CodePaths from '~/components/svg/Files/CodePaths'; export const partialTypes = ['text/x-']; const textDocument = { paths: TextPaths, fill: '#FF5588', title: 'Document', }; const spreadsheet = { paths: SheetPaths, fill: '#10A37F', title: 'Spreadsheet', }; const codeFile = { paths: CodePaths, fill: '#FF6E3C', // TODO: make this dynamic to the language title: 'Code', }; const artifact = { paths: CodePaths, fill: '#2D305C', title: 'Code', }; export const fileTypes = { /* Category matches */ file: { paths: FilePaths, fill: '#0000FF', title: 'File', }, text: textDocument, // application:, /* Partial matches */ csv: spreadsheet, 'application/pdf': textDocument, pdf: textDocument, 'text/x-': codeFile, artifact: artifact, /* Exact matches */ // 'application/json':, // 'text/html':, // 'text/css':, // image, }; // export const getFileType = (type = '') => { // let fileType = fileTypes.file; // const exactMatch = fileTypes[type]; // const partialMatch = !exactMatch && partialTypes.find((type) => type.includes(type)); // const category = (!partialMatch && (type.split('/')[0] ?? 'text') || 'text'); // if (exactMatch) { // fileType = exactMatch; // } else if (partialMatch) { // fileType = fileTypes[partialMatch]; // } else if (fileTypes[category]) { // fileType = fileTypes[category]; // } // if (!fileType) { // fileType = fileTypes.file; // } // return fileType; // }; export const getFileType = ( type = '', ): { paths: React.FC; fill: string; title: string; } => { // Direct match check if (fileTypes[type]) { return fileTypes[type]; } if (excelMimeTypes.test(type)) { return spreadsheet; } // Partial match check const partialMatch = partialTypes.find((partial) => type.includes(partial)); if (partialMatch && fileTypes[partialMatch]) { return fileTypes[partialMatch]; } // Category check const category = type.split('/')[0] || 'text'; if (fileTypes[category]) { return fileTypes[category]; } // Default file type return fileTypes.file; }; /** * Format a date string to a human readable format * @example * formatDate('2020-01-01T00:00:00.000Z') // '1 Jan 2020' */ export function formatDate(dateString: string, isSmallScreen = false) { if (!dateString) { return ''; } const date = new Date(dateString); if (isSmallScreen) { return date.toLocaleDateString('en-US', { month: 'numeric', day: 'numeric', year: '2-digit', }); } const months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; const day = date.getDate(); const month = months[date.getMonth()]; const year = date.getFullYear(); return `${day} ${month} ${year}`; } /** * Adds a file to the query cache */ export function addFileToCache(queryClient: QueryClient, newfile: TFile) { const currentFiles = queryClient.getQueryData([QueryKeys.files]); if (!currentFiles) { console.warn('No current files found in cache, skipped updating file query cache'); return; } const fileIndex = currentFiles.findIndex((file) => file.file_id === newfile.file_id); if (fileIndex > -1) { console.warn('File already exists in cache, skipped updating file query cache'); return; } queryClient.setQueryData( [QueryKeys.files], [ { ...newfile, }, ...currentFiles, ], ); } export function formatBytes(bytes: number, decimals = 2) { if (bytes === 0) { return 0; } const k = 1024; const dm = decimals < 0 ? 0 : decimals; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)); }