|
import React, { useState, useRef, useEffect } from "react"; |
|
import { |
|
Box, |
|
Paper, |
|
Typography, |
|
CircularProgress, |
|
Alert, |
|
Button, |
|
Stepper, |
|
Step, |
|
StepLabel, |
|
} from "@mui/material"; |
|
import { useLocation } from "react-router-dom"; |
|
import CloudUploadIcon from "@mui/icons-material/CloudUpload"; |
|
import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh"; |
|
import AuthContainer from "./shared/AuthContainer"; |
|
import { useThemeMode } from "../hooks/useThemeMode"; |
|
import getTheme from "../config/theme"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const StepsDisplay = ({ activeStep }) => { |
|
const steps = ["Login", "Upload File", "Generate"]; |
|
|
|
return ( |
|
<Box sx={{ width: "100%", mb: 4 }}> |
|
<Stepper activeStep={activeStep} alternativeLabel> |
|
{steps.map((label) => ( |
|
<Step key={label}> |
|
<StepLabel>{label}</StepLabel> |
|
</Step> |
|
))} |
|
</Stepper> |
|
</Box> |
|
); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 [activeStep, setActiveStep] = useState(0); |
|
const [sessionId, setSessionId] = useState(null); |
|
const fileInputRef = useRef(null); |
|
const location = useLocation(); |
|
|
|
|
|
useEffect(() => { |
|
|
|
const params = new URLSearchParams(window.location.search); |
|
if (params.has("code")) { |
|
console.log("Detected OAuth callback, cleaning URL"); |
|
|
|
|
|
window.history.replaceState({}, document.title, window.location.pathname); |
|
|
|
|
|
setTimeout(() => { |
|
const storedAuth = localStorage.getItem("hf_oauth"); |
|
if (storedAuth) { |
|
console.log("Found auth data after redirect, refreshing UI state"); |
|
setActiveStep(1); |
|
} |
|
}, 1000); |
|
} |
|
}, [location]); |
|
|
|
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; |
|
|
|
|
|
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", |
|
}); |
|
return; |
|
} |
|
|
|
handleFileUpload(file); |
|
}; |
|
|
|
const handleFileUpload = async (file) => { |
|
setIsLoading(true); |
|
setUploadStatus(null); |
|
|
|
try { |
|
const formData = new FormData(); |
|
formData.append("file", file); |
|
|
|
const response = await fetch("http://localhost:3001/upload", { |
|
method: "POST", |
|
body: formData, |
|
}); |
|
|
|
const result = await response.json(); |
|
|
|
if (response.ok) { |
|
setUploadStatus({ |
|
success: true, |
|
message: `File ${result.filename} uploaded successfully`, |
|
}); |
|
|
|
setSessionId(result.session_id); |
|
setActiveStep(2); |
|
} else { |
|
setUploadStatus({ |
|
success: false, |
|
message: result.error || "Upload failed", |
|
}); |
|
} |
|
} catch (error) { |
|
setUploadStatus({ |
|
success: false, |
|
message: "Server connection error", |
|
}); |
|
} 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" }); |
|
return; |
|
} |
|
|
|
|
|
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", |
|
}); |
|
return; |
|
} |
|
|
|
handleFileUpload(file); |
|
}; |
|
|
|
const handleGenerateClick = () => { |
|
if (onStartGeneration && sessionId) { |
|
onStartGeneration(sessionId); |
|
} |
|
}; |
|
|
|
return ( |
|
<> |
|
<StepsDisplay activeStep={activeStep} /> |
|
|
|
{/* Authentication step */} |
|
{activeStep === 0 && ( |
|
<AuthContainer |
|
actionText="use this demo" |
|
onSuccess={() => setActiveStep(1)} |
|
/> |
|
)} |
|
|
|
{/* File upload step */} |
|
{activeStep === 1 && ( |
|
<Paper |
|
elevation={3} |
|
sx={{ |
|
p: 4, |
|
mt: 3, |
|
mb: 3, |
|
border: isDragging |
|
? `2px dashed ${theme.palette.primary.main}` |
|
: "2px dashed #ccc", |
|
backgroundColor: isDragging ? "rgba(0, 0, 0, 0.05)" : "transparent", |
|
display: "flex", |
|
flexDirection: "column", |
|
alignItems: "center", |
|
justifyContent: "center", |
|
minHeight: 200, |
|
cursor: "pointer", |
|
transition: "all 0.3s ease", |
|
}} |
|
onDragOver={handleDragOver} |
|
onDragLeave={handleDragLeave} |
|
onDrop={handleDrop} |
|
onClick={handleClick} |
|
> |
|
<input |
|
type="file" |
|
ref={fileInputRef} |
|
onChange={handleFileChange} |
|
accept=".pdf,.txt,.html,.md" |
|
style={{ display: "none" }} |
|
/> |
|
<CloudUploadIcon |
|
sx={{ fontSize: 60, color: "text.secondary", mb: 1 }} |
|
/> |
|
<Typography variant="h6" component="div" gutterBottom> |
|
Drag and drop your file here or click to browse |
|
</Typography> |
|
<Typography variant="body2" color="text.secondary"> |
|
Accepted formats: PDF, TXT, HTML, MD |
|
</Typography> |
|
|
|
{isLoading && ( |
|
<Box sx={{ mt: 2 }}> |
|
<CircularProgress size={30} /> |
|
</Box> |
|
)} |
|
|
|
{uploadStatus && ( |
|
<Alert |
|
severity={uploadStatus.success ? "success" : "error"} |
|
sx={{ mt: 2, width: "100%" }} |
|
> |
|
{uploadStatus.message} |
|
</Alert> |
|
)} |
|
</Paper> |
|
)} |
|
|
|
{/* Generate button step */} |
|
{activeStep === 2 && ( |
|
<Paper |
|
elevation={3} |
|
sx={{ |
|
p: 4, |
|
mt: 3, |
|
display: "flex", |
|
flexDirection: "column", |
|
alignItems: "center", |
|
justifyContent: "center", |
|
minHeight: 200, |
|
}} |
|
> |
|
<AutoFixHighIcon |
|
sx={{ fontSize: 60, color: "text.secondary", mb: 1 }} |
|
/> |
|
<Typography variant="h6" component="div" gutterBottom> |
|
Ready to generate your benchmark |
|
</Typography> |
|
<Button |
|
variant="contained" |
|
color="primary" |
|
onClick={handleGenerateClick} |
|
sx={{ mt: 2 }} |
|
> |
|
Generate Benchmark |
|
</Button> |
|
</Paper> |
|
)} |
|
</> |
|
); |
|
} |
|
|
|
export default BenchmarkCreateForm; |
|
|