Aimember commited on
Commit
e5898b7
Β·
1 Parent(s): 42b8183

refactor: classes

Browse files
Files changed (1) hide show
  1. app.py +101 -266
app.py CHANGED
@@ -37,6 +37,21 @@ import ssl
37
  # Fix SSL error for model download (macOS specific)
38
  ssl._create_default_https_context = ssl._create_unverified_context
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  class ImageSimilarityLeaderboard:
41
  def __init__(self, reference_image_path="label2.jpg", data_file="leaderboard.json"):
42
  self.reference_image_path = reference_image_path
@@ -431,93 +446,43 @@ class ImageSimilarityLeaderboard:
431
  self.leaderboard_data = []
432
  self.save_leaderboard()
433
  return "βœ… λ¦¬λ”λ³΄λ“œκ°€ μ΄ˆκΈ°ν™”λ˜μ—ˆμŠ΅λ‹ˆλ‹€.", pd.DataFrame(columns=['μˆœμœ„', 'μ‚¬μš©μžλͺ…', '점수', 'λ‚ μ§œ'])
434
-
435
 
436
- # μ „μ—­ λ¦¬λ”λ³΄λ“œ μΈμŠ€ν„΄μŠ€λ“€ (5개 νƒ­: 4개 반 + μ—°μŠ΅)
437
- leaderboards = {
438
- 'respect': ImageSimilarityLeaderboard("label2.jpg", "respect.json"),
439
- 'challenge': ImageSimilarityLeaderboard("label2.jpg", "challenge.json"),
440
- 'originality': ImageSimilarityLeaderboard("label2.jpg", "originality.json"),
441
- 'bce': ImageSimilarityLeaderboard("label2.jpg", "bce.json"),
442
- 'practice': ImageSimilarityLeaderboard("label2.jpg", "practice.json")
443
- }
444
-
445
- def process_user_image_respect(image, username):
446
- """Respect반 μ‚¬μš©μž 이미지 처리 ν•¨μˆ˜"""
447
- return leaderboards['respect'].process_image(image, username)
448
-
449
- def process_user_image_challenge(image, username):
450
- """Challenge반 μ‚¬μš©μž 이미지 처리 ν•¨μˆ˜"""
451
- return leaderboards['challenge'].process_image(image, username)
452
-
453
- def process_user_image_originality(image, username):
454
- """Originality반 μ‚¬μš©μž 이미지 처리 ν•¨μˆ˜"""
455
- return leaderboards['originality'].process_image(image, username)
456
-
457
- def process_user_image_bce(image, username):
458
- """BCE반 μ‚¬μš©μž 이미지 처리 ν•¨μˆ˜"""
459
- return leaderboards['bce'].process_image(image, username)
460
-
461
- def get_current_leaderboard_respect():
462
- """Respect반 ν˜„μž¬ λ¦¬λ”λ³΄λ“œ λ°˜ν™˜"""
463
- return leaderboards['respect'].get_leaderboard_df()
464
-
465
- def get_current_leaderboard_challenge():
466
- """Challenge반 ν˜„μž¬ λ¦¬λ”λ³΄λ“œ λ°˜ν™˜"""
467
- return leaderboards['challenge'].get_leaderboard_df()
468
-
469
- def get_current_leaderboard_originality():
470
- """Originality반 ν˜„μž¬ λ¦¬λ”λ³΄λ“œ λ°˜ν™˜"""
471
- return leaderboards['originality'].get_leaderboard_df()
472
-
473
- def get_current_leaderboard_bce():
474
- """BCE반 ν˜„μž¬ λ¦¬λ”λ³΄λ“œ λ°˜ν™˜"""
475
- return leaderboards['bce'].get_leaderboard_df()
476
-
477
- def check_and_update_leaderboard_respect():
478
- """Respect반 λ¦¬λ”λ³΄λ“œ μ—…λ°μ΄νŠΈ 확인 및 λ°˜ν™˜"""
479
- leaderboards['respect'].check_for_updates()
480
- return leaderboards['respect'].get_leaderboard_df()
481
-
482
- def check_and_update_leaderboard_challenge():
483
- """Challenge반 λ¦¬λ”λ³΄λ“œ μ—…λ°μ΄νŠΈ 확인 및 λ°˜ν™˜"""
484
- leaderboards['challenge'].check_for_updates()
485
- return leaderboards['challenge'].get_leaderboard_df()
486
-
487
- def check_and_update_leaderboard_originality():
488
- """Originality반 λ¦¬λ”λ³΄λ“œ μ—…λ°μ΄νŠΈ 확인 및 λ°˜ν™˜"""
489
- leaderboards['originality'].check_for_updates()
490
- return leaderboards['originality'].get_leaderboard_df()
491
-
492
- def check_and_update_leaderboard_bce():
493
- """BCE반 λ¦¬λ”λ³΄λ“œ μ—…λ°μ΄νŠΈ 확인 및 λ°˜ν™˜"""
494
- leaderboards['bce'].check_for_updates()
495
- return leaderboards['bce'].get_leaderboard_df()
496
-
497
- def process_user_image_practice(image, username):
498
- """μ—°μŠ΅ νƒ­ μ‚¬μš©μž 이미지 처리 ν•¨μˆ˜"""
499
- return leaderboards['practice'].process_image(image, username)
500
-
501
- def get_current_leaderboard_practice():
502
- """μ—°μŠ΅ νƒ­ ν˜„μž¬ λ¦¬λ”λ³΄λ“œ λ°˜ν™˜"""
503
- return leaderboards['practice'].get_leaderboard_df()
504
-
505
- def check_and_update_leaderboard_practice():
506
- """μ—°μŠ΅ νƒ­ λ¦¬λ”λ³΄λ“œ μ—…λ°μ΄νŠΈ 확인 및 λ°˜ν™˜"""
507
- leaderboards['practice'].check_for_updates()
508
- return leaderboards['practice'].get_leaderboard_df()
509
 
