Mark Duppenthaler
Combined leaderboard, simplified filters
b087e88
raw
history blame
4.53 kB
import React, { useState, useEffect } from 'react'
import API from '../API'
import AudioPlayer from './AudioPlayer'
import LoadingSpinner from './LoadingSpinner'
interface ExamplesProps {
fileType: 'image' | 'audio' | 'video'
}
type ExamplesData = {
image_url: string
audio_url?: string
video_url?: string
description: string
}
const Examples = ({ fileType }: ExamplesProps) => {
const [examples, setExamples] = useState<{
[model: string]: { [attack: string]: ExamplesData[] }
}>({})
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [selectedModel, setSelectedModel] = useState<string | null>(null)
const [selectedAttack, setSelectedAttack] = useState<string | null>(null)
useEffect(() => {
setLoading(true)
setError(null)
API.fetchExamplesByType(fileType)
.then((data) => {
// data is a dictionary from {[model]: {[attack]: {image_url, audio_url, video_url, description}}}
setExamples(data)
// get the first model and attack if available
const models = Object.keys(data)
if (models.length > 0) {
setSelectedModel(models[0])
const attacks = Object.keys(data[models[0]])
if (attacks.length > 0) {
setSelectedAttack(attacks[0]) // Set the first attack of the first model
} else {
setSelectedAttack(null) // No attacks available
}
} else {
setSelectedModel(null)
setSelectedAttack(null) // No models available
}
// Reset loading state
setLoading(false)
})
.catch((err) => {
setError(err.message)
setLoading(false)
})
}, [fileType])
// Define the Gallery component within this file
const Gallery = ({
selectedModel,
selectedAttack,
examples,
fileType,
}: {
selectedModel: string
selectedAttack: string
examples: {
[model: string]: {
[attack: string]: ExamplesData[]
}
}
fileType: 'image' | 'audio' | 'video'
}) => {
const exampleItems = examples[selectedModel][selectedAttack]
return (
<div className="example-display">
{exampleItems.map((item, index) => (
<div key={index} className="example-item">
<p>{item.description}</p>
{fileType === 'image' && (
<img src={item.image_url} alt={item.description} className="example-image" />
)}
{fileType === 'audio' && item.audio_url && (
<>
<AudioPlayer src={item.audio_url} />
<img src={item.image_url} alt={item.description} className="example-image" />
</>
)}
{fileType === 'video' && (
<video controls src={item.video_url} className="example-video" />
)}
</div>
))}
</div>
)
}
return (
<div className="examples-container">
<div className="selectors-container flex flex-col md:flex-row gap-4 mb-4">
<fieldset className="fieldset">
<legend className="fieldset-legend">Model</legend>
<select
className="select select-bordered w-full"
value={selectedModel || ''}
onChange={(e) => setSelectedModel(e.target.value || null)}
>
{Object.keys(examples).map((model) => (
<option key={model} value={model}>
{model}
</option>
))}
</select>
</fieldset>
{selectedModel && (
<fieldset className="fieldset">
<legend className="fieldset-legend">Attack</legend>
<select
className="select select-bordered w-full"
value={selectedAttack || ''}
onChange={(e) => setSelectedAttack(e.target.value || null)}
>
{Object.keys(examples[selectedModel]).map((attack) => (
<option key={attack} value={attack}>
{attack}
</option>
))}
</select>
</fieldset>
)}
</div>
{loading && <LoadingSpinner />}
{error && <p className="error">Error: {error}</p>}
{selectedModel && selectedAttack && (
<Gallery
selectedModel={selectedModel}
selectedAttack={selectedAttack}
examples={examples}
fileType={fileType}
/>
)}
</div>
)
}
export default Examples