ginipick commited on
Commit
88d099b
Β·
verified Β·
1 Parent(s): df5bbd7

Update app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +211 -1
app-backup.py CHANGED
@@ -206,6 +206,7 @@ TRANSLATOR = None
206
  # API URLs
207
  TEXT2IMG_API_URL = "http://211.233.58.201:7896"
208
  VIDEO_API_URL = "http://211.233.58.201:7875"
 
209
 
210
  # Image size presets
211
  IMAGE_PRESETS = {
@@ -987,6 +988,140 @@ def merge_videos_with_audio(video_files, audio_file, audio_mode, audio_volume, o
987
  traceback.print_exc()
988
  return None, f"❌ 였λ₯˜ λ°œμƒ: {str(e)}"
989
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
990
  # CSS
991
  css = """
992
  :root {
@@ -1012,7 +1147,7 @@ css = """
1012
  padding: 20px !important;
1013
  margin-bottom: 20px !important;
1014
  }
1015
- #generate-btn, #video-btn, #outpaint-btn, #preview-btn, #audio-btn, #bg-remove-btn, #merge-btn {
1016
  background: linear-gradient(135deg, #ff9a9e, #fad0c4) !important;
1017
  font-size: 1.1rem !important;
1018
  padding: 12px 24px !important;
@@ -1419,6 +1554,74 @@ with demo:
1419
  κΈ΄ λΉ„λ””μ˜€λŠ” μž‘μ€ 쑰각으둜 λ‚˜λˆ„μ–΄ μ²˜λ¦¬ν•˜μ„Έμš”.
1420
  """)
1421
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1422
  # λͺ¨λΈ λ‘œλ“œ ν•¨μˆ˜ μ‹€ν–‰
1423
  def on_demo_load():
1424
  try:
@@ -1508,6 +1711,13 @@ with demo:
1508
  outputs=[stream_image, output_bg_video, time_textbox]
1509
  )
1510
 
 
 
 
 
 
 
 
1511
  # 데λͺ¨ λ‘œλ“œ μ‹œ μ‹€ν–‰
1512
  demo.load(on_demo_load, outputs=model_status)
1513
 
 
206
  # API URLs
207
  TEXT2IMG_API_URL = "http://211.233.58.201:7896"
208
  VIDEO_API_URL = "http://211.233.58.201:7875"
209
+ AVATAR_API_URL = "http://211.233.58.201:7788"
210
 
211
  # Image size presets
212
  IMAGE_PRESETS = {
 
988
  traceback.print_exc()
989
  return None, f"❌ 였λ₯˜ λ°œμƒ: {str(e)}"
990
 
991
+ @spaces.GPU(duration=180)
992
+ def generate_avatar_animation(portrait_image, driving_audio, guidance_scale, inference_steps):
993
+ """이미지와 μ˜€λ””μ˜€λ‘œ 아바타 μ• λ‹ˆλ©”μ΄μ…˜ 생성"""
994
+ if portrait_image is None:
995
+ return None, None, "μ΄ˆμƒν™” 이미지λ₯Ό μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”."
996
+
997
+ if driving_audio is None:
998
+ return None, None, "μ˜€λ””μ˜€ νŒŒμΌμ„ μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”."
999
+
1000
+ try:
1001
+ # μƒνƒœ μ—…λ°μ΄νŠΈ
1002
+ status = "아바타 생성 μ‹œμž‘..."
1003
+
1004
+ # 이미지 처리 - filepath둜 λ°›μœΌλ―€λ‘œ 직접 μ‚¬μš©
1005
+ portrait_path = portrait_image
1006
+
1007
+ # 이미지가 μ‹€μ œλ‘œ μ‘΄μž¬ν•˜λŠ”μ§€ 확인
1008
+ if not os.path.exists(portrait_path):
1009
+ # λ§Œμ•½ numpy arrayλ‚˜ PIL μ΄λ―Έμ§€λ‘œ μ™”λ‹€λ©΄ μ €μž₯
1010
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as fp:
1011
+ temp_portrait_path = fp.name
1012
+ if isinstance(portrait_image, np.ndarray):
1013
+ Image.fromarray(portrait_image).save(temp_portrait_path)
1014
+ elif isinstance(portrait_image, Image.Image):
1015
+ portrait_image.save(temp_portrait_path)
1016
+ else:
1017
+ return None, None, "❌ 이미지 ν˜•μ‹μ„ 인식할 수 μ—†μŠ΅λ‹ˆλ‹€."
1018
+ portrait_path = temp_portrait_path
1019
+
1020
+ # μ˜€λ””μ˜€ 경둜 확인
1021
+ audio_path = driving_audio
1022
+
1023
+ # 경둜 λ‘œκΉ…
1024
+ logging.info(f"Portrait path: {portrait_path}")
1025
+ logging.info(f"Audio path: {audio_path}")
1026
+ logging.info(f"Guidance Scale: {guidance_scale}")
1027
+ logging.info(f"Inference Steps: {inference_steps}")
1028
+
1029
+ # 파일 쑴재 확인
1030
+ if not os.path.exists(portrait_path):
1031
+ return None, None, f"❌ 이미지 νŒŒμΌμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€: {portrait_path}"
1032
+
1033
+ if not os.path.exists(audio_path):
1034
+ return None, None, f"❌ μ˜€λ””μ˜€ νŒŒμΌμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€: {audio_path}"
1035
+
1036
+ # API μ—°κ²° μž¬μ‹œλ„ 둜직
1037
+ max_retries = 3
1038
+ retry_delay = 5 # 초
1039
+
1040
+ for attempt in range(max_retries):
1041
+ try:
1042
+ logging.info(f"API μ—°κ²° μ‹œλ„ {attempt + 1}/{max_retries}")
1043
+
1044
+ # νƒ€μž„μ•„μ›ƒμ„ 늘린 Client 생성
1045
+ # gradio_client의 νƒ€μž„μ•„μ›ƒ 섀정을 μœ„ν•΄ httpx client μ„€μ •
1046
+ import httpx
1047
+ client = Client(
1048
+ AVATAR_API_URL,
1049
+ timeout=httpx.Timeout(60.0, connect=30.0) # μ—°κ²° νƒ€μž„μ•„μ›ƒ 30초, 전체 νƒ€μž„μ•„μ›ƒ 60초
1050
+ )
1051
+
1052
+ logging.info("API ν΄λΌμ΄μ–ΈνŠΈ 생성 성곡")
1053
+
1054
+ # API 호좜
1055
+ result = client.predict(
1056
+ portrait_path, # 직접 경둜 전달
1057
+ audio_path, # 직접 경둜 전달
1058
+ float(guidance_scale),
1059
+ float(inference_steps),
1060
+ api_name="/generate_animation"
1061
+ )
1062
+
1063
+ # μ„±κ³΅ν•˜λ©΄ 루프 μ’…λ£Œ
1064
+ break
1065
+
1066
+ except (httpx.ConnectTimeout, httpx.TimeoutException) as e:
1067
+ logging.warning(f"μ—°κ²° νƒ€μž„μ•„μ›ƒ (μ‹œλ„ {attempt + 1}/{max_retries}): {str(e)}")
1068
+ if attempt < max_retries - 1:
1069
+ logging.info(f"{retry_delay}초 ν›„ μž¬μ‹œλ„...")
1070
+ time.sleep(retry_delay)
1071
+ else:
1072
+ return None, None, "❌ API μ„œλ²„μ— μ—°κ²°ν•  수 μ—†μŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”."
1073
+ except Exception as e:
1074
+ # λ‹€λ₯Έ μ˜ˆμ™ΈλŠ” μ¦‰μ‹œ 처리
1075
+ raise e
1076
+
1077
+ # μž„μ‹œ 파일 μ‚­μ œ (μžˆλŠ” 경우)
1078
+ if 'temp_portrait_path' in locals() and os.path.exists(temp_portrait_path):
1079
+ os.unlink(temp_portrait_path)
1080
+
1081
+ # 결과 처리
1082
+ if result and len(result) >= 2:
1083
+ animation_result = result[0]
1084
+ comparison_result = result[1]
1085
+
1086
+ # κ²°κ³Όκ°€ dict인지 직접 κ²½λ‘œμΈμ§€ 확인
1087
+ if isinstance(animation_result, dict):
1088
+ animation_video = animation_result.get("video")
1089
+ else:
1090
+ animation_video = animation_result
1091
+
1092
+ if isinstance(comparison_result, dict):
1093
+ comparison_video = comparison_result.get("video")
1094
+ else:
1095
+ comparison_video = comparison_result
1096
+
1097
+ # λΉ„λ””μ˜€ 파일 쑴재 확인
1098
+ if animation_video and os.path.exists(str(animation_video)):
1099
+ logging.info(f"Animation video created: {animation_video}")
1100
+ else:
1101
+ logging.warning(f"Animation video not found or invalid: {animation_video}")
1102
+
1103
+ if comparison_video and os.path.exists(str(comparison_video)):
1104
+ logging.info(f"Comparison video created: {comparison_video}")
1105
+ else:
1106
+ logging.warning(f"Comparison video not found or invalid: {comparison_video}")
1107
+
1108
+ return animation_video, comparison_video, "βœ… 아바타 μ• λ‹ˆλ©”μ΄μ…˜ 생성 μ™„λ£Œ!"
1109
+ else:
1110
+ logging.error(f"Unexpected API response: {result}")
1111
+ return None, None, "❌ API 응닡이 μ˜ˆμƒκ³Ό λ‹€λ¦…λ‹ˆλ‹€."
1112
+
1113
+ except httpx.ConnectTimeout:
1114
+ logging.error("Connection timeout to API server")
1115
+ return None, None, "❌ API μ„œλ²„ μ—°κ²° μ‹œκ°„ 초과. μ„œλ²„κ°€ μ‘λ‹΅ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
1116
+ except httpx.TimeoutException:
1117
+ logging.error("Request timeout")
1118
+ return None, None, "❌ μš”μ²­ μ‹œκ°„ 초과. μ„œλ²„ 처리 μ‹œκ°„μ΄ λ„ˆλ¬΄ κΉλ‹ˆλ‹€."
1119
+ except Exception as e:
1120
+ logging.error(f"Avatar generation error: {str(e)}")
1121
+ import traceback
1122
+ traceback.print_exc()
1123
+ return None, None, f"❌ 였λ₯˜ λ°œμƒ: {str(e)}"
1124
+
1125
  # CSS
1126
  css = """
1127
  :root {
 
1147
  padding: 20px !important;
1148
  margin-bottom: 20px !important;
1149
  }
1150
+ #generate-btn, #video-btn, #outpaint-btn, #preview-btn, #audio-btn, #bg-remove-btn, #merge-btn, #avatar-btn {
1151
  background: linear-gradient(135deg, #ff9a9e, #fad0c4) !important;
1152
  font-size: 1.1rem !important;
1153
  padding: 12px 24px !important;
 
1554
  κΈ΄ λΉ„λ””μ˜€λŠ” μž‘μ€ 쑰각으둜 λ‚˜λˆ„μ–΄ μ²˜λ¦¬ν•˜μ„Έμš”.
1555
  """)
1556
 
1557
+ # μ—¬μ„― 번째 νƒ­: 이미지to아바타
1558
+ with gr.Tab("이미지to아바타", elem_classes="tabitem"):
1559
+ with gr.Row(equal_height=True):
1560
+ # μž…λ ₯ 컬럼
1561
+ with gr.Column(scale=1):
1562
+ with gr.Group(elem_classes="panel-box"):
1563
+ gr.Markdown("### πŸ–ΌοΈ μ΄ˆμƒν™” 이미지 μ—…λ‘œλ“œ")
1564
+
1565
+ avatar_portrait = gr.Image(
1566
+ label="μ΄ˆμƒν™” 이미지 (아무 λΉ„μœ¨ κ°€λŠ₯)",
1567
+ type="filepath",
1568
+ sources=["upload"]
1569
+ )
1570
+
1571
+ with gr.Group(elem_classes="panel-box"):
1572
+ gr.Markdown("### 🎡 μ˜€λ””μ˜€ μ—…λ‘œλ“œ")
1573
+
1574
+ avatar_audio = gr.Audio(
1575
+ label="ꡬ동 μ˜€λ””μ˜€",
1576
+ type="filepath",
1577
+ sources=["upload"]
1578
+ )
1579
+
1580
+ with gr.Group(elem_classes="panel-box"):
1581
+ gr.Markdown("### βš™οΈ 생성 μ„€μ •")
1582
+
1583
+ avatar_guidance = gr.Slider(
1584
+ minimum=1.0,
1585
+ maximum=7.0,
1586
+ value=2.5,
1587
+ step=0.1,
1588
+ label="κ°€μ΄λ˜μŠ€ μŠ€μΌ€μΌ",
1589
+ info="값이 λ†’μ„μˆ˜λ‘ 더 κ°•ν•œ κ°€μ΄λ“œ"
1590
+ )
1591
+
1592
+ avatar_steps = gr.Slider(
1593
+ minimum=5,
1594
+ maximum=30,
1595
+ value=15,
1596
+ step=1,
1597
+ label="μΆ”λ‘  μŠ€ν…",
1598
+ info="μŠ€ν…μ΄ λ§Žμ„μˆ˜λ‘ ν’ˆμ§ˆ ν–₯상"
1599
+ )
1600
+
1601
+ avatar_btn = gr.Button("🎭 아바타 생성", variant="primary", elem_id="avatar-btn")
1602
+
1603
+ # 좜λ ₯ 컬럼
1604
+ with gr.Column(scale=1):
1605
+ with gr.Group(elem_classes="panel-box"):
1606
+ gr.Markdown("### 🎬 생성 κ²°κ³Ό")
1607
+
1608
+ avatar_status = gr.Textbox(label="처리 μƒνƒœ", interactive=False)
1609
+ avatar_result = gr.Video(label="μ• λ‹ˆλ©”μ΄μ…˜ κ²°κ³Ό")
1610
+ avatar_comparison = gr.Video(label="원본-μ• λ‹ˆλ©”μ΄μ…˜ 비ꡐ")
1611
+
1612
+ gr.Markdown("""
1613
+ ### ℹ️ μ‚¬μš© 방법
1614
+ 1. 정면을 보고 μžˆλŠ” μ΄ˆμƒν™” 이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”
1615
+ 2. μŒμ„±μ΄λ‚˜ μŒμ•… μ˜€λ””μ˜€ νŒŒμΌμ„ μ—…λ‘œλ“œν•˜μ„Έμš”
1616
+ 3. κ°€μ΄λ˜μŠ€μ™€ μŠ€ν… 섀정을 μ‘°μ •ν•˜μ„Έμš”
1617
+ 4. '아바타 생성' λ²„νŠΌμ„ ν΄λ¦­ν•˜μ„Έμš”
1618
+
1619
+ **팁**:
1620
+ - μ •λ©΄ μ–Όκ΅΄ 이미지가 κ°€μž₯ 쒋은 κ²°κ³Όλ₯Ό λ§Œλ“­λ‹ˆλ‹€
1621
+ - μ˜€λ””μ˜€μ˜ μŒμ„±μ΄ λͺ…ν™•ν• μˆ˜λ‘ 립싱크가 μ •ν™•ν•©λ‹ˆλ‹€
1622
+ - κ°€μ΄λ˜μŠ€λ₯Ό 높이면 μ›€μ§μž„μ΄ κ°•ν•΄μ§‘λ‹ˆλ‹€
1623
+ """)
1624
+
1625
  # λͺ¨λΈ λ‘œλ“œ ν•¨μˆ˜ μ‹€ν–‰
1626
  def on_demo_load():
1627
  try:
 
1711
  outputs=[stream_image, output_bg_video, time_textbox]
1712
  )
1713
 
1714
+ # 이벀트 μ—°κ²° - μ—¬μ„― 번째 νƒ­ (이미지to아바타)
1715
+ avatar_btn.click(
1716
+ generate_avatar_animation,
1717
+ inputs=[avatar_portrait, avatar_audio, avatar_guidance, avatar_steps],
1718
+ outputs=[avatar_result, avatar_comparison, avatar_status]
1719
+ )
1720
+
1721
  # 데λͺ¨ λ‘œλ“œ μ‹œ μ‹€ν–‰
1722
  demo.load(on_demo_load, outputs=model_status)
1723