zirui-wang commited on
Commit
6b5b33d
Β·
1 Parent(s): 02d4217
Files changed (7) hide show
  1. .gitignore +2 -0
  2. .vscode/settings.json +21 -0
  3. README.md +13 -0
  4. app.py +522 -4
  5. detail.md +18 -0
  6. start.md +6 -0
  7. sync_dataset.py +59 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ survey-hf-dataset/
2
+ survey-hf-dataset
.vscode/settings.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "files.watcherExclude": {
3
+ "**/datadir/**": true,
4
+ "**/log*/**": true,
5
+ "**/survey-hf-dataset/**": true
6
+ },
7
+ "search.exclude": {
8
+ "**/datadir/**": true,
9
+ "**/log*/**": true,
10
+ "datadir/**": true,
11
+ "log*/**": true,
12
+ "**/survey-hf-dataset/**": true
13
+ },
14
+ "python.analysis.exclude": [
15
+ "**/datadir/**",
16
+ "**/survey-hf-dataset/**"
17
+ ],
18
+ "black-formatter.args": [
19
+ "--line-length=100"
20
+ ]
21
+ }
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Video Quality Survey
3
+ emoji: 🧐
4
+ colorFrom: green
5
+ colorTo: yellow
6
+ sdk: gradio
7
+ sdk_version: 4.41.0
8
+ python_version: 3.10.14
9
+ app_file: app.py
10
+ pinned: true
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,7 +1,525 @@
 
 
 
 
 
 
1
  import gradio as gr
 
2
 
3
- def greet(name):
4
- return "Hello " + name + "!!"
5
 
6
- demo = gr.Interface(fn=greet, inputs="text", outputs="text")
7
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from argparse import ArgumentParser
2
+ import os, threading, time
3
+ from dataclasses import dataclass
4
+ from datetime import datetime, timezone
5
+ from pprint import pprint
6
+ import numpy as np
7
  import gradio as gr
8
+ from huggingface_hub import HfApi
9
 
 
 
10
 
