forouzanfallah commited on
Commit
8d601ec
·
verified ·
1 Parent(s): 5a6cec3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -94
app.py CHANGED
@@ -22,7 +22,7 @@ _hf_api = HfApi(token=HF_TOKEN)
22
 
23
  # --- Main settings ---
24
  TARGET_PER_PERSON = 30
25
- CONTACT_EMAIL = "ffallah[at]asu.edu"
26
 
27
  # --- Paths ---
28
  CAPTIONS_JSON_PATH = os.environ.get("CAPTIONS_JSON_PATH", "data/captions.json")
@@ -32,6 +32,7 @@ GT_MASKED_DIR = os.environ.get("GT_MASKED_DIR", "data/gt_masked") # Image 1
32
  GT_UNMASKED_DIR = os.environ.get("GT_UNMASKED_DIR", "data/gt") # Image 2
33
  SR_DIR = os.environ.get("SR_DIR", "data/sr") # Image 3
34
  ORIGINAL_DIR = os.environ.get("ORIGINAL_DIR", "data/lr") # Image 4
 
35
  # --- Results ---
36
  RESULTS_DIR = os.environ.get("RESULTS_DIR", "results")
37
  PROGRESS_PATH = os.path.join(RESULTS_DIR, "progress.json")
@@ -189,6 +190,33 @@ def append_jsonl(path: str, record: Dict[str, Any]):
189
  with open(path, "a", encoding="utf-8") as f:
190
  f.write(line + "\n")
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  # ----------------------
193
  # App logic
194
  # ----------------------
@@ -225,7 +253,7 @@ def start_or_resume(name: str, email: str):
225
  )
226
  return (
227
  uid, samples, user_seen, -1,
228
- None, None, None, None,None, # images and caption
229
  status,
230
  os.path.join(RESULTS_DIR, f"{uid}.jsonl"),
231
  gr.update(visible=False),
@@ -249,7 +277,6 @@ def start_or_resume(name: str, email: str):
249
  load_image(sample.masked_gt_path),
250
  load_image(sample.unmasked_gt_path),
251
  load_image(sample.sr_path),
252
- # sample.caption,
253
  load_image(sample.original_path),
254
  f"**VLM caption:** {sample.caption}",
255
  status,
@@ -259,7 +286,6 @@ def start_or_resume(name: str, email: str):
259
  gr.update(visible=False),
260
  )
261
 
