File size: 7,046 Bytes
fb0aa05 | 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 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | import gradio as gr
import requests
import os
import time
import json
import logging
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Get API key from environment (your "Key" secret)
API_KEY = os.environ.get("Key", "")
if not API_KEY:
logger.error("❌ No API key found in environment variable 'Key'")
else:
logger.info(f"✅ API key loaded (length: {len(API_KEY)})")
def generate_video(prompt_text, image_url, model_id, progress=gr.Progress()):
"""Generate video using direct API calls (curl approach)"""
if not API_KEY:
yield "❌ API key not configured. Please set the 'Key' secret.", None
return
try:
progress(0, desc="Starting request...")
# Use the path from curl command
url = "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}" # Same as curl: -H "Authorization: Bearer $ARK_API_KEY"
}
# Prepare the request body exactly like curl
data = {
"model": model_id,
"content": [
{
"type": "text",
"text": prompt_text
},
{
"type": "image_url",
"image_url": {
"url": image_url
}
}
]
}
logger.info(f"📤 Sending request to: {url}")
logger.info(f"📝 Model: {model_id}")
# Make the POST request (like curl -X POST)
response = requests.post(url, headers=headers, json=data)
logger.info(f"📥 Response status: {response.status_code}")
if response.status_code != 200:
error_msg = f"Error {response.status_code}: {response.text}"
logger.error(f"❌ {error_msg}")
yield error_msg, None
return
result = response.json()
task_id = result.get('id')
if not task_id:
yield "❌ No task ID in response", None
return
logger.info(f"✅ Task created: {task_id}")
yield f"Task created: {task_id}", None
# Poll for results (like the while loop in original code)
progress(0.2, desc="Waiting for generation...")
# Status URL (adjust if different)
status_url = f"https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks/{task_id}"
max_attempts = 60
attempts = 0
while attempts < max_attempts:
progress(0.2 + (attempts / max_attempts) * 0.7,
desc=f"Polling... ({attempts + 1}/{max_attempts})")
status_response = requests.get(status_url, headers=headers)
if status_response.status_code != 200:
yield f"❌ Error checking status: {status_response.text}", None
return
status_result = status_response.json()
status = status_result.get('status')
logger.info(f"Status: {status}")
if status == "succeeded":
progress(1.0, desc="Complete!")
# Extract video URL (adjust based on actual response structure)
video_url = None
if 'output' in status_result and status_result['output']:
if isinstance(status_result['output'], list) and len(status_result['output']) > 0:
video_url = status_result['output'][0].get('video_url')
elif isinstance(status_result['output'], dict):
video_url = status_result['output'].get('video_url')
if video_url:
yield "✅ Video generated successfully!", video_url
else:
yield "✅ Task completed (no video URL in response)", None
return
elif status == "failed":
error = status_result.get('error', 'Unknown error')
yield f"❌ Task failed: {error}", None
return
else:
yield f"⏳ Status: {status}...", None
time.sleep(1)
attempts += 1
yield "⏰ Timeout: Task took too long", None
except Exception as e:
logger.error(f"❌ Exception: {str(e)}")
yield f"❌ Error: {str(e)}", None
# Simple Gradio interface
with gr.Blocks(title="BytePlus Video Generator", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🎥 BytePlus Video Generator
Using direct API calls (curl approach)
""")
# 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():
model_id = gr.Textbox(
label="Model ID",
value="seedance-1-5-pro-251215"
)
image_url = gr.Textbox(
label="Image URL",
value="https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png"
)
prompt = gr.Textbox(
label="Prompt",
lines=4,
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", variant="primary")
with gr.Column():
status = gr.Textbox(label="Status", lines=3)
video = gr.Video(label="Generated Video")
video_url = gr.Textbox(label="Video URL")
# Example prompts
gr.Markdown("---")
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
generate_btn.click(
fn=generate_video,
inputs=[prompt, image_url, model_id],
outputs=[status, video]
).then(
fn=lambda v: v if v else "",
inputs=[video],
outputs=[video_url]
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0") |