File size: 3,541 Bytes
85923d4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | import gradio as gr
import torch
import json
import os
from diffusers import AnimateDiffPipeline, MotionAdapter, EulerDiscreteScheduler
from diffusers.utils import export_to_gif
from huggingface_hub import InferenceClient, hf_hub_download
from safetensors.torch import load_file
import spaces
# 1. 初始化 LLM 客户端 (使用 Hugging Face 免费的 Serverless API)
client = InferenceClient("meta-llama/Llama-3.3-70B-Instruct")
# 2. 初始化视频生成 Pipeline (AnimateDiff-Lightning)
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if torch.cuda.is_available() else torch.float32
step = 4 # 4-step inference, fast and good quality
repo = "ByteDance/AnimateDiff-Lightning"
ckpt = f"animatediff_lightning_{step}step_diffusers.safetensors"
base = "emilianJR/epiCRealism"
adapter = MotionAdapter().to(device, dtype)
adapter.load_state_dict(load_file(hf_hub_download(repo, ckpt), device=device))
pipe = AnimateDiffPipeline.from_pretrained(base, motion_adapter=adapter, torch_dtype=dtype).to(device)
pipe.scheduler = EulerDiscreteScheduler.from_config(
pipe.scheduler.config, timestep_spacing="trailing", beta_schedule="linear"
)
def generate_llm_content(query):
system_prompt = "You are a talented video creator. Generate a response in JSON format with 'title', 'cover_prompt', and 'video_prompt' (3s)."
user_prompt = f"User Query: {query}\n\nRequirements:\n- title: MAX 50 chars\n- cover_prompt: image description\n- video_prompt: 3s motion description\n\nReturn JSON ONLY."
response = client.chat_completion(
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
max_tokens=500,
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
@spaces.GPU(duration=60) # 申请 ZeroGPU A100 资源
def create_popcorn(query):
# Step 1: LLM 生成内容
content = generate_llm_content(query)
title = content.get("title", "Untitled Video")
video_prompt = content.get("video_prompt", query)
# Step 2: 生成视频
print(f"Generating video for: {video_prompt}")
output = pipe(prompt=video_prompt, guidance_scale=1.0, num_inference_steps=4, num_frames=16)
# 保存为 GIF (Gradio 支持展示)
video_path = "output_video.gif"
export_to_gif(output.frames[0], video_path)
return title, content.get("cover_prompt"), video_prompt, video_path
# 3. 构建 Gradio UI
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🍿 LLMPopcorn Demo")
gr.Markdown("Input a topic, and LLMPopcorn will generate the **Title**, **Prompts**, and a **3-second AI Video**.")
with gr.Row():
with gr.Column():
input_text = gr.Textbox(label="Enter your video idea", placeholder="e.g., A futuristic city with flying cars")
btn = gr.Button("Generate Popcorn!", variant="primary")
with gr.Column():
output_title = gr.Textbox(label="Generated Title")
output_video = gr.Image(label="Generated 3s Video (GIF)")
with gr.Accordion("Prompt Details", open=False):
output_cover_prompt = gr.Textbox(label="Cover Prompt")
output_video_prompt = gr.Textbox(label="Video Prompt")
btn.click(
fn=create_popcorn,
inputs=[input_text],
outputs=[output_title, output_cover_prompt, output_video_prompt, output_video]
)
if __name__ == "__main__":
demo.launch()
|