ArmanRV commited on
Commit
ad05eaa
·
verified ·
1 Parent(s): 9d74976

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -60
app.py CHANGED
@@ -200,7 +200,10 @@ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
200
  DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
201
  print("DEVICE:", DEVICE, "DTYPE:", DTYPE, flush=True)
202
 
203
- tensor_transfrom = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5], [0.5])])
 
 
 
204
 
205
  unet = UNet2DConditionModel.from_pretrained(base_path, subfolder="unet", torch_dtype=DTYPE)
206
  unet.requires_grad_(False)
@@ -309,7 +312,6 @@ def start_tryon(
309
  if device == "cuda":
310
  autocast_ctx = torch.cuda.amp.autocast()
311
  else:
312
-
313
  class _NoCtx:
314
  def __enter__(self):
315
  return None
@@ -393,6 +395,7 @@ button[aria-label="Settings"] {display:none !important;}
393
  border-radius: 12px;
394
  padding: 10px 12px;
395
  font-size: 14px;
 
396
  }
397
 
398
  .feedback-idle {
@@ -402,6 +405,7 @@ button[aria-label="Settings"] {display:none !important;}
402
  border-radius: 12px;
403
  padding: 10px 12px;
404
  font-size: 14px;
 
405
  }
406
  """
407
 
@@ -441,7 +445,7 @@ def on_gallery_select(files_list: List[str], evt: gr.SelectData):
441
 
442
 
443
  # =========================
444
- # Feedback
445
  # =========================
446
  FEEDBACK_DIR = "./feedback"
447
  FEEDBACK_PATH = os.path.join(FEEDBACK_DIR, "feedback.jsonl")
@@ -486,6 +490,7 @@ def _upload_repo_feedback(api: HfApi, token: str, text: str) -> None:
486
 
487
  os.makedirs(FEEDBACK_DIR, exist_ok=True)
488
  tmp_path = os.path.join(FEEDBACK_DIR, "_feedback_upload.jsonl")
 
489
  with open(tmp_path, "w", encoding="utf-8") as f:
490
  f.write(text)
491
 
@@ -499,19 +504,7 @@ def _upload_repo_feedback(api: HfApi, token: str, text: str) -> None:
499
  )
500
 
501
 
502
- def save_feedback(is_like: bool, garment_name: str, comment: str):
503
- os.makedirs(FEEDBACK_DIR, exist_ok=True)
504
-
505
- clean_comment = (comment or "").strip()
506
- if len(clean_comment) > 1500:
507
- clean_comment = clean_comment[:1500]
508
-
509
- record = {
510
- "timestamp": datetime.utcnow().isoformat(),
511
- "like": bool(is_like),
512
- "garment": garment_name or "",
513
- "comment": clean_comment,
514
- }
515
  line = json.dumps(record, ensure_ascii=False) + "\n"
516
 
517
  try:
@@ -525,11 +518,11 @@ def save_feedback(is_like: bool, garment_name: str, comment: str):
525
  token = (os.getenv("HF_TOKEN", "").strip() or os.getenv("HUGGINGFACEHUB_API_TOKEN", "").strip())
526
  if not token:
527
  print("Feedback repo sync skipped: HF_TOKEN not set", flush=True)
528
- return True
529
 
530
  if not FEEDBACK_REPO_ID:
531
  print("Feedback repo sync skipped: FEEDBACK_REPO_ID not set", flush=True)
532
- return True
533
 
534
  api = HfApi()
535
  repo_text = _download_repo_feedback(api, token)
@@ -538,63 +531,132 @@ def save_feedback(is_like: bool, garment_name: str, comment: str):
538
  except Exception as e:
539
  print("Feedback repo sync failed:", repr(e), flush=True)
540
 
541
- return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
 
543
 
544
- def _feedback_idle_html():
545
  return """
546
  <div class="feedback-idle">
547
- Оцените результат и при желании оставьте комментарий.
548
  </div>
549
  """
550
 
551
 
552
- def _feedback_ok_html(action_text: str, has_comment: bool):
553
- comment_text = " и комментарий" if has_comment else ""
554
  return f"""
555
  <div class="feedback-ok">
556
- Спасибо! Оценка <b>{action_text}</b>{comment_text} сохранены.
 
 
 
 
 
 
 
 
557
  </div>
