import React, { useState, useMemo } from "react"; import axios from "axios"; import { Box, Button, Container, Typography, Paper, ThemeProvider, createTheme, IconButton, Card, CardMedia, Chip, AppBar, Toolbar, TextField, Select, FormControl, InputLabel, MenuItem, LinearProgress, Collapse, Tooltip, Divider } from "@mui/material"; import { CloudUpload as CloudUploadIcon, Landscape as LandscapeIcon, DarkMode as DarkModeIcon, LightMode as LightModeIcon, ExpandMore as ExpandMoreIcon, ExpandLess as ExpandLessIcon, GitHub as GitHubIcon, LinkedIn as LinkedInIcon } from "@mui/icons-material"; const LANGUAGES = [ { code: "en", flag: "en", label: "English" }, { code: "fr", flag: "fr", label: "Français" }, { code: "wo", flag: "wo", label: "Wolof" }, ]; function App() { const [mode, setMode] = useState("light"); const theme = useMemo(() => createTheme({ palette: { mode, primary: { main: "#2e7d32" }, }, shape: { borderRadius: 16 }, components: { MuiPaper: { styleOverrides: { root: { borderRadius: 20, boxShadow: mode === "dark" ? "0 8px 32px rgba(0,0,0,0.6)" : "0 8px 32px rgba(0,0,0,0.12)", transition: "transform 0.25s ease, box-shadow 0.25s ease", "&:hover": { transform: "translateY(-4px)", boxShadow: mode === "dark" ? "0 16px 48px rgba(0,0,0,0.7)" : "0 16px 48px rgba(0,0,0,0.18)", }, }, }, }, MuiCard: { styleOverrides: { root: { borderRadius: 20, boxShadow: mode === "dark" ? "0 8px 32px rgba(0,0,0,0.6)" : "0 8px 32px rgba(0,0,0,0.12)", transition: "transform 0.25s ease, box-shadow 0.25s ease", "&:hover": { transform: "translateY(-4px)", boxShadow: mode === "dark" ? "0 16px 48px rgba(0,0,0,0.7)" : "0 16px 48px rgba(0,0,0,0.18)", }, }, }, }, MuiButton: { styleOverrides: { root: { borderRadius: 10, textTransform: "none", fontWeight: 600 }, }, }, }, }), [mode] ); const [language, setLanguage] = useState("en"); const texts = { en: { title: "Intel Image Classifier", subtitle: "Classify natural scenes", upload: "Upload Image", urlBtn: "Load image from URL", classify: "Classify", result: "Result", confidence: "Confidence", selectModel: "Select Model", processing: "Processing...", selectImage: "Please provide an image", classes: "Possible Classes", reset: "Reset", details: "Details", hideDetails: "Hide", unknown: "Image not recognized", }, fr: { title: "Classificateur Intel", subtitle: "Classifiez des scènes naturelles avec le deep learning", upload: "Télécharger Image", urlBtn: "Charger image depuis URL", classify: "Classer", result: "Résultat", confidence: "Confiance", selectModel: "Choisir modèle", processing: "Traitement...", selectImage: "Veuillez fournir une image", classes: "Classes possibles", reset: "Réinitialiser", details: "Détails", hideDetails: "Masquer", unknown: "Image non reconnue", }, wo: { title: "Intel Xët-Nataal (IA)", subtitle: "Jëfandikoo IA ngir xool nataal yi", upload: "Yeb Nataal bi", urlBtn: "Yeb nataal ci URL", classify: "Wone", result: "Njëg", confidence: "Loo xam ne", selectModel: "Tànn modil", processing: "Di liggéey...", selectImage: "Tànnal ab nataal", classes: "Yëgël yi", reset: "Tàkku", details: "Xam ci kanam", hideDetails: "Planque", unknown: "Nataal xamul", } }; const t = texts[language]; const CLASS_LABELS = { buildings: { en: "Buildings", fr: "Bâtiments", wo: "Kër yi" }, forest: { en: "Forest", fr: "Forêt", wo: "Géej bu wees" }, glacier: { en: "Glacier", fr: "Glacier", wo: "Dëkk bu sedd" }, mountain: { en: "Mountain", fr: "Montagne", wo: "Tund bi" }, sea: { en: "Sea", fr: "Mer", wo: "Géej bi" }, street: { en: "Street", fr: "Rue", wo: "Yoon bi" }, }; const getLabel = (cls) => CLASS_LABELS[cls]?.[language] ?? cls; const [selectedImage, setSelectedImage] = useState(null); const [imageUrl, setImageUrl] = useState(""); const [preview, setPreview] = useState(null); const [showUrlInput, setShowUrlInput] = useState(false); const [model, setModel] = useState("pytorch"); const [result, setResult] = useState(null); const [isProcessing, setIsProcessing] = useState(false); const [error, setError] = useState(null); const [showDetails, setShowDetails] = useState(false); const handleImageUpload = (event) => { const file = event.target.files[0]; if (!file) return; setSelectedImage(file); setPreview(URL.createObjectURL(file)); setImageUrl(""); setResult(null); setError(null); setShowDetails(false); }; const resetAll = () => { setSelectedImage(null); setImageUrl(""); setPreview(null); setResult(null); setError(null); setShowDetails(false); }; const processImage = async () => { if (!selectedImage && !imageUrl) { setError(t.selectImage); return; } setIsProcessing(true); setError(null); try { const formData = new FormData(); if (selectedImage) { formData.append("image", selectedImage); } else { formData.append("image_url", imageUrl); } formData.append("model", model); const response = await axios.post( "http://127.0.0.1:8000/api/classify/", formData, { headers: { "Content-Type": "multipart/form-data" } } ); const data = response.data; const conf = Math.round((parseFloat(data.confidence) || 0) * 100); const allProbs = (data.all_probabilities || []).map(item => ({ class: item.class, probability: parseFloat(item.probability) || 0 })); setResult({ predictedClass: conf < 50 ? "unknown" : (data.predicted_class || "unknown"), confidence: conf, allProbabilities: allProbs, modelUsed: data.model_used || model }); } catch (err) { console.error(err); setError("Classification error. Please try again."); } finally { setIsProcessing(false); } }; return ( {/* HEADER */} {t.title} {LANGUAGES.map((lang) => ( setLanguage(lang.code)} size="small" sx={{ fontSize: "1.4rem", opacity: language === lang.code ? 1 : 0.35, transition: "opacity 0.2s", p: "4px", "&:hover": { opacity: 0.8 } }} > {lang.flag} ))} setMode(mode === "light" ? "dark" : "light")}> {mode === "light" ? : } {/* MAIN */} {/* INPUT BOX */} {t.title} {t.subtitle} {t.selectModel} {t.upload} {t.urlBtn} {showUrlInput && ( { setImageUrl(e.target.value); setSelectedImage(null); setPreview(e.target.value); }} sx={{ mt: 2 }} /> )} {t.classes}: {Object.keys(CLASS_LABELS).map((cls) => ( ))} {/* IMAGE PREVIEW */} {preview && ( {isProcessing && } )} {/* ERROR */} {error && ( {error} )} {/* RESULT */} {result && ( {t.result} {t.confidence}: {result.confidence}% Model: {result.modelUsed} {result.allProbabilities.map((item) => ( {getLabel(item.class)} {Math.round(item.probability * 100)}% ))} )} {/* FOOTER */} © 2026 Intel Image Classifier By Tsemo Danielle window.open("https://github.com/nguemtchuengdanielle/")}> window.open("https://linkedin.com/in/danielle-tsemo3")} sx={{ color: "#0077b5" }}> ); } export default App;