Update app-backup.py
Browse files- 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 |
|