MySafeCode commited on
Commit
eada439
·
verified ·
1 Parent(s): 517b5dc

Create app5.py

Browse files
Files changed (1) hide show
  1. app5.py +351 -0
app5.py ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import time
4
+ import json
5
+ from PIL import Image
6
+ import logging
7
+
8
+ # Set up logging
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # Import BytePlus SDK
13
+ try:
14
+ import byteplussdkcore
15
+ from byteplussdkarkruntime import Ark
16
+ SDK_AVAILABLE = True
17
+ logger.info("✅ BytePlus SDK loaded successfully")
18
+ except ImportError as e:
19
+ SDK_AVAILABLE = False
20
+ logger.warning(f"⚠️ BytePlus SDK not available: {e}")
21
+
22
+ def initialize_sdk_config():
23
+ """Initialize SDK configuration as per docs"""
24
+ try:
25
+ configuration = byteplussdkcore.Configuration()
26
+ configuration.client_side_validation = True
27
+ configuration.schema = "http"
28
+ configuration.debug = False
29
+ configuration.logger_file = "sdk.log"
30
+ byteplussdkcore.Configuration.set_default(configuration)
31
+ return True
32
+ except Exception as e:
33
+ logger.error(f"SDK config error: {e}")
34
+ return False
35
+
36
+ def generate_video(api_key, prompt_text, image_url, model_id, progress=gr.Progress()):
37
+ """Generate video using the BytePlus SDK"""
38
+
39
+ if not api_key or api_key == "key":
40
+ yield "⚠️ Please enter your actual BytePlus API key (the 'key' is just a placeholder)", None
41
+ return
42
+
43
+ if not SDK_AVAILABLE:
44
+ yield "❌ BytePlus SDK not available. Please check installation of byteplus-python-sdk-v2", None
45
+ return
46
+
47
+ try:
48
+ progress(0, desc="Initializing SDK...")
49
+ # Initialize SDK config
50
+ initialize_sdk_config()
51
+
52
+ # Set environment variable as per original code
53
+ os.environ["ARK_API_KEY"] = api_key
54
+
55
+ # Initialize client
56
+ client = Ark(
57
+ base_url="https://ark.ap-southeast.bytepluses.com/api/v3",
58
+ api_key=os.environ.get("ARK_API_KEY"),
59
+ )
60
+
61
+ progress(0.1, desc="Creating video generation request...")
62
+ logger.info("🚀 Creating video generation request...")
63
+
64
+ # Create task as per original code
65
+ create_result = client.content_generation.tasks.create(
66
+ model=model_id,
67
+ content=[
68
+ {
69
+ "type": "text",
70
+ "text": prompt_text
71
+ },
72
+ {
73
+ "type": "image_url",
74
+ "image_url": {
75
+ "url": image_url
76
+ }
77
+ }
78
+ ]
79
+ )
80
+
81
+ task_id = create_result.id
82
+ logger.info(f"📋 Task ID: {task_id}")
83
+
84
+ yield f"⏳ Task created with ID: {task_id}. Waiting for completion...", None
85
+
86
+ # Polling as per original code
87
+ max_attempts = 60
88
+ attempts = 0
89
+
90
+ while attempts < max_attempts:
91
+ progress(0.1 + (attempts / max_attempts) * 0.8,
92
+ desc=f"Polling status: {attempts + 1}/{max_attempts}")
93
+
94
+ get_result = client.content_generation.tasks.get(task_id=task_id)
95
+ status = get_result.status
96
+
97
+ if status == "succeeded":
98
+ progress(1.0, desc="Complete!")
99
+ logger.info("✅ Task succeeded!")
100
+ # Try to extract video URL
101
+ video_url = None
102
+ if hasattr(get_result, 'output') and get_result.output:
103
+ if isinstance(get_result.output, list) and len(get_result.output) > 0:
104
+ video_url = get_result.output[0].get('video_url')
105
+ elif hasattr(get_result.output, 'video_url'):
106
+ video_url = get_result.output.video_url
107
+ elif isinstance(get_result.output, dict):
108
+ video_url = get_result.output.get('video_url')
109
+
110
+ if video_url:
111
+ yield f"✅ Video generated successfully!", video_url
112
+ else:
113
+ # If no URL, show the full result for debugging
114
+ result_str = str(get_result)
115
+ yield f"✅ Task completed. Response: {result_str[:500]}...", None
116
+ break
117
+
118
+ elif status == "failed":
119
+ error_msg = get_result.error if hasattr(get_result, 'error') else "Unknown error"
120
+ yield f"❌ Task failed: {error_msg}", None
121
+ break
122
+ else:
123
+ yield f"⏳ Current status: {status}, waiting... ({attempts + 1}/{max_attempts})", None
124
+ time.sleep(1)
125
+ attempts += 1
126
+
127
+ if attempts >= max_attempts:
128
+ yield "⏰ Timeout: Task took too long to complete. Please try again.", None
129
+
130
+ except Exception as e:
131
+ logger.error(f"Error: {e}")
132
+ yield f"❌ Error: {str(e)}", None
133
+
134
+ # Custom CSS for better UI
135
+ custom_css = """
136
+ .gradio-container {
137
+ max-width: 1200px !important;
138
+ margin: auto !important;
139
+ }
140
+ .video-container {
141
+ border-radius: 8px;
142
+ overflow: hidden;
143
+ }
144
+ .status-box {
145
+ background: #f5f5f5;
146
+ border-radius: 8px;
147
+ padding: 10px;
148
+ margin: 10px 0;
149
+ }
150
+ """
151
+
152
+ # Create Gradio interface with latest features
153
+ with gr.Blocks(
154
+ title="BytePlus Video Generator",
155
+ theme=gr.themes.Soft(
156
+ primary_hue="blue",
157
+ secondary_hue="purple",
158
+ ),
159
+ css=custom_css
160
+ ) as demo:
161
+
162
+ gr.Markdown("""
163
+ # 🎥 BytePlus Video Generator
164
+ Generate stunning videos from images and text prompts using BytePlus AI
165
+
166
+ ### 📊 System Status
167
+ """)
168
+
169
+ # SDK Status with modern indicator
170
+ with gr.Row():
171
+ if SDK_AVAILABLE:
172
+ gr.Markdown("✅ **SDK Status:** Connected to BytePlus SDK")
173
+ else:
174
+ gr.Markdown("❌ **SDK Status:** SDK not available")
175
+
176
+ gr.Markdown("---")
177
+
178
+ with gr.Row():
179
+ with gr.Column(scale=1, variant="panel"):
180
+ # API Key input with better UX
181
+ api_key = gr.Textbox(
182
+ label="🔑 BytePlus API Key",
183
+ placeholder="Enter your BytePlus API key here",
184
+ type="password",
185
+ value="key",
186
+ info="Your API key will be set as ARK_API_KEY environment variable",
187
+ container=True,
188
+ scale=1
189
+ )
190
+
191
+ # Model ID with examples
192
+ model_id = gr.Dropdown(
193
+ label="🤖 Model Selection",
194
+ choices=[
195
+ "seedance-1-5-pro-251215",
196
+ "seedance-1-5-pro-251215-v2",
197
+ "byteplus-video-v1"
198
+ ],
199
+ value="seedance-1-5-pro-251215",
200
+ info="Select the model for video generation",
201
+ allow_custom_value=True
202
+ )
203
+
204
+ # Image URL input with preview
205
+ with gr.Group():
206
+ image_url_input = gr.Textbox(
207
+ label="🔗 Image URL",
208
+ placeholder="Enter public image URL",
209
+ value="https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png",
210
+ info="Image must be publicly accessible"
211
+ )
212
+
213
+ image_preview = gr.Image(
214
+ label="Image Preview",
215
+ type="pil",
216
+ height=200,
217
+ interactive=False
218
+ )
219
+
220
+ # Text prompt with character count
221
+ prompt_input = gr.Textbox(
222
+ label="📝 Text Prompt",
223
+ placeholder="Describe your video...",
224
+ value="At breakneck speed, drones thread through intricate obstacles or stunning natural wonders, delivering an immersive, heart-pounding flying experience. --duration 5 --camerafixed false",
225
+ lines=4,
226
+ max_lines=6,
227
+ show_copy_button=True
228
+ )
229
+
230
+ # Generate button with loading state
231
+ generate_btn = gr.Button(
232
+ "🚀 Generate Video",
233
+ variant="primary",
234
+ size="lg"
235
+ )
236
+
237
+ with gr.Column(scale=1, variant="panel"):
238
+ # Status output with better styling
239
+ status_output = gr.Textbox(
240
+ label="📊 Generation Status",
241
+ lines=5,
242
+ show_copy_button=True,
243
+ container=True
244
+ )
245
+
246
+ # Video output with player
247
+ with gr.Group(elem_classes="video-container"):
248
+ video_output = gr.Video(
249
+ label="🎬 Generated Video",
250
+ interactive=False,
251
+ show_download_button=True,
252
+ show_share_button=True
253
+ )
254
+
255
+ # Video URL with copy button
256
+ video_url_output = gr.Textbox(
257
+ label="🔗 Video URL",
258
+ interactive=False,
259
+ show_copy_button=True
260
+ )
261
+
262
+ # Example prompts section with gallery
263
+ gr.Markdown("---")
264
+ gr.Markdown("## 📋 Example Prompts")
265
+
266
+ with gr.Row():
267
+ with gr.Column():
268
+ example1 = gr.Button("🌄 Nature Drone", size="sm")
269
+ gr.Markdown("Aerial shot over mountains at sunrise")
270
+ with gr.Column():
271
+ example2 = gr.Button("🏙️ City Racing", size="sm")
272
+ gr.Markdown("Fast drone racing through neon city")
273
+ with gr.Column():
274
+ example3 = gr.Button("🌊 Ocean Waves", size="sm")
275
+ gr.Markdown("Drone following surfers on waves")
276
+
277
+ # Function to update image preview
278
+ def update_preview(url):
279
+ try:
280
+ if url and url.startswith(('http://', 'https://')):
281
+ from PIL import Image
282
+ import requests
283
+ from io import BytesIO
284
+
285
+ response = requests.get(url, timeout=5)
286
+ img = Image.open(BytesIO(response.content))
287
+ return img
288
+ return None
289
+ except:
290
+ return None
291
+
292
+ # Event handlers
293
+ def set_nature():
294
+ return "Aerial drone shot flying over majestic mountains at sunrise, cinematic lighting, smooth motion --duration 5 --camerafixed false"
295
+
296
+ def set_city():
297
+ return "Fast-paced drone racing through futuristic city streets with neon lights, dynamic angles, high speed --duration 5 --camerafixed false"
298
+
299
+ def set_ocean():
300
+ return "Drone following surfers riding massive waves, slow motion, dramatic ocean views, golden hour --duration 5 --camerafixed false"
301
+
302
+ # Connect events
303
+ image_url_input.change(
304
+ fn=update_preview,
305
+ inputs=image_url_input,
306
+ outputs=image_preview
307
+ )
308
+
309
+ example1.click(fn=set_nature, outputs=prompt_input)
310
+ example2.click(fn=set_city, outputs=prompt_input)
311
+ example3.click(fn=set_ocean, outputs=prompt_input)
312
+
313
+ # Generate with progress bar
314
+ generate_event = generate_btn.click(
315
+ fn=generate_video,
316
+ inputs=[api_key, prompt_input, image_url_input, model_id],
317
+ outputs=[status_output, video_output],
318
+ show_progress='full'
319
+ )
320
+
321
+ # Update video URL when video changes
322
+ generate_event.then(
323
+ fn=lambda url: url if url else "No URL available",
324
+ inputs=[video_output],
325
+ outputs=[video_url_output]
326
+ )
327
+
328
+ # Clear button with confirmation
329
+ clear_btn = gr.Button("🗑️ Clear All", variant="secondary", size="sm")
330
+ clear_btn.click(
331
+ fn=lambda: (
332
+ "https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png",
333
+ "Enter your prompt here...",
334
+ "",
335
+ None,
336
+ ""
337
+ ),
338
+ outputs=[image_url_input, prompt_input, status_output, video_output, video_url_output]
339
+ )
340
+
341
+ # Add footer
342
+ gr.Markdown("---")
343
+ gr.Markdown("""
344
+ <div style='text-align: center'>
345
+ <p>Powered by BytePlus SDK | Updated with Gradio 5.23.3</p>
346
+ <p style='font-size: 0.8em; color: gray;'>Images must be publicly accessible. Generation takes 30-60 seconds.</p>
347
+ </div>
348
+ """)
349
+
350
+ if __name__ == "__main__":
351
+ demo.launch()