Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -2319,7 +2319,7 @@ def apply_example(idx: str):
|
|
| 2319 |
|
| 2320 |
|
| 2321 |
####################################################################################################
|
| 2322 |
-
### PART 20: Gradio UI Layout & Launch
|
| 2323 |
####################################################################################################
|
| 2324 |
|
| 2325 |
# JS Function to handle download request via PostMessage
|
|
@@ -2329,30 +2329,11 @@ async (video) => {
|
|
| 2329 |
alert("لطفاً ابتدا ویدیو را تولید کنید.");
|
| 2330 |
return;
|
| 2331 |
}
|
| 2332 |
-
|
| 2333 |
-
// Gradio Video component passes an object or string
|
| 2334 |
-
let fileUrl = "";
|
| 2335 |
-
if (typeof video === 'string') {
|
| 2336 |
-
fileUrl = video;
|
| 2337 |
-
} else if (video && video.url) {
|
| 2338 |
-
fileUrl = video.url;
|
| 2339 |
-
} else if (video && video.path) {
|
| 2340 |
-
fileUrl = video.path;
|
| 2341 |
-
}
|
| 2342 |
-
|
| 2343 |
-
// Fix relative paths to absolute URLs for the parent iframe
|
| 2344 |
if (fileUrl && !fileUrl.startsWith('http')) {
|
| 2345 |
-
// Remove leading slash if exists to prevent double slash with origin
|
| 2346 |
let cleanPath = fileUrl.startsWith('/') ? fileUrl.substring(1) : fileUrl;
|
| 2347 |
-
|
| 2348 |
-
// Check if it's already a file route
|
| 2349 |
-
if (cleanPath.startsWith('file=')) {
|
| 2350 |
-
fileUrl = window.location.origin + "/" + cleanPath;
|
| 2351 |
-
} else {
|
| 2352 |
-
fileUrl = window.location.origin + "/file=" + cleanPath;
|
| 2353 |
-
}
|
| 2354 |
}
|
| 2355 |
-
|
| 2356 |
if (fileUrl) {
|
| 2357 |
console.log("Sending download request for:", fileUrl);
|
| 2358 |
window.parent.postMessage({ type: 'DOWNLOAD_REQUEST', url: fileUrl }, '*');
|
|
@@ -2360,125 +2341,75 @@ async (video) => {
|
|
| 2360 |
}
|
| 2361 |
"""
|
| 2362 |
|
| 2363 |
-
# این تابع جاوااسکریپت
|
| 2364 |
-
#
|
| 2365 |
-
|
| 2366 |
async (firstFrame, promptText, mode) => {
|
| 2367 |
-
// گر
|
| 2368 |
-
const enhancerBtn = document.querySelector("#enhancer_btn button");
|
| 2369 |
-
const realGenerateBtn = document.querySelector("#real_generate_btn button");
|
| 2370 |
-
const promptTextarea = document.querySelector("#prompt_ui textarea");
|
| 2371 |
-
|
| 2372 |
-
// اگر حالت انتخابی نیازی به بهینه سازی ندارد، مستقیما ویدیو را بساز
|
| 2373 |
if (mode !== 'تبدیل تصویر به ویدیو' && mode !== 'تکمیل فریمهای میانی') {
|
| 2374 |
-
|
| 2375 |
-
return [firstFrame, promptText, mode]; // بازگشت مقادیر بدون تغییر
|
| 2376 |
}
|
| 2377 |
|
| 2378 |
// API بهینه ساز به تصویر نیاز دارد
|
| 2379 |
if (!firstFrame) {
|
| 2380 |
-
|
| 2381 |
-
|
|
|
|
| 2382 |
}
|
| 2383 |
|
| 2384 |
-
const originalButtonText = enhancerBtn.textContent;
|
| 2385 |
-
enhancerBtn.disabled = true;
|
| 2386 |
-
enhancerBtn.textContent = "⏳ در حال بهینه سازی پرامپت...";
|
| 2387 |
-
|
| 2388 |
try {
|
| 2389 |
-
// داده های تصویر را از URL آن دریافت می کنیم
|
| 2390 |
const response = await fetch(firstFrame.url);
|
| 2391 |
const imageBlob = await response.blob();
|
| 2392 |
|
| 2393 |
-
// آماده سازی FormData برای ارسال به API
|
| 2394 |
const formData = new FormData();
|
| 2395 |
-
// نام فایل را برای سازگاری با API تنظیم می کنیم
|
| 2396 |
const imageFile = new File([imageBlob], "image.jpg", { type: "image/jpeg" });
|
| 2397 |
formData.append('image', imageFile);
|
| 2398 |
formData.append('prompt', promptText);
|
| 2399 |
formData.append('is_extension', 'false');
|
| 2400 |
|
| 2401 |
-
// ارسال درخواست به API بهینه ساز
|
| 2402 |
const apiResponse = await fetch('https://ezmarynoori-vidtolani.hf.space/api/enhance-animation-prompt', {
|
| 2403 |
method: 'POST',
|
| 2404 |
body: formData
|
| 2405 |
});
|
| 2406 |
|
| 2407 |
-
const data = await apiResponse.json();
|
| 2408 |
-
|
| 2409 |
if (!apiResponse.ok) {
|
| 2410 |
-
|
|
|
|
| 2411 |
}
|
| 2412 |
|
| 2413 |
-
const
|
| 2414 |
-
console.log("
|
| 2415 |
-
|
| 2416 |
-
|
| 2417 |
-
// پرامپت جدید را در جعبه متن قرار می دهیم
|
| 2418 |
-
promptTextarea.value = enhancedPrompt;
|
| 2419 |
-
// یک رویداد input ایجاد می کنیم تا Gradio متوجه تغییر شود
|
| 2420 |
-
promptTextarea.dispatchEvent(new Event('input', { bubbles: true }));
|
| 2421 |
-
|
| 2422 |
-
// حالا دکمه پنهان ساخت ویدیو را کلیک می کنیم
|
| 2423 |
-
realGenerateBtn.click();
|
| 2424 |
|
| 2425 |
} catch (error) {
|
| 2426 |
-
console.error("Enhancement Error:", error);
|
| 2427 |
-
|
| 2428 |
-
|
| 2429 |
-
// دکمه را به حالت اولیه برمی گردانیم
|
| 2430 |
-
enhancerBtn.disabled = false;
|
| 2431 |
-
enhancerBtn.textContent = originalButtonText;
|
| 2432 |
}
|
| 2433 |
-
|
| 2434 |
-
// مقادیر ورودی را برمیگردانیم تا زنجیره گرادیو قطع نشود
|
| 2435 |
-
// گرچه پرامپت اصلی دیگر استفاده نمی شود چون ما آن را مستقیما در DOM تغییر دادیم
|
| 2436 |
-
return [firstFrame, promptText, mode];
|
| 2437 |
}
|
| 2438 |
"""
|
| 2439 |
|
| 2440 |
|
| 2441 |
def apply_example(idx: str):
|
| 2442 |
idx = int(idx)
|
| 2443 |
-
|
| 2444 |
-
# Read the example row from your list
|
| 2445 |
img, prompt_txt, cam, res, mode, vid, aud, end_img = examples_list[idx]
|
| 2446 |
-
|
| 2447 |
-
img_path = img if img else None
|
| 2448 |
-
vid_path = vid if vid else None
|
| 2449 |
-
aud_path = aud if aud else None
|
| 2450 |
-
|
| 2451 |
-
input_image_update = img_path
|
| 2452 |
-
prompt_update = prompt_txt
|
| 2453 |
-
camera_update = cam
|
| 2454 |
-
resolution_update = res
|
| 2455 |
-
mode_update = mode
|
| 2456 |
-
video_update = gr.update(value=vid_path, visible=(mode == "Motion Control"))
|
| 2457 |
-
audio_update = aud_path
|
| 2458 |
-
end_image = end_img
|
| 2459 |
-
|
| 2460 |
-
# Clear the output video AND Hide download button when loading a new example
|
| 2461 |
-
output_video_update = gr.update(value=None)
|
| 2462 |
-
download_btn_update = gr.update(visible=False)
|
| 2463 |
-
|
| 2464 |
return (
|
| 2465 |
-
|
| 2466 |
-
|
| 2467 |
-
|
| 2468 |
-
|
| 2469 |
-
|
| 2470 |
-
|
| 2471 |
-
|
| 2472 |
-
|
| 2473 |
-
|
| 2474 |
-
|
| 2475 |
-
|
| 2476 |
)
|
| 2477 |
|
| 2478 |
-
|
| 2479 |
with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
| 2480 |
|
| 2481 |
-
# Updated Header to Persian
|
| 2482 |
gr.HTML(
|
| 2483 |
"""
|
| 2484 |
<div style="text-align: center; padding: 20px;">
|
|
@@ -2492,9 +2423,12 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
|
| 2492 |
"""
|
| 2493 |
)
|
| 2494 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2495 |
with gr.Column(elem_id="col-container"):
|
| 2496 |
with gr.Row(elem_id="mode-row"):
|
| 2497 |
-
# Updated choices to Persian
|
| 2498 |
radioanimated_mode = RadioAnimated(
|
| 2499 |
choices=["تبدیل تصویر به ویدیو", "تکمیل فریمهای میانی"],
|
| 2500 |
value="تبدیل تصویر به ویدیو",
|
|
@@ -2502,335 +2436,134 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
|
| 2502 |
)
|
| 2503 |
with gr.Row():
|
| 2504 |
with gr.Column(elem_id="step-column"):
|
| 2505 |
-
|
| 2506 |
with gr.Row():
|
| 2507 |
-
|
| 2508 |
first_frame = gr.Image(
|
| 2509 |
label="تصویر اول (برای بهینهسازی پرامپت الزامی است)",
|
| 2510 |
type="filepath",
|
| 2511 |
height=256
|
| 2512 |
)
|
| 2513 |
-
|
| 2514 |
end_frame = gr.Image(
|
| 2515 |
label="تصویر آخر (اختیاری)",
|
| 2516 |
type="filepath",
|
| 2517 |
height=256,
|
| 2518 |
visible=False,
|
| 2519 |
)
|
|
|
|
| 2520 |
|
| 2521 |
-
|
| 2522 |
-
input_video = gr.Video(
|
| 2523 |
-
label="Motion Reference Video",
|
| 2524 |
-
height=256,
|
| 2525 |
-
visible=False,
|
| 2526 |
-
)
|
| 2527 |
-
|
| 2528 |
-
relocate = gr.HTML(
|
| 2529 |
-
value="",
|
| 2530 |
-
html_template="<div></div>",
|
| 2531 |
-
js_on_load=r"""
|
| 2532 |
(() => {
|
| 2533 |
function moveIntoFooter() {
|
| 2534 |
-
const promptRoot = document.querySelector("#prompt_ui");
|
| 2535 |
-
if (!
|
| 2536 |
-
|
| 2537 |
-
const footer = promptRoot.querySelector(".ds-footer");
|
| 2538 |
-
if (!footer) return false;
|
| 2539 |
-
|
| 2540 |
const dur = document.querySelector("#duration_ui .cd-wrap");
|
| 2541 |
const res = document.querySelector("#resolution_ui .cd-wrap");
|
| 2542 |
const cam = document.querySelector("#camera_ui .cd-wrap");
|
| 2543 |
-
|
| 2544 |
if (!dur || !res || !cam) return false;
|
| 2545 |
-
|
| 2546 |
-
footer.appendChild(dur);
|
| 2547 |
-
footer.appendChild(res);
|
| 2548 |
-
footer.appendChild(cam);
|
| 2549 |
-
|
| 2550 |
return true;
|
| 2551 |
}
|
| 2552 |
-
|
| 2553 |
-
const tick = () => {
|
| 2554 |
-
if (!moveIntoFooter()) requestAnimationFrame(tick);
|
| 2555 |
-
};
|
| 2556 |
requestAnimationFrame(tick);
|
| 2557 |
})();
|
| 2558 |
-
"""
|
| 2559 |
-
)
|
| 2560 |
|
| 2561 |
-
|
| 2562 |
-
|
| 2563 |
-
|
| 2564 |
-
|
| 2565 |
-
)
|
| 2566 |
-
|
| 2567 |
-
# Hidden real audio input (backend value)
|
| 2568 |
-
audio_input = gr.File(
|
| 2569 |
-
label="Audio (Optional)",
|
| 2570 |
-
file_types=["audio"],
|
| 2571 |
-
type="filepath",
|
| 2572 |
-
elem_id="audio_input_hidden",
|
| 2573 |
-
)
|
| 2574 |
-
|
| 2575 |
-
# Custom UI that feeds the hidden gr.Audio above
|
| 2576 |
-
audio_ui = AudioDropUpload(
|
| 2577 |
-
target_audio_elem_id="audio_input_hidden",
|
| 2578 |
-
elem_id="audio_ui",
|
| 2579 |
-
)
|
| 2580 |
-
|
| 2581 |
-
prompt = gr.Textbox(
|
| 2582 |
-
label="Prompt",
|
| 2583 |
-
value="این تصویر را با حرکت سینمایی و انیمیشن روان زنده کن",
|
| 2584 |
-
lines=3,
|
| 2585 |
-
max_lines=3,
|
| 2586 |
-
placeholder="حرکت و انیمیشن مورد نظر خود را توصیف کنید...",
|
| 2587 |
-
visible=False
|
| 2588 |
-
)
|
| 2589 |
-
|
| 2590 |
-
enhance_prompt = gr.Checkbox(
|
| 2591 |
-
label="Enhance Prompt",
|
| 2592 |
-
value=True,
|
| 2593 |
-
visible=False
|
| 2594 |
-
)
|
| 2595 |
|
| 2596 |
with gr.Accordion("تنظیمات پیشرفته", open=False, visible=False):
|
| 2597 |
-
seed = gr.Slider(
|
| 2598 |
-
label="سید (Seed)",
|
| 2599 |
-
minimum=0,
|
| 2600 |
-
maximum=MAX_SEED,
|
| 2601 |
-
value=DEFAULT_SEED,
|
| 2602 |
-
step=1
|
| 2603 |
-
)
|
| 2604 |
-
|
| 2605 |
randomize_seed = gr.Checkbox(label="استفاده از سید تصادفی", value=True)
|
| 2606 |
-
|
| 2607 |
|
| 2608 |
with gr.Column(elem_id="step-column"):
|
| 2609 |
output_video = gr.Video(label="ویدیوی ساخته شده", autoplay=True, height=512)
|
| 2610 |
-
|
| 2611 |
with gr.Row():
|
| 2612 |
-
download_btn = gr.Button(
|
| 2613 |
-
"📥 دانلود ویدیو",
|
| 2614 |
-
variant="secondary",
|
| 2615 |
-
size="sm",
|
| 2616 |
-
scale=0,
|
| 2617 |
-
visible=False
|
| 2618 |
-
)
|
| 2619 |
|
| 2620 |
with gr.Row(elem_id="controls-row"):
|
| 2621 |
-
|
| 2622 |
-
|
| 2623 |
-
choices=["3s", "5s", "10s"],
|
| 2624 |
-
value="5s",
|
| 2625 |
-
title="مدت زمان ویدیو",
|
| 2626 |
-
elem_id="duration_ui"
|
| 2627 |
-
)
|
| 2628 |
-
|
| 2629 |
-
duration = gr.Slider(
|
| 2630 |
-
label="Duration (seconds)",
|
| 2631 |
-
minimum=1.0,
|
| 2632 |
-
maximum=10.0,
|
| 2633 |
-
value=5.0,
|
| 2634 |
-
step=0.1,
|
| 2635 |
-
visible=False
|
| 2636 |
-
)
|
| 2637 |
-
|
| 2638 |
-
ICON_16_9 = """<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
| 2639 |
-
<rect x="3" y="7" width="18" height="10" rx="2" stroke="currentColor" stroke-width="2"/>
|
| 2640 |
-
</svg>"""
|
| 2641 |
-
|
| 2642 |
-
ICON_1_1 = """<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
| 2643 |
-
<rect x="6" y="6" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"/>
|
| 2644 |
-
</svg>"""
|
| 2645 |
-
|
| 2646 |
-
ICON_9_16 = """<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
| 2647 |
-
<rect x="7" y="3" width="10" height="18" rx="2" stroke="currentColor" stroke-width="2"/>
|
| 2648 |
-
</svg>"""
|
| 2649 |
|
|
|
|
|
|
|
|
|
|
| 2650 |
|
| 2651 |
resolution_ui = CameraDropdown(
|
| 2652 |
-
choices=[
|
| 2653 |
-
|
| 2654 |
-
{"label": "1:1", "value": "1:1", "icon": ICON_1_1},
|
| 2655 |
-
{"label": "9:16", "value": "9:16", "icon": ICON_9_16},
|
| 2656 |
-
],
|
| 2657 |
-
value="16:9",
|
| 2658 |
-
title="ابعاد تصویر",
|
| 2659 |
-
elem_id="resolution_ui"
|
| 2660 |
)
|
| 2661 |
-
|
| 2662 |
-
|
| 2663 |
width = gr.Number(label="Width", value=DEFAULT_1_STAGE_WIDTH, precision=0, visible=False)
|
| 2664 |
height = gr.Number(label="Height", value=DEFAULT_1_STAGE_HEIGHT, precision=0, visible=False)
|
| 2665 |
-
|
| 2666 |
-
|
| 2667 |
-
choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES],
|
| 2668 |
-
value="No LoRA",
|
| 2669 |
-
title="افکت دوربین (LoRA)",
|
| 2670 |
-
elem_id="camera_ui",
|
| 2671 |
-
)
|
| 2672 |
-
|
| 2673 |
-
# Hidden real dropdown (backend value)
|
| 2674 |
-
camera_lora = gr.Dropdown(
|
| 2675 |
-
label="Camera Control LoRA",
|
| 2676 |
-
choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES],
|
| 2677 |
-
value="No LoRA",
|
| 2678 |
-
visible=False
|
| 2679 |
-
)
|
| 2680 |
-
|
| 2681 |
-
# دکمه اصلی که کاربر می بیند و فرآیند بهینه سازی را شروع می کند
|
| 2682 |
-
enhancer_btn = gr.Button("🤩 ساخت ویدیو", variant="primary", elem_classes="button-gradient", elem_id="enhancer_btn")
|
| 2683 |
|
| 2684 |
-
|
| 2685 |
-
real_generate_btn = gr.Button("Hidden Generate", visible=False, elem_id="real_generate_btn")
|
| 2686 |
|
|
|
|
|
|
|
|
|
|
| 2687 |
|
| 2688 |
-
|
| 2689 |
-
|
| 2690 |
-
inputs=camera_ui,
|
| 2691 |
-
outputs=camera_lora,
|
| 2692 |
-
api_visibility="private"
|
| 2693 |
-
)
|
| 2694 |
-
|
| 2695 |
-
radioanimated_mode.change(
|
| 2696 |
-
fn=on_mode_change,
|
| 2697 |
-
inputs=radioanimated_mode,
|
| 2698 |
-
outputs=[input_video, end_frame],
|
| 2699 |
-
api_visibility="private",
|
| 2700 |
-
)
|
| 2701 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2702 |
|
| 2703 |
-
|
| 2704 |
-
fn=apply_duration,
|
| 2705 |
-
inputs=duration_ui,
|
| 2706 |
-
outputs=[duration],
|
| 2707 |
-
api_visibility="private"
|
| 2708 |
-
)
|
| 2709 |
-
resolution_ui.change(
|
| 2710 |
-
fn=apply_resolution,
|
| 2711 |
-
inputs=resolution_ui,
|
| 2712 |
-
outputs=[width, height],
|
| 2713 |
-
api_visibility="private"
|
| 2714 |
-
)
|
| 2715 |
-
prompt_ui.change(
|
| 2716 |
-
fn=lambda x: x,
|
| 2717 |
-
inputs=prompt_ui,
|
| 2718 |
-
outputs=prompt,
|
| 2719 |
-
api_visibility="private"
|
| 2720 |
-
)
|
| 2721 |
-
|
| 2722 |
-
# مرحله 1: دکمه قابل مشاهده، جاوا اسکریپت بهینه ساز را اجرا می کند
|
| 2723 |
-
enhancer_btn.click(
|
| 2724 |
-
fn=None, # هیچ تابع پایتونی اجرا نمی شود
|
| 2725 |
-
inputs=[first_frame, prompt, radioanimated_mode],
|
| 2726 |
-
js=js_enhancer_and_trigger # فقط جاوااسکریپت اجرا می شود
|
| 2727 |
-
)
|
| 2728 |
|
| 2729 |
-
#
|
| 2730 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2731 |
fn=generate_video,
|
| 2732 |
inputs=[
|
| 2733 |
-
first_frame,
|
| 2734 |
-
|
| 2735 |
-
|
| 2736 |
-
duration,
|
| 2737 |
-
input_video,
|
| 2738 |
-
radioanimated_mode,
|
| 2739 |
-
enhance_prompt, # این گزینه دیگر استفاده نمی شود چون بهینه سازی سمت مرورگر است
|
| 2740 |
-
seed,
|
| 2741 |
-
randomize_seed,
|
| 2742 |
-
height,
|
| 2743 |
-
width,
|
| 2744 |
-
camera_lora,
|
| 2745 |
-
audio_input
|
| 2746 |
],
|
| 2747 |
outputs=[output_video]
|
| 2748 |
-
)
|
| 2749 |
-
|
|
|
|
|
|
|
| 2750 |
outputs=[download_btn]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2751 |
)
|
| 2752 |
|
| 2753 |
-
#
|
| 2754 |
-
download_btn.click(
|
| 2755 |
-
fn=None,
|
| 2756 |
-
inputs=[output_video],
|
| 2757 |
-
js=js_download_video
|
| 2758 |
-
)
|
| 2759 |
-
|
| 2760 |
-
# Updated Examples to use Persian modes
|
| 2761 |
examples_list = [
|
| 2762 |
-
[
|
| 2763 |
-
|
| 2764 |
-
|
| 2765 |
-
|
| 2766 |
-
|
| 2767 |
-
|
| 2768 |
-
None,
|
| 2769 |
-
"examples/supergirl.m4a",
|
| 2770 |
-
None,
|
| 2771 |
-
],
|
| 2772 |
-
[
|
| 2773 |
-
"examples/frame3.png",
|
| 2774 |
-
"a woman in a white dress standing in a supermarket, looking at a stack of pomegranates, she picks one and takes a bite, the camera zooms in to a close up of the pomegranate seeds. A calm music is playing in the supermarket and you can hear her taking a bite.",
|
| 2775 |
-
"Zoom In",
|
| 2776 |
-
"16:9",
|
| 2777 |
-
"تکمیل فریمهای میانی",
|
| 2778 |
-
None,
|
| 2779 |
-
None,
|
| 2780 |
-
"examples/frame4.png",
|
| 2781 |
-
],
|
| 2782 |
-
[
|
| 2783 |
-
"examples/supergirl.png",
|
| 2784 |
-
"A fuzzy puppet superhero character resembling a female puppet with blonde hair and a blue superhero suit stands inside an icy cave made of frozen walls and icicles, she looks panicked and frantic, rapidly turning her head left and right and scanning the cave while waving her arms and shouting angrily and desperately, mouthing the words “where the hell is my dog,” her movements exaggerated and puppet-like with high energy and urgency, suddenly a second puppet dog bursts into frame from the side, jumping up excitedly and tackling her affectionately while licking her face repeatedly, she freezes in surprise and then breaks into relief and laughter as the dog continues licking her, the scene feels chaotic, comedic, and emotional with expressive puppet reactions, cinematic lighting, smooth camera motion, shallow depth of field, and high-quality puppet-style animation",
|
| 2785 |
-
"No LoRA",
|
| 2786 |
-
"16:9",
|
| 2787 |
-
"تبدیل تصویر به ویدیو",
|
| 2788 |
-
None,
|
| 2789 |
-
None,
|
| 2790 |
-
None,
|
| 2791 |
-
],
|
| 2792 |
-
[
|
| 2793 |
-
"examples/highland.png",
|
| 2794 |
-
"Realistic POV selfie-style video in a snowy, foggy field. Two shaggy Highland cows with long curved horns stand ahead. The camera is handheld and slightly shaky. The woman filming talks nervously and excitedly in a vlog tone: \"Oh my god guys… look how big those horns are… I’m kinda scared.\" The cow on the left walks toward the camera in a cute, bouncy, hopping way, curious and gentle. Snow crunches under its hooves, breath visible in the cold air. The horns look massive from the POV. As the cow gets very close, its wet nose with slight dripping fills part of the frame. She laughs nervously but reaches out and pets the cow. The cow makes deep, soft, interesting mooing and snorting sounds, calm and friendly. Ultra-realistic, natural lighting, immersive audio, documentary-style realism.",
|
| 2795 |
-
"No LoRA",
|
| 2796 |
-
"16:9",
|
| 2797 |
-
"تبدیل تصویر به ویدیو",
|
| 2798 |
-
None,
|
| 2799 |
-
None,
|
| 2800 |
-
None,
|
| 2801 |
-
],
|
| 2802 |
-
[
|
| 2803 |
-
"examples/wednesday.png",
|
| 2804 |
-
"A cinematic dolly out of Wednesday Addams frozen mid-dance on a dark, blue-lit ballroom floor as students move indistinctly behind her, their footsteps and muffled music reduced to a distant, underwater thrum; the audio foregrounds her steady breathing and the faint rustle of fabric as she slowly raises one arm, never breaking eye contact with the camera, then after a deliberately long silence she speaks in a flat, dry, perfectly controlled voice, “I don’t dance… I vibe code,” each word crisp and unemotional, followed by an abrupt cutoff of her voice as the background sound swells slightly, reinforcing the deadpan humor, with precise lip sync, minimal facial movement, stark gothic lighting, and cinematic realism.",
|
| 2805 |
-
"Zoom Out",
|
| 2806 |
-
"16:9",
|
| 2807 |
-
"تبدیل تصویر به ویدیو",
|
| 2808 |
-
None,
|
| 2809 |
-
None,
|
| 2810 |
-
None,
|
| 2811 |
-
],
|
| 2812 |
-
[
|
| 2813 |
-
"examples/astronaut.png",
|
| 2814 |
-
"An astronaut hatches from a fragile egg on the surface of the Moon, the shell cracking and peeling apart in gentle low-gravity motion. Fine lunar dust lifts and drifts outward with each movement, floating in slow arcs before settling back onto the ground. The astronaut pushes free in a deliberate, weightless motion, small fragments of the egg tumbling and spinning through the air. In the background, the deep darkness of space subtly shifts as stars glide with the camera's movement, emphasizing vast depth and scale. The camera performs a smooth, cinematic slow push-in, with natural parallax between the foreground dust, the astronaut, and the distant starfield. Ultra-realistic detail, physically accurate low-gravity motion, cinematic lighting, and a breath-taking, movie-like shot.",
|
| 2815 |
-
"Static",
|
| 2816 |
-
"1:1",
|
| 2817 |
-
"تبدیل تصویر به ویدیو",
|
| 2818 |
-
None,
|
| 2819 |
-
None,
|
| 2820 |
-
None,
|
| 2821 |
-
],
|
| 2822 |
]
|
| 2823 |
|
| 2824 |
-
examples_obj = create_examples(
|
| 2825 |
-
examples=examples_list,
|
| 2826 |
-
fn=generate_video_example,
|
| 2827 |
-
inputs=[first_frame, prompt_ui, camera_ui, resolution_ui, radioanimated_mode, input_video, audio_input, end_frame],
|
| 2828 |
-
outputs = [output_video],
|
| 2829 |
-
label="نمونهها",
|
| 2830 |
-
cache_examples=True,
|
| 2831 |
-
visible=False
|
| 2832 |
-
)
|
| 2833 |
-
|
| 2834 |
preset_gallery = PresetGallery(
|
| 2835 |
items=[
|
| 2836 |
{"thumb": "examples/supergirl-2.png", "label": "تصویر و صدا به ویدیو"},
|
|
@@ -2843,35 +2576,13 @@ with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
|
| 2843 |
title="برای شروع روی یکی از نمونهها کلیک کنید",
|
| 2844 |
)
|
| 2845 |
|
| 2846 |
-
def on_audio_ui_change(v):
|
| 2847 |
-
# Our JS sends "__CLEAR__" when the user presses the X
|
| 2848 |
-
if v == "__CLEAR__" or v is None or v == "":
|
| 2849 |
-
return None
|
| 2850 |
-
# For normal events (uploads), do nothing (keep whatever gr.File already has)
|
| 2851 |
-
return gr.update()
|
| 2852 |
-
|
| 2853 |
-
audio_ui.change(
|
| 2854 |
-
fn=on_audio_ui_change,
|
| 2855 |
-
inputs=audio_ui,
|
| 2856 |
-
outputs=audio_input,
|
| 2857 |
-
api_visibility="private",
|
| 2858 |
-
)
|
| 2859 |
-
|
| 2860 |
preset_gallery.change(
|
| 2861 |
fn=apply_example,
|
| 2862 |
inputs=preset_gallery,
|
| 2863 |
outputs=[
|
| 2864 |
-
first_frame,
|
| 2865 |
-
|
| 2866 |
-
|
| 2867 |
-
resolution_ui,
|
| 2868 |
-
radioanimated_mode,
|
| 2869 |
-
input_video,
|
| 2870 |
-
audio_input,
|
| 2871 |
-
audio_ui,
|
| 2872 |
-
end_frame,
|
| 2873 |
-
output_video, # Clears the output video
|
| 2874 |
-
download_btn # Hides the download button
|
| 2875 |
],
|
| 2876 |
api_visibility="private",
|
| 2877 |
)
|
|
|
|
| 2319 |
|
| 2320 |
|
| 2321 |
####################################################################################################
|
| 2322 |
+
### PART 20: Gradio UI Layout & Launch (REVISED & FIXED)
|
| 2323 |
####################################################################################################
|
| 2324 |
|
| 2325 |
# JS Function to handle download request via PostMessage
|
|
|
|
| 2329 |
alert("لطفاً ابتدا ویدیو را تولید کنید.");
|
| 2330 |
return;
|
| 2331 |
}
|
| 2332 |
+
let fileUrl = typeof video === 'string' ? video : (video && (video.url || video.path));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2333 |
if (fileUrl && !fileUrl.startsWith('http')) {
|
|
|
|
| 2334 |
let cleanPath = fileUrl.startsWith('/') ? fileUrl.substring(1) : fileUrl;
|
| 2335 |
+
fileUrl = window.location.origin + (cleanPath.startsWith('file=') ? "/" + cleanPath : "/file=" + cleanPath);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2336 |
}
|
|
|
|
| 2337 |
if (fileUrl) {
|
| 2338 |
console.log("Sending download request for:", fileUrl);
|
| 2339 |
window.parent.postMessage({ type: 'DOWNLOAD_REQUEST', url: fileUrl }, '*');
|
|
|
|
| 2341 |
}
|
| 2342 |
"""
|
| 2343 |
|
| 2344 |
+
# این تابع جاوااسکریپت فقط مسئول فراخوانی API بهینه ساز است
|
| 2345 |
+
# ورودی ها را از پایتون می گیرد و خروجی (پرامپت بهینه شده) را به پایتون برمی گرداند
|
| 2346 |
+
js_enhancer_api_call = """
|
| 2347 |
async (firstFrame, promptText, mode) => {
|
| 2348 |
+
// اگر حالت انتخابی نیازی به بهینه سازی ندارد، پرامپت اصلی را برگردان
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2349 |
if (mode !== 'تبدیل تصویر به ویدیو' && mode !== 'تکمیل فریمهای میانی') {
|
| 2350 |
+
return promptText;
|
|
|
|
| 2351 |
}
|
| 2352 |
|
| 2353 |
// API بهینه ساز به تصویر نیاز دارد
|
| 2354 |
if (!firstFrame) {
|
| 2355 |
+
// چون این مرحله در میانه راه است، به کاربر اطلاع داده و با پرامپت اصلی ادامه می دهیم
|
| 2356 |
+
console.warn("Enhancement skipped: First frame image is required.");
|
| 2357 |
+
return promptText;
|
| 2358 |
}
|
| 2359 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2360 |
try {
|
|
|
|
| 2361 |
const response = await fetch(firstFrame.url);
|
| 2362 |
const imageBlob = await response.blob();
|
| 2363 |
|
|
|
|
| 2364 |
const formData = new FormData();
|
|
|
|
| 2365 |
const imageFile = new File([imageBlob], "image.jpg", { type: "image/jpeg" });
|
| 2366 |
formData.append('image', imageFile);
|
| 2367 |
formData.append('prompt', promptText);
|
| 2368 |
formData.append('is_extension', 'false');
|
| 2369 |
|
|
|
|
| 2370 |
const apiResponse = await fetch('https://ezmarynoori-vidtolani.hf.space/api/enhance-animation-prompt', {
|
| 2371 |
method: 'POST',
|
| 2372 |
body: formData
|
| 2373 |
});
|
| 2374 |
|
|
|
|
|
|
|
| 2375 |
if (!apiResponse.ok) {
|
| 2376 |
+
const errorData = await apiResponse.json();
|
| 2377 |
+
throw new Error(errorData.error || 'خطای ناشناخته از سرور بهینه ساز.');
|
| 2378 |
}
|
| 2379 |
|
| 2380 |
+
const data = await apiResponse.json();
|
| 2381 |
+
console.log("Enhanced Prompt received:", data.animation_prompt);
|
| 2382 |
+
// پرامپت بهینه شده را برای مرحله بعد در گرادیو برگردان
|
| 2383 |
+
return data.animation_prompt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2384 |
|
| 2385 |
} catch (error) {
|
| 2386 |
+
console.error("Enhancement API Error:", error);
|
| 2387 |
+
// در صورت خطا، پرامپت اصلی را برگردان تا فرآیند ساخت ویدیو متوقف نشود
|
| 2388 |
+
return promptText;
|
|
|
|
|
|
|
|
|
|
| 2389 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2390 |
}
|
| 2391 |
"""
|
| 2392 |
|
| 2393 |
|
| 2394 |
def apply_example(idx: str):
|
| 2395 |
idx = int(idx)
|
|
|
|
|
|
|
| 2396 |
img, prompt_txt, cam, res, mode, vid, aud, end_img = examples_list[idx]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2397 |
return (
|
| 2398 |
+
img or None,
|
| 2399 |
+
prompt_txt,
|
| 2400 |
+
cam,
|
| 2401 |
+
res,
|
| 2402 |
+
mode,
|
| 2403 |
+
gr.update(value=vid or None, visible=(mode == "Motion Control")),
|
| 2404 |
+
aud or None,
|
| 2405 |
+
aud or None,
|
| 2406 |
+
end_img or None,
|
| 2407 |
+
gr.update(value=None),
|
| 2408 |
+
gr.update(visible=False)
|
| 2409 |
)
|
| 2410 |
|
|
|
|
| 2411 |
with gr.Blocks(title="LTX-2 Video Distilled 🎥🔈") as demo:
|
| 2412 |
|
|
|
|
| 2413 |
gr.HTML(
|
| 2414 |
"""
|
| 2415 |
<div style="text-align: center; padding: 20px;">
|
|
|
|
| 2423 |
"""
|
| 2424 |
)
|
| 2425 |
|
| 2426 |
+
# State components to pass data between Python and JS
|
| 2427 |
+
# این کامپوننت ها برای کاربر قابل مشاهده نیستند
|
| 2428 |
+
enhanced_prompt_state = gr.State("")
|
| 2429 |
+
|
| 2430 |
with gr.Column(elem_id="col-container"):
|
| 2431 |
with gr.Row(elem_id="mode-row"):
|
|
|
|
| 2432 |
radioanimated_mode = RadioAnimated(
|
| 2433 |
choices=["تبدیل تصویر به ویدیو", "تکمیل فریمهای میانی"],
|
| 2434 |
value="تبدیل تصویر به ویدیو",
|
|
|
|
| 2436 |
)
|
| 2437 |
with gr.Row():
|
| 2438 |
with gr.Column(elem_id="step-column"):
|
|
|
|
| 2439 |
with gr.Row():
|
|
|
|
| 2440 |
first_frame = gr.Image(
|
| 2441 |
label="تصویر اول (برای بهینهسازی پرامپت الزامی است)",
|
| 2442 |
type="filepath",
|
| 2443 |
height=256
|
| 2444 |
)
|
|
|
|
| 2445 |
end_frame = gr.Image(
|
| 2446 |
label="تصویر آخر (اختیاری)",
|
| 2447 |
type="filepath",
|
| 2448 |
height=256,
|
| 2449 |
visible=False,
|
| 2450 |
)
|
| 2451 |
+
input_video = gr.Video(label="Motion Reference Video", height=256, visible=False)
|
| 2452 |
|
| 2453 |
+
relocate = gr.HTML(value="", html_template="<div></div>", js_on_load=r"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2454 |
(() => {
|
| 2455 |
function moveIntoFooter() {
|
| 2456 |
+
const promptRoot = document.querySelector("#prompt_ui"); if (!promptRoot) return false;
|
| 2457 |
+
const footer = promptRoot.querySelector(".ds-footer"); if (!footer) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2458 |
const dur = document.querySelector("#duration_ui .cd-wrap");
|
| 2459 |
const res = document.querySelector("#resolution_ui .cd-wrap");
|
| 2460 |
const cam = document.querySelector("#camera_ui .cd-wrap");
|
|
|
|
| 2461 |
if (!dur || !res || !cam) return false;
|
| 2462 |
+
footer.appendChild(dur); footer.appendChild(res); footer.appendChild(cam);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2463 |
return true;
|
| 2464 |
}
|
| 2465 |
+
const tick = () => { if (!moveIntoFooter()) requestAnimationFrame(tick); };
|
|
|
|
|
|
|
|
|
|
| 2466 |
requestAnimationFrame(tick);
|
| 2467 |
})();
|
| 2468 |
+
""")
|
|
|
|
| 2469 |
|
| 2470 |
+
prompt_ui = PromptBox(value="این تصویر را با حرکت سینمایی و انیمیشن روان زنده کن", elem_id="prompt_ui")
|
| 2471 |
+
audio_input = gr.File(label="Audio (Optional)", file_types=["audio"], type="filepath", elem_id="audio_input_hidden")
|
| 2472 |
+
audio_ui = AudioDropUpload(target_audio_elem_id="audio_input_hidden", elem_id="audio_ui")
|
| 2473 |
+
prompt = gr.Textbox(label="Prompt", value="این تصویر را با حرکت سینمایی و انیمیشن روان زنده کن", lines=3, max_lines=3, placeholder="حرکت و انیمیشن مورد نظر خود را توصیف کنید...", visible=False)
|
| 2474 |
+
enhance_prompt = gr.Checkbox(label="Enhance Prompt", value=True, visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2475 |
|
| 2476 |
with gr.Accordion("تنظیمات پیشرفته", open=False, visible=False):
|
| 2477 |
+
seed = gr.Slider(label="سید (Seed)", minimum=0, maximum=MAX_SEED, value=DEFAULT_SEED, step=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2478 |
randomize_seed = gr.Checkbox(label="استفاده از سید تصادفی", value=True)
|
|
|
|
| 2479 |
|
| 2480 |
with gr.Column(elem_id="step-column"):
|
| 2481 |
output_video = gr.Video(label="ویدیوی ساخته شده", autoplay=True, height=512)
|
|
|
|
| 2482 |
with gr.Row():
|
| 2483 |
+
download_btn = gr.Button("📥 دانلود ویدیو", variant="secondary", size="sm", scale=0, visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2484 |
|
| 2485 |
with gr.Row(elem_id="controls-row"):
|
| 2486 |
+
duration_ui = CameraDropdown(choices=["3s", "5s", "10s"], value="5s", title="مدت زمان ویدیو", elem_id="duration_ui")
|
| 2487 |
+
duration = gr.Slider(label="Duration (seconds)", minimum=1.0, maximum=10.0, value=5.0, step=0.1, visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2488 |
|
| 2489 |
+
ICON_16_9 = """<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><rect x="3" y="7" width="18" height="10" rx="2" stroke="currentColor" stroke-width="2"/></svg>"""
|
| 2490 |
+
ICON_1_1 = """<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"/></svg>"""
|
| 2491 |
+
ICON_9_16 = """<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><rect x="7" y="3" width="10" height="18" rx="2" stroke="currentColor" stroke-width="2"/></svg>"""
|
| 2492 |
|
| 2493 |
resolution_ui = CameraDropdown(
|
| 2494 |
+
choices=[{"label": "16:9", "value": "16:9", "icon": ICON_16_9}, {"label": "1:1", "value": "1:1", "icon": ICON_1_1}, {"label": "9:16", "value": "9:16", "icon": ICON_9_16}],
|
| 2495 |
+
value="16:9", title="ابعاد تصویر", elem_id="resolution_ui"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2496 |
)
|
|
|
|
|
|
|
| 2497 |
width = gr.Number(label="Width", value=DEFAULT_1_STAGE_WIDTH, precision=0, visible=False)
|
| 2498 |
height = gr.Number(label="Height", value=DEFAULT_1_STAGE_HEIGHT, precision=0, visible=False)
|
| 2499 |
+
camera_ui = CameraDropdown(choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES], value="No LoRA", title="افکت دوربین (LoRA)", elem_id="camera_ui")
|
| 2500 |
+
camera_lora = gr.Dropdown(label="Camera Control LoRA", choices=[name for name, _ in VISIBLE_RUNTIME_LORA_CHOICES], value="No LoRA", visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2501 |
|
| 2502 |
+
generate_btn = gr.Button("🤩 ساخت ویدیو", variant="primary", elem_classes="button-gradient")
|
|
|
|
| 2503 |
|
| 2504 |
+
# توابع کمکی برای بهروزرسانی UI
|
| 2505 |
+
def lock_ui():
|
| 2506 |
+
return gr.Button(value="⏳ در حال بهینه سازی پرامپت...", interactive=False)
|
| 2507 |
|
| 2508 |
+
def re_enable_ui():
|
| 2509 |
+
return gr.Button(value="🤩 ساخت ویدیو", interactive=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2510 |
|
| 2511 |
+
# اتصال رویدادها
|
| 2512 |
+
camera_ui.change(fn=lambda x: x, inputs=camera_ui, outputs=camera_lora, api_visibility="private")
|
| 2513 |
+
radioanimated_mode.change(fn=on_mode_change, inputs=radioanimated_mode, outputs=[input_video, end_frame], api_visibility="private")
|
| 2514 |
+
duration_ui.change(fn=apply_duration, inputs=duration_ui, outputs=[duration], api_visibility="private")
|
| 2515 |
+
resolution_ui.change(fn=apply_resolution, inputs=resolution_ui, outputs=[width, height], api_visibility="private")
|
| 2516 |
+
prompt_ui.change(fn=lambda x: x, inputs=prompt_ui, outputs=prompt, api_visibility="private")
|
| 2517 |
+
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")
|
| 2518 |
+
download_btn.click(fn=None, inputs=[output_video], js=js_download_video)
|
| 2519 |
|
| 2520 |
+
# --- زنجیره اصلی رویداد ساخت ویدیو ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2521 |
|
| 2522 |
+
# 1. وقتی کاربر روی دکمه کلیک می کند، ابتدا UI را قفل کرده و متن دکمه را تغییر می دهیم.
|
| 2523 |
+
# این تابع پایتون هیچ کاری جز آماده سازی UI انجام نمی دهد.
|
| 2524 |
+
generate_btn.click(
|
| 2525 |
+
fn=lock_ui,
|
| 2526 |
+
outputs=[generate_btn]
|
| 2527 |
+
) \
|
| 2528 |
+
.then(
|
| 2529 |
+
# 2. سپس، تابع جاوااسکریپت را برای بهینه سازی پرامپت فراخوانی می کنیم.
|
| 2530 |
+
# ورودی های آن از کامپوننت های گرادیو گرفته شده و خروجی آن در یک State ذخیره می شود.
|
| 2531 |
+
fn=None,
|
| 2532 |
+
inputs=[first_frame, prompt, radioanimated_mode],
|
| 2533 |
+
outputs=[enhanced_prompt_state],
|
| 2534 |
+
js=js_enhancer_api_call
|
| 2535 |
+
) \
|
| 2536 |
+
.then(
|
| 2537 |
+
# 3. حالا، تابع اصلی ساخت ویدیو را با پرامپت بهینه شده (که از State خوانده می شود) اجرا می کنیم.
|
| 2538 |
fn=generate_video,
|
| 2539 |
inputs=[
|
| 2540 |
+
first_frame, end_frame, enhanced_prompt_state, duration, input_video,
|
| 2541 |
+
radioanimated_mode, enhance_prompt, seed, randomize_seed,
|
| 2542 |
+
height, width, camera_lora, audio_input
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2543 |
],
|
| 2544 |
outputs=[output_video]
|
| 2545 |
+
) \
|
| 2546 |
+
.then(
|
| 2547 |
+
# 4. پس از اتمام ساخت ویدیو، دکمه دانلود را نمایش می دهیم.
|
| 2548 |
+
fn=lambda: gr.update(visible=True),
|
| 2549 |
outputs=[download_btn]
|
| 2550 |
+
) \
|
| 2551 |
+
.then(
|
| 2552 |
+
# 5. در نهایت، UI را دوباره فعال می کنیم.
|
| 2553 |
+
fn=re_enable_ui,
|
| 2554 |
+
outputs=[generate_btn]
|
| 2555 |
)
|
| 2556 |
|
| 2557 |
+
# منطق نمونه ها
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2558 |
examples_list = [
|
| 2559 |
+
["examples/supergirl-2.png", "A fuzzy puppet superhero...", "Static", "16:9", "تبدیل تصویر به ویدیو", None, "examples/supergirl.m4a", None],
|
| 2560 |
+
["examples/frame3.png", "a woman in a white dress...", "Zoom In", "16:9", "تکمیل فریمهای میانی", None, None, "examples/frame4.png"],
|
| 2561 |
+
["examples/supergirl.png", "A fuzzy puppet superhero character...", "No LoRA", "16:9", "تبدیل تصویر به ویدیو", None, None, None],
|
| 2562 |
+
["examples/highland.png", "Realistic POV selfie-style video...", "No LoRA", "16:9", "تبدیل تصویر به ویدیو", None, None, None],
|
| 2563 |
+
["examples/wednesday.png", "A cinematic dolly out of Wednesday Addams...", "Zoom Out", "16:9", "تبدیل تصویر به ویدیو", None, None, None],
|
| 2564 |
+
["examples/astronaut.png", "An astronaut hatches from a fragile egg...", "Static", "1:1", "تبدیل تصویر به ویدیو", None, None, None],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2565 |
]
|
| 2566 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2567 |
preset_gallery = PresetGallery(
|
| 2568 |
items=[
|
| 2569 |
{"thumb": "examples/supergirl-2.png", "label": "تصویر و صدا به ویدیو"},
|
|
|
|
| 2576 |
title="برای شروع روی یکی از نمونهها کلیک کنید",
|
| 2577 |
)
|
| 2578 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2579 |
preset_gallery.change(
|
| 2580 |
fn=apply_example,
|
| 2581 |
inputs=preset_gallery,
|
| 2582 |
outputs=[
|
| 2583 |
+
first_frame, prompt_ui, camera_ui, resolution_ui, radioanimated_mode,
|
| 2584 |
+
input_video, audio_input, audio_ui, end_frame,
|
| 2585 |
+
output_video, download_btn
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2586 |
],
|
| 2587 |
api_visibility="private",
|
| 2588 |
)
|