558
  """
559
 
560
 
561
- def submit_feedback_ui(is_like: bool, garment_name: str, comment: str):
562
- action_text = "«Нравится»" if is_like else "«Не нравится»"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563
 
564
  if not garment_name:
565
  return (
566
  "⚠️ Сначала выполните примерку и выберите одежду",
567
- _feedback_idle_html(),
 
 
 
 
 
 
 
568
  gr.update(value=comment),
569
  )
570
 
571
  try:
572
- save_feedback(is_like=is_like, garment_name=garment_name, comment=comment)
573
  return (
574
- f"✅ Отзыв сохранён: {action_text}",
575
- _feedback_ok_html(action_text, bool((comment or "").strip())),
576
  gr.update(value=""),
577
  )
578
  except Exception as e:
579
  return (
580
- f"❌ Ошибка сохранения отзыва: {type(e).__name__}: {str(e)[:200]}",
581
- """
582
- <div class="feedback-idle">
583
- Не удалось сохранить отзыв. Попробуйте ещё раз.
584
- </div>
585
- """,
586
  gr.update(value=comment),
587
  )
588
 
589
 
590
- def submit_like_feedback(garment_name: str, comment: str):
591
- return submit_feedback_ui(True, garment_name, comment)
592
-
593
-
594
- def submit_dislike_feedback(garment_name: str, comment: str):
595
- return submit_feedback_ui(False, garment_name, comment)
596
-
597
-
598
  def tryon_ui(person_pil, selected_filename):
599
  for msg in [
600
  "🧵 Анализируем посадку ткани…",
@@ -609,7 +671,8 @@ def tryon_ui(person_pil, selected_filename):
609
  msg,
610
  gr.update(visible=False),
611
  gr.update(value=""),
612
- gr.update(value=_feedback_idle_html()),
 
613
  )
614
  time.sleep(2.3)
615
 
@@ -620,7 +683,8 @@ def tryon_ui(person_pil, selected_filename):
620
  msg,
621
  gr.update(visible=False),
622
  gr.update(value=""),
623
- gr.update(value=_feedback_idle_html()),
 
624
  )
625
  return
626
 
@@ -630,7 +694,8 @@ def tryon_ui(person_pil, selected_filename):
630
  "❌ Загрузите фото человека",
631
  gr.update(visible=False),
632
  gr.update(value=""),
633
- gr.update(value=_feedback_idle_html()),
 
634
  )
635
  return
636
 
@@ -640,7 +705,8 @@ def tryon_ui(person_pil, selected_filename):
640
  "❌ Выберите одежду (клик по превью)",
641
  gr.update(visible=False),
642
  gr.update(value=""),
643
- gr.update(value=_feedback_idle_html()),
 
644
  )
645
  return
646
 
@@ -651,7 +717,8 @@ def tryon_ui(person_pil, selected_filename):
651
  "❌ Не удалось загрузить выбранную одежду",
652
  gr.update(visible=False),
653
  gr.update(value=""),
654
- gr.update(value=_feedback_idle_html()),
 
655
  )
656
  return
657
 
@@ -659,10 +726,11 @@ def tryon_ui(person_pil, selected_filename):
659
  out_img = start_tryon(human_pil=person_pil, garm_img=garm)
660
  yield (
661
  out_img,
662
- "✅ Готово — оцените результат ниже",
663
  gr.update(visible=True),
664
  gr.update(value=""),
665
- gr.update(value=_feedback_idle_html()),
 
666
  )
667
  except Exception as e:
668
  yield (
@@ -670,11 +738,14 @@ def tryon_ui(person_pil, selected_filename):
670
  f"❌ Ошибка: {type(e).__name__}: {str(e)[:220]}",
671
  gr.update(visible=False),
672
  gr.update(value=""),
673
- gr.update(value=_feedback_idle_html()),
 
674
  )
675
 
676
 
677
- # boot
 
 
678
  ensure_garments_available()
679
  _default_gender = "Женская"
680
  _initial_files = list_garments(gender=_default_gender)
@@ -734,18 +805,23 @@ with gr.Blocks(title="Virtual Try-On Rendez-vous", css=CUSTOM_CSS) as demo:
734
  with gr.Column(visible=False) as feedback_box:
735
  gr.HTML('<div class="feedback-box">')
736
 
 
737
  with gr.Row():
738
  like_btn = gr.Button("👍 Нравится")
739
  dislike_btn = gr.Button("👎 Не нравится")
 
740
 
 
741
  feedback_comment = gr.Textbox(
742
- label="Комментарий",
743
  placeholder="Напишите, что понравилось или что стоит улучшить...",
744
  lines=3,
745
- max_lines=5,
 
746
  )
 
 
747
 
748
- feedback_notice = gr.HTML(_feedback_idle_html())
749
  gr.HTML("</div>")
750
 
751
  gender.change(
@@ -763,21 +839,28 @@ with gr.Blocks(title="Virtual Try-On Rendez-vous", css=CUSTOM_CSS) as demo:
763
  run.click(
764
  fn=tryon_ui,
765
  inputs=[person, selected_garment_state],
766
- outputs=[out, status, feedback_box, feedback_comment, feedback_notice],
767
  concurrency_limit=1,
768
  )
769
 
770
  like_btn.click(
771
  fn=submit_like_feedback,
772
- inputs=[selected_garment_state, feedback_comment],
773
- outputs=[status, feedback_notice, feedback_comment],
774
  concurrency_limit=1,
775
  )
776
 
777
  dislike_btn.click(
778
  fn=submit_dislike_feedback,
 
 
 
 
 
 
 
779
  inputs=[selected_garment_state, feedback_comment],
780
- outputs=[status, feedback_notice, feedback_comment],
781
  concurrency_limit=1,
782
  )
783
 
 
200
  DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
201
  print("DEVICE:", DEVICE, "DTYPE:", DTYPE, flush=True)
202
 
203
+ tensor_transfrom = transforms.Compose([
204
+ transforms.ToTensor(),
205
+ transforms.Normalize([0.5], [0.5]),
206
+ ])
207
 
208
  unet = UNet2DConditionModel.from_pretrained(base_path, subfolder="unet", torch_dtype=DTYPE)
209
  unet.requires_grad_(False)
 
312
  if device == "cuda":
313
  autocast_ctx = torch.cuda.amp.autocast()
314
  else:
 
315
  class _NoCtx:
316
  def __enter__(self):
317
  return None
 
395
  border-radius: 12px;
396
  padding: 10px 12px;
397
  font-size: 14px;
398
+ margin-top: 8px;
399
  }
400
 
401
  .feedback-idle {
 
405
  border-radius: 12px;
406
  padding: 10px 12px;
407
  font-size: 14px;
408
+ margin-top: 8px;
409
  }
410
  """
