openfree commited on
Commit
d06a374
Β·
verified Β·
1 Parent(s): 36eaa13

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -1
app.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,69 @@ 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 +1076,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 +1483,73 @@ with demo:
1419
  κΈ΄ λΉ„λ””μ˜€λŠ” μž‘μ€ 쑰각으둜 λ‚˜λˆ„μ–΄ μ²˜λ¦¬ν•˜μ„Έμš”.
1420
  """)
1421
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1422
  # λͺ¨λΈ λ‘œλ“œ ν•¨μˆ˜ μ‹€ν–‰
1423
  def on_demo_load():
1424
  try:
@@ -1508,6 +1639,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
+ # 이미지 μ €μž₯
1005
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as fp:
1006
+ portrait_path = fp.name
1007
+ if isinstance(portrait_image, np.ndarray):
1008
+ Image.fromarray(portrait_image).save(portrait_path)
1009
+ else:
1010
+ Image.open(portrait_image).save(portrait_path)
1011
+
1012
+ # μ˜€λ””μ˜€ 경둜 확인
1013
+ if isinstance(driving_audio, str):
1014
+ audio_path = driving_audio
1015
+ else:
1016
+ audio_path = driving_audio
1017
+
1018
+ logging.info(f"Portrait: {portrait_path}")
1019
+ logging.info(f"Audio: {audio_path}")
1020
+ logging.info(f"Guidance Scale: {guidance_scale}")
1021
+ logging.info(f"Inference Steps: {inference_steps}")
1022
+
1023
+ # API 호좜
1024
+ client = Client(AVATAR_API_URL)
1025
+ result = client.predict(
1026
+ handle_file(portrait_path),
1027
+ handle_file(audio_path),
1028
+ float(guidance_scale),
1029
+ float(inference_steps),
1030
+ api_name="/generate_animation"
1031
+ )
1032
+
1033
+ # μž„μ‹œ 파일 μ‚­μ œ
1034
+ os.unlink(portrait_path)
1035
+
1036
+ if result and len(result) >= 2:
1037
+ animation_result = result[0]
1038
+ comparison_result = result[1]
1039
+
1040
+ # λΉ„λ””μ˜€ 경둜 μΆ”μΆœ
1041
+ animation_video = animation_result.get("video") if isinstance(animation_result, dict) else None
1042
+ comparison_video = comparison_result.get("video") if isinstance(comparison_result, dict) else None
1043
+
1044
+ return animation_video, comparison_video, "βœ… 아바타 μ• λ‹ˆλ©”μ΄μ…˜ 생성 μ™„λ£Œ!"
1045
+ else:
1046
+ return None, None, "❌ API 응닡이 μ˜ˆμƒκ³Ό λ‹€λ¦…λ‹ˆλ‹€."
1047
+
1048
+ except Exception as e:
1049
+ logging.error(f"Avatar generation error: {str(e)}")
1050
+ import traceback
1051
+ traceback.print_exc()
1052
+ return None, None, f"❌ 였λ₯˜ λ°œμƒ: {str(e)}"
1053
+
1054
  # CSS
1055
  css = """
1056
  :root {
 
1076
  padding: 20px !important;
1077
  margin-bottom: 20px !important;
1078
  }