262
- # [CHANGE] Updated function to handle the new multiple-choice question
263
  def _save_record_and_progress(
264
  name: str,
265
  email: str,
@@ -267,10 +293,10 @@ def _save_record_and_progress(
267
  samples: List[Sample],
268
  user_seen: List[str],
269
  idx: int,
270
- rank_1: str,
271
- rank_2: str,
272
- rank_3: str,
273
- rank_4: str,
274
  q1_notes: str,
275
  q3_caption_quality: str,
276
  ):
@@ -280,17 +306,12 @@ def _save_record_and_progress(
280
  if idx is None or idx < 0 or idx >= len(samples):
281
  return load_progress()
282
 
283
- # --- validate ranks ---
284
- ranks = [rank_1, rank_2, rank_3, rank_4]
285
- if any(r is None or r == "" for r in ranks):
286
- raise gr.Error("Please rank all four images from 1 (clearest) to 4 (least clear).")
287
-
288
- if set(ranks) != {"1", "2", "3", "4"}:
289
- raise gr.Error("Each rank 1, 2, 3, 4 must be used exactly once.")
290
-
291
  if not q3_caption_quality:
292
  raise gr.Error("Please answer Question 2 about caption quality.")
293
 
 
 
 
294
  sample = samples[idx]
295
  progress = load_progress()
296
  progress.setdefault(uid, {"seen": []})
@@ -314,13 +335,15 @@ def _save_record_and_progress(
314
  "sr": sample.sr_path,
315
  "original": sample.original_path,
316
  },
 
 
 
 
 
 
 
317
  "responses": {
318
- "image_ranking": {
319
- "image_1": int(rank_1),
320
- "image_2": int(rank_2),
321
- "image_3": int(rank_3),
322
- "image_4": int(rank_4),
323
- },
324
  "notes": q1_notes or "",
325
  "caption_quality": q3_caption_quality,
326
  },
@@ -336,7 +359,9 @@ def _save_record_and_progress(
336
  save_progress(progress)
337
  return progress
338
 
339
- # [CHANGE] Updated function signature
 
 
340
  def submit_finish(
341
  name: str,
342
  email: str,
@@ -344,41 +369,35 @@ def submit_finish(
344
  samples: List[Sample],
345
  user_seen: List[str],
346
  idx: int,
347
- rank_1: str,
348
- rank_2: str,
349
- rank_3: str,
350
- rank_4: str,
351
  q1_notes: str,
352
  q3_caption_quality: str,
353
  ):
354
  try:
355
  _save_record_and_progress(
356
  name, email, uid, samples, user_seen, idx,
357
- rank_1, rank_2, rank_3, rank_4,
358
  q1_notes, q3_caption_quality
359
  )
360
  except gr.Error:
361
  return (
362
  user_seen, idx,
363
- gr.update(), gr.update(), gr.update(), gr.update(), # images
364
- gr.update(), # caption_display
365
- gr.update(), # status
366
- gr.update(), # notes_q1
367
- gr.update(), gr.update(), gr.update(), gr.update(), # rank_1..4
368
- gr.update(), # q3
369
  )
370
 
371
  return (
372
  user_seen, idx,
373
- gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None), # images
374
  gr.update(value=""),
375
  gr.update(value="Finished!"),
376
  gr.update(value=""),
377
- gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None), # rank_1..4
378
- gr.update(value=None), # q3
379
  )
380
 
381
- # [CHANGE] Updated function signature
382
  def submit_next_image(
383
  name: str,
384
  email: str,
@@ -386,28 +405,23 @@ def submit_next_image(
386
  samples: List[Sample],
387
  user_seen: List[str],
388
  idx: int,
389
- rank_1: str,
390
- rank_2: str,
391
- rank_3: str,
392
- rank_4: str,
393
  q1_notes: str,
394
  q3_caption_quality: str,
395
  ):
396
  try:
397
  progress = _save_record_and_progress(
398
  name, email, uid, samples, user_seen, idx,
399
- rank_1, rank_2, rank_3, rank_4,
400
  q1_notes, q3_caption_quality
401
  )
402
  except gr.Error:
403
  return (
404
  user_seen, idx,
405
- gr.update(), gr.update(), gr.update(), gr.update(), # images
406
- gr.update(), # caption_display
407
- gr.update(), # status
408
- gr.update(), # notes_q1
409
- gr.update(), gr.update(), gr.update(), gr.update(), # rank_1..4
410
- gr.update(), # q3
411
  )
412
 
413
  left_after = user_left_count(progress[uid]["seen"], samples)
@@ -420,12 +434,12 @@ def submit_next_image(
420
  )
421
  return (
422
  progress[uid]["seen"], idx,
423
- gr.update(), gr.update(), gr.update(), gr.update(), # images unchanged
424
- gr.update(), # caption_display unchanged
425
- gr.update(value=status), # status
426
- gr.update(value=""), # notes cleared
427
- gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None), # ranks cleared
428
- gr.update(value=None), # q3 cleared
429
  )
430
 
431
  idx_next = pick_next_index(progress[uid]["seen"], samples)
@@ -443,9 +457,9 @@ def submit_next_image(
443
  load_image(sample_next.original_path),
444
  f"**VLM caption:** {sample_next.caption}",
445
  gr.update(value=status),
446
- gr.update(value=""), # notes cleared
447
- gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None), # ranks cleared
448
- gr.update(value=None), # q3 cleared
449
  )
450
 
451
 
@@ -510,24 +524,35 @@ with gr.Blocks(title="RTS Human Evaluation", theme=gr.themes.Soft()) as demo:
510
 
511
  eval_panel = gr.Group(visible=False)
512
  with eval_panel:
 
 
 
 
513
  with gr.Row():
514
- with gr.Column(scale=1, min_width=260):
515
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 1</div>")
516
  image_1 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
517
- with gr.Column(scale=1, min_width=260):
 
 
518
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 2</div>")
519
  image_2 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
520
- with gr.Column(scale=1, min_width=260):
 
 
521
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 3</div>")
522
  image_3 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
523
- with gr.Column(scale=1, min_width=260):
 
 
524
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 4</div>")
525
  image_4 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
 
526
 
527
  notes_q1 = gr.Textbox(
528
- label="If the image contains multiple RTS, and some are clear and some are not, please add notes here.",
529
- lines=3,
530
- placeholder="Add any brief justification or observations…"
531
  )
532
 
533
  caption_display = gr.Markdown(label="Reference Caption")
@@ -544,23 +569,6 @@ with gr.Blocks(title="RTS Human Evaluation", theme=gr.themes.Soft()) as demo:
544
  )
