ginipick commited on
Commit
2b5656b
ยท
verified ยท
1 Parent(s): 9a28049

Update app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +159 -170
app-backup.py CHANGED
@@ -31,12 +31,10 @@ from einops import rearrange
31
  from scipy.io import wavfile
32
  from transformers import pipeline
33
 
34
- # ๋น„๋””์˜ค ๋ฐฐ๊ฒฝ์ œ๊ฑฐ ๊ด€๋ จ import
35
  # ๋น„๋””์˜ค ๋ฐฐ๊ฒฝ์ œ๊ฑฐ ๊ด€๋ จ import
36
  from transformers import AutoModelForImageSegmentation
37
  from torchvision import transforms
38
 
39
-
40
  # โ”€โ”€ moviepy import โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
41
  try:
42
  from moviepy.editor import (
@@ -148,8 +146,8 @@ from concurrent.futures import ThreadPoolExecutor
148
 
149
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
150
 
151
-
152
-
153
 
154
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •์œผ๋กœ torch.load ์ฒดํฌ ์šฐํšŒ (์ž„์‹œ ํ•ด๊ฒฐ์ฑ…)
155
  os.environ["TRANSFORMERS_ALLOW_UNSAFE_DESERIALIZATION"] = "1"
@@ -206,8 +204,11 @@ 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
- AVATAR_API_URL = "http://211.233.58.201:7788"
210
 
 
 
 
211
  # Image size presets
212
  IMAGE_PRESETS = {
213
  "์ปค์Šคํ…€": {"width": 1024, "height": 1024},
@@ -988,140 +989,82 @@ def merge_videos_with_audio(video_files, audio_file, audio_mode, audio_volume, o
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,13 +1090,16 @@ css = """
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;
1154
  margin-top: 10px !important;
1155
  width: 100% !important;
1156
  }
 
 
 
1157
  .tabitem {
1158
  min-height: 700px !important;
1159
  }
@@ -1345,8 +1291,7 @@ with demo:
1345
  interactive=False
1346
  )
1347
 
1348
-
1349
- # ๋„ค ๋ฒˆ์งธ ํƒญ: ๋น„๋””์˜ค ํŽธ์ง‘ ๋ถ€๋ถ„์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •
1350
  with gr.Tab("๋น„๋””์˜ค ํŽธ์ง‘", elem_classes="tabitem"):
1351
  with gr.Row(equal_height=True):
1352
  # ์ž…๋ ฅ ์ปฌ๋Ÿผ
@@ -1380,7 +1325,6 @@ with demo:
1380
  - ์ตœ์ƒ์˜ ๊ฒฐ๊ณผ๋ฅผ ์œ„ํ•ด ๊ฐ™์€ ํฌ๊ธฐ์˜ ๋น„๋””์˜ค๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”
1381
  """)
1382
 
1383
-
1384
  with gr.Group(elem_classes="panel-box"):
1385
  gr.Markdown("### ๐ŸŽต ์˜ค๋””์˜ค ์„ค์ • (์„ ํƒ)")
1386
 
@@ -1553,73 +1497,114 @@ with demo:
1553
  **์ฐธ๊ณ **: GPU ์ œํ•œ์œผ๋กœ ํ•œ ๋ฒˆ์— ์•ฝ 200ํ”„๋ ˆ์ž„๊นŒ์ง€ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
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
  # ๋ชจ๋ธ ๋กœ๋“œ ํ•จ์ˆ˜ ์‹คํ–‰
@@ -1671,7 +1656,6 @@ with demo:
1671
  )
1672
 
1673
  # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - ๋„ค ๋ฒˆ์งธ ํƒญ (๋น„๋””์˜ค ํŽธ์ง‘)
1674
-
1675
  def toggle_original_volume(mode):
1676
  return gr.update(visible=(mode == "๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฎค์ง"))
1677
 
@@ -1681,12 +1665,12 @@ with demo:
1681
  outputs=[original_audio_volume]
1682
  )