411
 
 
445
 
446
 
447
  # =========================
448
+ # Feedback storage
449
  # =========================
450
  FEEDBACK_DIR = "./feedback"
451
  FEEDBACK_PATH = os.path.join(FEEDBACK_DIR, "feedback.jsonl")
 
490
 
491
  os.makedirs(FEEDBACK_DIR, exist_ok=True)
492
  tmp_path = os.path.join(FEEDBACK_DIR, "_feedback_upload.jsonl")
493
+
494
  with open(tmp_path, "w", encoding="utf-8") as f:
495
  f.write(text)
496
 
 
504
  )
505
 
506
 
507
+ def _append_feedback_record(record: dict) -> None:
 
 
 
 
 
 
 
 
 
 
 
 
508
  line = json.dumps(record, ensure_ascii=False) + "\n"
509
 
510
  try:
 
518
  token = (os.getenv("HF_TOKEN", "").strip() or os.getenv("HUGGINGFACEHUB_API_TOKEN", "").strip())
519
  if not token:
520
  print("Feedback repo sync skipped: HF_TOKEN not set", flush=True)
521
+ return
522
 
523
  if not FEEDBACK_REPO_ID:
524
  print("Feedback repo sync skipped: FEEDBACK_REPO_ID not set", flush=True)
525
+ return
526
 
527
  api = HfApi()
528
  repo_text = _download_repo_feedback(api, token)
 
531
  except Exception as e:
532
  print("Feedback repo sync failed:", repr(e), flush=True)
533
 