545
 
546
  with gr.Row():
547
-
548
- rank_1 = gr.Dropdown(
549
- label="Question 1: Rank for Image 1 (1 = clearest RTS in the bounding box, 4 = least clear)",
550
- choices=["1", "2", "3", "4"]
551
- )
552
- rank_2 = gr.Dropdown(
553
- label="Rank for Image 2 (1 = clearest, 4 = least clear)",
554
- choices=["1", "2", "3", "4"]
555
- )
556
- rank_3 = gr.Dropdown(
557
- label="Rank for Image 3 (1 = clearest, 4 = least clear)",
558
- choices=["1", "2", "3", "4"]
559
- )
560
- rank_4 = gr.Dropdown(
561
- label="Rank for Image 4 (1 = clearest, 4 = least clear)",
562
- choices=["1", "2", "3", "4"]
563
- )
564
  submit_next_btn = gr.Button("Submit & Next Image", variant="primary")
565
  submit_finish_btn = gr.Button("Submit & Finish", variant="secondary")
566
 
@@ -572,14 +580,6 @@ with gr.Blocks(title="RTS Human Evaluation", theme=gr.themes.Soft()) as demo:
572
 
573
  # --- Wiring ---
574
 
575
- # def toggle_q2_visibility(q1_choice):
576
- # if q1_choice == "No":
577
- # return gr.update(visible=True)
578
- # else:
579
- # return gr.update(visible=True, value=None)
580
-
581
- # q1.change(toggle_q2_visibility, inputs=q1, outputs=q2)
582
-
583
  start_event = start_btn.click(
584
  start_or_resume,
585
  inputs=[name, email],
@@ -595,11 +595,11 @@ with gr.Blocks(title="RTS Human Evaluation", theme=gr.themes.Soft()) as demo:
595
  finish_event = submit_finish_btn.click(
596
  submit_finish,
597
  inputs=[name, email, state_uid, state_samples, state_seen, state_idx,
598
- rank_1, rank_2, rank_3, rank_4, notes_q1, q3],
599
  outputs=[state_seen, state_idx,
600
  image_1, image_2, image_3, image_4,
601
  caption_display, status, notes_q1,
602
- rank_1, rank_2, rank_3, rank_4, q3],
603
  )
604
  finish_event.then(
605
  to_thanks,
@@ -610,11 +610,11 @@ with gr.Blocks(title="RTS Human Evaluation", theme=gr.themes.Soft()) as demo:
610
  nextimg_event = submit_next_btn.click(
611
  submit_next_image,
612
  inputs=[name, email, state_uid, state_samples, state_seen, state_idx,
613
- rank_1, rank_2, rank_3, rank_4, notes_q1, q3],
614
  outputs=[state_seen, state_idx,
615
  image_1, image_2, image_3, image_4,
616
  caption_display, status, notes_q1,
617
- rank_1, rank_2, rank_3, rank_4, q3],
618
  )
619
  nextimg_event.then(
620
  maybe_show_thanks,
 
22
 
23
  # --- Main settings ---
24
  TARGET_PER_PERSON = 30
25
+ CONTACT_EMAIL = "ffallah@asu.edu"
26
 
27
  # --- Paths ---
28
  CAPTIONS_JSON_PATH = os.environ.get("CAPTIONS_JSON_PATH", "data/captions.json")
 
32
  GT_UNMASKED_DIR = os.environ.get("GT_UNMASKED_DIR", "data/gt") # Image 2
33
  SR_DIR = os.environ.get("SR_DIR", "data/sr") # Image 3
34
  ORIGINAL_DIR = os.environ.get("ORIGINAL_DIR", "data/lr") # Image 4
35
+
36
  # --- Results ---
37
  RESULTS_DIR = os.environ.get("RESULTS_DIR", "results")
38
  PROGRESS_PATH = os.path.join(RESULTS_DIR, "progress.json")
 
190
  with open(path, "a", encoding="utf-8") as f:
191
  f.write(line + "\n")
192
 
193
+ # ----------------------
194
+ # LOGIC FOR CONVERTING SLIDERS TO RANK
195
+ # ----------------------
196
+ def convert_scores_to_rank(s1, s2, s3, s4) -> Dict[str, int]:
197
+ """
198
+ Takes 4 scores (0-100). Returns a dictionary:
199
+ {'image_1': rank, 'image_2': rank...}
200
+ where Rank 1 is the Highest Score.
201
+ """
202
+ # Create list of (image_key, score)
203
+ scores = [
204
+ ("image_1", s1),
205
+ ("image_2", s2),
206
+ ("image_3", s3),
207
+ ("image_4", s4)
208
+ ]
209
+ # Sort by score descending (High score first)
210
+ scores.sort(key=lambda x: x[1], reverse=True)
211
+
212
+ ranks = {}
213
+ current_rank = 1
214
+ for img_key, score in scores:
215
+ ranks[img_key] = current_rank
216
+ current_rank += 1
217
+
218
+ return ranks
219
+
220
  # ----------------------
221
  # App logic
222
  # ----------------------
 
253
  )
254
  return (
255
  uid, samples, user_seen, -1,
256
+ None, None, None, None, None, # images and caption
257
  status,
258
  os.path.join(RESULTS_DIR, f"{uid}.jsonl"),
259
  gr.update(visible=False),
 
277
  load_image(sample.masked_gt_path),
278
  load_image(sample.unmasked_gt_path),
279
  load_image(sample.sr_path),
 
280
  load_image(sample.original_path),
281
  f"**VLM caption:** {sample.caption}",
282
  status,
 
286
  gr.update(visible=False),
287
  )
288
 
 
289
  def _save_record_and_progress(
290
  name: str,
291
  email: str,
 
293
  samples: List[Sample],
294
  user_seen: List[str],
295
  idx: int,
296
+ score_1: float,
297
+ score_2: float,
298
+ score_3: float,
299
+ score_4: float,
300
  q1_notes: str,
301
  q3_caption_quality: str,
302
  ):
 
306
  if idx is None or idx < 0 or idx >= len(samples):
307
  return load_progress()
308
 
 
 
 
 
 
 
 
 
309
  if not q3_caption_quality:
310
  raise gr.Error("Please answer Question 2 about caption quality.")
311
 
312
+ # --- CALCULATE RANK FROM SLIDERS ---
313
+ rank_dict = convert_scores_to_rank(score_1, score_2, score_3, score_4)
314
+
315
  sample = samples[idx]
316
  progress = load_progress()
317
  progress.setdefault(uid, {"seen": []})
 
335
  "sr": sample.sr_path,
336
  "original": sample.original_path,
337
  },
338
+ # We save raw scores AND the ranking required by your analysis
339
+ "raw_scores": {
340
+ "image_1": score_1,
341
+ "image_2": score_2,
342
+ "image_3": score_3,
343
+ "image_4": score_4,
344
+ },
345
  "responses": {
346
+ "image_ranking": rank_dict, # Format: {"image_1": 1, "image_2": 4, ...}
 
 
 
 
 
347
  "notes": q1_notes or "",
348
  "caption_quality": q3_caption_quality,
349
  },
 
359
  save_progress(progress)
360
  return progress
361
 
362
+ # ----------------------
363
+ # Buttons
364
+ # ----------------------
365
  def submit_finish(
366
  name: str,
367
  email: str,
 
369
  samples: List[Sample],
370
  user_seen: List[str],
371
  idx: int,
372
+ s1: float, s2: float, s3: float, s4: float,
 
 
 
373
  q1_notes: str,
374
  q3_caption_quality: str,
375
  ):
376
  try:
377
  _save_record_and_progress(
378
  name, email, uid, samples, user_seen, idx,
379
+ s1, s2, s3, s4,
380
  q1_notes, q3_caption_quality
381
  )
382
  except gr.Error:
383
  return (
384
  user_seen, idx,
385
+ gr.update(), gr.update(), gr.update(), gr.update(),
386
+ gr.update(), gr.update(), gr.update(),
387
+ gr.update(), gr.update(), gr.update(), gr.update(),
388
+ gr.update(),
 
 
389
  )
390
 
391
  return (
392
  user_seen, idx,
393
+ gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None),
394
  gr.update(value=""),
395
  gr.update(value="Finished!"),
396
  gr.update(value=""),
397
+ gr.update(value=50), gr.update(value=50), gr.update(value=50), gr.update(value=50),
398
+ gr.update(value=None),
399
  )