510
  def create_interface():
511
- """Gradio μΈν„°νŽ˜μ΄μŠ€ 생성"""
512
  with gr.Blocks(title="λΉ„μŠ·ν•œ 이미지λ₯Ό λ§Œλ“€μ–΄μ£Όμ„Έμš”!", theme=gr.themes.Soft()) as demo:
513
  gr.Markdown("""
514
  # πŸ† 둯데 λΉ„μ „ μŠ€νŠœλ””μ˜€ λ¦¬λ”λ³΄λ“œ
515
  """)
516
 
 
 
517
 
518
  # νƒ­ 생성
519
  with gr.Tabs():
520
- # μ—°μŠ΅ νƒ­ (메인)
521
  with gr.Tab("πŸŽ“ μ—°μŠ΅"):
522
  gr.Markdown("### πŸ’‘ μ—°μŠ΅μš© νƒ­ (메인)")
523
  gr.Markdown("μ—…λ‘œλ“œ 및 이미지 μœ μ‚¬λ„λ₯Ό ν…ŒμŠ€νŠΈν•΄λ³Ό 수 μžˆλŠ” μ—°μŠ΅ κ³΅κ°„μž…λ‹ˆλ‹€.")
@@ -553,204 +518,75 @@ def create_interface():
553
  interactive=False
554
  )
555
 
 
 
556
  # μ—°μŠ΅ νƒ­ 이벀트 ν•Έλ“€λŸ¬
557
  submit_btn_practice.click(
558
- fn=process_user_image_practice,
559
  inputs=[image_input_practice, username_input_practice],
560
  outputs=[result_output_practice, leaderboard_output_practice]
561
  )
562
 
