Mark Duppenthaler
update with css
d588824
import React, { useState, useEffect } from 'react';
import api from '../api';
// Dummy examples for when API fails
const dummyExamples = [
{
name: 'Sample Image 1',
attack: 'Gaussian Blur',
path: 'https://via.placeholder.com/300x200?text=Example+Image',
detected: true
},
{
name: 'Sample Image 2',
attack: 'JPEG Compression',
path: 'https://via.placeholder.com/300x200?text=Example+Image',
detected: false
},
{
name: 'Sample Image 3',
attack: 'Rotation',
path: 'https://via.placeholder.com/300x200?text=Example+Image',
detected: true
}
];
function ExampleViewer({ benchmark }) {
const [models, setModels] = useState([]);
const [selectedModel, setSelectedModel] = useState('');
const [attacks, setAttacks] = useState([]);
const [selectedAttack, setSelectedAttack] = useState('');
const [examples, setExamples] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// Fetch models when benchmark changes
useEffect(() => {
async function fetchModels() {
try {
setLoading(true);
const response = await api.getLeaderboard(benchmark);
if (response.success) {
// Extract unique model names
const modelNames = [...new Set(response.data.map(item => item.model))];
setModels(modelNames);
// Set first model as default if available
if (modelNames.length > 0) {
setSelectedModel(modelNames[0]);
}
} else {
console.error('Failed to fetch models:', response.error);
// Use dummy models
setModels(['WatermarkA', 'WatermarkB', 'WatermarkC']);
setSelectedModel('WatermarkA');
}
} catch (err) {
console.error('Error fetching models:', err);
// Use dummy models
setModels(['WatermarkA', 'WatermarkB', 'WatermarkC']);
setSelectedModel('WatermarkA');
} finally {
setLoading(false);
}
}
fetchModels();
}, [benchmark]);
// Fetch attacks when benchmark changes
useEffect(() => {
async function fetchAttacks() {
try {
const response = await api.getAttacks(benchmark);
if (response.success) {
setAttacks(response.attacks);
} else {
// Use dummy attacks
setAttacks([
{ name: 'Gaussian Blur', description: 'Applies a Gaussian blur to the image' },
{ name: 'JPEG Compression', description: 'Compresses the image using JPEG algorithm' },
{ name: 'Rotation', description: 'Rotates the image slightly' }
]);
}
} catch (err) {
console.error('Error fetching attacks:', err);
// Use dummy attacks
setAttacks([
{ name: 'Gaussian Blur', description: 'Applies a Gaussian blur to the image' },
{ name: 'JPEG Compression', description: 'Compresses the image using JPEG algorithm' },
{ name: 'Rotation', description: 'Rotates the image slightly' }
]);
}
}
fetchAttacks();
}, [benchmark]);
// Fetch examples when model or attack changes
useEffect(() => {
if (!selectedModel) return;
async function fetchExamples() {
try {
setLoading(true);
const response = await api.getExamples(benchmark, selectedModel, selectedAttack);
if (response.success) {
setExamples(response.examples);
setError(null);
} else {
console.error('Failed to fetch examples:', response.error);
// Use dummy examples instead of showing an error
setExamples(dummyExamples);
setError(null);
}
} catch (err) {
console.error('Error fetching examples:', err);
// Use dummy examples instead of showing an error
setExamples(dummyExamples);
setError(null);
} finally {
setLoading(false);
}
}
fetchExamples();
}, [benchmark, selectedModel, selectedAttack]);
const handleModelChange = (e) => {
setSelectedModel(e.target.value);
};
const handleAttackChange = (e) => {
setSelectedAttack(e.target.value);
};
const renderExampleContent = (example) => {
// Check if it's an image or audio based on file extension
const isImage = /\.(jpg|jpeg|png|gif|webp)$/i.test(example.path) || example.path.includes('placeholder');
const isAudio = /\.(mp3|wav|ogg)$/i.test(example.path);
if (isImage) {
return (
<img
src={example.path}
alt={example.name}
className="w-full h-auto rounded object-cover"
/>
);
} else if (isAudio) {
return (
<audio
controls
src={example.path}
className="w-full mt-2"
>
Your browser does not support audio.
</audio>
);
} else {
return <div className="p-4 bg-gray-100 text-gray-500 text-center rounded">Unsupported file type</div>;
}
};
return (
<div className="mt-4">
<h2 className="text-2xl font-display font-medium text-secondary mb-6">
Example Viewer - {benchmark.charAt(0).toUpperCase() + benchmark.slice(1)} Watermarks
</h2>
<div className="flex flex-wrap gap-4 mb-6">
<div className="flex flex-col">
<label htmlFor="model-select" className="mb-2 text-sm font-medium text-gray-700">
Model:
</label>
<select
id="model-select"
value={selectedModel}
onChange={handleModelChange}
disabled={loading || models.length === 0}
className="border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary/50 min-w-[200px]"
>
{models.map(model => (
<option key={model} value={model}>{model}</option>
))}
</select>
</div>
<div className="flex flex-col">
<label htmlFor="attack-select" className="mb-2 text-sm font-medium text-gray-700">
Attack:
</label>
<select
id="attack-select"
value={selectedAttack}
onChange={handleAttackChange}
disabled={loading}
className="border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary/50 min-w-[200px]"
>
<option value="">All Attacks</option>
{attacks.map(attack => (
<option key={attack.name} value={attack.name}>{attack.name}</option>
))}
</select>
</div>
</div>
{loading ? (
<div className="flex justify-center items-center p-8">
<div className="animate-pulse text-primary font-medium">Loading examples...</div>
</div>
) : error ? (
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md">
Error: {error}
</div>
) : examples.length === 0 ? (
<div className="bg-yellow-50 border border-yellow-200 text-yellow-700 px-4 py-3 rounded-md">
No examples found for the selected options.
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{examples.map((example, index) => (
<div key={index} className="bg-white rounded-lg shadow-md overflow-hidden border border-gray-200 hover:shadow-lg transition-shadow">
<div className="bg-primary text-white px-4 py-3">
<h3 className="font-medium truncate">{example.name}</h3>
</div>
{example.attack && (
<div className="px-4 py-2 bg-gray-50 border-b border-gray-200 text-sm text-gray-600">
Attack: {example.attack}
</div>
)}
<div className="p-4">
{renderExampleContent(example)}
{example.hasOwnProperty('detected') && (
<div className={`mt-3 text-sm font-medium ${example.detected ? 'text-green-600' : 'text-red-600'}`}>
Watermark {example.detected ? 'detected ✓' : 'not detected ✗'}
</div>
)}
</div>
</div>
))}
</div>
)}
</div>
);
}
export default ExampleViewer;