MySafeCode commited on
Commit
bc714d3
·
verified ·
1 Parent(s): f4e46e5

Update app7.py

Browse files
Files changed (1) hide show
  1. app7.py +96 -327
app7.py CHANGED
@@ -1,377 +1,146 @@
1
  import gradio as gr
 
2
  import os
3
  import time
4
- import json
5
- from PIL import Image
6
  import logging
7
- import sys
 
8
 
9
  # Set up logging
10
  logging.basicConfig(level=logging.INFO)
11
  logger = logging.getLogger(__name__)
12
 
13
- # Print versions for debugging
14
- logger.info(f"Gradio version: {gr.__version__}")
15
- logger.info(f"Python version: {sys.version}")
16
-
17
- # Get API key from environment variable "Key"
18
- api_key = os.environ.get("Key", "")
19
- if not api_key:
20
- logger.warning("⚠️ API Key not set in environment variable 'Key'!")
21
- logger.info("Will use input field instead")
22
- else:
23
- logger.info("✅ API Key loaded from environment")
24
 
25
- # Import BytePlus SDK
26
- try:
27
- import byteplussdkcore
28
- from byteplussdkarkruntime import Ark
29
- SDK_AVAILABLE = True
30
- logger.info("✅ BytePlus SDK loaded successfully")
31
- except ImportError as e:
32
- SDK_AVAILABLE = False
33
- logger.warning(f"⚠️ BytePlus SDK not available: {e}")
 
34
 
35
- def initialize_sdk_config():
36
- """Initialize SDK configuration as per docs"""
37
- try:
38
- configuration = byteplussdkcore.Configuration()
39
- configuration.client_side_validation = True
40
- configuration.schema = "http"
41
- configuration.debug = False
42
- configuration.logger_file = "sdk.log"
43
- byteplussdkcore.Configuration.set_default(configuration)
44
- return True
45
- except Exception as e:
46
- logger.error(f"SDK config error: {e}")
47
- return False
48
-
49
- def generate_video(input_api_key, prompt_text, image_url, model_id, progress=gr.Progress()):
50
- """Generate video using the BytePlus SDK"""
51
-
52
- # Use input API key if provided and not "key", otherwise fall back to environment variable
53
- effective_api_key = input_api_key if input_api_key and input_api_key != "key" else api_key
54
-
55
- if not effective_api_key:
56
- yield "⚠️ Please enter your BytePlus API key or set it in the 'Key' environment variable", None
57
- return
58
 
59
- if not SDK_AVAILABLE:
60
- yield "❌ BytePlus SDK not available. Please check installation.", None
61
  return
62
 
63
  try:
64
- progress(0, desc="Initializing SDK...")
65
-
66
- # Initialize SDK config
67
- try:
68
- initialize_sdk_config()
69
- except:
70
- pass # Continue even if config fails
71
-
72
- # Set environment variable for SDK (it expects ARK_API_KEY)
73
- os.environ["ARK_API_KEY"] = effective_api_key
74
-
75
- # Initialize client
76
- client = Ark(
77
- base_url="https://ark.ap-southeast.bytepluses.com/api/v3",
78
- api_key=os.environ.get("ARK_API_KEY"),
79
- )
80
-
81
- progress(0.1, desc="Creating video generation request...")
82
- logger.info("🚀 Creating video generation request...")
83
-
84
- # Create task
85
- create_result = client.content_generation.tasks.create(
86
- model=model_id,
87
- content=[
88
- {
89
- "type": "text",
90
- "text": prompt_text
91
- },
92
- {
93
- "type": "image_url",
94
- "image_url": {
95
- "url": image_url
96
- }
97
- }
98
- ]
99
- )
100
-
101
- task_id = create_result.id
102
- logger.info(f"📋 Task ID: {task_id}")
103
 
104
- yield f"⏳ Task created with ID: {task_id}. Waiting for completion...", None
 
 
 
 
 
105
 
106
- # Polling
107
- max_attempts = 60
108
- attempts = 0
 
109
 