563
- # Respect반 νƒ­
564
- with gr.Tab("🎯 Respect반"):
565
- with gr.Row():
566
- with gr.Column(scale=1):
567
- gr.Markdown("### πŸ“€ 이미지 μ—…λ‘œλ“œ (Respect반)")
568
- image_input_respect = gr.Image(
569
- label="비ꡐ할 이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”",
570
- type="pil",
571
- height=300
572
- )
573
- username_input_respect = gr.Textbox(
574
- label="μ‚¬μš©μž 이름",
575
- placeholder="이름을 μž…λ ₯ν•˜μ„Έμš”",
576
- max_lines=1
577
- )
578
- submit_btn_respect = gr.Button("πŸš€ 점수 계산 및 등둝", variant="primary", size="lg")
579
-
580
- with gr.Column(scale=1):
581
- gr.Markdown("### πŸ“Š κ²°κ³Ό (Respect반)")
582
- result_output_respect = gr.Textbox(
583
- label="계산 κ²°κ³Ό",
584
- lines=10,
585
- interactive=False
586
- )
587
-
588
- gr.Markdown("### πŸ… Respect반 λ¦¬λ”λ³΄λ“œ")
589
- leaderboard_output_respect = gr.Dataframe(
590
- headers=["μˆœμœ„", "μ‚¬μš©μžλͺ…", "점수", "λ‚ μ§œ"],
591
- datatype=["number", "str", "number", "str"],
592
- interactive=False
593
- )
594
-
595
- # Respect반 이벀트 ν•Έλ“€λŸ¬
596
- submit_btn_respect.click(
597
- fn=process_user_image_respect,
598
- inputs=[image_input_respect, username_input_respect],
599
- outputs=[result_output_respect, leaderboard_output_respect]
600
- )
601
-
602
- # Challenge반 νƒ­
603
- with gr.Tab("⚑ Challenge반"):
604
- with gr.Row():
605
- with gr.Column(scale=1):
606
- gr.Markdown("### πŸ“€ 이미지 μ—…λ‘œλ“œ (Challenge반)")
607
- image_input_challenge = gr.Image(
608
- label="비ꡐ할 이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”",
609
- type="pil",
610
- height=300
611
- )
612
- username_input_challenge = gr.Textbox(
613
- label="μ‚¬μš©μž 이름",
614
- placeholder="이름을 μž…λ ₯ν•˜μ„Έμš”",
615
- max_lines=1
616
- )
617
- submit_btn_challenge = gr.Button("πŸš€ 점수 계산 및 등둝", variant="primary", size="lg")
618
-
619
- with gr.Column(scale=1):
620
- gr.Markdown("### πŸ“Š κ²°κ³Ό (Challenge반)")
621
- result_output_challenge = gr.Textbox(
622
- label="계산 κ²°κ³Ό",
623
- lines=10,
624
- interactive=False
625
- )
626
 