400
 
 
401
  def submit_next_image(
402
  name: str,
403
  email: str,
 
405
  samples: List[Sample],
406
  user_seen: List[str],
407
  idx: int,
408
+ s1: float, s2: float, s3: float, s4: float,
 
 
 
409
  q1_notes: str,
410
  q3_caption_quality: str,
411
  ):
412
  try:
413
  progress = _save_record_and_progress(
414
  name, email, uid, samples, user_seen, idx,
415
+ s1, s2, s3, s4,
416
  q1_notes, q3_caption_quality
417
  )
418
  except gr.Error:
419
  return (
420
  user_seen, idx,
421
+ gr.update(), gr.update(), gr.update(), gr.update(),
422
+ gr.update(), gr.update(), gr.update(),
423
+ gr.update(), gr.update(), gr.update(), gr.update(),
424
+ gr.update(),
 
 
425
  )
426
 
427
  left_after = user_left_count(progress[uid]["seen"], samples)
 
434
  )
435
  return (
436
  progress[uid]["seen"], idx,
437
+ gr.update(), gr.update(), gr.update(), gr.update(),
438
+ gr.update(),
439
+ gr.update(value=status),
440
+ gr.update(value=""),
441
+ gr.update(value=50), gr.update(value=50), gr.update(value=50), gr.update(value=50),
442
+ gr.update(value=None),
443
  )