110
- while attempts < max_attempts:
111
- progress(0.1 + (attempts / max_attempts) * 0.8,
112
- desc=f"Polling status: {attempts + 1}/{max_attempts}")
113
-
114
- get_result = client.content_generation.tasks.get(task_id=task_id)
115
- status = get_result.status
116
-
117
- if status == "succeeded":
118
- progress(1.0, desc="Complete!")
119
- logger.info("✅ Task succeeded!")
120
-
121
- # Extract video URL
122
- video_url = None
123
- if hasattr(get_result, 'output') and get_result.output:
124
- if isinstance(get_result.output, list) and len(get_result.output) > 0:
125
- video_url = get_result.output[0].get('video_url')
126
- elif hasattr(get_result.output, 'video_url'):
127
- video_url = get_result.output.video_url
128
- elif isinstance(get_result.output, dict):
129
- video_url = get_result.output.get('video_url')
130
-
131
- if video_url:
132
- yield f"✅ Video generated successfully!", video_url
133
- else:
134
- yield f"✅ Task completed but no video URL in response", None
135
- break
136
-
137
- elif status == "failed":
138
- error_msg = get_result.error if hasattr(get_result, 'error') else "Unknown error"
139
- yield f"❌ Task failed: {error_msg}", None
140
- break
141
- else:
142
- yield f"⏳ Current status: {status}, waiting... ({attempts + 1}/{max_attempts})", None
143
- time.sleep(1)
144
- attempts += 1
145
 
146
- if attempts >= max_attempts:
147
- yield "⏰ Timeout: Task took too long to complete. Please try again.", None
148
-
149
  except Exception as e:
150
- logger.error(f"Error: {e}")
151
  yield f"❌ Error: {str(e)}", None
152
 
153
- # Custom CSS
154
- custom_css = """
155
- .gradio-container {
156
- max-width: 1200px !important;
157
- margin: auto !important;
158
- }
159
- .video-container {
160
- border-radius: 8px;
161
- overflow: hidden;
162
- }
163
- .env-badge {
164
- background: #e3f2fd;
165
- color: #0d47a1;
166
- padding: 5px 10px;
167
- border-radius: 4px;
168
- font-size: 0.9em;
169
- margin-bottom: 10px;
170
- }
171
- """
172
-
173
- # Create Gradio interface
174
- with gr.Blocks(title="BytePlus Video Generator", fill_width=True) as demo:
175
 
176
  gr.Markdown("""
177
  # 🎥 BytePlus Video Generator
178
- Generate stunning videos from images and text prompts using BytePlus AI
179
  """)
180
 
181
- # Show API key source
182
- if api_key:
183
- gr.Markdown(f"""
184
- <div class="env-badge">
185
- ✅ API Key loaded from environment variable 'Key'
186
- </div>
187
- """)
188
- else:
189
- gr.Markdown("""
190
- <div class="env-badge" style="background: #fff3e0; color: #bf360c;">
191
- ⚠️ No API Key in environment variable 'Key'. Please enter below.
192
- </div>
193
- """)
194
-
195
- # SDK Status
196
- with gr.Row():
197
- if SDK_AVAILABLE:
198
- gr.Markdown("✅ **SDK Status:** Connected to BytePlus SDK")
199
- else:
200
- gr.Markdown("❌ **SDK Status:** SDK not available")
201
-
202
- gr.Markdown("---")
203
-
204
  with gr.Row():
205
- with gr.Column(scale=1):
206
- # API Key input - will use env var as default if available
207
- api_key_input = gr.Textbox(
208
- label="🔑 BytePlus API Key",
209
- placeholder="Enter your BytePlus API key here",
210
- type="password",
211
- value="" if api_key else "key", # Empty if env var exists, otherwise "key"
212
- info="Using env var 'Key' by default. Enter only to override."
213
- )
214
-
215
- # Model ID
216
- model_id = gr.Textbox(
217
- label="🤖 Model ID",
218
- value="seedance-1-5-pro-251215",
219
- info="Model ID for video generation"
220
- )
221
-
222
- # Image URL input
223
- image_url = gr.Textbox(
224
- label="🔗 Image URL",
225
- placeholder="Enter public image URL",
226
- value="https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png",
227
- info="Image must be publicly accessible"
228
- )
229
-
230
- # Image preview
231
- image_preview = gr.Image(
232
- label="Image Preview",
233
  type="pil",
234
- height=200
235
  )
236
 
237
  # Text prompt
238
  prompt = gr.Textbox(
239
- label="📝 Text Prompt",
240
- placeholder="Describe your video...",
241
- value="At breakneck speed, drones thread through intricate obstacles or stunning natural wonders, delivering an immersive, heart-pounding flying experience. --duration 5 --camerafixed false",
242
- lines=4
 
 
 
 
 
 
 
243
  )
244
 
245
  # Generate button
246
  generate_btn = gr.Button("🚀 Generate Video", variant="primary", size="lg")
247
 
248
- with gr.Column(scale=1):
249
- # Status output
250
  status = gr.Textbox(
251
- label="📊 Generation Status",
252
- lines=5
253
- )
254
-
255
- # Video output - REMOVED the unsupported parameters
256
- video = gr.Video(
257
- label="🎬 Generated Video"
258
- # show_download_button and show_share_button removed as they're not in Gradio 6.5.1
259
- )
260
-
261
- # Video URL
262
- video_url = gr.Textbox(
263
- label="🔗 Video URL",
264
  interactive=False
265
  )