1683
 
1684
-
1685
  merge_videos_btn.click(
1686
  merge_videos_with_audio,
1687
  inputs=[video_files, audio_file, audio_mode, audio_volume, original_audio_volume, output_fps],
1688
  outputs=[merged_video, merge_status]
1689
- )
 
1690
  # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - ๋‹ค์„ฏ ๋ฒˆ์งธ ํƒญ (๋น„๋””์˜ค ๋ฐฐ๊ฒฝ์ œ๊ฑฐ/ํ•ฉ์„ฑ)
1691
  def update_bg_visibility(bg_type):
1692
  if bg_type == "์ƒ‰์ƒ":
@@ -1710,12 +1694,17 @@ with demo:
1710
  fps_slider, video_handling_radio, fast_mode_checkbox, max_workers_slider],
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
  # ๋ฐ๋ชจ ๋กœ๋“œ ์‹œ ์‹คํ–‰
@@ -1729,4 +1718,4 @@ if __name__ == "__main__":
1729
  except:
1730
  pass
1731
 
1732
- demo.launch()
 
31
  from scipy.io import wavfile
32
  from transformers import pipeline
33
 
 
34
  # ๋น„๋””์˜ค ๋ฐฐ๊ฒฝ์ œ๊ฑฐ ๊ด€๋ จ import
35
  from transformers import AutoModelForImageSegmentation
36
  from torchvision import transforms
37
 
 
38
  # โ”€โ”€ moviepy import โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
39
  try:
40
  from moviepy.editor import (
 
146
 
147
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
148
 
149
+ import httpx
150
+ from datetime import datetime
151
 
152
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •์œผ๋กœ torch.load ์ฒดํฌ ์šฐํšŒ (์ž„์‹œ ํ•ด๊ฒฐ์ฑ…)
153
  os.environ["TRANSFORMERS_ALLOW_UNSAFE_DESERIALIZATION"] = "1"
 
204
  # API URLs
205
  TEXT2IMG_API_URL = "http://211.233.58.201:7896"
206
  VIDEO_API_URL = "http://211.233.58.201:7875"
207
+ ANIM_API_URL = os.getenv("ANIM_API_URL", "http://211.233.58.201:7862/")
208
 
209
+ # HTTP ํƒ€์ž„์•„์›ƒ ์„ค์ • - ๊ด„ํ˜ธ ์ˆ˜์ •
210
+ ANIM_TIMEOUT = httpx.Timeout(connect=30.0, read=120.0, write=120.0, pool=30.0)
211
+
212
  # Image size presets
213
  IMAGE_PRESETS = {
214
  "์ปค์Šคํ…€": {"width": 1024, "height": 1024},
 
989
  traceback.print_exc()
990
  return None, f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
991
 
992
+ def test_anim_api_connection():
993
+ """์• ๋‹ˆ๋ฉ”์ด์…˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ"""
994
+ now = datetime.now().strftime("%H:%M:%S")
995
+ try:
996
+ resp = httpx.get(f"{ANIM_API_URL.rstrip('/')}/healthz", timeout=ANIM_TIMEOUT)
997
+ ready = resp.json().get("ready", False)
998
+ msg = f"[{now}] ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต โœ… (ready={ready})"
999
+ logging.info(msg)
1000
+ return True, msg
1001
+ except Exception as e:
1002
+ msg = f"[{now}] ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ โŒ : {e}"
1003
+ logging.error(msg)
1004
+ return False, msg
1005
+
1006
+ def generate_avatar_animation(image, audio, guidance_scale, steps, progress=gr.Progress()):
1007
  """์ด๋ฏธ์ง€์™€ ์˜ค๋””์˜ค๋กœ ์•„๋ฐ”ํƒ€ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒ์„ฑ"""
1008
+ start = datetime.now().strftime("%H:%M:%S")
1009
+ logs = [f"[{start}] ์š”์ฒญ ์‹œ์ž‘"]
 
 
 
1010
 
1011
  try:
1012
+ if image is None or audio is None:
1013
+ raise ValueError("์ด๋ฏธ์ง€์™€ ์˜ค๋””์˜ค๋ฅผ ๋ชจ๋‘ ์—…๋กœ๋“œํ•˜์„ธ์š”.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1014
 
1015
+ progress(0.05, desc="ํŒŒ์ผ ์ค€๋น„")
1016
+ client = Client(ANIM_API_URL)
 
1017
 
1018
+ progress(0.15, desc="์„œ๋ฒ„ ํ˜ธ์ถœ ์ค‘โ€ฆ (์ˆ˜ ๋ถ„ ์†Œ์š” ๊ฐ€๋Šฅ)")
1019
+ result = client.predict(
1020
+ image_path=handle_file(image),
1021
+ audio_path=handle_file(audio),
1022
+ guidance_scale=guidance_scale,
1023
+ steps=steps,
1024
+ api_name="/generate_animation"
1025
+ )
1026
 
1027
+ progress(0.95, desc="๊ฒฐ๊ณผ ์ •๋ฆฌ")
1028
+
1029
+ # ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ - dict ํ˜•ํƒœ ์ฒ˜๋ฆฌ ์ถ”๊ฐ€
1030
+ def extract_video_path(obj):
1031
+ """๋น„๋””์˜ค ๊ฐ์ฒด์—์„œ ๊ฒฝ๋กœ ์ถ”์ถœ"""
1032
+ if isinstance(obj, str):
1033
+ return obj
1034
+ elif isinstance(obj, dict):
1035
+ # Gradio์˜ FileData dict ์ฒ˜๋ฆฌ
1036
+ if 'video' in obj:
1037
+ return obj['video'] # {'video': '๊ฒฝ๋กœ', 'subtitles': None} ํ˜•ํƒœ ์ฒ˜๋ฆฌ
1038
+ elif 'path' in obj:
1039
+ return obj['path']
1040
+ elif 'url' in obj:
1041
+ return obj['url']
1042
+ elif 'name' in obj:
1043
+ return obj['name']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1044
  else:
1045
+ logging.warning(f"Unexpected dict structure: {obj.keys()}")
1046
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1047
  else:
1048
+ logging.warning(f"Unexpected type: {type(obj)}")
1049
+ return None
1050
+
1051
+ if isinstance(result, (list, tuple)) and len(result) >= 2:
1052
+ anim_path = extract_video_path(result[0])
1053
+ comp_path = extract_video_path(result[1])
1054
 
1055
+ if anim_path and comp_path:
1056
+ logs.append(f"[{datetime.now().strftime('%H:%M:%S')}] ์„ฑ๊ณต")
1057
+ return anim_path, comp_path, "\n".join(logs)
 
 
 
 
 
1058
  else:
1059
+ raise RuntimeError(f"๋น„๋””์˜ค ๊ฒฝ๋กœ ์ถ”์ถœ ์‹คํŒจ: {result}")
 
 
1060
  else:
1061
+ raise RuntimeError(f"์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฐ˜ํ™˜ ํ˜•์‹: {type(result)}")
1062
+
 
 
 
 
 
 
 
1063
  except Exception as e:
1064
+ logs.append(f"[{datetime.now().strftime('%H:%M:%S')}] ์˜ค๋ฅ˜: {e}")
1065
+ logging.error(f"Avatar animation generation error: {e}", exc_info=True)
1066
+ return None, None, "\n".join(logs)
1067
+
 
1068
  # CSS
1069
  css = """
1070
  :root {
 
1090
  padding: 20px !important;
1091
  margin-bottom: 20px !important;
1092
  }
1093
+ #generate-btn, #video-btn, #outpaint-btn, #preview-btn, #audio-btn, #bg-remove-btn, #merge-btn, #avatar-btn, #test-connection-btn {
1094
  background: linear-gradient(135deg, #ff9a9e, #fad0c4) !important;
1095
  font-size: 1.1rem !important;
1096
  padding: 12px 24px !important;
1097
  margin-top: 10px !important;
1098
  width: 100% !important;
1099
  }
1100
+ #avatar-btn, #test-connection-btn {
1101
+ background: linear-gradient(135deg, #667eea, #764ba2) !important;
1102
+ }
1103
  .tabitem {
1104
  min-height: 700px !important;
1105
  }
 
1291
  interactive=False
1292
  )
1293
 
1294
+ # ๋„ค ๋ฒˆ์งธ ํƒญ: ๋น„๋””์˜ค ํŽธ์ง‘
 
1295
  with gr.Tab("๋น„๋””์˜ค ํŽธ์ง‘", elem_classes="tabitem"):
1296
  with gr.Row(equal_height=True):
1297
  # ์ž…๋ ฅ ์ปฌ๋Ÿผ
 
1325
  - ์ตœ์ƒ์˜ ๊ฒฐ๊ณผ๋ฅผ ์œ„ํ•ด ๊ฐ™์€ ํฌ๊ธฐ์˜ ๋น„๋””์˜ค๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”
1326
  """)
1327
 
 
1328
  with gr.Group(elem_classes="panel-box"):
1329
  gr.Markdown("### ๐ŸŽต ์˜ค๋””์˜ค ์„ค์ • (์„ ํƒ)")
1330
 
 
1497
  **์ฐธ๊ณ **: GPU ์ œํ•œ์œผ๋กœ ํ•œ ๋ฒˆ์— ์•ฝ 200ํ”„๋ ˆ์ž„๊นŒ์ง€ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
1498
  ๊ธด ๋น„๋””์˜ค๋Š” ์ž‘์€ ์กฐ๊ฐ์œผ๋กœ ๋‚˜๋ˆ„์–ด ์ฒ˜๋ฆฌํ•˜์„ธ์š”.
1499
  """)
1500
+
1501
+ # ์—ฌ์„ฏ ๋ฒˆ์งธ ํƒญ: ์ด๋ฏธ์ง€to์•„๋ฐ”ํƒ€ (์ค‘๋ณต ์ œ๊ฑฐํ•˜๊ณ  ํ•˜๋‚˜๋งŒ ์œ ์ง€)
1502
  with gr.Tab("์ด๋ฏธ์ง€to์•„๋ฐ”ํƒ€", elem_classes="tabitem"):
1503
  with gr.Row(equal_height=True):
1504
  # ์ž…๋ ฅ ์ปฌ๋Ÿผ
1505
  with gr.Column(scale=1):
1506
  with gr.Group(elem_classes="panel-box"):
1507
+ gr.Markdown("### ๐ŸŽญ ์•„๋ฐ”ํƒ€ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒ์„ฑ")
1508
+ gr.Markdown("""
1509
+ ํฌํŠธ๋ ˆ์ดํŠธ ์ด๋ฏธ์ง€์™€ ์˜ค๋””์˜ค๋ฅผ ์—…๋กœ๋“œํ•˜๋ฉด ๋งํ•˜๋Š” ์•„๋ฐ”ํƒ€ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
1510
 
1511
+ **๊ถŒ์žฅ ์‚ฌํ•ญ**:
1512
+ - ์ด๋ฏธ์ง€: ์ •๋ฉด์„ ๋ณด๊ณ  ์žˆ๋Š” ์–ผ๊ตด ์‚ฌ์ง„
1513
+ - ์˜ค๋””์˜ค: ๋ช…ํ™•ํ•œ ์Œ์„ฑ์ด ๋‹ด๊ธด ์˜ค๋””์˜ค ํŒŒ์ผ
1514
+ """)
1515
+
1516
+ avatar_image = gr.Image(
1517
+ label="ํฌํŠธ๋ ˆ์ดํŠธ ์ด๋ฏธ์ง€",
1518
  type="filepath",
1519
+ elem_classes="panel-box"
1520
  )
1521
 
 
 
 
1522
  avatar_audio = gr.Audio(
1523
+ label="๋“œ๋ผ์ด๋น™ ์˜ค๋””์˜ค",
1524
  type="filepath",
1525
+ elem_classes="panel-box"
1526
  )
1527
+
1528
  with gr.Group(elem_classes="panel-box"):
1529
  gr.Markdown("### โš™๏ธ ์ƒ์„ฑ ์„ค์ •")
1530
 
1531
+ guidance_scale = gr.Slider(
1532
  minimum=1.0,
1533
+ maximum=10.0,
1534
+ value=3.0,
1535
  step=0.1,
1536
  label="๊ฐ€์ด๋˜์Šค ์Šค์ผ€์ผ",
1537
+ info="๋†’์„์ˆ˜๋ก ์˜ค๋””์˜ค์— ๋” ์ถฉ์‹คํ•œ ์›€์ง์ž„ ์ƒ์„ฑ"
1538
  )
1539
 
1540
+ inference_steps = gr.Slider(
1541
  minimum=5,
1542
  maximum=30,
1543
+ value=10,
1544
  step=1,
1545
  label="์ถ”๋ก  ์Šคํ…",
1546
+ info="๋†’์„์ˆ˜๋ก ํ’ˆ์งˆ์ด ์ข‹์•„์ง€์ง€๋งŒ ์ƒ์„ฑ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€"
1547
  )
1548
 
1549
+ # ์„œ๋ฒ„ ์ƒํƒœ ์ฒดํฌ
1550
+ with gr.Row():
1551
+ test_connection_btn = gr.Button(
1552
+ "๐Ÿ”Œ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ",
1553
+ elem_id="test-connection-btn",
1554
+ scale=1
1555
+ )
1556
+
1557
+ anim_status = gr.Textbox(
1558
+ label="์„œ๋ฒ„ ์ƒํƒœ",
1559
+ interactive=False,
1560
+ elem_classes="panel-box"
1561
+ )
1562
+
1563
+ generate_avatar_btn = gr.Button(
1564
+ "๐ŸŽฌ ์•„๋ฐ”ํƒ€ ์ƒ์„ฑ",
1565
+ variant="primary",
1566
+ elem_id="avatar-btn"
1567
+ )
1568
 
1569
  # ์ถœ๋ ฅ ์ปฌ๋Ÿผ
1570
  with gr.Column(scale=1):
1571
  with gr.Group(elem_classes="panel-box"):
1572
+ gr.Markdown("### ๐ŸŽญ ์ƒ์„ฑ ๊ฒฐ๊ณผ")
1573
+
1574
+ avatar_result = gr.Video(
1575
+ label="์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฒฐ๊ณผ",
1576
+ elem_classes="panel-box"
1577
+ )
1578
 
1579
+ avatar_comparison = gr.Video(
1580
+ label="์›๋ณธ ๋Œ€๋น„ ๊ฒฐ๊ณผ (Side-by-Side)",
1581
+ elem_classes="panel-box"
1582
+ )
1583
+
1584
+ with gr.Accordion("์‹คํ–‰ ๋กœ๊ทธ", open=False):
1585
+ avatar_logs = gr.Textbox(
1586
+ label="๋กœ๊ทธ",
1587
+ lines=10,
1588
+ max_lines=20,
1589
+ interactive=False,
1590
+ elem_classes="panel-box"
1591
+ )
1592
 
1593
  gr.Markdown("""
1594
+ ### โ„น๏ธ ์‚ฌ์šฉ ์•ˆ๋‚ด
1595
+
1596
+ 1. **ํฌํŠธ๋ ˆ์ดํŠธ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ**: ์ •๋ฉด์„ ๋ณด๊ณ  ์žˆ๋Š” ์„ ๋ช…ํ•œ ์–ผ๊ตด ์‚ฌ์ง„
1597
+ 2. **์˜ค๋””์˜ค ์—…๋กœ๋“œ**: ์• ๋‹ˆ๋ฉ”์ด์…˜์— ์‚ฌ์šฉํ•  ์Œ์„ฑ ํŒŒ์ผ
1598
+ 3. **์„ค์ • ์กฐ์ •**: ๊ฐ€์ด๋˜์Šค ์Šค์ผ€์ผ๊ณผ ์ถ”๋ก  ์Šคํ… ์กฐ์ •
1599
+ 4. **์ƒ์„ฑ ์‹œ์ž‘**: '์•„๋ฐ”ํƒ€ ์ƒ์„ฑ' ๋ฒ„ํŠผ ํด๋ฆญ
1600
+
1601
+ **์ฒ˜๋ฆฌ ์‹œ๊ฐ„**:
1602
+ - ์ผ๋ฐ˜์ ์œผ๋กœ 2-5๋ถ„ ์†Œ์š”
1603
+ - ๊ธด ์˜ค๋””์˜ค์ผ์ˆ˜๋ก ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ ์ฆ๊ฐ€
1604
 
1605
  **ํŒ**:
1606
+ - ๋ฐฐ๊ฒฝ์ด ๋‹จ์ˆœํ•œ ์ด๋ฏธ์ง€๊ฐ€ ๋” ์ข‹์€ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค
1607
  - ์˜ค๋””์˜ค์˜ ์Œ์„ฑ์ด ๋ช…ํ™•ํ• ์ˆ˜๋ก ๋ฆฝ์‹ฑํฌ๊ฐ€ ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค
 
1608
  """)
1609
 
1610
  # ๋ชจ๋ธ ๋กœ๋“œ ํ•จ์ˆ˜ ์‹คํ–‰
 
1656
  )
1657
 
1658
  # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - ๋„ค ๋ฒˆ์งธ ํƒญ (๋น„๋””์˜ค ํŽธ์ง‘)
 
1659
  def toggle_original_volume(mode):
1660
  return gr.update(visible=(mode == "๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฎค์ง"))
1661
 
 
1665
  outputs=[original_audio_volume]
1666
  )
1667
 
 
1668
  merge_videos_btn.click(
1669
  merge_videos_with_audio,
1670
  inputs=[video_files, audio_file, audio_mode, audio_volume, original_audio_volume, output_fps],
1671
  outputs=[merged_video, merge_status]
1672
+ )
1673
+
1674
  # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - ๋‹ค์„ฏ ๋ฒˆ์งธ ํƒญ (๋น„๋””์˜ค ๋ฐฐ๊ฒฝ์ œ๊ฑฐ/ํ•ฉ์„ฑ)
1675
  def update_bg_visibility(bg_type):
1676
  if bg_type == "์ƒ‰์ƒ":
 
1694
  fps_slider, video_handling_radio, fast_mode_checkbox, max_workers_slider],
1695
  outputs=[stream_image, output_bg_video, time_textbox]
1696
  )
1697
+
1698
  # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - ์—ฌ์„ฏ ๋ฒˆ์งธ ํƒญ (์ด๋ฏธ์ง€to์•„๋ฐ”ํƒ€)
1699
+ test_connection_btn.click(
1700
+ test_anim_api_connection,
1701
+ outputs=[anim_status, anim_status]
1702
+ )
1703
+
1704
+ generate_avatar_btn.click(
1705
  generate_avatar_animation,
1706
+ inputs=[avatar_image, avatar_audio, guidance_scale, inference_steps],
1707
+ outputs=[avatar_result, avatar_comparison, avatar_logs]
1708
  )
1709
 
1710
  # ๋ฐ๋ชจ ๋กœ๋“œ ์‹œ ์‹คํ–‰
 
1718
  except:
1719
  pass
1720
 
1721
+ demo.launch()