'use client'; import { useState, useRef, useEffect } from 'react'; import { Header } from '@/components/header'; import { MainLayout } from '@/components/main-layout'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Card, CardContent } from '@/components/ui/card'; import { apiClient, type JobInfo, type ModelInfo } from '@/lib/api'; import { Loader2, Download, X, Upload } from 'lucide-react'; import { downloadImage, fileToBase64 } from '@/lib/utils'; export default function UpscalerPage() { const [formData, setFormData] = useState({ image: '', upscale_factor: 2, model: '', }); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [jobInfo, setJobInfo] = useState(null); const [generatedImages, setGeneratedImages] = useState([]); const [previewImage, setPreviewImage] = useState(null); const fileInputRef = useRef(null); const [upscalerModels, setUpscalerModels] = useState([]); useEffect(() => { const loadModels = async () => { try { // Fetch ESRGAN and upscaler models const [esrganModels, upscalerMods] = await Promise.all([ apiClient.getModels('esrgan'), apiClient.getModels('upscaler'), ]); const allModels = [...esrganModels, ...upscalerMods]; setUpscalerModels(allModels); // Set first model as default if (allModels.length > 0 && !formData.model) { setFormData(prev => ({ ...prev, model: allModels[0].name })); } } catch (err) { console.error('Failed to load upscaler models:', err); } }; loadModels(); }, []); const handleInputChange = ( e: React.ChangeEvent ) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: name === 'upscale_factor' ? Number(value) : value, })); }; const handleImageUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; try { const base64 = await fileToBase64(file); setFormData((prev) => ({ ...prev, image: base64 })); setPreviewImage(base64); setError(null); } catch (err) { setError('Failed to load image'); } }; const pollJobStatus = async (jobId: string) => { const maxAttempts = 300; let attempts = 0; const poll = async () => { try { const status = await apiClient.getJobStatus(jobId); setJobInfo(status); if (status.status === 'completed' && status.result?.images) { setGeneratedImages(status.result.images); setLoading(false); } else if (status.status === 'failed') { setError(status.error || 'Upscaling failed'); setLoading(false); } else if (status.status === 'cancelled') { setError('Upscaling was cancelled'); setLoading(false); } else if (attempts < maxAttempts) { attempts++; setTimeout(poll, 1000); } else { setError('Job polling timeout'); setLoading(false); } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to check job status'); setLoading(false); } }; poll(); }; const handleUpscale = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.image) { setError('Please upload an image first'); return; } setLoading(true); setError(null); setGeneratedImages([]); setJobInfo(null); try { // Note: You may need to adjust the API endpoint based on your backend implementation const job = await apiClient.generateImage({ prompt: `upscale ${formData.upscale_factor}x`, // Add upscale-specific parameters here based on your API } as any); setJobInfo(job); const jobId = job.request_id || job.id; if (jobId) { await pollJobStatus(jobId); } else { setError('No job ID returned from server'); setLoading(false); } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to upscale image'); setLoading(false); } }; const handleCancel = async () => { const jobId = jobInfo?.request_id || jobInfo?.id; if (jobId) { try { await apiClient.cancelJob(jobId); setLoading(false); setError('Upscaling cancelled'); } catch (err) { console.error('Failed to cancel job:', err); } } }; return (
{/* Left Panel - Form */}
{previewImage && (
Source
)}

Higher factors take longer to process

{upscalerModels.length === 0 && !loading && (

No upscaler models found. Please add ESRGAN or upscaler models to your models directory.

)}
{loading && ( )}
{error && (
{error}
)} {jobInfo && (

Job ID: {jobInfo.id}

Status: {jobInfo.status}

{jobInfo.progress !== undefined && (

Progress: {Math.round(jobInfo.progress * 100)}%

)}
)}

Note

Upscaling functionality depends on your backend configuration and available upscaler models.

{/* Right Panel - Upscaled Images */}

Upscaled Image

{generatedImages.length === 0 ? (

{loading ? 'Upscaling...' : 'Upscaled image will appear here'}

) : (
{generatedImages.map((image, index) => (
{`Upscaled
))}
)}
); }