'use client'; import { useState, useEffect } from 'react'; import { apiClient, type ModelInfo, type QueueStatus, type JobInfo } from '@/lib/api'; import { AlertCircle, CheckCircle2, Loader2, Activity, Image } from 'lucide-react'; import { cn } from '@/lib/utils'; export function ModelStatusBar() { const [loadedModel, setLoadedModel] = useState(null); const [loading, setLoading] = useState(true); const [queueStatus, setQueueStatus] = useState(null); const [activeJob, setActiveJob] = useState(null); const [recentlyCompleted, setRecentlyCompleted] = useState([]); useEffect(() => { const checkStatus = async () => { try { const [loadedModels, queue] = await Promise.all([ apiClient.getModels(undefined, true), apiClient.getQueueStatus(), ]); setLoadedModel(loadedModels.models.length > 0 ? loadedModels.models[0] : null); setQueueStatus(queue); // Find active/processing job const processing = queue.jobs.find( (job) => job.status === 'processing' || job.status === 'queued' ); setActiveJob(processing || null); // Keep track of recently completed jobs (last 30 seconds) const now = Date.now(); const thirtySecondsAgo = now - 30000; // Update recently completed jobs const completedJobs = queue.jobs.filter( (job) => job.status === 'completed' && job.updated_at && new Date(job.updated_at).getTime() > thirtySecondsAgo ); setRecentlyCompleted(completedJobs); } catch (error) { console.error('Failed to check status:', error); } finally { setLoading(false); } }; checkStatus(); // Poll every 2 seconds when there's an active job, otherwise every 5 seconds const pollInterval = activeJob ? 2000 : 5000; const interval = setInterval(checkStatus, pollInterval); return () => clearInterval(interval); }, [activeJob]); if (loading) { return null; } // Determine status styling let statusBg = ''; let statusBorder = ''; let statusText = ''; let icon = null; let content = null; if (activeJob && activeJob.status === 'processing') { // Active generation in progress statusBg = 'bg-blue-600 dark:bg-blue-700'; statusBorder = 'border-blue-500 dark:border-blue-600'; statusText = 'text-white'; icon = ; const progress = activeJob.progress !== undefined ? Math.round(activeJob.progress * 100) : 0; content = ( <> Generating: {activeJob.id}
{progress}%
); } else if (activeJob && activeJob.status === 'queued') { // Job queued but not processing yet statusBg = 'bg-purple-600 dark:bg-purple-700'; statusBorder = 'border-purple-500 dark:border-purple-600'; statusText = 'text-white'; icon = ; content = ( <> Queued: {queueStatus?.size || 0} job(s) waiting {activeJob.queue_position !== undefined && ( Position: {activeJob.queue_position} )} ); } else if (recentlyCompleted.length > 0) { // Show recently completed jobs with their results const latestCompleted = recentlyCompleted[0]; const hasOutputs = (latestCompleted.outputs?.length ?? 0) > 0 || (latestCompleted.result?.images?.length ?? 0) > 0; statusBg = 'bg-green-600 dark:bg-green-700'; statusBorder = 'border-green-500 dark:border-green-600'; statusText = 'text-white'; icon = hasOutputs ? : ; const outputCount = (latestCompleted.outputs?.length ?? 0) + (latestCompleted.result?.images?.length ?? 0); content = ( <> Completed: {latestCompleted.id} {hasOutputs && ( <> • Generated {outputCount} image{outputCount !== 1 ? 's' : ''}
100%
)} ); } else if (loadedModel) { // Model loaded, ready statusBg = 'bg-green-600 dark:bg-green-700'; statusBorder = 'border-green-500 dark:border-green-600'; statusText = 'text-white'; icon = ; content = ( <> Model Ready: {loadedModel.name} {loadedModel.sha256_short && ( ({loadedModel.sha256_short}) )} ); } else { // No model loaded statusBg = 'bg-amber-600 dark:bg-amber-700'; statusBorder = 'border-amber-500 dark:border-amber-600'; statusText = 'text-white'; icon = ; content = ( <> No Model Loaded Please load a model from the Models page ); } return (
{icon} {content}
); }