Spaces:
Running
Running
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 | |