import React from 'react' import AudioPlayer, { AudioPlayerHandle } from './AudioPlayer' import type { ExamplesData } from './Examples' import { groupByNameAndVariant, VARIANT_NAME_MAP } from './galleryUtils' import ExampleDetailsSection from './ExampleDetailsSection' import ExampleVariantSelector from './ExampleVariantSelector' import ExampleVariantMetricsTables from './ExampleVariantMetricsTable' import ExampleVariantToggle, { handleVariantToggleClick } from './ExampleVariantToggle' import LoadingSpinner from './LoadingSpinner' import API from '../API' import { InformationCircleIcon } from '@heroicons/react/24/outline' import { Tooltip as ReactTooltip } from 'react-tooltip' import 'react-tooltip/dist/react-tooltip.css' interface GalleryProps { selectedModel: string selectedAttack: string examples: { [model: string]: { [attack: string]: ExamplesData[] } } } const AudioGallery: React.FC = ({ selectedModel, selectedAttack, examples }) => { const exampleItems = examples[selectedModel][selectedAttack] const grouped = groupByNameAndVariant(exampleItems) const audioNames = Object.keys(grouped) const [selectedAudio, setSelectedAudio] = React.useState(audioNames[0] || '') const variants = grouped[selectedAudio] || {} const variantKeys = Object.keys(variants) const [selectedVariant, setSelectedVariant] = React.useState(variantKeys[0] || '') const [toggleMode, setToggleMode] = React.useState<'wmd' | 'attacked'>('wmd') // Shared playback state const playbackTimeRef = React.useRef(0) const [playingVariant, setPlayingVariant] = React.useState(null) // Refs for all players const audioRefs = React.useMemo(() => { const refs: Record> = {} variantKeys.forEach((v) => { refs[v] = React.createRef() }) return refs }, [variantKeys.join(',')]) // Add state for rewind seconds const [rewindSeconds, setRewindSeconds] = React.useState(0.5) const [imageLoading, setImageLoading] = React.useState(true) // Play handler: pause all others, sync time const handlePlay = (variant: string) => { console.log(`Playing variant: ${variant}`) setPlayingVariant(variant) variantKeys.forEach((v) => { if (v !== variant && audioRefs[v]?.current) { audioRefs[v]?.current?.pause() // audioRefs[v]?.current?.setTime(playbackTimeRef.current) } }) } // Pause handler const handlePause = (variant: string) => { console.log(`Pausing variant: ${variant}`) if (playingVariant === variant) setPlayingVariant(null) } React.useEffect(() => { setSelectedVariant(variantKeys[0] || '') }, [selectedAudio]) // Reset image loading state when selected variant changes React.useEffect(() => { if (variants[selectedVariant]?.image_url) { setImageLoading(true) } }, [selectedVariant, variants[selectedVariant]?.image_url]) // When selectedVariant changes, play that variant and pause others, syncing position React.useEffect(() => { if (!selectedVariant) { return } if (playingVariant == null) { // On page load don't auto play, only when swapping tracks return } // Rewind playbackTimeRef by rewindSeconds, clamp to 0 playbackTimeRef.current = Math.max(0, playbackTimeRef.current - rewindSeconds) setPlayingVariant(selectedVariant) variantKeys.forEach((v) => { if (v !== selectedVariant) { audioRefs[v]?.current?.pause() } if (audioRefs[v]?.current) { audioRefs[v]?.current?.setTime(playbackTimeRef.current) } }) }, [selectedVariant]) console.log(audioRefs[selectedVariant]?.current?.getCurrentTime()) if (!audioNames.length) { return (
No audio examples available. Please select another model and attack.
) } return (
Audio
{selectedAudio && selectedVariant && variants[selectedVariant] && ( <> [v, variants[v]?.metadata || {}]) )} />
You can also change the variant using keys 1, 2, 3, 4{' '} on your keyboard.
Rewind Seconds setRewindSeconds(Math.max(0, Number(e.target.value)))} className="input input-bordered w-20" placeholder="Seconds" />
{variantKeys.map((variantKey) => variants[variantKey].audio_url ? (
{variantKey}
handlePlay(variantKey)} onPause={() => handlePause(variantKey)} onAudioProcess={(currentTime) => { playbackTimeRef.current = currentTime variantKeys.forEach((v) => { if (v !== variantKey && audioRefs[v]?.current) { audioRefs[v]?.current?.setTime(currentTime) } }) }} />
) : null )} {variants[selectedVariant].image_url && (
{imageLoading && } {selectedAudio} setImageLoading(false)} onError={() => setImageLoading(false)} onClick={() => handleVariantToggleClick( toggleMode, selectedVariant, setSelectedVariant, variantKeys ) } />
)}
)}
) } export default AudioGallery