627
- gr.Markdown("### πŸ… Challenge반 λ¦¬λ”λ³΄λ“œ")
628
- leaderboard_output_challenge = gr.Dataframe(
629
- headers=["μˆœμœ„", "μ‚¬μš©μžλͺ…", "점수", "λ‚ μ§œ"],
630
- datatype=["number", "str", "number", "str"],
631
- interactive=False
632
- )
633
-
634
- # Challenge반 이벀트 ν•Έλ“€λŸ¬
635
- submit_btn_challenge.click(
636
- fn=process_user_image_challenge,
637
- inputs=[image_input_challenge, username_input_challenge],
638
- outputs=[result_output_challenge, leaderboard_output_challenge]
639
- )
640
-
641
- # Originality반 νƒ­
642
- with gr.Tab("🎨 Originality반"):
643
- with gr.Row():
644
- with gr.Column(scale=1):
645
- gr.Markdown("### πŸ“€ 이미지 μ—…λ‘œλ“œ (Originality반)")
646
- image_input_originality = gr.Image(
647
- label="비ꡐ할 이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”",
648
- type="pil",
649
- height=300
650
- )
651
- username_input_originality = gr.Textbox(
652
- label="μ‚¬μš©μž 이름",
653
- placeholder="이름을 μž…λ ₯ν•˜μ„Έμš”",
654
- max_lines=1
655
- )
656
- submit_btn_originality = gr.Button("πŸš€ 점수 계산 및 등둝", variant="primary", size="lg")
657
-
658
- with gr.Column(scale=1):
659
- gr.Markdown("### πŸ“Š κ²°κ³Ό (Originality반)")
660
- result_output_originality = gr.Textbox(
661
- label="계산 κ²°κ³Ό",
662
- lines=10,
663
- interactive=False
664
- )
665
-
666
- gr.Markdown("### πŸ… Originality반 λ¦¬λ”λ³΄λ“œ")
667
- leaderboard_output_originality = gr.Dataframe(
668
- headers=["μˆœμœ„", "μ‚¬μš©μžλͺ…", "점수", "λ‚ μ§œ"],
669
- datatype=["number", "str", "number", "str"],
670
- interactive=False
671
- )
672
-
673
- # Originality반 이벀트 ν•Έλ“€λŸ¬
674
- submit_btn_originality.click(
675
- fn=process_user_image_originality,
676
- inputs=[image_input_originality, username_input_originality],
677
- outputs=[result_output_originality, leaderboard_output_originality]
678
- )
679
-
680
- # BCE반 νƒ­
681
- with gr.Tab("πŸ”₯ BCE반"):
682
- with gr.Row():
683
- with gr.Column(scale=1):
684
- gr.Markdown("### πŸ“€ 이미지 μ—…λ‘œλ“œ (BCE반)")
685
- image_input_bce = gr.Image(
686
- label="비ꡐ할 이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”",
687
- type="pil",
688
- height=300
689
- )
690
- username_input_bce = gr.Textbox(
691
- label="μ‚¬μš©μž 이름",
692
- placeholder="이름을 μž…λ ₯ν•˜μ„Έμš”",
693
- max_lines=1
694
- )
695
- submit_btn_bce = gr.Button("πŸš€ 점수 계산 및 등둝", variant="primary", size="lg")
696
-
697
- with gr.Column(scale=1):
698
- gr.Markdown("### πŸ“Š κ²°κ³Ό (BCE반)")
699
- result_output_bce = gr.Textbox(
700
- label="계산 κ²°κ³Ό",
701
- lines=10,
702
- interactive=False
703
- )
704
-
705
- gr.Markdown("### πŸ… BCE반 λ¦¬λ”λ³΄λ“œ")
706
- leaderboard_output_bce = gr.Dataframe(
707
- headers=["μˆœμœ„", "μ‚¬μš©μžλͺ…", "점수", "λ‚ μ§œ"],
708
- datatype=["number", "str", "number", "str"],
709
- interactive=False
710
- )
711
-
712
- # BCE반 이벀트 ν•Έλ“€λŸ¬
713
- submit_btn_bce.click(
714
- fn=process_user_image_bce,
715
- inputs=[image_input_bce, username_input_bce],
716
- outputs=[result_output_bce, leaderboard_output_bce]
717
- )
718
-
719
  # νŽ˜μ΄μ§€ λ‘œλ“œ μ‹œ λͺ¨λ“  λ¦¬λ”λ³΄λ“œ ν‘œμ‹œ
720
  demo.load(
721
- fn=lambda: (
722
- get_current_leaderboard_practice(),
723
- get_current_leaderboard_respect(),
724
- get_current_leaderboard_challenge(),
725
- # get_current_leaderboard_originality(),
726
- # get_current_leaderboard_bce()
727
- ),
728
- outputs=[
729
- leaderboard_output_practice,
730
- leaderboard_output_respect,
731
- leaderboard_output_challenge,
732
- # leaderboard_output_originality,
733
- # leaderboard_output_bce,
734
- ]
735
  )
736
 
737
  # μ‹€μ‹œκ°„ μ—…λ°μ΄νŠΈ (10μ΄ˆλ§ˆλ‹€ - λͺ¨λ“  νƒ­ μ—…λ°μ΄νŠΈ)
738
  timer = gr.Timer(value=10)
739
  timer.tick(
740
- fn=lambda: (
741
- get_current_leaderboard_practice(),
742
- get_current_leaderboard_respect(),
743
- get_current_leaderboard_challenge(),
744
- # get_current_leaderboard_originality(),
745
- # get_current_leaderboard_bce()
746
- ),
747
- outputs=[
748
- leaderboard_output_practice,
749
- leaderboard_output_respect,
750
- leaderboard_output_challenge,
751
- # leaderboard_output_originality,
752
- # leaderboard_output_bce,
753
- ]
754
  )
755
 
756
  return demo
@@ -760,11 +596,10 @@ def main():
760
  print("πŸ† 이미지 μœ μ‚¬λ„ λ¦¬λ”λ³΄λ“œ μ‹œμŠ€ν…œμ„ μ‹œμž‘ν•©λ‹ˆλ‹€...")
