import React, { useState, useRef } from "react"; import { Box, Paper, Typography, CircularProgress, Button, Snackbar, Alert, Grid, IconButton, Tooltip, Dialog, DialogTitle, DialogContent, DialogActions, } from "@mui/material"; import { alpha } from "@mui/material/styles"; import CloudUploadIcon from "@mui/icons-material/CloudUpload"; import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh"; import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile"; import DescriptionIcon from "@mui/icons-material/Description"; import ArticleIcon from "@mui/icons-material/Article"; import MenuBookIcon from "@mui/icons-material/MenuBook"; import DownloadIcon from "@mui/icons-material/Download"; import VisibilityIcon from "@mui/icons-material/Visibility"; import CloseIcon from "@mui/icons-material/Close"; import { useThemeMode } from "../hooks/useThemeMode"; import getTheme from "../config/theme"; import API_CONFIG from "../config/api"; /** * Component for creating a new benchmark, including file upload and generation initiation * * @param {Object} props - Component props * @param {Function} props.onStartGeneration - Callback when generation starts with sessionId * @returns {JSX.Element} BenchmarkCreateForm component */ function BenchmarkCreateForm({ onStartGeneration }) { const { mode } = useThemeMode(); const theme = getTheme(mode); const [isDragging, setIsDragging] = useState(false); const [uploadStatus, setUploadStatus] = useState(null); const [isLoading, setIsLoading] = useState(false); const [sessionId, setSessionId] = useState(null); const [openSnackbar, setOpenSnackbar] = useState(false); const [selectedDocument, setSelectedDocument] = useState(null); const [isDefaultDocument, setIsDefaultDocument] = useState(false); const [isDownloading, setIsDownloading] = useState(false); const [documentContent, setDocumentContent] = useState(""); const [openContentModal, setOpenContentModal] = useState(false); const [isLoadingContent, setIsLoadingContent] = useState(false); const [modalDocument, setModalDocument] = useState(null); const fileInputRef = useRef(null); const defaultDocuments = [ { id: "the-bitter-lesson", name: "The Bitter Lesson", icon: , description: "A seminal paper on AI development by Rich Sutton", }, { id: "hurricane-faq", name: "Hurricane FAQ", icon: , description: "Frequently asked questions about hurricanes", }, { id: "pokemon-guide", name: "Pokemon Guide", icon: , description: "A comprehensive guide for Pokemon enthusiasts", }, ]; const handleCloseSnackbar = () => { setOpenSnackbar(false); }; const handleDragOver = (e) => { e.preventDefault(); setIsDragging(true); }; const handleDragLeave = () => { setIsDragging(false); }; const handleClick = () => { fileInputRef.current.click(); }; const handleFileChange = (e) => { const file = e.target.files[0]; if (!file) return; // Check if it's a PDF, TXT, HTML or MD if ( !file.name.endsWith(".pdf") && !file.name.endsWith(".txt") && !file.name.endsWith(".html") && !file.name.endsWith(".md") ) { setUploadStatus({ success: false, message: "Only PDF, TXT, HTML and MD files are accepted", }); setOpenSnackbar(true); return; } // Check file size limit (1MB = 1048576 bytes) if (file.size > 1048576) { setUploadStatus({ success: false, message: "File size exceeds the 1MB limit", }); setOpenSnackbar(true); return; } handleFileUpload(file); }; const handleFileUpload = async (file) => { setIsLoading(true); setUploadStatus(null); setIsDefaultDocument(false); setSelectedDocument(null); try { const formData = new FormData(); formData.append("file", file); const response = await fetch(`${API_CONFIG.BASE_URL}/upload`, { method: "POST", body: formData, }); const result = await response.json(); if (response.ok) { setUploadStatus({ success: true, message: "File uploaded successfully", }); setOpenSnackbar(true); setSessionId(result.session_id); setSelectedDocument({ name: file.name }); } else { setUploadStatus({ success: false, message: result.detail || "Upload failed", }); setOpenSnackbar(true); } } catch (error) { setUploadStatus({ success: false, message: "Server connection error", }); setOpenSnackbar(true); } finally { setIsLoading(false); } }; const handleDrop = async (e) => { e.preventDefault(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (!file) { setUploadStatus({ success: false, message: "No file detected" }); setOpenSnackbar(true); return; } // Check if it's a PDF, TXT, HTML or MD if ( !file.name.endsWith(".pdf") && !file.name.endsWith(".txt") && !file.name.endsWith(".html") && !file.name.endsWith(".md") ) { setUploadStatus({ success: false, message: "Only PDF, TXT, HTML and MD files are accepted", }); setOpenSnackbar(true); return; } // Check file size limit (10MB = 10485760 bytes) if (file.size > 10485760) { setUploadStatus({ success: false, message: "File size exceeds the 10MB limit", }); setOpenSnackbar(true); return; } handleFileUpload(file); }; const handleDefaultDocClick = (doc) => { setSelectedDocument(doc); setSessionId(doc.id); setIsDefaultDocument(true); }; const handleGenerateClick = () => { if (onStartGeneration && sessionId) { onStartGeneration(sessionId, isDefaultDocument); } }; const handleDownloadDocument = async (doc) => { setIsDownloading(true); try { const link = document.createElement("a"); link.href = `/${doc.id}.${ doc.id === "the-bitter-lesson" ? "html" : doc.id === "hurricane-faq" ? "md" : "txt" }`; link.setAttribute( "download", `${doc.name}.${ doc.id === "the-bitter-lesson" ? "html" : doc.id === "hurricane-faq" ? "md" : "txt" }` ); document.body.appendChild(link); link.click(); document.body.removeChild(link); } catch (error) { console.error("Error downloading document:", error); setUploadStatus({ success: false, message: "Error downloading document", }); setOpenSnackbar(true); } finally { setIsDownloading(false); } }; const handleViewDocument = async (doc) => { setIsLoadingContent(true); try { let extension = ""; if (doc.id === "the-bitter-lesson") { extension = "html"; } else if (doc.id === "hurricane-faq") { extension = "md"; } else { extension = "txt"; } // Mettre à jour l'état du document pour la modale setModalDocument(doc); const response = await fetch(`/${doc.id}.${extension}`); const text = await response.text(); setDocumentContent(text); setOpenContentModal(true); } catch (error) { console.error("Error loading document content:", error); setUploadStatus({ success: false, message: "Error loading document content", }); setOpenSnackbar(true); } finally { setIsLoadingContent(false); } }; const handleCloseContentModal = () => { setOpenContentModal(false); // Réinitialiser après la fermeture de la modale setTimeout(() => { setDocumentContent(""); setModalDocument(null); }, 300); }; return ( To create a benchmark, choose a sample document {defaultDocuments.map((doc) => ( handleDefaultDocClick(doc)} > { e.stopPropagation(); handleViewDocument(doc); }} sx={{ position: "absolute", top: 4, right: 4, color: "text.secondary", opacity: 0.4, "&:hover": { opacity: 0.8, backgroundColor: alpha(theme.palette.primary.main, 0.05), }, padding: 0.3, "& .MuiSvgIcon-root": { fontSize: 16, }, }} disabled={isLoadingContent} > {isLoadingContent && selectedDocument?.id === doc.id ? ( ) : ( )} {doc.icon} {doc.name} {doc.description} ))} Or upload your own ... {selectedDocument?.name && !isDefaultDocument ? ( <> {selectedDocument.name} Click to upload a different file ) : ( <> {isLoading ? ( ) : ( )} {isLoading ? "Uploading your file..." : "Drag and drop your file here or click to browse"} Accepted formats: PDF, TXT, HTML, MD )} {uploadStatus?.message} {modalDocument && ( {modalDocument.name} )} {modalDocument && (modalDocument.id === "the-bitter-lesson" ? "HTML" : modalDocument.id === "hurricane-faq" ? "Markdown" : "Text")} {modalDocument && ( handleDownloadDocument(modalDocument)} disabled={isDownloading} aria-label="download" sx={{ color: "text.secondary", opacity: 0.4, "&:hover": { opacity: 0.8, }, }} > {isDownloading ? ( ) : ( )} )} {isLoadingContent ? ( ) : ( {documentContent} )} ); } export default BenchmarkCreateForm;