11
+ @dataclass
12
+ class VideoCfg:
13
+ value: str
14
+ label: str
15
+ visible: bool
16
+ interactive: bool = False
17
+ autoplay: bool = True
18
+ show_share_button: bool = False
19
+ show_download_button: bool = False
20
+ loop: bool = False
21
+ show_label: bool = True
22
+ width: int | str | None = None
23
+
24
+
25
+ def time_now():
26
+ return datetime.now(timezone.utc).strftime("%Y-%m-%d_%H-%M-%s")
27
+
28
+
29
+ class SurveyEngine:
30
+ def __init__(self, args):
31
+ self.args = args
32
+ self.api = HfApi()
33
+
34
+ # pull videos from hf dataset to hf space
35
+ self.repo_id = "zirui-wang/survey-hf-dataset"
36
+ self.local_dir = "./survey-hf-dataset"
37
+ self.api.snapshot_download(self.repo_id, local_dir=self.local_dir, repo_type="dataset")
38
+
39
+ # create a file to record the user study
40
+ response_file_name = f"{time_now()}.csv"
41
+ self.response_file_path_local = f"{self.local_dir}/response/{response_file_name}"
42
+ self.response_file_path_remote = f"response/{response_file_name}"
43
+ os.makedirs(f"{self.local_dir}/response", exist_ok=True)
44
+ self._update_local_file("timestamp,path1,path2,selection\n", self.response_file_path_local)
45
+
46
+ # create a file to record optional feedback
47
+ feedback_file_name = f"{time_now()}.txt"
48
+ self.feedback_file_path_local = f"{self.local_dir}/optional_feedback/{feedback_file_name}"
49
+ self.feedback_file_path_remote = f"optional_feedback/{feedback_file_name}"
50
+ os.makedirs(f"{self.local_dir}/optional_feedback", exist_ok=True)
51
+ self._update_local_file("", self.feedback_file_path_local)
52
+
53
+ self.video_paths, self.N_prompts, self.N_methods = self._get_all_video_paths()
54
+
55
+ self.theme = gr.themes.Default(
56
+ text_size=gr.themes.sizes.text_lg,
57
+ spacing_size=gr.themes.sizes.spacing_sm,
58
+ radius_size=gr.themes.sizes.radius_md,
59
+ )
60
+
61
+ self._start_periodic_sync()
62
+
63
+ def _start_periodic_sync(self):
64
+ def _upload_periodically(path_local, path_remote):
65
+ while True:
66
+ print(time_now())
67
+ print(f"Uploading {path_local}.")
68
+ try:
69
+ self._update_remote_file(path_local, path_remote)
70
+ except Exception as e:
71
+ print(e)
72
+ time.sleep(args.period_upload)
73
+
74
+ def _squash_commits_periodically():
75
+ while True:
76
+ print(time_now())
77
+ print("Squashing commits.")
78
+ try:
79
+ self.api.super_squash_history("zirui-wang/survey-videos", repo_type="dataset")
80
+ except Exception as e:
81
+ print(e)
82
+ time.sleep(args.period_squash)
83
+
84
+ thread_upload_response = threading.Thread(
85
+ target=_upload_periodically,
86
+ args=(self.response_file_path_local, self.response_file_path_remote),
87
+ )
88
+ thread_upload_response.daemon = True
89
+ thread_upload_response.start()
90
+
91
+ thread_upload_feedback = threading.Thread(
92
+ target=_upload_periodically,
93
+ args=(self.feedback_file_path_local, self.feedback_file_path_remote),
94
+ )
95
+ thread_upload_feedback.daemon = True
96
+ thread_upload_feedback.start()
97
+
98
+ thread_squash_commits = threading.Thread(target=_squash_commits_periodically)
99
+ thread_squash_commits.daemon = True
100
+ thread_squash_commits.start()
101
+
102
+ def _get_all_video_paths(self):
103
+ video_dir = f"{self.local_dir}/video"
104
+ method_list = sorted(os.listdir(video_dir))
105
+ video_name_list = sorted(os.listdir(f"{video_dir}/{method_list[0]}"))
106
+
107
+ N_prompts = len(video_name_list)
108
+ N_methods = len(method_list)
109
+
110
+ video_paths = [] # (N_prompts, N_methods)
111
+ for video_name in video_name_list:
112
+ paths = [os.path.join(video_dir, method, video_name) for method in method_list]
113
+ video_paths.append(paths)
114
+ video_paths = np.array(video_paths)
115
+ return video_paths, N_prompts, N_methods
116
+
117
+ def _sample_video_pair(self):
118
+ # random choose two prompts
119
+ prompt_ids = np.random.choice(self.N_prompts, 2, replace=False)
120
+
121
+ video_pair1 = self.video_paths[prompt_ids[0]]
122
+ video_pair1 = np.random.permutation(video_pair1)
123
+
124
+ video_pair2 = self.video_paths[prompt_ids[1]]
125
+ video_pair2 = np.random.permutation(video_pair2)
126
+
127
+ radio_select_to_path_lut = {
128
+ "Video 1 πŸ‘": str(video_pair1[0]),
129
+ "Video 2 πŸ‘": str(video_pair1[1]),
130
+ "Video 3 πŸ‘": str(video_pair2[0]),
131
+ "Video 4 πŸ‘": str(video_pair2[1]),
132
+ "Similar πŸ€”": "Similar",
133
+ "Seen & Next ⏭️": "Seen",
134
+ }
135
+ print("---------------")
136
+ print(time_now())
137
+ pprint(radio_select_to_path_lut)
138
+ return video_pair1, video_pair2, radio_select_to_path_lut
139
+
140
+ def _update_local_file(self, message, file_path_local):
141
+ with open(file_path_local, "a") as f:
142
+ f.write(message)
143
+
144
+ def _update_remote_file(self, file_path_local, file_path_remote):
145
+ self.api.upload_file(
146
+ path_or_fileobj=file_path_local,
147
+ path_in_repo=file_path_remote,
148
+ repo_id=self.repo_id,
149
+ repo_type="dataset",
150
+ )
151
+
152
+ def _setup_video(self, path_a, path_b, label_a, label_b, visible):
153
+ cfg_a = VideoCfg(value=path_a, label=label_a, visible=visible)
154
+ cfg_b = VideoCfg(value=path_b, label=label_b, visible=visible)
155
+ video_a = gr.Video(**cfg_a.__dict__)
156
+ video_b = gr.Video(**cfg_b.__dict__)
157
+ return video_a, video_b
158
+
159
+ def _load_callback(self):
160
+ video_pair1, video_pair2, radio_select_to_path_lut = self._sample_video_pair()
161
+ update_video1 = gr.update(value=video_pair1[0])
162
+ update_video2 = gr.update(value=video_pair1[1])
163
+ update_video3 = gr.update(value=video_pair2[0])
164
+ update_video4 = gr.update(value=video_pair2[1])
165
+ return (
166
+ video_pair1,
167
+ video_pair2,
168
+ radio_select_to_path_lut,
169
+ update_video1,
170
+ update_video2,
171
+ update_video3,
172
+ update_video4,
173
+ )
174
+
175
+ def _click_select_radio(self):
176
+ update1 = gr.update(visible=True)
177
+ return update1
178
+
179
+ def _click_button_confirm1(self, radio_select, radio_select_to_path_lut):
180
+ # update response file with the acutal file path
181
+ selected_path = radio_select_to_path_lut[radio_select]
182
+ path1 = radio_select_to_path_lut["Video 1 πŸ‘"]
183
+ path2 = radio_select_to_path_lut["Video 2 πŸ‘"]
184
+ message = f"{time_now()},{path1},{path2},{selected_path}\n"
185
+ self._update_local_file(message, self.response_file_path_local)
186
+
187
+ confirm_message = f"""
188
+ Your selection was:  
189
+ <span style="font-size:20px; color:orange "> {radio_select} </span> \n\n
190
+ """
191
+ # display confirm message
192
+ update_md_confirm1 = gr.update(visible=True, value=confirm_message)
193
+
194
+ # hide the radio and button for video 1-2
195
+ update_button_confirm1 = gr.update(visible=False)
196
+ update_ratio_select1 = gr.update(visible=False)
197
+
198
+ # show video 3-4 and radio
199
+ update_md_pair_34 = gr.update(visible=True)
200
+ update_video_3 = gr.update(visible=True)
201
+ update_video_4 = gr.update(visible=True)
202
+ update_radio_select2 = gr.update(visible=True)
203
+ return (
204
+ update_md_confirm1,
205
+ update_button_confirm1,
206
+ update_ratio_select1,
207
+ update_md_pair_34,
208
+ update_video_3,
209
+ update_video_4,
210
+ update_radio_select2,
211
+ )
212
+
213
+ def _click_button_confirm2(self, radio_select, radio_select_to_path_lut):
214
+ # update response file with the acutal file path
215
+ selected_path = radio_select_to_path_lut[radio_select]
216
+ path1 = radio_select_to_path_lut["Video 3 πŸ‘"]
217
+ path2 = radio_select_to_path_lut["Video 4 πŸ‘"]
218
+ message = f"{time_now()},{path1},{path2},{selected_path}\n"
219
+ self._update_local_file(message, self.response_file_path_local)
220
+
221
+ confirm_message = f"""
222
+ Your selection was:&nbsp;&nbsp;
223
+ <span style="font-size:20px; color:orange "> {radio_select} </span> \n\n
224
+ ## Study Done!
225
+ Click the button below 🎲 if you'd like to evaluate another set. \n\n
226
+ You can exit this study by closing this page.
227
+ For more details about this study, click
228
+ [here](https://huggingface.co/spaces/zirui-wang/toy/blob/main/detail.md).
229
+ """
230
+
231
+ # display confirm message
232
+ update_md_confirm2 = gr.update(visible=True, value=confirm_message)
233
+
234
+ # hide the radio and button for video 3-4
235
+ update_button_confirm2 = gr.update(visible=False)
236
+ update_radio_select2 = gr.update(visible=False)
237
+
238
+ # show button_new
239
+ update_button_new = gr.update(visible=True)
240
+
241
+ # show textbox and button for optional feedback
242
+ update_textbox_optional = gr.update(visible=True)
243
+ update_button_submit_optional = gr.update(visible=True)
244
+ return (
245
+ update_md_confirm2,
246
+ update_button_confirm2,
247
+ update_radio_select2,
248
+ update_button_new,
249
+ update_textbox_optional,
250
+ update_button_submit_optional,
251
+ )
252
+
253
+ def _click_button_new(self):
254
+ video_pair1, video_pair2, radio_select_to_path_lut = self._sample_video_pair()
255
+
256
+ update_video1 = gr.update(value=video_pair1[0])
257
+ update_video2 = gr.update(value=video_pair1[1])
258
+ update_radio_select1 = gr.update(visible=True, value=None)
259
+ update_button_confirm1 = gr.update(visible=False)
260
+ update_md_confirm1 = gr.update(visible=False)
261
+
262
+ update_md_pair_34 = gr.update(visible=False)
263
+ update_video3 = gr.update(value=video_pair2[0], visible=False)
264
+ update_video4 = gr.update(value=video_pair2[1], visible=False)
265
+ update_radio_select2 = gr.update(visible=False, value=None)
266
+ update_button_confirm2 = gr.update(visible=False)
267
+ update_md_confirm2 = gr.update(visible=False)
268
+
269
+ update_button_new = gr.update(visible=False)
270
+
271
+ update_textbox_optional = gr.update(visible=False, value=None)
272
+ update_button_submit_optional = gr.update(visible=False)
273
+ update_md_optional_feedback = gr.update(visible=False)
274
+ return (
275
+ video_pair1,
276
+ video_pair2,
277
+ radio_select_to_path_lut,
278
+ update_video1,
279
+ update_video2,
280
+ update_radio_select1,
281
+ update_button_confirm1,
282
+ update_md_confirm1,
283
+ update_md_pair_34,
284
+ update_video3,
285
+ update_video4,
286
+ update_radio_select2,
287
+ update_button_confirm2,
288
+ update_md_confirm2,
289
+ update_button_new,
290
+ update_textbox_optional,
291
+ update_button_submit_optional,
292
+ update_md_optional_feedback,
293
+ )
294
+
295
+ def _click_button_optional_feedback(self, textbox_optional_feedback):
296
+ if textbox_optional_feedback == "":
297
+ return gr.skip(), gr.skip()
298
+ message = f"{time_now()}\n{textbox_optional_feedback}\n\n"
299
+ self._update_local_file(message, self.feedback_file_path_local)
300
+
301
+ update_md_optional_feedback = gr.update(visible=True)
302
+ update_button_submit_optional = gr.update(visible=False)
303
+ return update_md_optional_feedback, update_button_submit_optional
304
+
305
+ def main(self):
306
+ # read in md file
307
+ with open("start.md", "r") as f:
308
+ md_start = f.read()
309
+
310
+ with gr.Blocks(theme=self.theme, title="Video Quality User Study") as demo:
311
+
312
+ # set up session states
313
+ video_pair1 = gr.State(value=["path1", "path2"], time_to_live=900)
314
+ video_pair2 = gr.State(value=["path2", "path4"], time_to_live=900)
315
+ radio_select_to_path_lut = gr.State(value={}, time_to_live=900) # hold a dict
316
+
317
+ # set up layout
318
+ with gr.Column():
319
+ gr.Markdown(md_start)
320
+
321
+ # a debug button
322
+ if self.args.debug:
323
+
324
+ def _click_button_debug(video_pair1, video_pair2, radio_select_to_path_lut):
325
+ print(f"video_pair1: {video_pair1}")
326
+ print(f"video_pair2: {video_pair2}")
327
+ print(f"radio_select_to_path_lut: {radio_select_to_path_lut}")
328
+
329
+ button_debug = gr.Button("debug", variant="primary", scale=1)
330
+ button_debug.click(
331
+ _click_button_debug,
332
+ inputs=[video_pair1, video_pair2, radio_select_to_path_lut],
333
+ )
334
+
335
+ # ---------------- video 1-2 ----------------
336
+ gr.Markdown("## Video Pair 1")
337
+ with gr.Row():
338
+ video1, video2 = self._setup_video(
339
+ path_a=video_pair1.value[0],
340
+ path_b=video_pair1.value[1],
341
+ label_a="Video 1",
342
+ label_b="Video 2",
343
+ visible=True,
344
+ )
345
+ with gr.Row():
346
+ radio_select1 = gr.Radio(
347
+ choices=["Video 1 πŸ‘", "Video 2 πŸ‘", "Similar πŸ€”", "Seen & Next ⏭️"],
348
+ label="Your Preference:",
349
+ scale=2,
350
+ )
351
+
352
+ button_confirm1 = gr.Button(
353
+ value="Confirm",
354
+ variant="primary",
355
+ scale=1,
356
+ visible=False,
357
+ )
358
+
359
+ md_confirm1 = gr.Markdown(visible=False, inputs=button_confirm1)
360
+
361
+ # ---------------- video 3-4 ----------------
362
+ md_pair_34 = gr.Markdown("## Video Pair 2", visible=False)
363
+ with gr.Row():
364
+ video3, video4 = self._setup_video(
365
+ path_a=video_pair2.value[0],
366
+ path_b=video_pair2.value[1],
367
+ label_a="Video 3",
368
+ label_b="Video 4",
369
+ visible=False,
370
+ )
371
+ with gr.Row():
372
+ radio_select2 = gr.Radio(
373
+ choices=["Video 3 πŸ‘", "Video 4 πŸ‘", "Similar πŸ€”", "Seen & Next ⏭️"],
374
+ label="Your Preference:",
375
+ scale=2,
376
+ visible=False,
377
+ )
378
+
379
+ button_confirm2 = gr.Button(
380
+ value="Confirm",
381
+ variant="primary",
382
+ scale=1,
383
+ visible=False,
384
+ )
385
+
386
+ md_confirm2 = gr.Markdown(visible=False, inputs=button_confirm2)
387
+
388
+ # ---------------- new button ----------------
389
+ button_new = gr.Button(
390
+ value="New One 🎲",
391
+ variant="primary",
392
+ visible=False,
393
+ )
394
+
395
+ # ---------------- optional feedback ----------------
396
+ with gr.Row():
397
+ textbox_optional_feedback = gr.Textbox(
398
+ label="Optional Comments:",
399
+ placeholder="Type here...",
400
+ lines=1,
401
+ scale=4,
402
+ interactive=True,
403
+ visible=False,
404
+ )
405
+ button_submit_optional_feedback = gr.Button(
406
+ value="Submit Comments",
407
+ variant="secondary",
408
+ scale=1,
409
+ visible=False,
410
+ )
411
+
412
+ md_optional_feedback = gr.Markdown(
413
+ "Thank you for providing additional comments! πŸ™",
414
+ visible=False,
415
+ )
416
+
417
+ # set up callbacks
418
+ radio_select1.select(
419
+ self._click_select_radio,
420
+ trigger_mode="once",
421
+ outputs=button_confirm1,
422
+ )
423
+
424
+ button_confirm1.click(
425
+ self._click_button_confirm1,
426
+ trigger_mode="once",
427
+ inputs=[radio_select1, radio_select_to_path_lut],
428
+ outputs=[
429
+ md_confirm1,
430
+ button_confirm1,
431
+ radio_select1,
432
+ md_pair_34,
433
+ video3,
434
+ video4,
435
+ radio_select2,
436
+ ],
437
+ )
438
+
439
+ radio_select2.select(
440
+ self._click_select_radio,
441
+ trigger_mode="once",
442
+ outputs=button_confirm2,
443
+ )
444
+
445
+ button_confirm2.click(
446
+ self._click_button_confirm2,
447
+ trigger_mode="once",
448
+ inputs=[radio_select2, radio_select_to_path_lut],
449
+ outputs=[
450
+ md_confirm2,
451
+ button_confirm2,
452
+ radio_select2,
453
+ button_new,
454
+ textbox_optional_feedback,
455
+ button_submit_optional_feedback,
456
+ ],
457
+ )
458
+
459
+ button_new.click(
460
+ self._click_button_new,
461
+ trigger_mode="once",
462
+ outputs=[
463
+ video_pair1,
464
+ video_pair2,
465
+ radio_select_to_path_lut,
466
+ video1,
467
+ video2,
468
+ radio_select1,
469
+ button_confirm1,
470
+ md_confirm1,
471
+ md_pair_34,
472
+ video3,
473
+ video4,
474
+ radio_select2,
475
+ button_confirm2,
476
+ md_confirm2,
477
+ button_new,
478
+ textbox_optional_feedback,
479
+ button_submit_optional_feedback,
480
+ md_optional_feedback,
481
+ ],
482
+ )
483
+
484
+ button_submit_optional_feedback.click(
485
+ self._click_button_optional_feedback,
486
+ trigger_mode="once",
487
+ inputs=textbox_optional_feedback,
488
+ outputs=[md_optional_feedback, button_submit_optional_feedback],
489
+ )
490
+
491
+ demo.load(
492
+ self._load_callback,
493
+ outputs=[
494
+ video_pair1,
495
+ video_pair2,
496
+ radio_select_to_path_lut,
497
+ video1,
498
+ video2,
499
+ video3,
500
+ video4,
501
+ ],
502
+ )
503
+ demo.launch(share=self.args.share, show_api=False)
504
+
505
+
506
+ if __name__ == "__main__":
507
+ parser = ArgumentParser()
508
+ parser.add_argument("--debug", action="store_true")
509
+ parser.add_argument("--share", action="store_true")
510
+ parser.add_argument(
511
+ "--period_upload",
512
+ type=int,
513
+ default=300,
514
+ help="Period (sec) to upload response files in seconds, 300sec=5min",
515
+ )
516
+ parser.add_argument(
517
+ "--period_squash",
518
+ type=int,
519
+ default=43200,
520
+ help="Period (sec) to squash commits in seconds, 43200sec=12h",
521
+ )
522
+ args = parser.parse_args()
523
+
524
+ survey_engine = SurveyEngine(args)
525
+ survey_engine.main()
detail.md ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # A Video Quality User Study for Video Diffusion Models
2
+ Are you interested in the latest developments in video diffusion models? We invite you to participate in our user study, where you can watch a few video samples and provide your ratings. By participating, you will have the chance to experience the latest video diffusion models firsthand. The study should take as little as 1 minute to complete.
3
+
4
+ ### What Are We Evaluating?
5
+ This study aims to assess the quality of videos generated by two different diffusion-based generative models. We are focusing on key aspects such as spatial and temporal consistency, as well as multi-view coherence. While these models produce impressive results, they can also generate unexpected artifacts, such as strange morphing effects, abrupt changes in subjects, or unusual occlusions and geometries. We have created 50 videos for this study, each video is generated using identical text prompts across these two models, and we may expand the study to include more videos and additional models in the future.
6
+
7
+ | ![GIF 1](example/good.gif) | ![GIF 2](example/bad.gif) |
8
+ |:---------------------------------------------------------------------------:|:---------------------------------------------------------------------------:|
9
+ | πŸ™‚ Pretty Good | πŸ€” Subject changed and weird books. |
10
+
11
+ ### Your Contribution Matters
12
+ The results of this study, along with the videos and prompts used, will be made publicly available as part of a dataset. This dataset will contribute to a research report aimed at advancing the understanding of video diffusion models. Your feedback is crucial in helping us identify and understand these phenomena. Rest assured, the study is fully anonymous, and no personal information will be collected.
13
+
14
+ ### How to Participate
15
+ You can join the study using any device, whether it is a phone, tablet, laptop, or desktop computer. For the best experience, we recommend using a larger screen to observe potential artifacts more clearly. Please note that some mobile devices may have energy-saving settings that prevent videos from autoplaying; if this happens, simply click on the video boxes to play them manually.
16
+
17
+ Your participation is invaluable to us. Thank you for contributing to the advancement of video diffusion technology.
18
+ Feel free to contact me Zirui Wang (zirui dot wang @eng.ox.ac.uk) for additional feedbacks.
start.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # 🧐 Video Quality Study
2
+ πŸ™ Thank you for participating our study! This study should take ~1 minute.
3
+
4
+ πŸ’Ό **Task: You'll watch 2 pairs of videos. For each pair, select the video that has better spatial and temporal consistency, as well as multi-view coherence, and less noise.**
5
+
6
+ πŸš— On mobile devices: you might need to manually πŸ•ΉοΈ **click** video boxes to play videos.
sync_dataset.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from argparse import ArgumentParser
2
+ from huggingface_hub import HfApi
3
+
4
+
5
+ def upload_videos(api, upload_dir):
6
+ api.upload_folder(
7
+ folder_path=upload_dir,
8
+ repo_id="zirui-wang/survey-videos",
9
+ repo_type="dataset",
10
+ )
11
+
12
+
13
+ def delete_response(api):
14
+ api.delete_folder("response", "zirui-wang/survey-videos", repo_type="dataset")
15
+
16
+
17
+ def delete_optional_feedback(api):
18
+ api.delete_folder("optional_feedback", "zirui-wang/survey-videos", repo_type="dataset")
19
+
20
+
21
+ def main():
22
+ parser = ArgumentParser()
23
+ parser.add_argument(
24
+ "--upload_dir",
25
+ type=str,
26
+ default="~/projects/mview/storage/data/video_diffusion/text-to-video-debug-anonymised",
27
+ )
28
+ parser.add_argument("--upload_videos", type=eval, default=False, choices=[True, False])
29
+ parser.add_argument("--delete_response", type=eval, default=False, choices=[True, False])
30
+ parser.add_argument(
31
+ "--delete_optional_feedback", type=eval, default=False, choices=[True, False]
32
+ )
33
+ args = parser.parse_args()
34
+
35
+ api = HfApi()
36
+ if args.upload_videos:
37
+ upload_videos(api, args.upload_dir)
38
+
39
+ if args.delete_response:
40
+ answer = input("Are you sure you want to delete the response folder? (y/n)")
41
+ if answer == "y":
42
+ try:
43
+ delete_response(api)
44
+ except Exception as e:
45
+ print(e)
46
+
47
+ if args.delete_optional_feedback:
48
+ answer = input("Are you sure you want to delete the optional_feedback folder? (y/n)")
49
+ if answer == "y":
50
+ try:
51
+ delete_optional_feedback(api)
52
+ except Exception as e:
53
+ print(e)
54
+
55
+ api.super_squash_history("zirui-wang/survey-videos", repo_type="dataset")
56
+
57
+
58
+ if __name__ == "__main__":
59
+ main()