266
 
267
- # Add download button separately if needed
268
- with gr.Row():
269
- download_btn = gr.DownloadButton(
270
- label="📥 Download Video",
271
- variant="secondary",
272
- visible=False # Hidden until video is generated
273
- )
274
 
275
- # Example prompts
276
  gr.Markdown("---")
277
- gr.Markdown("## 📋 Example Prompts")
278
-
279
  with gr.Row():
280
- example1 = gr.Button("🌄 Nature Drone", size="sm")
281
- example2 = gr.Button("🏙️ City Racing", size="sm")
282
- example3 = gr.Button("🌊 Ocean Waves", size="sm")
283
-
284
- # Function to update image preview
285
- def update_preview(url):
286
- try:
287
- if url and url.startswith(('http://', 'https://')):
288
- import requests
289
- from io import BytesIO
290
-
291
- response = requests.get(url, timeout=5)
292
- img = Image.open(BytesIO(response.content))
293
- return img
294
- return None
295
- except Exception as e:
296
- logger.error(f"Preview error: {e}")
297
- return None
298
-
299
- # Example prompt functions
300
- def set_nature():
301
- return "Aerial drone shot flying over majestic mountains at sunrise, cinematic lighting, smooth motion --duration 5 --camerafixed false"
302
-
303
- def set_city():
304
- return "Fast-paced drone racing through futuristic city streets with neon lights, dynamic angles, high speed --duration 5 --camerafixed false"
305
-
306
- def set_ocean():
307
- return "Drone following surfers riding massive waves, slow motion, dramatic ocean views, golden hour --duration 5 --camerafixed false"
308
-
309
- # Function to update download button when video is generated
310
- def update_download_button(video_path):
311
- if video_path and video_path != "None" and video_path != "":
312
- return gr.update(visible=True, value=video_path)
313
- return gr.update(visible=False)
314
-
315
- # Connect events
316
- image_url.change(
317
- fn=update_preview,
318
- inputs=image_url,
319
- outputs=image_preview
320
- )
321
-
322
- example1.click(fn=set_nature, outputs=prompt)
323
- example2.click(fn=set_city, outputs=prompt)
324
- example3.click(fn=set_ocean, outputs=prompt)
325
-
326
- # Generate
327
- generate_event = generate_btn.click(
328
- fn=generate_video,
329
- inputs=[api_key_input, prompt, image_url, model_id],
330
- outputs=[status, video]
331
- )
332
-
333
- # Update video URL and download button
334
- generate_event.then(
335
- fn=lambda url: url if url else "",
336
- inputs=[video],
337
- outputs=[video_url]
338
- ).then(
339
- fn=update_download_button,
340
- inputs=[video],
341
- outputs=[download_btn]
342
- )
343
-
344
- # Clear button
345
- clear_btn = gr.Button("🗑️ Clear", variant="secondary")
346
- clear_btn.click(
347
- fn=lambda: (
348
- "" if api_key else "key", # Reset API key input
349
- "https://ark-doc.tos-ap-southeast-1.bytepluses.com/seepro_i2v%20.png",
350
- "Enter your prompt here...",
351
- "",
352
- None,
353
- "",
354
- gr.update(visible=False)
355
- ),
356
- outputs=[api_key_input, image_url, prompt, status, video, video_url, download_btn]
357
- )
358
 