761
  print("πŸ“ μ°Έμ‘° 이미지: label2.jpg")
762
  print("πŸ’Ύ 데이터 파일:")
763
- print(" β€’ Respect반: respect.json")
764
- print(" β€’ Challenge반: challenge.json")
765
- print(" β€’ Originality반: originality.json")
766
- print(" β€’ BCE반: bce.json")
767
- print(" β€’ μ—°μŠ΅: practice.json")
768
 
769
  # 각 λ°˜λ³„ λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰ 체크
770
  for class_name, lb in leaderboards.items():
@@ -784,7 +619,7 @@ def main():
784
  print(" β€’ λ™μ‹œμ„± μ œμ–΄ ν™œμ„±ν™”")
785
  print(" β€’ λ©”λͺ¨λ¦¬ 정리 μžλ™ν™”")
786
  print(" β€’ μ‹€μ‹œκ°„ μ—…λ°μ΄νŠΈ: 10초 간격")
787
- print(" β€’ 5개 탭별 독립 λ¦¬λ”λ³΄λ“œ 운영 (4개 반 + μ—°μŠ΅)")
788
 
789
  # μ™ΈλΆ€ 곡유 μš°μ„  μ‹œλ„
790
  print("\n🌐 μ™ΈλΆ€ μ ‘κ·Ό μ‹œλ„ 쀑...")
 
37
  # Fix SSL error for model download (macOS specific)
38
  ssl._create_default_https_context = ssl._create_unverified_context
39
 
40
+ # ========== μ—¬κΈ°λ§Œ μˆ˜μ •ν•˜λ©΄ 탭이 λ™μ μœΌλ‘œ λ°˜μ˜λ©λ‹ˆλ‹€ ==========
41
+ # μ˜ˆμ‹œ: ["Response반", "Challenge반"] β†’ μ—°μŠ΅ νƒ­ + 2개 반 = 총 3개 νƒ­
42
+ # μ˜ˆμ‹œ: ["206호", "207호", "305호"] β†’ μ—°μŠ΅ νƒ­ + 3개 반 = 총 4개 νƒ­
43
+ CLASSES = ["Respect반", "Challenge반", "Originality반", "BCE반"]
44
+ # ============================================================
45
+
46
+ # νƒ­ μ•„μ΄μ½˜ μžλ™ λ°°μ •
47
+ _TAB_ICONS = ["🎯", "⚑", "🎨", "πŸ”₯", "πŸ’Ž", "🌟", "πŸš€", "πŸ’‘", "πŸ…", "✨"]
48
+
49
+ def _class_key(name):
50
+ """반 이름을 json 파일λͺ…/λ”•μ…”λ„ˆλ¦¬ ν‚€λ‘œ λ³€ν™˜ (예: 'Respect반' β†’ 'respect')"""
51
+ # ν•œκΈ€ '반' 제거, κ³΅λ°±β†’μ–Έλ”μŠ€μ½”μ–΄, μ†Œλ¬Έμž
52
+ return name.replace("반", "").replace("호", "").strip().lower().replace(" ", "_")
53
+
54
+
55
  class ImageSimilarityLeaderboard:
56
  def __init__(self, reference_image_path="label2.jpg", data_file="leaderboard.json"):
57
  self.reference_image_path = reference_image_path
 
446
  self.leaderboard_data = []
447
  self.save_leaderboard()
448
  return "βœ… λ¦¬λ”λ³΄λ“œκ°€ μ΄ˆκΈ°ν™”λ˜μ—ˆμŠ΅λ‹ˆλ‹€.", pd.DataFrame(columns=['μˆœμœ„', 'μ‚¬μš©μžλͺ…', '점수', 'λ‚ μ§œ'])
 
449
 