534
+
535
+ def save_rating_feedback(is_like: bool, garment_name: str) -> None:
536
+ record = {
537
+ "timestamp": datetime.utcnow().isoformat(),
538
+ "event": "rating",
539
+ "like": bool(is_like),
540
+ "garment": garment_name or "",
541
+ }
542
+ _append_feedback_record(record)
543
+
544
+
545
+ def save_comment_feedback(garment_name: str, comment: str) -> None:
546
+ clean_comment = (comment or "").strip()
547
+ if len(clean_comment) > 1500:
548
+ clean_comment = clean_comment[:1500]
549
+
550
+ record = {
551
+ "timestamp": datetime.utcnow().isoformat(),
552
+ "event": "comment",
553
+ "garment": garment_name or "",
554
+ "comment": clean_comment,
555
+ }
556
+ _append_feedback_record(record)
557
+
558
+
559
+ # =========================
560
+ # Feedback UI helpers
561
+ # =========================
562
+ def _rating_notice_idle_html():
563
+ return """
564
+ <div class="feedback-idle">
565
+ Оцените результат: нажмите лайк или дизлайк.
566
+ </div>
567
+ """
568
 
569
 
570
+ def _comment_notice_idle_html():
571
  return """
572
  <div class="feedback-idle">
573
+ При желании напишите комментарий и нажмите кнопку отправки.
574
  </div>
575
  """
576
 
577
 
578
+ def _rating_notice_ok_html(action_text: str):
 
579
  return f"""
580
  <div class="feedback-ok">
581
+ Ваша оценка <b>{action_text}</b> сохранена.
582
+ </div>
583
+ """
584
+
585
+
586
+ def _comment_notice_ok_html():
587
+ return """
588
+ <div class="feedback-ok">
589
+ ✅ Комментарий отправлен. Спасибо за обратную связь.
590
  </div>
591
  """
592
 
593
 
594
+ # =========================
595
+ # Feedback actions
596
+ # =========================
597
+ def submit_like_feedback(garment_name: str):
598
+ if not garment_name:
599
+ return "⚠️ Сначала выполните примерку и выберите одежду", _rating_notice_idle_html()
600
+
601
+ try:
602
+ save_rating_feedback(True, garment_name)
603
+ return "✅ Оценка сохранена: «Нравится»", _rating_notice_ok_html("«Нравится»")
604
+ except Exception as e:
605
+ return (
606
+ f"❌ Ошибка сохранения оценки: {type(e).__name__}: {str(e)[:200]}",
607
+ _rating_notice_idle_html(),
608
+ )
609
+
610
+
611
+ def submit_dislike_feedback(garment_name: str):
612
+ if not garment_name:
613
+ return "⚠️ Сначала выполните примерку и выберите одежду", _rating_notice_idle_html()
614
+
615
+ try:
616
+ save_rating_feedback(False, garment_name)
617
+ return "✅ Оценка сохранена: «Не нравится»", _rating_notice_ok_html("«Не нравится»")
618
+ except Exception as e:
619
+ return (
620
+ f"❌ Ошибка сохранения оценки: {type(e).__name__}: {str(e)[:200]}",
621
+ _rating_notice_idle_html(),
622
+ )
623
+
624
+
625
+ def submit_comment_feedback(garment_name: str, comment: str):
626
+ clean_comment = (comment or "").strip()
627
 
628
  if not garment_name:
629
  return (
630
  "⚠️ Сначала выполните примерку и выберите одежду",
631
+ _comment_notice_idle_html(),
632
+ gr.update(value=comment),
633
+ )
634
+
635
+ if not clean_comment:
636
+ return (
637
+ "⚠️ Напишите комментарий перед отправкой",
638
+ _comment_notice_idle_html(),
639
  gr.update(value=comment),
640
  )
641
 
642
  try:
643
+ save_comment_feedback(garment_name, clean_comment)
644
  return (
645
+ "✅ Комментарий отправлен",
646
+ _comment_notice_ok_html(),
647
  gr.update(value=""),
648
  )
649
  except Exception as e:
650
  return (
651
+ f"❌ Ошибка отправки комментария: {type(e).__name__}: {str(e)[:200]}",
652
+ _comment_notice_idle_html(),
 
 
 
 
653
  gr.update(value=comment),
654
  )
655
 
656
 
657
+ # =========================
658
+ # Try-on UI
659
+ # =========================
 
 
 
 
 
660
  def tryon_ui(person_pil, selected_filename):