1079
+ #generate-btn, #video-btn, #outpaint-btn, #preview-btn, #audio-btn, #bg-remove-btn, #merge-btn, #avatar-btn {
1080
  background: linear-gradient(135deg, #ff9a9e, #fad0c4) !important;
1081
  font-size: 1.1rem !important;
1082
  padding: 12px 24px !important;
 
1483
  κΈ΄ λΉ„λ””μ˜€λŠ” μž‘μ€ 쑰각으둜 λ‚˜λˆ„μ–΄ μ²˜λ¦¬ν•˜μ„Έμš”.
1484
  """)
1485
 
1486
+ # μ—¬μ„― 번째 νƒ­: 이미지to아바타
1487
+ with gr.Tab("이미지to아바타", elem_classes="tabitem"):
1488
+ with gr.Row(equal_height=True):
1489
+ # μž…λ ₯ 컬럼
1490
+ with gr.Column(scale=1):
1491
+ with gr.Group(elem_classes="panel-box"):
1492
+ gr.Markdown("### πŸ–ΌοΈ μ΄ˆμƒν™” 이미지 μ—…λ‘œλ“œ")
1493
+
1494
+ avatar_portrait = gr.Image(
1495
+ label="μ΄ˆμƒν™” 이미지 (아무 λΉ„μœ¨ κ°€λŠ₯)",
1496
+ type="filepath"
1497
+ )
1498
+
1499
+ with gr.Group(elem_classes="panel-box"):
1500
+ gr.Markdown("### 🎡 μ˜€λ””μ˜€ μ—…λ‘œλ“œ")
1501
+
1502
+ avatar_audio = gr.Audio(
1503
+ label="ꡬ동 μ˜€λ””μ˜€",
1504
+ type="filepath",
1505
+ sources=["upload"]
1506
+ )
1507
+
1508
+ with gr.Group(elem_classes="panel-box"):
1509
+ gr.Markdown("### βš™οΈ 생성 μ„€μ •")
1510
+
1511
+ avatar_guidance = gr.Slider(
1512
+ minimum=1.0,
1513
+ maximum=7.0,
1514
+ value=2.5,
1515
+ step=0.1,
1516
+ label="κ°€μ΄λ˜μŠ€ μŠ€μΌ€μΌ",
1517
+ info="값이 λ†’μ„μˆ˜λ‘ 더 κ°•ν•œ οΏ½οΏ½μ΄λ“œ"
1518
+ )
1519
+
1520
+ avatar_steps = gr.Slider(
1521
+ minimum=5,
1522
+ maximum=30,
1523
+ value=15,
1524
+ step=1,
1525
+ label="μΆ”λ‘  μŠ€ν…",
1526
+ info="μŠ€ν…μ΄ λ§Žμ„μˆ˜λ‘ ν’ˆμ§ˆ ν–₯상"
1527
+ )
1528
+
1529
+ avatar_btn = gr.Button("🎭 아바타 생성", variant="primary", elem_id="avatar-btn")
1530
+
1531
+ # 좜λ ₯ 컬럼
1532
+ with gr.Column(scale=1):
1533
+ with gr.Group(elem_classes="panel-box"):
1534
+ gr.Markdown("### 🎬 생성 κ²°κ³Ό")
1535
+
1536
+ avatar_status = gr.Textbox(label="처리 μƒνƒœ", interactive=False)
1537
+ avatar_result = gr.Video(label="μ• λ‹ˆλ©”μ΄μ…˜ κ²°κ³Ό")
1538
+ avatar_comparison = gr.Video(label="원본-μ• λ‹ˆλ©”μ΄μ…˜ 비ꡐ")
1539
+
1540
+ gr.Markdown("""
1541
+ ### ℹ️ μ‚¬μš© 방법
1542
+ 1. 정면을 보고 μžˆλŠ” μ΄ˆμƒν™” 이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”
1543
+ 2. μŒμ„±μ΄λ‚˜ μŒμ•… μ˜€λ””μ˜€ νŒŒμΌμ„ μ—…λ‘œλ“œν•˜μ„Έμš”
1544
+ 3. κ°€μ΄λ˜μŠ€μ™€ μŠ€ν… 섀정을 μ‘°μ •ν•˜μ„Έμš”
1545
+ 4. '아바타 생성' λ²„νŠΌμ„ ν΄λ¦­ν•˜μ„Έμš”
1546
+
1547
+ **팁**:
1548
+ - μ •λ©΄ μ–Όκ΅΄ 이미지가 κ°€μž₯ 쒋은 κ²°κ³Όλ₯Ό λ§Œλ“­λ‹ˆλ‹€
1549
+ - μ˜€λ””μ˜€μ˜ μŒμ„±μ΄ λͺ…ν™•ν• μˆ˜λ‘ 립싱크가 μ •ν™•ν•©λ‹ˆλ‹€
1550
+ - κ°€μ΄λ˜μŠ€λ₯Ό 높이면 μ›€μ§μž„μ΄ κ°•ν•΄μ§‘λ‹ˆλ‹€
1551
+ """)
1552
+
1553
  # λͺ¨λΈ λ‘œλ“œ ν•¨μˆ˜ μ‹€ν–‰
1554
  def on_demo_load():
1555
  try:
 
1639
  outputs=[stream_image, output_bg_video, time_textbox]
1640
  )
1641
 
1642
+ # 이벀트 μ—°κ²° - μ—¬μ„― 번째 νƒ­ (이미지to아바타)
1643
+ avatar_btn.click(
1644
+ generate_avatar_animation,
1645
+ inputs=[avatar_portrait, avatar_audio, avatar_guidance, avatar_steps],
1646
+ outputs=[avatar_result, avatar_comparison, avatar_status]
1647
+ )
1648
+
1649
  # 데λͺ¨ λ‘œλ“œ μ‹œ μ‹€ν–‰
1650
  demo.load(on_demo_load, outputs=model_status)
1651