video / app.py
kines9661's picture
Upload 4 files
5f5acc5 verified
Raw
History Blame Contribute Delete
7.13 kB
import glob
import os
import time
import uuid
from pathlib import Path
import gradio as gr
from cli import ProxyRotator, VeoEngine
OUTPUT_DIR = Path("outputs")
PROXY_FILE = Path("proxies-res-any-1777564385571.txt")
def cleanup_outputs(max_age_seconds=3600):
OUTPUT_DIR.mkdir(exist_ok=True)
now = time.time()
for path in glob.glob(str(OUTPUT_DIR / "*.mp4")):
try:
if os.path.getmtime(path) < now - max_age_seconds:
os.remove(path)
except OSError:
pass
def build_engine(model_key="veo"):
proxy_file = str(PROXY_FILE) if PROXY_FILE.exists() else str(PROXY_FILE)
rotator = ProxyRotator(proxy_file)
return VeoEngine(rotator, model_key=model_key)
def generate_video(prompt, model_key, prompt_mode, aspect_ratio, audio_mode, require_audio, max_retries):
prompt = (prompt or "").strip()
if not prompt:
return None, "請先輸入 Prompt。"
cleanup_outputs()
max_retries = int(max_retries or 1)
last_error = None
for attempt in range(1, max_retries + 1):
try:
engine = build_engine(model_key)
yield None, f"Attempt {attempt}/{max_retries}\n正在取得 session nonce..."
engine.fetch_nonce()
if prompt_mode == "enhanced":
yield None, f"Attempt {attempt}/{max_retries}\n正在增強 Prompt..."
generation_prompt = engine.enhance_prompt(prompt)
else:
generation_prompt = prompt
yield None, f"Attempt {attempt}/{max_retries}\n使用原始 Prompt 生成,避免提示語被改寫..."
yield None, f"Attempt {attempt}/{max_retries}\n正在提交影片生成任務..."
scene_id = engine.generate_video(generation_prompt, aspect_ratio, audio_mode=audio_mode)
yield None, (
f"Attempt {attempt}/{max_retries}\n"
f"Scene ID: {scene_id}\n"
f"伺服器正在生成影片,通常需要 1-5 分鐘..."
)
video_url = engine.wait_for_video(scene_id)
if not video_url:
raise RuntimeError("生成完成檢查失敗,沒有取得影片 URL。")
filename = OUTPUT_DIR / f"veo_video_{scene_id}_{uuid.uuid4().hex[:8]}.mp4"
yield None, (
f"Attempt {attempt}/{max_retries}\n"
f"Scene ID: {scene_id}\n"
f"已取得影片 URL,正在下載...\n{video_url}"
)
saved_file = engine.download(video_url, str(filename))
has_audio = engine.has_audio_track(saved_file)
if require_audio and not has_audio:
raise RuntimeError("已下載影片,但沒有偵測到音軌。")
status = (
"生成完成!\n\n"
f"Model: {engine.MODEL_NAME}\n"
f"Referrer: {engine.PAGE_URL}\n"
f"Scene ID: {scene_id}\n"
f"Aspect Ratio: {aspect_ratio}\n"
f"Audio Mode: {audio_mode}\n"
f"Audio Detected: {'Yes' if has_audio else 'No'}\n"
f"Video URL: {video_url}\n\n"
f"Prompt Mode: {prompt_mode}\n"
f"Generation Prompt:\n{generation_prompt}"
)
yield saved_file, status
return
except Exception as exc:
last_error = exc
if attempt < max_retries:
yield None, f"Attempt {attempt}/{max_retries} 失敗:{exc}\n準備重試..."
time.sleep(2)
else:
yield None, f"全部重試失敗。\n最後錯誤:{last_error}"
return
def create_demo():
with gr.Blocks(title="Veo Video Generator") as demo:
gr.Markdown(
"# 🎬 AI Video Generator\n"
"**Models: Veo 3.1 / Grok 4.5**\n\n"
"Hugging Face Spaces 免費版 UI。選擇模型、輸入 Prompt 後會生成影片、下載 MP4,並檢查是否包含音軌。"
)
with gr.Row():
with gr.Column(scale=1):
prompt = gr.Textbox(
label="Prompt",
lines=5,
placeholder="A cinematic shot of a futuristic city at sunset",
)
model_key = gr.Radio(
choices=[("Veo 3.1", "veo"), ("Grok 4.5", "grok")],
value="veo",
label="Model",
info="Veo 3.1 使用 /veo-video-generator/;Grok 4.5 使用 /grok-ai-video-generator/。",
)
prompt_mode = gr.Radio(
choices=[("原始提示語(推薦,生成更一致)", "raw"), ("AI 增強提示語", "enhanced")],
value="raw",
label="Prompt Mode",
info="raw 會直接用你輸入的 Prompt 生成;enhanced 會先讓網站改寫 Prompt,畫面可能和原提示不同。",
)
aspect_ratio = gr.Radio(
choices=["16:9", "9:16"],
value="16:9",
label="Aspect Ratio",
)
audio_mode = gr.Radio(
choices=["auto", "try", "none"],
value="auto",
label="Audio Mode",
info="auto 使用網站預設;try 會附加實驗音效參數;none 不附加音效偏好。",
)
require_audio = gr.Checkbox(
value=False,
label="Require Audio",
info="啟用後,如果下載影片沒有偵測到音軌,任務會標記為失敗。",
)
max_retries = gr.Slider(
minimum=1,
maximum=3,
step=1,
value=1,
label="Max Retries",
)
generate_btn = gr.Button("Generate Video", variant="primary")
with gr.Column(scale=1):
video = gr.Video(label="Generated Video")
status = gr.Textbox(label="Status", lines=14)
gr.Markdown(
"## 使用提示\n"
"- 免費 Space 可能會休眠,首次啟動較慢。\n"
"- 一次只建議生成一個任務。\n"
"- 影片會暫存在 Space 的 outputs 目錄,重啟後可能消失。\n"
"- 若設為 Public Space,任何人都可能使用你的介面。"
)
generate_btn.click(
fn=generate_video,
inputs=[prompt, model_key, prompt_mode, aspect_ratio, audio_mode, require_audio, max_retries],
outputs=[video, status],
)
return demo
if __name__ == "__main__":
cleanup_outputs()
app = create_demo()
app.queue(default_concurrency_limit=1).launch(theme=gr.themes.Soft())