661
  for msg in [
662
  "🧵 Анализируем посадку ткани…",
 
671
  msg,
672
  gr.update(visible=False),
673
  gr.update(value=""),
674
+ gr.update(value=_rating_notice_idle_html()),
675
+ gr.update(value=_comment_notice_idle_html()),
676
  )
677
  time.sleep(2.3)
678
 
 
683
  msg,
684
  gr.update(visible=False),
685
  gr.update(value=""),
686
+ gr.update(value=_rating_notice_idle_html()),
687
+ gr.update(value=_comment_notice_idle_html()),
688
  )
689
  return
690
 
 
694
  "❌ Загрузите фото человека",
695
  gr.update(visible=False),
696
  gr.update(value=""),
697
+ gr.update(value=_rating_notice_idle_html()),
698
+ gr.update(value=_comment_notice_idle_html()),
699
  )
700
  return
701
 
 
705
  "❌ Выберите одежду (клик по превью)",
706
  gr.update(visible=False),
707
  gr.update(value=""),
708
+ gr.update(value=_rating_notice_idle_html()),
709
+ gr.update(value=_comment_notice_idle_html()),
710
  )
711
  return
712
 
 
717
  "❌ Не удалось загрузить выбранную одежду",
718
  gr.update(visible=False),
719
  gr.update(value=""),
720
+ gr.update(value=_rating_notice_idle_html()),
721
+ gr.update(value=_comment_notice_idle_html()),
722
  )
723
  return
724
 
 
726
  out_img = start_tryon(human_pil=person_pil, garm_img=garm)
727
  yield (
728
  out_img,
729
+ "✅ Готово — оцените результат и при желании оставьте комментарий",
730
  gr.update(visible=True),
731
  gr.update(value=""),
732
+ gr.update(value=_rating_notice_idle_html()),
733
+ gr.update(value=_comment_notice_idle_html()),
734
  )
735
  except Exception as e:
736
  yield (
 
738
  f"❌ Ошибка: {type(e).__name__}: {str(e)[:220]}",
739
  gr.update(visible=False),
740
  gr.update(value=""),
741
+ gr.update(value=_rating_notice_idle_html()),
742
+ gr.update(value=_comment_notice_idle_html()),
743
  )
744
 
745
 
746
+ # =========================
747
+ # Boot
748
+ # =========================
749
  ensure_garments_available()
750
  _default_gender = "Женская"
751
  _initial_files = list_garments(gender=_default_gender)
 
805
  with gr.Column(visible=False) as feedback_box:
806
  gr.HTML('<div class="feedback-box">')
807
 
808
+ gr.Markdown("### Оценка результата")
809
  with gr.Row():
810
  like_btn = gr.Button("👍 Нравится")
811
  dislike_btn = gr.Button("👎 Не нравится")
812
+ rating_notice = gr.HTML(_rating_notice_idle_html())
813
 
814
+ gr.Markdown("### Комментарий")
815
  feedback_comment = gr.Textbox(
816
+ label="",
817
  placeholder="Напишите, что понравилось или что стоит улучшить...",
818
  lines=3,
819
+ max_lines=6,
820
+ show_label=False,
821
  )
822
+ submit_comment_btn = gr.Button("Отправить комментарий")
823
+ comment_notice = gr.HTML(_comment_notice_idle_html())
824
 
 
825
  gr.HTML("</div>")
826
 
827
  gender.change(
 
839
  run.click(
840
  fn=tryon_ui,
841
  inputs=[person, selected_garment_state],
842
+ outputs=[out, status, feedback_box, feedback_comment, rating_notice, comment_notice],
843
  concurrency_limit=1,
844
  )
845
 
846
  like_btn.click(
847
  fn=submit_like_feedback,
848
+ inputs=[selected_garment_state],
849
+ outputs=[status, rating_notice],
850
  concurrency_limit=1,
851
  )
852
 
853
  dislike_btn.click(
854
  fn=submit_dislike_feedback,
855
+ inputs=[selected_garment_state],
856
+ outputs=[status, rating_notice],
857
+ concurrency_limit=1,
858
+ )
859
+
860
+ submit_comment_btn.click(
861
+ fn=submit_comment_feedback,
862
  inputs=[selected_garment_state, feedback_comment],
863
+ outputs=[status, comment_notice, feedback_comment],
864
  concurrency_limit=1,
865
  )
866