import React, { useState, useEffect } from 'react'; import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, TextField, Box, CircularProgress, Stepper, Step, StepLabel, Link, Alert, LinearProgress } from '@mui/material'; import api from '../api'; import { hfAuthDialogStyles } from '../theme'; const HfAuthDialog = ({ open, onClose, onModelsDownloaded }) => { const [activeStep, setActiveStep] = useState(0); const [missingModels, setMissingModels] = useState([]); const [checkingStatus, setCheckingStatus] = useState(true); const [token, setToken] = useState(''); const [error, setError] = useState(null); const [isProcessing, setIsProcessing] = useState(false); const [downloadingModel, setDownloadingModel] = useState(null); const steps = ['Check required models', 'Authenticate', 'Download models']; useEffect(() => { if (open) { checkModelStatus(); } else { setActiveStep(0); setError(null); setToken(''); setMissingModels([]); } }, [open]); const checkModelStatus = async () => { setCheckingStatus(true); setError(null); try { const response = await api.get('/api/base-models/status'); const models = response.data.base_models; const missing = Object.entries(models) .filter(([_, info]) => !info.downloaded) .map(([id, info]) => ({ id, ...info })); setMissingModels(missing); if (missing.length === 0) { setActiveStep(3); } else { setActiveStep(1); } } catch (err) { setError(err.response?.data?.error || err.message || 'Failed to check model status.'); } finally { setCheckingStatus(false); } }; const handleLogin = async () => { if (!token.trim()) { setError('Please enter a Hugging Face token.'); return; } setIsProcessing(true); setError(null); try { await api.post('/api/hf-login', { token: token.trim() }); setActiveStep(2); startDownloads(); } catch (err) { setError(err.response?.data?.error || err.message || 'Authentication failed. Please check your token.'); setIsProcessing(false); } }; const startDownloads = async () => { try { for (const model of missingModels) { setDownloadingModel(model.name); await api.post(`/api/models/${model.id}/accept-terms`); await api.post(`/api/models/${model.id}/download`); } setActiveStep(3); if (onModelsDownloaded) { onModelsDownloaded(); } } catch (err) { setError(err.response?.data?.error || err.message || 'Failed to download models.'); } finally { setIsProcessing(false); setDownloadingModel(null); } }; const handleClose = () => { if (isProcessing && activeStep === 2) { return; } onClose(activeStep === 3); }; const getStepContent = (stepIndex) => { if (checkingStatus) { return ( Checking model availability... ); } switch (stepIndex) { case 1: return ( Some required base models are missing. You need a Hugging Face access token to download them. Before proceeding, please ensure you have visited huggingface.co and accepted the terms of use for the required models (e.g., stabilityai/stable-audio-open-1.0). setToken(e.target.value)} placeholder="hf_xxxxxxxxxxxxxxxxxxx..." margin="normal" variant="outlined" /> You can get a token from{' '} your Hugging Face settings . "Read" access to public gated repos is needed. ); case 2: return ( Downloading {downloadingModel}... This may take several minutes depending on your connection speed. Do not close the application. ); case 3: return ( All models are ready! You can now close this dialog and begin using Fragmenta. ); default: return "Unknown step"; } }; return ( Hugging Face Authentication {steps.map((label) => ( {label} ))} {error && ( {error} )} {getStepContent(activeStep)} {activeStep !== 3 && activeStep !== 2 && ( )} {activeStep === 1 && ( )} {activeStep === 3 && ( )} ); }; export default HfAuthDialog;