File size: 6,498 Bytes
6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 70ce8b4 6a7f147 b3904ee 9643953 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 9643953 6a7f147 b3904ee 6a7f147 b3904ee 9643953 b3904ee 6a7f147 b3904ee 9643953 b3904ee 6a7f147 b3904ee 9643953 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 b3904ee 6a7f147 | 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | import os
import time
import gradio as gr
import tempfile
import requests
from byteplussdkarkruntime import Ark
from PIL import Image
import io
# Get API key from Hugging Face secret "Key"
API_KEY = os.environ.get("Key", "")
# Initialize client exactly like your working code
client = Ark(
base_url="https://ark.ap-southeast.bytepluses.com/api/v3",
api_key=API_KEY,
)
def upload_image_to_temp_url(image):
"""Upload image to temporary hosting and return URL"""
# For now, we need a public URL for the API
# Option 1: Use a free image hosting service
# Option 2: Save temporarily and return path (won't work for API)
# Option 3: Keep URL input for now with preview
# Let's keep it simple - return None and we'll handle it in the UI
return None
def generate_video(image, prompt_text, progress=gr.Progress()):
"""Generate video using your exact working code pattern"""
if not API_KEY:
yield "❌ API Key not configured. Please add 'Key' secret.", None
return
if image is None:
yield "⚠️ Please upload an image first", None
return
try:
progress(0, desc="Preparing image...")
# Save uploaded image temporarily
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
image.save(tmp_file.name)
# Upload to a temporary hosting service
# For now, we'll use a placeholder - we need to implement this
# Option: Use imgbb.com API or similar
image_url = "https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png" # Placeholder
# TODO: Implement actual image upload to hosting service
yield "⏳ Note: Direct image upload needs hosting service. Using placeholder for now.", None
time.sleep(1)
progress(0.2, desc="Creating request...")
# Exactly your working code structure
print("----- create request -----")
create_result = client.content_generation.tasks.create(
model="seedance-1-5-pro-251215",
content=[
{
"type": "text",
"text": prompt_text
},
{
"type": "image_url",
"image_url": {
"url": image_url
}
}
]
)
task_id = create_result.id
print(f"Task created: {task_id}")
yield f"✅ Task created: {task_id}", None
progress(0.3, desc="Polling for results...")
# Polling exactly like your working code
attempts = 0
max_attempts = 120 # 2 minutes max
while attempts < max_attempts:
get_result = client.content_generation.tasks.get(task_id=task_id)
status = get_result.status
if status == "succeeded":
progress(1.0, desc="Complete!")
# Extract video URL from the response structure we saw
video_url = get_result.content.video_url if hasattr(get_result, 'content') else None
print(f"Video URL: {video_url}")
yield "✅ Video generated successfully!", video_url
return
elif status == "failed":
error_msg = get_result.error if hasattr(get_result, 'error') else "Unknown error"
yield f"❌ Failed: {error_msg}", None
return
else:
progress(0.3 + (attempts/max_attempts)*0.7, desc=f"Status: {status}")
yield f"⏳ Status: {status}... (attempt {attempts + 1})", None
time.sleep(1)
attempts += 1
yield "⏰ Timeout after 2 minutes", None
except Exception as e:
print(f"Error: {e}")
yield f"❌ Error: {str(e)}", None
# Simple, clean interface
with gr.Blocks(title="BytePlus Video Generator", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🎥 BytePlus Video Generator
Upload an image and describe the video you want to generate.
""")
# Show API key status
if API_KEY:
gr.Markdown("✅ **API Key:** Configured")
else:
gr.Markdown("❌ **API Key:** Not configured - please add 'Key' secret")
with gr.Row():
with gr.Column():
# Image upload
image_input = gr.Image(
label="Upload Starting Image",
type="pil",
height=300
)
# Text prompt
prompt = gr.Textbox(
label="Video Description",
lines=4,
placeholder="Describe what you want to see...",
value="At breakneck speed, drones thread through intricate obstacles or stunning natural wonders, delivering an immersive, heart-pounding flying experience. --duration 5 --camerafixed false"
)
# Generate button
generate_btn = gr.Button("🚀 Generate Video", variant="primary", size="lg")
with gr.Column():
# Status
status = gr.Textbox(
label="Status",
lines=4,
interactive=False
)
# Video output
video_output = gr.Video(
label="Generated Video",
interactive=False
)
# Example prompts
gr.Markdown("---")
gr.Markdown("### Example Prompts")
with gr.Row():
gr.Button("Nature").click(
fn=lambda: "Aerial drone shot over mountains at sunrise, cinematic --duration 5 --camerafixed false",
outputs=prompt
)
gr.Button("City").click(
fn=lambda: "Fast drone racing through futuristic city streets --duration 5 --camerafixed false",
outputs=prompt
)
gr.Button("Ocean").click(
fn=lambda: "Drone following waves at golden hour --duration 5 --camerafixed false",
outputs=prompt
)
# Connect the generate button
generate_event = generate_btn.click(
fn=generate_video,
inputs=[image_input, prompt],
outputs=[status, video_output]
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0") |