/** * QuickActions - One-click enhancement buttons for the Edit page. * * Provides quick access to AI enhancement features: * - Enhance (RealESRGAN): Improve photo quality * - Restore (SwinIR): Remove artifacts and compression * - Fix Faces (GFPGAN): Restore and enhance faces * - Upscale (UltraSharp): Increase resolution 2x/4x * * This component is additive and can be dropped into any page. */ import React, { useState, useEffect } from 'react'; import { Loader2, Sparkles, Wand2, User, Maximize, Info, AlertTriangle } from 'lucide-react'; import { enhanceImage, ENHANCE_MODES } from '../enhance/enhanceApi'; import { upscaleImage } from '../enhance/upscaleApi'; import { checkCapability } from '../enhance/capabilitiesApi'; /** * QuickActions component for one-click image enhancement. * * @example * ```tsx * { * console.log(`Enhanced with ${mode}: ${url}`) * setCurrentImage(url) * }} * onError={(err) => setError(err)} * /> * ``` */ export function QuickActions({ backendUrl, apiKey, imageUrl, onResult, onError, disabled = false, compact = false, showInfo = false, }) { const [loading, setLoading] = useState(null); const [upscaleLoading, setUpscaleLoading] = useState(false); const [upscaleScale, setUpscaleScale] = useState(2); const [showInfoTip, setShowInfoTip] = useState(null); // Capability check for Fix Faces — avoids blind 503 errors const [facesAvailable, setFacesAvailable] = useState(null); // null = checking const [facesReason, setFacesReason] = useState(null); const [showFacesSetup, setShowFacesSetup] = useState(false); useEffect(() => { let cancelled = false; checkCapability(backendUrl, 'enhance_faces', apiKey) .then((cap) => { if (cancelled) return; setFacesAvailable(cap.available); if (!cap.available) setFacesReason(cap.reason ?? 'Face restoration nodes not installed in ComfyUI'); }) .catch(() => { if (!cancelled) setFacesAvailable(null); // unknown — let user try }); return () => { cancelled = true; }; }, [backendUrl, apiKey]); const handleEnhance = async (mode) => { if (!imageUrl || loading || disabled) return; // If Fix Faces is unavailable, show setup instructions instead of hitting 503 if (mode === 'faces' && facesAvailable === false) { setShowFacesSetup(true); return; } setLoading(mode); try { const result = await enhanceImage({ backendUrl, apiKey, imageUrl, mode, scale: mode === 'faces' ? 1 : 2, // Faces doesn't need upscaling }); const enhancedUrl = result?.media?.images?.[0]; if (enhancedUrl) { onResult(enhancedUrl, mode); } else { onError('Enhancement completed but no image was returned.'); } } catch (e) { onError(e instanceof Error ? e.message : 'Enhancement failed'); } finally { setLoading(null); } }; const handleUpscale = async () => { if (!imageUrl || upscaleLoading || loading || disabled) return; setUpscaleLoading(true); try { const result = await upscaleImage({ backendUrl, apiKey, imageUrl, scale: upscaleScale, model: '4x-UltraSharp.pth', }); const upscaledUrl = result?.media?.images?.[0]; if (upscaledUrl) { onResult(upscaledUrl, 'upscale'); } else { onError('Upscale completed but no image was returned.'); } } catch (e) { onError(e instanceof Error ? e.message : 'Upscale failed'); } finally { setUpscaleLoading(false); } }; const getIcon = (mode) => { switch (mode) { case 'photo': return ; case 'restore': return ; case 'faces': return ; } }; const isDisabled = !imageUrl || disabled; const anyLoading = loading !== null || upscaleLoading; if (compact) { return (
{ENHANCE_MODES.map((modeInfo) => ())} {/* Compact upscale button */}
); } // Technical info for each action const actionInfo = { photo: { endpoint: '/v1/enhance', model: 'RealESRGAN_x4plus', type: '1-click' }, restore: { endpoint: '/v1/enhance', model: 'SwinIR', type: '1-click' }, faces: { endpoint: '/v1/enhance', model: 'GFPGAN (ComfyUI)', type: '1-click' }, upscale: { endpoint: '/v1/upscale', model: '4x-UltraSharp', type: '1-click' }, }; return (
Quick Enhance
{ENHANCE_MODES.map((modeInfo) => (
{/* Info tooltip */} {showInfo && (
{showInfoTip === modeInfo.id && (
{actionInfo[modeInfo.id]?.endpoint}
Model: {actionInfo[modeInfo.id]?.model}
)}
)}
))} {/* Upscale section with 2x/4x toggle */}
Upscale 1-click
Increase resolution with AI
{/* Scale toggle */}
{/* Info tooltip for upscale */} {showInfo && (
{showInfoTip === 'upscale' && (
{actionInfo.upscale.endpoint}
Model: {actionInfo.upscale.model}
)}
)}

One-click AI enhancement. Results are added to your version history.

{/* Fix Faces setup guidance modal */} {showFacesSetup && (<>
setShowFacesSetup(false)}/>
setShowFacesSetup(false)}>
e.stopPropagation()}>

Fix Faces — Setup Required

ComfyUI face restoration nodes are not installed

If Impact-Pack is already installed:
# Restart ComfyUI so it registers the new nodes
Then click Re-check below
If not installed yet:
# 1. Install Impact-Pack custom node
cd ComfyUI/custom_nodes
git clone https://github.com/ltdrdata/ComfyUI-Impact-Pack.git
# 2. Install Python deps (in ComfyUI's Python env)
pip install ultralytics facexlib gfpgan
# 3. Restart ComfyUI
{facesReason && (

{facesReason}

)}
)}
); } export default QuickActions;