Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Mark Duppenthaler
commited on
Commit
·
013aff2
1
Parent(s):
08dfd47
Video Examples
Browse files- backend/examples.py +7 -5
- frontend/src/components/VideoGallery.tsx +116 -7
backend/examples.py
CHANGED
|
@@ -10,7 +10,7 @@ def group_files_by_index(file_paths, data_type="audio"):
|
|
| 10 |
if data_type == "audio":
|
| 11 |
pattern = r"audio_(\d+).(png|wav)"
|
| 12 |
elif data_type == "video":
|
| 13 |
-
pattern = r"video_(\d+).(png|
|
| 14 |
else:
|
| 15 |
pattern = r"img_(\d+).png"
|
| 16 |
# Dictionary to store the grouped files
|
|
@@ -110,11 +110,12 @@ def build_infos(abs_path: Path, datatype: str, dataset_name: str, db_key: str):
|
|
| 110 |
eval_results_path = abs_path + f"{dataset_name}_1k/examples_eval_results.json"
|
| 111 |
elif datatype == "video":
|
| 112 |
quality_metrics = ["psnr", "ssim", "lpips", "msssim", "vmaf"]
|
| 113 |
-
extensions = ["
|
| 114 |
datatype_abbr = "video"
|
| 115 |
eval_results_path = abs_path + f"{dataset_name}/examples_eval_results.json"
|
| 116 |
|
| 117 |
response = requests.get(eval_results_path)
|
|
|
|
| 118 |
if response.status_code == 200:
|
| 119 |
results_data = response.json()
|
| 120 |
else:
|
|
@@ -130,7 +131,7 @@ def build_infos(abs_path: Path, datatype: str, dataset_name: str, db_key: str):
|
|
| 130 |
]
|
| 131 |
|
| 132 |
file_patterns = generate_file_patterns(prefixes, extensions)
|
| 133 |
-
|
| 134 |
infos = {}
|
| 135 |
for model_name in dataset.keys():
|
| 136 |
model_infos = {}
|
|
@@ -192,7 +193,7 @@ def build_infos(abs_path: Path, datatype: str, dataset_name: str, db_key: str):
|
|
| 192 |
file_info["image_url"] = file.replace(".wav", ".png")
|
| 193 |
file_info["audio_url"] = file
|
| 194 |
elif datatype == "video":
|
| 195 |
-
file_info["image_url"] = file.replace(".
|
| 196 |
file_info["video_url"] = file
|
| 197 |
else:
|
| 198 |
file_info["image_url"] = file
|
|
@@ -263,7 +264,8 @@ def image_examples_tab(abs_path: Path):
|
|
| 263 |
|
| 264 |
|
| 265 |
def video_examples_tab(abs_path: Path):
|
| 266 |
-
dataset_name = "sav_val_full"
|
|
|
|
| 267 |
datatype = "video"
|
| 268 |
db_key = "sa-v_sav_val_videos"
|
| 269 |
|
|
|
|
| 10 |
if data_type == "audio":
|
| 11 |
pattern = r"audio_(\d+).(png|wav)"
|
| 12 |
elif data_type == "video":
|
| 13 |
+
pattern = r"video_(\d+).(png|mp4)"
|
| 14 |
else:
|
| 15 |
pattern = r"img_(\d+).png"
|
| 16 |
# Dictionary to store the grouped files
|
|
|
|
| 110 |
eval_results_path = abs_path + f"{dataset_name}_1k/examples_eval_results.json"
|
| 111 |
elif datatype == "video":
|
| 112 |
quality_metrics = ["psnr", "ssim", "lpips", "msssim", "vmaf"]
|
| 113 |
+
extensions = ["mp4"]
|
| 114 |
datatype_abbr = "video"
|
| 115 |
eval_results_path = abs_path + f"{dataset_name}/examples_eval_results.json"
|
| 116 |
|
| 117 |
response = requests.get(eval_results_path)
|
| 118 |
+
print(eval_results_path)
|
| 119 |
if response.status_code == 200:
|
| 120 |
results_data = response.json()
|
| 121 |
else:
|
|
|
|
| 131 |
]
|
| 132 |
|
| 133 |
file_patterns = generate_file_patterns(prefixes, extensions)
|
| 134 |
+
print(f"File patterns: {file_patterns}")
|
| 135 |
infos = {}
|
| 136 |
for model_name in dataset.keys():
|
| 137 |
model_infos = {}
|
|
|
|
| 193 |
file_info["image_url"] = file.replace(".wav", ".png")
|
| 194 |
file_info["audio_url"] = file
|
| 195 |
elif datatype == "video":
|
| 196 |
+
# file_info["image_url"] = file.replace(".mp4", ".png")
|
| 197 |
file_info["video_url"] = file
|
| 198 |
else:
|
| 199 |
file_info["image_url"] = file
|
|
|
|
| 264 |
|
| 265 |
|
| 266 |
def video_examples_tab(abs_path: Path):
|
| 267 |
+
# dataset_name = "sav_val_full"
|
| 268 |
+
dataset_name = "sav_val_full_v2"
|
| 269 |
datatype = "video"
|
| 270 |
db_key = "sa-v_sav_val_videos"
|
| 271 |
|
frontend/src/components/VideoGallery.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { groupByNameAndVariant } from './galleryUtils'
|
|
| 4 |
import ExampleVariantMetricsTable from './ExampleVariantMetricsTable'
|
| 5 |
import ExampleDetailsSection from './ExampleDetailsSection'
|
| 6 |
import ExampleVariantSelector from './ExampleVariantSelector'
|
|
|
|
| 7 |
|
| 8 |
interface GalleryProps {
|
| 9 |
selectedModel: string
|
|
@@ -23,6 +24,68 @@ const VideoGallery: React.FC<GalleryProps> = ({ selectedModel, selectedAttack, e
|
|
| 23 |
const variants = grouped[selectedVideo] || {}
|
| 24 |
const variantKeys = Object.keys(variants)
|
| 25 |
const [selectedVariant, setSelectedVariant] = React.useState(variantKeys[0] || '')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
React.useEffect(() => {
|
| 28 |
setSelectedVariant(variantKeys[0] || '')
|
|
@@ -72,14 +135,60 @@ const VideoGallery: React.FC<GalleryProps> = ({ selectedModel, selectedAttack, e
|
|
| 72 |
selectedVariant={selectedVariant}
|
| 73 |
setSelectedVariant={setSelectedVariant}
|
| 74 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
<div className="flex flex-col items-center gap-4">
|
| 76 |
-
{
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
)}
|
| 84 |
</div>
|
| 85 |
</ExampleDetailsSection>
|
|
|
|
| 4 |
import ExampleVariantMetricsTable from './ExampleVariantMetricsTable'
|
| 5 |
import ExampleDetailsSection from './ExampleDetailsSection'
|
| 6 |
import ExampleVariantSelector from './ExampleVariantSelector'
|
| 7 |
+
import ExampleVariantToggle from './ExampleVariantToggle'
|
| 8 |
|
| 9 |
interface GalleryProps {
|
| 10 |
selectedModel: string
|
|
|
|
| 24 |
const variants = grouped[selectedVideo] || {}
|
| 25 |
const variantKeys = Object.keys(variants)
|
| 26 |
const [selectedVariant, setSelectedVariant] = React.useState(variantKeys[0] || '')
|
| 27 |
+
const [toggleMode, setToggleMode] = React.useState<'wmd' | 'attacked'>('wmd')
|
| 28 |
+
// Add state for rewind seconds
|
| 29 |
+
const [rewindSeconds, setRewindSeconds] = React.useState(0.5)
|
| 30 |
+
// State for video scale
|
| 31 |
+
const [videoScale, setVideoScale] = React.useState(1)
|
| 32 |
+
|
| 33 |
+
// Playback time ref for syncing position
|
| 34 |
+
const playbackTimeRef = React.useRef(0)
|
| 35 |
+
// Refs for all video elements
|
| 36 |
+
const videoRefs = React.useMemo(() => {
|
| 37 |
+
const refs: Record<string, React.RefObject<HTMLVideoElement>> = {}
|
| 38 |
+
variantKeys.forEach((v) => {
|
| 39 |
+
refs[v] = React.createRef<HTMLVideoElement>()
|
| 40 |
+
})
|
| 41 |
+
return refs
|
| 42 |
+
}, [variantKeys.join(',')])
|
| 43 |
+
|
| 44 |
+
// Track which variant is currently playing
|
| 45 |
+
const [playingVariant, setPlayingVariant] = React.useState<string | null>(null)
|
| 46 |
+
|
| 47 |
+
// Play handler: pause all others, sync time
|
| 48 |
+
const handlePlay = (variant: string) => {
|
| 49 |
+
setPlayingVariant(variant)
|
| 50 |
+
variantKeys.forEach((v) => {
|
| 51 |
+
if (v !== variant && videoRefs[v]?.current) {
|
| 52 |
+
videoRefs[v]?.current?.pause()
|
| 53 |
+
}
|
| 54 |
+
})
|
| 55 |
+
}
|
| 56 |
+
// Pause handler
|
| 57 |
+
const handlePause = (variant: string) => {
|
| 58 |
+
if (playingVariant === variant) setPlayingVariant(null)
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
// When selectedVariant changes, sync playback position, rewind, and play state
|
| 62 |
+
React.useEffect(() => {
|
| 63 |
+
if (!selectedVariant) return
|
| 64 |
+
// Rewind playbackTimeRef by rewindSeconds, clamp to 0
|
| 65 |
+
playbackTimeRef.current = Math.max(0, playbackTimeRef.current - rewindSeconds)
|
| 66 |
+
// Set all videos to the new time, pause all except selected
|
| 67 |
+
variantKeys.forEach((v) => {
|
| 68 |
+
const ref = videoRefs[v]?.current
|
| 69 |
+
if (ref) {
|
| 70 |
+
ref.currentTime = playbackTimeRef.current
|
| 71 |
+
if (v !== selectedVariant) {
|
| 72 |
+
ref.pause()
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
})
|
| 76 |
+
// If a video was playing, continue playing the swapped variant
|
| 77 |
+
if (playingVariant && videoRefs[selectedVariant]?.current) {
|
| 78 |
+
videoRefs[selectedVariant].current.play()
|
| 79 |
+
}
|
| 80 |
+
}, [selectedVariant])
|
| 81 |
+
|
| 82 |
+
// When the selected video plays, update playbackTimeRef
|
| 83 |
+
const handleTimeUpdate = (variantKey: string) => {
|
| 84 |
+
const ref = videoRefs[variantKey]?.current
|
| 85 |
+
if (ref && variantKey === selectedVariant) {
|
| 86 |
+
playbackTimeRef.current = ref.currentTime
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
|
| 90 |
React.useEffect(() => {
|
| 91 |
setSelectedVariant(variantKeys[0] || '')
|
|
|
|
| 135 |
selectedVariant={selectedVariant}
|
| 136 |
setSelectedVariant={setSelectedVariant}
|
| 137 |
/>
|
| 138 |
+
<ExampleVariantToggle
|
| 139 |
+
toggleMode={toggleMode}
|
| 140 |
+
setToggleMode={setToggleMode}
|
| 141 |
+
type="button"
|
| 142 |
+
selectedVariant={selectedVariant}
|
| 143 |
+
setSelectedVariant={setSelectedVariant}
|
| 144 |
+
variantKeys={variantKeys}
|
| 145 |
+
/>
|
| 146 |
+
<div className="flex items-center gap-4 mt-2">
|
| 147 |
+
<label htmlFor="rewind-seconds" className="font-mono text-xs">Rewind Seconds:</label>
|
| 148 |
+
<input
|
| 149 |
+
id="rewind-seconds"
|
| 150 |
+
type="number"
|
| 151 |
+
min={0}
|
| 152 |
+
step={0.1}
|
| 153 |
+
value={rewindSeconds}
|
| 154 |
+
onChange={(e) => setRewindSeconds(Math.max(0, Number(e.target.value)))}
|
| 155 |
+
className="input input-bordered input-xs w-20"
|
| 156 |
+
placeholder="Seconds"
|
| 157 |
+
/>
|
| 158 |
+
<label htmlFor="video-scale" className="font-mono text-xs ml-4">Scale:</label>
|
| 159 |
+
<input
|
| 160 |
+
id="video-scale"
|
| 161 |
+
type="range"
|
| 162 |
+
min={0.3}
|
| 163 |
+
max={1}
|
| 164 |
+
step={0.01}
|
| 165 |
+
value={videoScale}
|
| 166 |
+
onChange={e => setVideoScale(Number(e.target.value))}
|
| 167 |
+
className="range range-xs w-40"
|
| 168 |
+
style={{ verticalAlign: 'middle' }}
|
| 169 |
+
/>
|
| 170 |
+
<span className="ml-2 font-mono text-xs">{(videoScale * 100).toFixed(0)}%</span>
|
| 171 |
+
</div>
|
| 172 |
<div className="flex flex-col items-center gap-4">
|
| 173 |
+
{variantKeys.map((variantKey) =>
|
| 174 |
+
variants[variantKey].video_url ? (
|
| 175 |
+
<video
|
| 176 |
+
key={variantKey}
|
| 177 |
+
ref={videoRefs[variantKey]}
|
| 178 |
+
controls
|
| 179 |
+
src={variants[variantKey].video_url}
|
| 180 |
+
className="example-video"
|
| 181 |
+
style={{
|
| 182 |
+
width: `${videoScale * 100}%`,
|
| 183 |
+
height: 'auto',
|
| 184 |
+
display: selectedVariant === variantKey ? 'block' : 'none',
|
| 185 |
+
maxWidth: '100%',
|
| 186 |
+
}}
|
| 187 |
+
onTimeUpdate={() => handleTimeUpdate(variantKey)}
|
| 188 |
+
onPlay={() => handlePlay(variantKey)}
|
| 189 |
+
onPause={() => handlePause(variantKey)}
|
| 190 |
+
/>
|
| 191 |
+
) : null
|
| 192 |
)}
|
| 193 |
</div>
|
| 194 |
</ExampleDetailsSection>
|