450
+
451
+ # ── μ „μ—­ λ¦¬λ”λ³΄λ“œ μΈμŠ€ν„΄μŠ€ (CLASSES 기반 동적 생성 + μ—°μŠ΅) ──
452
+ leaderboards = {}
453
+ for _cls in CLASSES:
454
+ leaderboards[_class_key(_cls)] = ImageSimilarityLeaderboard("label2.jpg", f"{_class_key(_cls)}.json")
455
+ leaderboards['practice'] = ImageSimilarityLeaderboard("label2.jpg", "practice.json")
456
+
457
+
458
+ # ── λ²”μš© 처리 ν•¨μˆ˜ ──
459
+ def process_user_image(class_key, image, username):
460
+ """이미지 처리 (λͺ¨λ“  반 곡용)"""
461
+ return leaderboards[class_key].process_image(image, username)
462
+
463
+ def get_current_leaderboard(class_key):
464
+ """ν˜„μž¬ λ¦¬λ”λ³΄λ“œ λ°˜ν™˜ (λͺ¨λ“  반 곡용)"""
465
+ return leaderboards[class_key].get_leaderboard_df()
466
+
467
+ def check_and_update_leaderboard(class_key):
468
+ """λ¦¬λ”λ³΄λ“œ μ—…λ°μ΄νŠΈ 확인 및 λ°˜ν™˜ (λͺ¨λ“  반 곡용)"""
469
+ leaderboards[class_key].check_for_updates()
470
+ return leaderboards[class_key].get_leaderboard_df()
471
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
 
473
  def create_interface():
474
+ """Gradio μΈν„°νŽ˜μ΄μŠ€ 생성 (CLASSES 기반 동적 νƒ­)"""
475
  with gr.Blocks(title="λΉ„μŠ·ν•œ 이미지λ₯Ό λ§Œλ“€μ–΄μ£Όμ„Έμš”!", theme=gr.themes.Soft()) as demo:
476
  gr.Markdown("""
477
  # πŸ† 둯데 λΉ„μ „ μŠ€νŠœλ””μ˜€ λ¦¬λ”λ³΄λ“œ
478
  """)
479
 
480
+ # λͺ¨λ“  λ¦¬λ”λ³΄λ“œ 좜λ ₯ μœ„μ ―μ„ λͺ¨μ•„λ‘˜ λ”•μ…”λ„ˆλ¦¬
481
+ leaderboard_outputs = {}
482
 
483
  # νƒ­ 생성
484
  with gr.Tabs():
485
+ # ── μ—°μŠ΅ νƒ­ (항상 첫 번째) ──
486
  with gr.Tab("πŸŽ“ μ—°μŠ΅"):
487
  gr.Markdown("### πŸ’‘ μ—°μŠ΅μš© νƒ­ (메인)")
488
  gr.Markdown("μ—…λ‘œλ“œ 및 이미지 μœ μ‚¬λ„λ₯Ό ν…ŒμŠ€νŠΈν•΄λ³Ό 수 μžˆλŠ” μ—°μŠ΅ κ³΅κ°„μž…λ‹ˆλ‹€.")
 
518
  interactive=False
519
  )
520
 
521
+ leaderboard_outputs['practice'] = leaderboard_output_practice
522
+
523
  # μ—°μŠ΅ νƒ­ 이벀트 ν•Έλ“€λŸ¬
524
  submit_btn_practice.click(
525
+ fn=lambda img, name: process_user_image('practice', img, name),
526
  inputs=[image_input_practice, username_input_practice],
527
  outputs=[result_output_practice, leaderboard_output_practice]
528
  )
529
 
