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