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"; // Temps de simulation en millisecondes pour les documents précalculés const SIMULATION_DURATION = 20000; // 20 secondes // Intervalle de changement des messages pour les documents standards vs précalculés const MESSAGE_CHANGE_INTERVAL = { DEFAULT: 20000, // 20 secondes pour documents standards PRECALCULATED: 5000, // 5 secondes pour documents précalculés }; // Starting messages with their timing 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(); // Add effect to handle automatic redirection when evaluation is complete useEffect(() => { if (evaluationComplete) { navigate(`/evaluation-display?session=${sessionId}`); } }, [evaluationComplete, sessionId, navigate]); // Add effect to handle starting messages 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]); // Start evaluation when component mounts useEffect(() => { // Set start time startTimeRef.current = Date.now(); // Start timer timerIntervalRef.current = setInterval(() => { const timeElapsed = Math.floor( (Date.now() - startTimeRef.current) / 1000 ); setElapsedTime(timeElapsed); }, 1000); // Gestionnaire pour détecter quand la page redevient visible const handleVisibilityChange = () => { if ( document.visibilityState === "visible" && !isDefault && !evaluationComplete ) { console.log("Page became visible, checking evaluation status..."); // Force une nouvelle requête pour récupérer l'état d'évaluation 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) { // Mettre fin à l'évaluation si elle est terminée setEvaluationComplete(true); // Avancer à la dernière étape des messages setStartingMessageIndex(STARTING_MESSAGES.length - 1); // Nettoyer les intervalles if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current); } if (startingMessageIntervalRef.current) { clearInterval(startingMessageIntervalRef.current); } } else { // Si l'évaluation est toujours en cours, mettre à jour l'étape actuelle // basée sur le temps écoulé 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(); } }; // Ajouter l'écouteur pour le changement de visibilité document.addEventListener("visibilitychange", handleVisibilityChange); if (isDefault) { simulateEvaluation(); } else { startEvaluation(); } // Clean up intervals on unmount 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]); // Simulate the evaluation process for pre-calculated documents const simulateEvaluation = () => { // Complete after 20 seconds simulationTimeoutRef.current = setTimeout(() => { setEvaluationComplete(true); if (startingMessageIntervalRef.current) { clearInterval(startingMessageIntervalRef.current); } setStartingMessageIndex(STARTING_MESSAGES.length - 1); // Set to last message }, SIMULATION_DURATION); }; // Format elapsed time as HH:MM:SS 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(":"); }; // Start benchmark evaluation const startEvaluation = async () => { if (!sessionId) { setError("Missing session ID"); return; } try { // Call API to start evaluation 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) { // Set up polling to check completion pollingIntervalRef.current = setInterval(async () => { try { const logsResponse = await fetch( `${API_CONFIG.BASE_URL}/evaluation-logs/${sessionId}` ); if (logsResponse.ok) { const logsResult = await logsResponse.json(); // Vérifier si l'évaluation est terminée if (logsResult.is_completed) { setEvaluationComplete(true); // Avancer à la dernière étape du message setStartingMessageIndex(STARTING_MESSAGES.length - 1); // Arrêter les intervalles clearInterval(pollingIntervalRef.current); if (startingMessageIntervalRef.current) { clearInterval(startingMessageIntervalRef.current); } } else { // Si l'évaluation est toujours en cours, estimer la progression // en fonction du temps écoulé const elapsedSinceStart = Date.now() - startTimeRef.current; // Estimer la progression (en supposant qu'une évaluation prend environ 80 secondes) const estimatedTotalTime = 80000; // 80 secondes const estimatedProgress = Math.min( elapsedSinceStart / estimatedTotalTime, 1 ); // Calculer l'étape estimée (0 à STARTING_MESSAGES.length - 1) const estimatedStepIndex = Math.min( Math.floor(estimatedProgress * STARTING_MESSAGES.length), STARTING_MESSAGES.length - 1 ); // Mettre à jour l'index des messages de démarrage si nécessaire if (estimatedStepIndex > startingMessageIndex) { setStartingMessageIndex(estimatedStepIndex); } } } } catch (error) { console.log("Error polling logs:", error); // Ne pas arrêter le polling en cas d'erreurs réseau temporaires } }, 2000); } else { setError(result.error || "Benchmark evaluation failed"); } } catch (error) { console.error("Error starting evaluation:", error); setError("Error connecting to server"); } }; return ( {error ? ( {error} ) : ( <> {evaluationComplete ? ( Evaluation completed successfully! ) : ( <> Benchmark evaluation... {/* Step progress indicator */} {`${STARTING_MESSAGES[startingMessageIndex].message} (${STARTING_MESSAGES[startingMessageIndex].step}/${STARTING_MESSAGES[startingMessageIndex].totalSteps})`} {/* Timer display */} {formatElapsedTime()} )} )} ); }; export default BenchmarkEvaluation;