Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -2347,7 +2347,6 @@ def enhance_prompt_on_cpu(image_path: str, prompt: str, mode: str):
|
|
| 2347 |
"""
|
| 2348 |
این تابع روی CPU اجرا میشود و هیچ سهمیهای از GPU کم نمیکند.
|
| 2349 |
"""
|
| 2350 |
-
# اگر نیازی به بهینه سازی نیست
|
| 2351 |
if mode not in ['تبدیل تصویر به ویدیو', 'تکمیل فریمهای میانی'] or not image_path:
|
| 2352 |
return prompt
|
| 2353 |
|
|
@@ -2357,7 +2356,6 @@ def enhance_prompt_on_cpu(image_path: str, prompt: str, mode: str):
|
|
| 2357 |
with open(image_path, 'rb') as f:
|
| 2358 |
files = {'image': f}
|
| 2359 |
data = {'prompt': prompt, 'is_extension': 'false'}
|
| 2360 |
-
# تایم اوت را بالا می بریم تا مطمئن شویم پاسخ می گیریم
|
| 2361 |
response = requests.post(url, files=files, data=data, timeout=60)
|
| 2362 |
|
| 2363 |
if response.status_code == 200:
|
|
@@ -2388,23 +2386,19 @@ def ui_lock_and_enhance(first_frame, prompt, mode):
|
|
| 2388 |
"""
|
| 2389 |
مرحله ۱: قفل کردن UI و اجرای بهینه سازی روی CPU
|
| 2390 |
"""
|
| 2391 |
-
# تغییر دکمه به حالت لودینگ
|
| 2392 |
yield (
|
| 2393 |
gr.Button(value="⏳ در حال بهینه سازی پرامپت (CPU)...", interactive=False),
|
| 2394 |
-
gr.update(),
|
| 2395 |
-
gr.update(),
|
| 2396 |
-
None
|
| 2397 |
)
|
| 2398 |
|
| 2399 |
-
# اجرای بهینه سازی (سنگین برای شبکه، سبک برای پردازنده)
|
| 2400 |
-
# چون دکوراتور @spaces.GPU ندارد، سهمیه شما مصرف نمی شود.
|
| 2401 |
enhanced = enhance_prompt_on_cpu(first_frame, prompt, mode)
|
| 2402 |
|
| 2403 |
-
# آماده سازی برای مرحله بعد
|
| 2404 |
yield (
|
| 2405 |
gr.Button(value="🚀 در حال ساخت ویدیو (GPU)...", interactive=False),
|
| 2406 |
-
gr.update(value=enhanced),
|
| 2407 |
-
enhanced,
|
| 2408 |
None
|
| 2409 |
)
|
| 2410 |
|
|
@@ -2416,7 +2410,6 @@ def ui_generate_video(
|
|
| 2416 |
):
|
| 2417 |
"""
|
| 2418 |
مرحله ۲: ساخت ویدیو با استفاده از GPU
|
| 2419 |
-
در اینجا تمام زمان تخصیص داده شده صرف ساخت ویدیو می شود.
|
| 2420 |
"""
|
| 2421 |
video_path = generate_video(
|
| 2422 |
first_frame, end_frame, enhanced_prompt, duration, input_video,
|
|
@@ -2430,6 +2423,52 @@ def ui_generate_video(
|
|
| 2430 |
)
|
| 2431 |
|
| 2432 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2433 |
with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
| 2434 |
gr.HTML(
|
| 2435 |
"""
|
|
@@ -2453,13 +2492,14 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
|
| 2453 |
first_frame = gr.Image(label="تصویر اول (برای بهینهسازی پرامپت الزامی است)", type="filepath", height=256)
|
| 2454 |
end_frame = gr.Image(label="تصویر آخر (اختیاری)", type="filepath", height=256, visible=False)
|
| 2455 |
input_video = gr.Video(label="Motion Reference Video", height=256, visible=False)
|
| 2456 |
-
|
|
|
|
|
|
|
| 2457 |
prompt_ui = PromptBox(value="این تصویر را با حرکت سینمایی و انیمیشن روان زنده کن", elem_id="prompt_ui")
|
| 2458 |
audio_input = gr.File(label="Audio (Optional)", file_types=["audio"], type="filepath", elem_id="audio_input_hidden")
|
| 2459 |
audio_ui = AudioDropUpload(target_audio_elem_id="audio_input_hidden", elem_id="audio_ui")
|
| 2460 |
prompt = gr.Textbox(label="Prompt", value="این تصویر را با حرکت سینمایی و انیمیشن روان زنده کن", lines=3, max_lines=3, visible=False)
|
| 2461 |
|
| 2462 |
-
# مقدار اولیه به False تغییر کرد تا تابع داخلی مدل دوباره تلاش نکند پرامپت را تغییر دهد
|
| 2463 |
enhance_prompt_flag_input = gr.Checkbox(label="Enhance Prompt", value=False, visible=False)
|
| 2464 |
|
| 2465 |
with gr.Accordion("تنظیمات پیشرفته", open=False, visible=False):
|
|
@@ -2480,7 +2520,9 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
|
| 2480 |
camera_ui = CameraDropdown(choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES], value="No LoRA", title="افکت دوربین (LoRA)", elem_id="camera_ui")
|
| 2481 |
camera_lora = gr.Dropdown(label="Camera Control LoRA", choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES], value="No LoRA", visible=False)
|
| 2482 |
|
| 2483 |
-
generate_btn = gr.Button("🤩 ساخت ویدیو", variant="primary", elem_classes="button-gradient")
|
|
|
|
|
|
|
| 2484 |
|
| 2485 |
# اتصال رویدادها
|
| 2486 |
camera_ui.change(fn=lambda x: x, inputs=camera_ui, outputs=camera_lora, api_visibility="private")
|
|
@@ -2491,9 +2533,16 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
|
| 2491 |
audio_ui.change(fn=lambda v: None if v == "__CLEAR__" or not v else gr.update(), inputs=audio_ui, outputs=audio_input, api_visibility="private")
|
| 2492 |
download_btn.click(fn=None, inputs=[output_video], js=js_download_video)
|
| 2493 |
|
| 2494 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2495 |
|
| 2496 |
-
|
|
|
|
| 2497 |
fn=ui_lock_and_enhance,
|
| 2498 |
inputs=[first_frame, prompt, radioanimated_mode],
|
| 2499 |
outputs=[generate_btn, prompt_ui, prompt, output_video]
|
|
@@ -2507,15 +2556,6 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
|
| 2507 |
outputs=[generate_btn, output_video, download_btn]
|
| 2508 |
)
|
| 2509 |
|
| 2510 |
-
# --- هندل کردن خطای محدودیت GPU ---
|
| 2511 |
-
# در صورتی که ساخت ویدیو (مثلا به خاطر اتمام سهمیه GPU) با خطا مواجه شود،
|
| 2512 |
-
# این بخش وارد عمل شده و فوراً دکمه را به حالت اولیه برمیگرداند.
|
| 2513 |
-
gen_event.catch(
|
| 2514 |
-
fn=lambda: gr.Button(value="🤩 ساخت ویدیو", interactive=True),
|
| 2515 |
-
inputs=[],
|
| 2516 |
-
outputs=[generate_btn]
|
| 2517 |
-
)
|
| 2518 |
-
|
| 2519 |
# منطق نمونه ها
|
| 2520 |
examples_list = [
|
| 2521 |
["examples/supergirl-2.png", "A fuzzy puppet superhero...", "Static", "16:9", "تبدیل تصویر به ویدیو", None, "examples/supergirl.m4a", None],
|
|
|
|
| 2347 |
"""
|
| 2348 |
این تابع روی CPU اجرا میشود و هیچ سهمیهای از GPU کم نمیکند.
|
| 2349 |
"""
|
|
|
|
| 2350 |
if mode not in ['تبدیل تصویر به ویدیو', 'تکمیل فریمهای میانی'] or not image_path:
|
| 2351 |
return prompt
|
| 2352 |
|
|
|
|
| 2356 |
with open(image_path, 'rb') as f:
|
| 2357 |
files = {'image': f}
|
| 2358 |
data = {'prompt': prompt, 'is_extension': 'false'}
|
|
|
|
| 2359 |
response = requests.post(url, files=files, data=data, timeout=60)
|
| 2360 |
|
| 2361 |
if response.status_code == 200:
|
|
|
|
| 2386 |
"""
|
| 2387 |
مرحله ۱: قفل کردن UI و اجرای بهینه سازی روی CPU
|
| 2388 |
"""
|
|
|
|
| 2389 |
yield (
|
| 2390 |
gr.Button(value="⏳ در حال بهینه سازی پرامپت (CPU)...", interactive=False),
|
| 2391 |
+
gr.update(),
|
| 2392 |
+
gr.update(),
|
| 2393 |
+
None
|
| 2394 |
)
|
| 2395 |
|
|
|
|
|
|
|
| 2396 |
enhanced = enhance_prompt_on_cpu(first_frame, prompt, mode)
|
| 2397 |
|
|
|
|
| 2398 |
yield (
|
| 2399 |
gr.Button(value="🚀 در حال ساخت ویدیو (GPU)...", interactive=False),
|
| 2400 |
+
gr.update(value=enhanced),
|
| 2401 |
+
enhanced,
|
| 2402 |
None
|
| 2403 |
)
|
| 2404 |
|
|
|
|
| 2410 |
):
|
| 2411 |
"""
|
| 2412 |
مرحله ۲: ساخت ویدیو با استفاده از GPU
|
|
|
|
| 2413 |
"""
|
| 2414 |
video_path = generate_video(
|
| 2415 |
first_frame, end_frame, enhanced_prompt, duration, input_video,
|
|
|
|
| 2423 |
)
|
| 2424 |
|
| 2425 |
|
| 2426 |
+
# کدهای جاوااسکریپت برای انتقال المانها و نظارت بر ارور محدودیت GPU
|
| 2427 |
+
relocate_js = r"""
|
| 2428 |
+
(() => {
|
| 2429 |
+
function moveIntoFooter() {
|
| 2430 |
+
const p = document.querySelector("#prompt_ui"), f = p ? p.querySelector(".ds-footer") : null;
|
| 2431 |
+
if (!f) return false;
|
| 2432 |
+
const d = document.querySelector("#duration_ui .cd-wrap"), r = document.querySelector("#resolution_ui .cd-wrap"), c = document.querySelector("#camera_ui .cd-wrap");
|
| 2433 |
+
if (!d || !r || !c) return false;
|
| 2434 |
+
f.appendChild(d); f.appendChild(r); f.appendChild(c);
|
| 2435 |
+
return true;
|
| 2436 |
+
}
|
| 2437 |
+
|
| 2438 |
+
function setupErrorObserver() {
|
| 2439 |
+
const getRoot = () => {
|
| 2440 |
+
const app = document.querySelector('gradio-app');
|
| 2441 |
+
return app && app.shadowRoot ? app.shadowRoot : document;
|
| 2442 |
+
};
|
| 2443 |
+
const observer = new MutationObserver((mutations) => {
|
| 2444 |
+
mutations.forEach(m => {
|
| 2445 |
+
m.addedNodes.forEach(node => {
|
| 2446 |
+
if (node.nodeType === 1) {
|
| 2447 |
+
// بررسی ظهور پاپآپهای خطا یا محدودیت
|
| 2448 |
+
const isToast = node.classList && (node.classList.contains('toast-wrap') || node.classList.contains('error') || node.tagName === 'TOAST');
|
| 2449 |
+
const nodeText = (node.innerText || "").toLowerCase();
|
| 2450 |
+
if (isToast || nodeText.includes('quota')) {
|
| 2451 |
+
if (nodeText.includes("quota") || nodeText.includes("exceeded") || nodeText.includes("error") || nodeText.includes("خطا")) {
|
| 2452 |
+
// در صورت مشاهده خطا دکمه ریست نامرئی کلیک میشود
|
| 2453 |
+
const rb = getRoot().querySelector("#reset_btn");
|
| 2454 |
+
if (rb) rb.click();
|
| 2455 |
+
}
|
| 2456 |
+
}
|
| 2457 |
+
}
|
| 2458 |
+
});
|
| 2459 |
+
});
|
| 2460 |
+
});
|
| 2461 |
+
observer.observe(document.body, {childList: true, subtree: true});
|
| 2462 |
+
}
|
| 2463 |
+
|
| 2464 |
+
const tick = () => {
|
| 2465 |
+
if (!moveIntoFooter()) requestAnimationFrame(tick);
|
| 2466 |
+
else setupErrorObserver();
|
| 2467 |
+
};
|
| 2468 |
+
requestAnimationFrame(tick);
|
| 2469 |
+
})();
|
| 2470 |
+
"""
|
| 2471 |
+
|
| 2472 |
with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
| 2473 |
gr.HTML(
|
| 2474 |
"""
|
|
|
|
| 2492 |
first_frame = gr.Image(label="تصویر اول (برای بهینهسازی پرامپت الزامی است)", type="filepath", height=256)
|
| 2493 |
end_frame = gr.Image(label="تصویر آخر (اختیاری)", type="filepath", height=256, visible=False)
|
| 2494 |
input_video = gr.Video(label="Motion Reference Video", height=256, visible=False)
|
| 2495 |
+
|
| 2496 |
+
relocate = gr.HTML(value="", html_template="<div></div>", js_on_load=relocate_js)
|
| 2497 |
+
|
| 2498 |
prompt_ui = PromptBox(value="این تصویر را با حرکت سینمایی و انیمیشن روان زنده کن", elem_id="prompt_ui")
|
| 2499 |
audio_input = gr.File(label="Audio (Optional)", file_types=["audio"], type="filepath", elem_id="audio_input_hidden")
|
| 2500 |
audio_ui = AudioDropUpload(target_audio_elem_id="audio_input_hidden", elem_id="audio_ui")
|
| 2501 |
prompt = gr.Textbox(label="Prompt", value="این تصویر را با حرکت سینمایی و انیمیشن روان زنده کن", lines=3, max_lines=3, visible=False)
|
| 2502 |
|
|
|
|
| 2503 |
enhance_prompt_flag_input = gr.Checkbox(label="Enhance Prompt", value=False, visible=False)
|
| 2504 |
|
| 2505 |
with gr.Accordion("تنظیمات پیشرفته", open=False, visible=False):
|
|
|
|
| 2520 |
camera_ui = CameraDropdown(choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES], value="No LoRA", title="افکت دوربین (LoRA)", elem_id="camera_ui")
|
| 2521 |
camera_lora = gr.Dropdown(label="Camera Control LoRA", choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES], value="No LoRA", visible=False)
|
| 2522 |
|
| 2523 |
+
generate_btn = gr.Button("🤩 ساخت ویدیو", variant="primary", elem_classes="button-gradient", elem_id="generate_btn")
|
| 2524 |
+
# دکمه پنهان که در صورت وقوع ارور توسط جاوااسکریپت کلیک میشود تا رابط کاربری بازیابی شود
|
| 2525 |
+
reset_btn = gr.Button("Reset", visible=False, elem_id="reset_btn")
|
| 2526 |
|
| 2527 |
# اتصال رویدادها
|
| 2528 |
camera_ui.change(fn=lambda x: x, inputs=camera_ui, outputs=camera_lora, api_visibility="private")
|
|
|
|
| 2533 |
audio_ui.change(fn=lambda v: None if v == "__CLEAR__" or not v else gr.update(), inputs=audio_ui, outputs=audio_input, api_visibility="private")
|
| 2534 |
download_btn.click(fn=None, inputs=[output_video], js=js_download_video)
|
| 2535 |
|
| 2536 |
+
# رویداد بازیابی دکمه در زمان وقوع محدودیت (وصل شده به دکمه مخفی)
|
| 2537 |
+
reset_btn.click(
|
| 2538 |
+
fn=lambda: gr.Button(value="🤩 ساخت ویدیو", interactive=True),
|
| 2539 |
+
inputs=[],
|
| 2540 |
+
outputs=[generate_btn],
|
| 2541 |
+
api_visibility="private"
|
| 2542 |
+
)
|
| 2543 |
|
| 2544 |
+
# زنجیره اصلی ساخت ویدیو
|
| 2545 |
+
generate_btn.click(
|
| 2546 |
fn=ui_lock_and_enhance,
|
| 2547 |
inputs=[first_frame, prompt, radioanimated_mode],
|
| 2548 |
outputs=[generate_btn, prompt_ui, prompt, output_video]
|
|
|
|
| 2556 |
outputs=[generate_btn, output_video, download_btn]
|
| 2557 |
)
|
| 2558 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2559 |
# منطق نمونه ها
|
| 2560 |
examples_list = [
|
| 2561 |
["examples/supergirl-2.png", "A fuzzy puppet superhero...", "Static", "16:9", "تبدیل تصویر به ویدیو", None, "examples/supergirl.m4a", None],
|