MySafeCode commited on
Commit
fb0aa05
·
verified ·
1 Parent(s): d51b0fb

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -0
app.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import os
4
+ import time
5
+ import json
6
+ import logging
7
+
8
+ # Set up logging
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # Get API key from environment (your "Key" secret)
13
+ API_KEY = os.environ.get("Key", "")
14
+ if not API_KEY:
15
+ logger.error("❌ No API key found in environment variable 'Key'")
16
+ else:
17
+ logger.info(f"✅ API key loaded (length: {len(API_KEY)})")
18
+
19
+ def generate_video(prompt_text, image_url, model_id, progress=gr.Progress()):
20
+ """Generate video using direct API calls (curl approach)"""
21
+
22
+ if not API_KEY:
23
+ yield "❌ API key not configured. Please set the 'Key' secret.", None
24
+ return
25
+
26
+ try:
27
+ progress(0, desc="Starting request...")
28
+
29
+ # Use the path from curl command
30
+ url = "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks"
31
+
32
+ headers = {
33
+ "Content-Type": "application/json",
34
+ "Authorization": f"Bearer {API_KEY}" # Same as curl: -H "Authorization: Bearer $ARK_API_KEY"
35
+ }
36
+
37
+ # Prepare the request body exactly like curl
38
+ data = {
39
+ "model": model_id,
40
+ "content": [
41
+ {
42
+ "type": "text",
43
+ "text": prompt_text
44
+ },
45
+ {
46
+ "type": "image_url",
47
+ "image_url": {
48
+ "url": image_url
49
+ }
50
+ }
51
+ ]
52
+ }
53
+
54
+ logger.info(f"📤 Sending request to: {url}")
55
+ logger.info(f"📝 Model: {model_id}")
56
+
57
+ # Make the POST request (like curl -X POST)
58
+ response = requests.post(url, headers=headers, json=data)
59
+
60
+ logger.info(f"📥 Response status: {response.status_code}")
61
+
62
+ if response.status_code != 200:
63
+ error_msg = f"Error {response.status_code}: {response.text}"
64
+ logger.error(f"❌ {error_msg}")
65
+ yield error_msg, None
66
+ return
67
+
68
+ result = response.json()
69
+ task_id = result.get('id')
70
+
71
+ if not task_id:
72
+ yield "❌ No task ID in response", None
73
+ return
74
+
75
+ logger.info(f"✅ Task created: {task_id}")
76
+ yield f"Task created: {task_id}", None
77
+
78
+ # Poll for results (like the while loop in original code)
79
+ progress(0.2, desc="Waiting for generation...")
80
+
81
+ # Status URL (adjust if different)
82
+ status_url = f"https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks/{task_id}"
83
+
84
+ max_attempts = 60
85
+ attempts = 0
86
+
87
+ while attempts < max_attempts:
88
+ progress(0.2 + (attempts / max_attempts) * 0.7,
89
+ desc=f"Polling... ({attempts + 1}/{max_attempts})")
90
+
91
+ status_response = requests.get(status_url, headers=headers)
92
+
93
+ if status_response.status_code != 200:
94
+ yield f"❌ Error checking status: {status_response.text}", None
95
+ return
96
+
97
+ status_result = status_response.json()
98
+ status = status_result.get('status')
99
+
100
+ logger.info(f"Status: {status}")
101
+
102
+ if status == "succeeded":
103
+ progress(1.0, desc="Complete!")
104
+
105
+ # Extract video URL (adjust based on actual response structure)
106
+ video_url = None
107
+ if 'output' in status_result and status_result['output']:
108
+ if isinstance(status_result['output'], list) and len(status_result['output']) > 0:
109
+ video_url = status_result['output'][0].get('video_url')
110
+ elif isinstance(status_result['output'], dict):
111
+ video_url = status_result['output'].get('video_url')
112
+
113
+ if video_url:
114
+ yield "✅ Video generated successfully!", video_url
115
+ else:
116
+ yield "✅ Task completed (no video URL in response)", None
117
+ return
118
+
119
+ elif status == "failed":
120
+ error = status_result.get('error', 'Unknown error')
121
+ yield f"❌ Task failed: {error}", None
122
+ return
123
+ else:
124
+ yield f"⏳ Status: {status}...", None
125
+ time.sleep(1)
126
+ attempts += 1
127
+
128
+ yield "⏰ Timeout: Task took too long", None
129
+
130
+ except Exception as e:
131
+ logger.error(f"❌ Exception: {str(e)}")
132
+ yield f"❌ Error: {str(e)}", None
133
+
134
+ # Simple Gradio interface
135
+ with gr.Blocks(title="BytePlus Video Generator", theme=gr.themes.Soft()) as demo:
136
+
137
+ gr.Markdown("""
138
+ # 🎥 BytePlus Video Generator
139
+
140
+ Using direct API calls (curl approach)
141
+ """)
142
+
143
+ # Show API key status
144
+ if API_KEY:
145
+ gr.Markdown("✅ **API Key:** Configured")
146
+ else:
147
+ gr.Markdown("❌ **API Key:** Not configured - please add 'Key' secret")
148
+
149
+ with gr.Row():
150
+ with gr.Column():
151
+ model_id = gr.Textbox(
152
+ label="Model ID",
153
+ value="seedance-1-5-pro-251215"
154
+ )
155
+
156
+ image_url = gr.Textbox(
157
+ label="Image URL",
158
+ value="https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png"
159
+ )
160
+
161
+ prompt = gr.Textbox(
162
+ label="Prompt",
163
+ lines=4,
164
+ value="At breakneck speed, drones thread through intricate obstacles or stunning natural wonders, delivering an immersive, heart-pounding flying experience. --duration 5 --camerafixed false"
165
+ )
166
+
167
+ generate_btn = gr.Button("🚀 Generate", variant="primary")
168
+
169
+ with gr.Column():
170
+ status = gr.Textbox(label="Status", lines=3)
171
+ video = gr.Video(label="Generated Video")
172
+ video_url = gr.Textbox(label="Video URL")
173
+
174
+ # Example prompts
175
+ gr.Markdown("---")
176
+ with gr.Row():
177
+ gr.Button("🌄 Nature").click(
178
+ fn=lambda: "Aerial drone shot over mountains at sunrise, cinematic --duration 5 --camerafixed false",
179
+ outputs=prompt
180
+ )
181
+ gr.Button("🏙️ City").click(
182
+ fn=lambda: "Fast drone racing through futuristic city streets --duration 5 --camerafixed false",
183
+ outputs=prompt
184
+ )
185
+ gr.Button("🌊 Ocean").click(
186
+ fn=lambda: "Drone following waves at golden hour --duration 5 --camerafixed false",
187
+ outputs=prompt
188
+ )
189
+
190
+ # Generate
191
+ generate_btn.click(
192
+ fn=generate_video,
193
+ inputs=[prompt, image_url, model_id],
194
+ outputs=[status, video]
195
+ ).then(
196
+ fn=lambda v: v if v else "",
197
+ inputs=[video],
198
+ outputs=[video_url]
199
+ )
200
+
201
+ if __name__ == "__main__":
202
+ demo.launch(server_name="0.0.0.0")