530
+ # ── λ°˜λ³„ νƒ­ (CLASSES 기반 동적 생성) ──
531
+ for idx, class_name in enumerate(CLASSES):
532
+ icon = _TAB_ICONS[idx % len(_TAB_ICONS)]
533
+ key = _class_key(class_name)
534
+
535
+ with gr.Tab(f"{icon} {class_name}"):
536
+ with gr.Row():
537
+ with gr.Column(scale=1):
538
+ gr.Markdown(f"### πŸ“€ 이미지 μ—…λ‘œλ“œ ({class_name})")
539
+ image_input = gr.Image(
540
+ label="비ꡐ할 이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”",
541
+ type="pil",
542
+ height=300
543
+ )
544
+ username_input = gr.Textbox(
545
+ label="μ‚¬μš©μž 이름",
546
+ placeholder="이름을 μž…λ ₯ν•˜μ„Έμš”",
547
+ max_lines=1
548
+ )
549
+ submit_btn = gr.Button("πŸš€ 점수 계산 및 등둝", variant="primary", size="lg")
550
+
551
+ with gr.Column(scale=1):
552
+ gr.Markdown(f"### πŸ“Š κ²°κ³Ό ({class_name})")
553
+ result_output = gr.Textbox(
554
+ label="계산 κ²°κ³Ό",
555
+ lines=10,
556
+ interactive=False
557
+ )
558
+
559
+ gr.Markdown(f"### πŸ… {class_name} λ¦¬λ”λ³΄λ“œ")
560
+ leaderboard_output = gr.Dataframe(
561
+ headers=["μˆœμœ„", "μ‚¬μš©μžλͺ…", "점수", "λ‚ μ§œ"],
562
+ datatype=["number", "str", "number", "str"],
563
+ interactive=False
564
+ )
565
+
566
+ leaderboard_outputs[key] = leaderboard_output
567
+
568
+ # ν΄λ‘œμ €μ—μ„œ key 값을 μΊ‘μ²˜ν•˜κΈ° μœ„ν•΄ default argument μ‚¬μš©
569
+ submit_btn.click(
570
+ fn=lambda img, name, k=key: process_user_image(k, img, name),
571
+ inputs=[image_input, username_input],
572
+ outputs=[result_output, leaderboard_output]
573
+ )
574
+
575
+ # ── λͺ¨λ“  ν‚€ μˆœμ„œ (practice λ¨Όμ €, 이후 CLASSES μˆœμ„œ) ──
576
+ all_keys = ['practice'] + [_class_key(c) for c in CLASSES]
577
+ all_outputs = [leaderboard_outputs[k] for k in all_keys]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  # νŽ˜μ΄μ§€ λ‘œλ“œ μ‹œ λͺ¨λ“  λ¦¬λ”λ³΄λ“œ ν‘œμ‹œ
580
  demo.load(
581
+ fn=lambda: tuple(get_current_leaderboard(k) for k in all_keys),
582
+ outputs=all_outputs
 
 
 
 
 
 
 
 
 
 
 
 
583
  )
584
 
585
  # μ‹€μ‹œκ°„ μ—…λ°μ΄νŠΈ (10μ΄ˆλ§ˆλ‹€ - λͺ¨λ“  νƒ­ μ—…λ°μ΄νŠΈ)
586
  timer = gr.Timer(value=10)
587
  timer.tick(
588
+ fn=lambda: tuple(check_and_update_leaderboard(k) for k in all_keys),
589
+ outputs=all_outputs
 
 
 
 
 
 
 
 
 
 
 
 
590
  )
591
 
592
  return demo
 
596
  print("πŸ† 이미지 μœ μ‚¬λ„ λ¦¬λ”λ³΄λ“œ μ‹œμŠ€ν…œμ„ μ‹œμž‘ν•©λ‹ˆλ‹€...")
597
  print("πŸ“ μ°Έμ‘° 이미지: label2.jpg")
598
  print("πŸ’Ύ 데이터 파일:")
599
+ for cls in CLASSES:
600
+ key = _class_key(cls)
601
+ print(f" β€’ {cls}: {key}.json")
602
+ print(f" β€’ μ—°μŠ΅: practice.json")
 
603
 
604
  # 각 λ°˜λ³„ λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰ 체크
605
  for class_name, lb in leaderboards.items():
 
619
  print(" β€’ λ™μ‹œμ„± μ œμ–΄ ν™œμ„±ν™”")
620
  print(" β€’ λ©”λͺ¨λ¦¬ 정리 μžλ™ν™”")
621
  print(" β€’ μ‹€μ‹œκ°„ μ—…λ°μ΄νŠΈ: 10초 간격")
622
+ print(f" β€’ {len(CLASSES)+1}개 탭별 독립 λ¦¬λ”λ³΄λ“œ 운영 ({len(CLASSES)}개 반 + μ—°μŠ΅)")
623
 
624
  # μ™ΈλΆ€ 곡유 μš°μ„  μ‹œλ„
625
  print("\n🌐 μ™ΈλΆ€ μ ‘κ·Ό μ‹œλ„ 쀑...")