|
import React, { useState, useEffect, useRef } from "react"; |
|
import { Box, Typography, CircularProgress, Alert, Paper } from "@mui/material"; |
|
import { useNavigate, useSearchParams } from "react-router-dom"; |
|
import API_CONFIG from "../config/api"; |
|
|
|
|
|
const SIMULATION_DURATION = 20000; |
|
|
|
|
|
const MESSAGE_CHANGE_INTERVAL = { |
|
DEFAULT: 20000, |
|
PRECALCULATED: 5000, |
|
}; |
|
|
|
|
|
const STARTING_MESSAGES = [ |
|
{ message: "Initializing evaluation environment...", step: 1, totalSteps: 4 }, |
|
{ message: "Starting evaluation process...", step: 2, totalSteps: 4 }, |
|
{ message: "Evaluating models...", step: 3, totalSteps: 4 }, |
|
{ message: "Storing evaluation results...", step: 4, totalSteps: 4 }, |
|
]; |
|
|
|
const BenchmarkEvaluation = ({ sessionId, isDefaultDocument, onComplete }) => { |
|
const [searchParams] = useSearchParams(); |
|
const isDefault = |
|
isDefaultDocument || |
|
["the-bitter-lesson", "hurricane-faq", "pokemon-guide"].includes(sessionId); |
|
const [evaluationComplete, setEvaluationComplete] = useState(false); |
|
const [error, setError] = useState(null); |
|
const [elapsedTime, setElapsedTime] = useState(0); |
|
const [startingMessageIndex, setStartingMessageIndex] = useState(0); |
|
|
|
const timerIntervalRef = useRef(null); |
|
const startTimeRef = useRef(null); |
|
const startingMessageIntervalRef = useRef(null); |
|
const pollingIntervalRef = useRef(null); |
|
const simulationTimeoutRef = useRef(null); |
|
|
|
const navigate = useNavigate(); |
|
|
|
|
|
useEffect(() => { |
|
if (evaluationComplete) { |
|
navigate(`/evaluation-display?session=${sessionId}`); |
|
} |
|
}, [evaluationComplete, sessionId, navigate]); |
|
|
|
|
|
useEffect(() => { |
|
startingMessageIntervalRef.current = setInterval( |
|
() => { |
|
setStartingMessageIndex((prev) => { |
|
if (prev < STARTING_MESSAGES.length - 1) { |
|
return prev + 1; |
|
} |
|
return prev; |
|
}); |
|
}, |
|
isDefault |
|
? MESSAGE_CHANGE_INTERVAL.PRECALCULATED |
|
: MESSAGE_CHANGE_INTERVAL.DEFAULT |
|
); |
|
|
|
return () => { |
|
if (startingMessageIntervalRef.current) { |
|
clearInterval(startingMessageIntervalRef.current); |
|
} |
|
}; |
|
}, [isDefault]); |
|
|
|
|
|
useEffect(() => { |
|
|
|
startTimeRef.current = Date.now(); |
|
|
|
|
|
timerIntervalRef.current = setInterval(() => { |
|
const timeElapsed = Math.floor( |
|
(Date.now() - startTimeRef.current) / 1000 |
|
); |
|
setElapsedTime(timeElapsed); |
|
}, 1000); |
|
|
|
|
|
const handleVisibilityChange = () => { |
|
if ( |
|
document.visibilityState === "visible" && |
|
!isDefault && |
|
!evaluationComplete |
|
) { |
|
console.log("Page became visible, checking evaluation status..."); |
|
|
|
const checkEvaluationStatus = async () => { |
|
try { |
|
const logsResponse = await fetch( |
|
`${API_CONFIG.BASE_URL}/evaluation-logs/${sessionId}` |
|
); |
|
|
|
if (logsResponse.ok) { |
|
const logsResult = await logsResponse.json(); |
|
if (logsResult.is_completed) { |
|
|
|
setEvaluationComplete(true); |
|
|
|
|
|
setStartingMessageIndex(STARTING_MESSAGES.length - 1); |
|
|
|
|
|
if (pollingIntervalRef.current) { |
|
clearInterval(pollingIntervalRef.current); |
|
} |
|
if (startingMessageIntervalRef.current) { |
|
clearInterval(startingMessageIntervalRef.current); |
|
} |
|
} else { |
|
|
|
|
|
const progress = Math.min( |
|
Math.floor( |
|
(Date.now() - startTimeRef.current) / |
|
MESSAGE_CHANGE_INTERVAL.DEFAULT |
|
), |
|
STARTING_MESSAGES.length - 1 |
|
); |
|
setStartingMessageIndex(progress); |
|
} |
|
} |
|
} catch (error) { |
|
console.error("Error checking evaluation status:", error); |
|
} |
|
}; |
|
|
|
checkEvaluationStatus(); |
|
} |
|
}; |
|
|
|
|
|
document.addEventListener("visibilitychange", handleVisibilityChange); |
|
|
|
if (isDefault) { |
|
simulateEvaluation(); |
|
} else { |
|
startEvaluation(); |
|
} |
|
|
|
|
|
return () => { |
|
if (pollingIntervalRef.current) { |
|
clearInterval(pollingIntervalRef.current); |
|
} |
|
if (timerIntervalRef.current) { |
|
clearInterval(timerIntervalRef.current); |
|
} |
|
if (simulationTimeoutRef.current) { |
|
clearTimeout(simulationTimeoutRef.current); |
|
} |
|
document.removeEventListener("visibilitychange", handleVisibilityChange); |
|
}; |
|
}, [isDefault, sessionId, evaluationComplete]); |
|
|
|
|
|
const simulateEvaluation = () => { |
|
|
|
simulationTimeoutRef.current = setTimeout(() => { |
|
setEvaluationComplete(true); |
|
|
|
if (startingMessageIntervalRef.current) { |
|
clearInterval(startingMessageIntervalRef.current); |
|
} |
|
|
|
setStartingMessageIndex(STARTING_MESSAGES.length - 1); |
|
}, SIMULATION_DURATION); |
|
}; |
|
|
|
|
|
const formatElapsedTime = () => { |
|
const hours = Math.floor(elapsedTime / 3600); |
|
const minutes = Math.floor((elapsedTime % 3600) / 60); |
|
const seconds = elapsedTime % 60; |
|
|
|
return [ |
|
hours.toString().padStart(2, "0"), |
|
minutes.toString().padStart(2, "0"), |
|
seconds.toString().padStart(2, "0"), |
|
].join(":"); |
|
}; |
|
|
|
|
|
const startEvaluation = async () => { |
|
if (!sessionId) { |
|
setError("Missing session ID"); |
|
return; |
|
} |
|
|
|
try { |
|
|
|
const response = await fetch( |
|
`${API_CONFIG.BASE_URL}/evaluate-benchmark`, |
|
{ |
|
method: "POST", |
|
headers: { |
|
"Content-Type": "application/json", |
|
}, |
|
body: JSON.stringify({ |
|
session_id: sessionId, |
|
}), |
|
} |
|
); |
|
|
|
const result = await response.json(); |
|
|
|
if (response.ok) { |
|
|
|
pollingIntervalRef.current = setInterval(async () => { |
|
try { |
|
const logsResponse = await fetch( |
|
`${API_CONFIG.BASE_URL}/evaluation-logs/${sessionId}` |
|
); |
|
|
|
if (logsResponse.ok) { |
|
const logsResult = await logsResponse.json(); |
|
|
|
|
|
if (logsResult.is_completed) { |
|
setEvaluationComplete(true); |
|
|
|
|
|
setStartingMessageIndex(STARTING_MESSAGES.length - 1); |
|
|
|
|
|
clearInterval(pollingIntervalRef.current); |
|
if (startingMessageIntervalRef.current) { |
|
clearInterval(startingMessageIntervalRef.current); |
|
} |
|
} else { |
|
|
|
|
|
const elapsedSinceStart = Date.now() - startTimeRef.current; |
|
|
|
|
|
const estimatedTotalTime = 80000; |
|
const estimatedProgress = Math.min( |
|
elapsedSinceStart / estimatedTotalTime, |
|
1 |
|
); |
|
|
|
|
|
const estimatedStepIndex = Math.min( |
|
Math.floor(estimatedProgress * STARTING_MESSAGES.length), |
|
STARTING_MESSAGES.length - 1 |
|
); |
|
|
|
|
|
if (estimatedStepIndex > startingMessageIndex) { |
|
setStartingMessageIndex(estimatedStepIndex); |
|
} |
|
} |
|
} |
|
} catch (error) { |
|
console.log("Error polling logs:", error); |
|
|
|
} |
|
}, 2000); |
|
} else { |
|
setError(result.error || "Benchmark evaluation failed"); |
|
} |
|
} catch (error) { |
|
console.error("Error starting evaluation:", error); |
|
setError("Error connecting to server"); |
|
} |
|
}; |
|
|
|
return ( |
|
<Paper |
|
elevation={3} |
|
sx={{ |
|
p: 4, |
|
mt: 3, |
|
mb: 3, |
|
display: "flex", |
|
flexDirection: "column", |
|
alignItems: "center", |
|
justifyContent: "center", |
|
minHeight: 200, |
|
position: "relative", |
|
}} |
|
> |
|
{/* Temps estimé */} |
|
<Box |
|
sx={{ |
|
position: "absolute", |
|
top: 12, |
|
right: 12, |
|
backgroundColor: "rgba(0, 0, 0, 0.04)", |
|
borderRadius: "4px", |
|
px: 1, |
|
py: 0.5, |
|
display: "inline-flex", |
|
alignItems: "center", |
|
}} |
|
> |
|
<Typography |
|
variant="caption" |
|
sx={{ |
|
fontSize: "0.675rem", |
|
color: "text.secondary", |
|
fontWeight: 500, |
|
}} |
|
> |
|
Estimated time: ~1 min |
|
</Typography> |
|
</Box> |
|
|
|
{error ? ( |
|
<Alert severity="error" sx={{ width: "100%" }}> |
|
{error} |
|
</Alert> |
|
) : ( |
|
<> |
|
{evaluationComplete ? ( |
|
<Alert severity="success" sx={{ width: "100%", mb: 3 }}> |
|
Evaluation completed successfully! |
|
</Alert> |
|
) : ( |
|
<> |
|
<CircularProgress size={60} sx={{ mb: 2 }} /> |
|
<Typography variant="h6" component="div" gutterBottom> |
|
Benchmark evaluation... |
|
</Typography> |
|
|
|
{/* Step progress indicator */} |
|
<Typography variant="body1" color="text.secondary"> |
|
{`${STARTING_MESSAGES[startingMessageIndex].message} (${STARTING_MESSAGES[startingMessageIndex].step}/${STARTING_MESSAGES[startingMessageIndex].totalSteps})`} |
|
</Typography> |
|
|
|
{/* Timer display */} |
|
<Box |
|
sx={{ |
|
display: "flex", |
|
alignItems: "center", |
|
mt: 1, |
|
color: "text.secondary", |
|
opacity: 0.5, |
|
}} |
|
> |
|
<Typography variant="body2">{formatElapsedTime()}</Typography> |
|
</Box> |
|
</> |
|
)} |
|
</> |
|
)} |
|
</Paper> |
|
); |
|
}; |
|
|
|
export default BenchmarkEvaluation; |
|
|