import React, { useEffect, useState } from 'react'; import { useTranscriptionStore } from '../stores/transcriptionStore'; import { CheckCircleIcon, ClockIcon, InformationCircleIcon } from '@heroicons/react/24/outline'; const ServerStatusIndicator: React.FC = () => { const { serverStatus, serverHealth, startStatusPolling, stopStatusPolling, fetchServerHealth } = useTranscriptionStore(); const [showTooltip, setShowTooltip] = useState(false); // Start polling when component mounts useEffect(() => { startStatusPolling(); // Also fetch server health initially fetchServerHealth(); // Cleanup on unmount return () => { stopStatusPolling(); }; }, [startStatusPolling, stopStatusPolling, fetchServerHealth]); if (!serverStatus) { return (
Connecting to server...
); } const formatDuration = (seconds: number): string => { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins}:${secs.toString().padStart(2, '0')}`; }; const getOperationLabel = (operation: string): string => { switch (operation) { case 'transcribe': return 'Short Transcription'; case 'transcribe_long': return 'Long Transcription'; case 'align': return 'Alignment'; default: return 'Processing'; } }; const renderHealthTooltip = () => { if (!serverHealth) return null; return (
Server Health
Status: {serverHealth.status}
Version: {serverHealth.version}
Device: {serverHealth.device}
CUDA: {serverHealth.cuda_available ? "Available" : "Unavailable"}
FFmpeg: {serverHealth.ffmpeg_available ? "Available" : "Unavailable"}
{serverHealth.gpu_name && (
GPU: {serverHealth.gpu_name}
)} {serverHealth.gpu_count && serverHealth.gpu_count > 1 && (
GPU Count: {serverHealth.gpu_count}
)} {/* GPU Memory Information */} {serverHealth.gpu_memory_total_mb && ( <>
GPU Memory
Used: {serverHealth.gpu_memory_reserved_mb?.toFixed(1)} MB
Total: {serverHealth.gpu_memory_total_mb?.toFixed(1)} MB
Free: {serverHealth.gpu_memory_free_mb?.toFixed(1)} MB
{/* Memory usage bar */} {serverHealth.gpu_memory_total_mb && serverHealth.gpu_memory_reserved_mb && (
{((serverHealth.gpu_memory_reserved_mb / serverHealth.gpu_memory_total_mb) * 100).toFixed(1)}% used
)} )}
{/* Tooltip arrow pointing to the left (towards the info icon) */}
); }; if (serverStatus.is_busy) { const progress = serverStatus.progress || 0; const progressPercent = Math.round(progress * 100); return (
Server Busy
{/* Health info icon with tooltip */}
setShowTooltip(true)} onMouseLeave={() => setShowTooltip(false)} /> {showTooltip && renderHealthTooltip()}
{getOperationLabel(serverStatus.current_operation || 'processing')} {progressPercent}%
{serverStatus.duration_seconds && (
Duration: {formatDuration(serverStatus.duration_seconds)}
)} {/* Progress bar */}
); } return (
Server Ready
{/* Health info icon with tooltip */}
setShowTooltip(true)} onMouseLeave={() => setShowTooltip(false)} /> {showTooltip && renderHealthTooltip()}
Completed: {serverStatus.total_completed} transcriptions
); }; export default ServerStatusIndicator;