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")