| | import os |
| | import time |
| | import gradio as gr |
| | import tempfile |
| | import requests |
| | from byteplussdkarkruntime import Ark |
| | from PIL import Image |
| | import io |
| |
|
| | |
| | API_KEY = os.environ.get("Key", "") |
| |
|
| | |
| | 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""" |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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...") |
| | |
| | |
| | with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file: |
| | image.save(tmp_file.name) |
| | |
| | |
| | |
| | |
| | image_url = "https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png" |
| | |
| | |
| | yield "⏳ Note: Direct image upload needs hosting service. Using placeholder for now.", None |
| | time.sleep(1) |
| | |
| | progress(0.2, desc="Creating request...") |
| | |
| | |
| | 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...") |
| | |
| | |
| | attempts = 0 |
| | max_attempts = 120 |
| | |
| | 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!") |
| | |
| | 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 |
| |
|
| | |
| | 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. |
| | """) |
| | |
| | |
| | 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_input = gr.Image( |
| | label="Upload Starting Image", |
| | type="pil", |
| | height=300 |
| | ) |
| | |
| | |
| | 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_btn = gr.Button("🚀 Generate Video", variant="primary", size="lg") |
| | |
| | with gr.Column(): |
| | |
| | status = gr.Textbox( |
| | label="Status", |
| | lines=4, |
| | interactive=False |
| | ) |
| | |
| | |
| | video_output = gr.Video( |
| | label="Generated Video", |
| | interactive=False |
| | ) |
| | |
| | |
| | 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 |
| | ) |
| | |
| | |
| | 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") |