import React from 'react' import AudioPlayer, { AudioPlayerHandle } from './AudioPlayer' import type { ExamplesData } from './Examples' import { groupByNameAndVariant } from './galleryUtils' import ExampleDetailsSection from './ExampleDetailsSection' import ExampleVariantSelector from './ExampleVariantSelector' import ExampleVariantMetricsTable from './ExampleVariantMetricsTable' import ExampleVariantToggle, { handleVariantToggleClick } from './ExampleVariantToggle' 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) // 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]) // 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 || {}]) )} />
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) => { // console.log(`Current time for ${variantKey}: ${currentTime}`) playbackTimeRef.current = currentTime variantKeys.forEach((v) => { if (v !== variantKey && audioRefs[v]?.current) { audioRefs[v]?.current?.setTime(currentTime) } }) }} />
) : null )} {variants[selectedVariant].image_url && ( {selectedAudio} handleVariantToggleClick( toggleMode, selectedVariant, setSelectedVariant, variantKeys ) } /> )}
)}
) } export default AudioGallery