359
- # Footer
360
- gr.Markdown("---")
361
  gr.Markdown("""
362
- <div style='text-align: center'>
363
- <p>Powered by BytePlus SDK | Gradio 6.5.1</p>
364
- <p style='font-size: 0.8em; color: gray;'>API key sourced from environment variable 'Key'</p>
365
- </div>
366
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
367
 
368
  if __name__ == "__main__":
369
- demo.launch(
370
- server_name="0.0.0.0",
371
- server_port=7860,
372
- theme=gr.themes.Soft(
373
- primary_hue="blue",
374
- secondary_hue="purple",
375
- ),
376
- css=custom_css
377
- )
 
1
  import gradio as gr
2
+ import requests
3
  import os
4
  import time
 
 
5
  import logging
6
+ from PIL import Image
7
+ import io
8
 
9
  # Set up logging
10
  logging.basicConfig(level=logging.INFO)
11
  logger = logging.getLogger(__name__)
12
 
13
+ # Get API key (match your secret name - 'key' or 'Key')
14
+ API_KEY = os.environ.get("key", os.environ.get("Key", ""))
15
+ if not API_KEY:
16
+ logger.error("❌ No API key found")
 
 
 
 
 
 
 
17
 
18
+ def upload_to_temp_url(image):
19
+ """Upload image to temporary hosting and return URL"""
20
+ # For now, we'll need a temporary hosting solution
21
+ # Option 1: Use imgbb.com API (need another key)
22
+ # Option 2: Use Hugging Face's temp files (but need public URL)
23
+ # Option 3: Keep URL input for now until we set up hosting
24
+
25
+ # For simplicity now, we'll keep URL input
26
+ # But we can add image preview
27
+ return None
28
 
29
+ def generate_video(image, prompt_text, model_id, progress=gr.Progress()):
30
+ """Generate video using image upload and prompt"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ if not API_KEY:
33
+ yield "❌ API key not configured", None
34
  return
35
 
36
  try:
37
+ progress(0, desc="Preparing request...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
+ # For now, we need a publicly accessible image URL
40
+ # This is a limitation - we need to host the uploaded image somewhere
41
+ # Let's use a placeholder message until we implement hosting
42
+ if image is None:
43
+ yield "⚠️ Please upload an image", None
44
+ return
45
 
46
+ # For demo purposes, we'll keep URL input for now
47
+ # But we show the uploaded image preview
48
+ yield "⏳ Image uploaded. For now, please also provide a public URL (hosting service needed)", None
49
+ return
50
 
51
+ # The actual API call would go here once we have URL hosting
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
 
 
 
53
  except Exception as e:
54
+ logger.error(f"Error: {str(e)}")
55
  yield f"❌ Error: {str(e)}", None
56
 
57
+ # Simple, clean interface
58
+ with gr.Blocks(title="BytePlus Video Generator", theme=gr.themes.Soft()) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  gr.Markdown("""
61
  # 🎥 BytePlus Video Generator
62
+ Upload an image and describe the video you want to generate
63
  """)
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  with gr.Row():
66
+ with gr.Column():
67
+ # Image upload (input only)
68
+ image_input = gr.Image(
69
+ label="📤 Upload Starting Image",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  type="pil",
71
+ height=300
72
  )
73
 
74
  # Text prompt
75
  prompt = gr.Textbox(
76
+ label="📝 Video Description",
77
+ placeholder="Describe what you want to see...",
78
+ lines=3,
79
+ value="At breakneck speed, drones thread through intricate obstacles --duration 5 --camerafixed false"
80
+ )
81
+
82
+ # Model ID (hidden or simplified)
83
+ model_id = gr.Textbox(
84
+ label="Model ID",
85
+ value="seedance-1-5-pro-251215",
86
+ visible=False # Hide it for simplicity
87
  )
88
 
89
  # Generate button
90
  generate_btn = gr.Button("🚀 Generate Video", variant="primary", size="lg")
91
 
92
+ with gr.Column():
93
+ # Status messages
94
  status = gr.Textbox(
95
+ label="Status",
96
+ lines=2,
 
 
 
 
 
 
 
 
 
 
 
97
  interactive=False
98
  )
99
 
100
+ # Video output (player only, not uploader)
101
+ video_output = gr.Video(
102
+ label="🎬 Generated Video",
103
+ interactive=False, # Can't upload, only view
104
+ show_download_button=True, # Allow download
105
+ height=300
106
+ )
107
 
108
+ # Example prompts (optional)
109
  gr.Markdown("---")
110
+ gr.Markdown("### Example Prompts")
 
111
  with gr.Row():
112
+ gr.Button("Nature Drone").click(
113
+ fn=lambda: "Aerial drone shot over mountains at sunrise, cinematic --duration 5 --camerafixed false",
114
+ outputs=prompt
115
+ )
116
+ gr.Button("City Race").click(
117
+ fn=lambda: "Fast drone racing through futuristic city streets --duration 5 --camerafixed false",
118
+ outputs=prompt
119
+ )
120
+ gr.Button("Ocean Waves").click(
121
+ fn=lambda: "Drone following waves at golden hour --duration 5 --camerafixed false",
122
+ outputs=prompt
123
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
+ # For now, show a note about image hosting
 
126
  gr.Markdown("""
127
+ ---
128
+ ⚠️ **Note:** Currently requires publicly accessible image URLs.
129
+ Working on direct image upload support!
 
130
  """)
131
+
132
+ # Placeholder function for now
133
+ def placeholder_gen(image, prompt, model):
134
+ if image is None:
135
+ return "Please upload an image first", None
136
+ return "Image uploaded! (URL hosting coming soon)", None
137
+
138
+ # Connect the button
139
+ generate_btn.click(
140
+ fn=placeholder_gen,
141
+ inputs=[image_input, prompt, model_id],
142
+ outputs=[status, video_output]
143
+ )
144
 
145
  if __name__ == "__main__":
146
+ demo.launch(server_name="0.0.0.0")