444
 
445
  idx_next = pick_next_index(progress[uid]["seen"], samples)
 
457
  load_image(sample_next.original_path),
458
  f"**VLM caption:** {sample_next.caption}",
459
  gr.update(value=status),
460
+ gr.update(value=""),
461
+ gr.update(value=50), gr.update(value=50), gr.update(value=50), gr.update(value=50),
462
+ gr.update(value=None),
463
  )
464
 
465
 
 
524
 
525
  eval_panel = gr.Group(visible=False)
526
  with eval_panel:
527
+
528
+ # --- NEW LAYOUT: SLIDERS UNDER IMAGES ---
529
+ gr.Markdown("### Question 1: Rate Image Clarity (Higher = Better / Clearer RTS)")
530
+
531
  with gr.Row():
532
+ with gr.Column(scale=1, min_width=200):
533
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 1</div>")
534
  image_1 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
535
+ score_1 = gr.Slider(minimum=0, maximum=100, step=1, value=50, label="Score (0-100)")
536
+
537
+ with gr.Column(scale=1, min_width=200):
538
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 2</div>")
539
  image_2 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
540
+ score_2 = gr.Slider(minimum=0, maximum=100, step=1, value=50, label="Score (0-100)")
541
+
542
+ with gr.Column(scale=1, min_width=200):
543
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 3</div>")
544
  image_3 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
545
+ score_3 = gr.Slider(minimum=0, maximum=100, step=1, value=50, label="Score (0-100)")
546
+
547
+ with gr.Column(scale=1, min_width=200):
548
  gr.Markdown("<div style='text-align:center; font-weight:600;'>Image 4</div>")
549
  image_4 = gr.Image(show_label=False, interactive=False, height=256, show_download_button=False)
550
+ score_4 = gr.Slider(minimum=0, maximum=100, step=1, value=50, label="Score (0-100)")
551
 
552
  notes_q1 = gr.Textbox(
553
+ label="Notes (Optional)",
554
+ lines=2,
555
+ placeholder="If there are multiple RTS or ambiguities, please note here."
556
  )
557
 
558
  caption_display = gr.Markdown(label="Reference Caption")
 
569
  )
570
 
571
  with gr.Row():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
  submit_next_btn = gr.Button("Submit & Next Image", variant="primary")
573
  submit_finish_btn = gr.Button("Submit & Finish", variant="secondary")
574
 
 
580
 
581
  # --- Wiring ---
582
 
 
 
 
 
 
 
 
 
583
  start_event = start_btn.click(
584
  start_or_resume,
585
  inputs=[name, email],
 
595
  finish_event = submit_finish_btn.click(
596
  submit_finish,
597
  inputs=[name, email, state_uid, state_samples, state_seen, state_idx,
598
+ score_1, score_2, score_3, score_4, notes_q1, q3],
599
  outputs=[state_seen, state_idx,
600
  image_1, image_2, image_3, image_4,
601
  caption_display, status, notes_q1,
602
+ score_1, score_2, score_3, score_4, q3],
603
  )
604
  finish_event.then(
605
  to_thanks,
 
610
  nextimg_event = submit_next_btn.click(
611
  submit_next_image,
612
  inputs=[name, email, state_uid, state_samples, state_seen, state_idx,
613
+ score_1, score_2, score_3, score_4, notes_q1, q3],
614
  outputs=[state_seen, state_idx,
615
  image_1, image_2, image_3, image_4,
616
  caption_display, status, notes_q1,
617
+ score_1, score_2, score_3, score_4, q3],
618
  )
619
  nextimg_event.then(
620
  maybe_show_thanks,