Let me try again, I only managed to do it once,,,

#22
Files changed (1) hide show
  1. app.py +47 -117
app.py CHANGED
@@ -4,84 +4,44 @@ from huggingface_hub import InferenceClient
4
  import tempfile
5
  import shutil
6
  from pathlib import Path
7
- from typing import Optional, Union
8
- import time
9
 
10
- # -------------------------
11
- # Utilities
12
- # -------------------------
 
 
 
13
 
14
- def cleanup_temp_files():
15
- try:
16
- temp_dir = tempfile.gettempdir()
17
- for file_path in Path(temp_dir).glob("*.mp4"):
18
- try:
19
- if file_path.stat().st_mtime < (time.time() - 300):
20
- file_path.unlink(missing_ok=True)
21
- except Exception:
22
- pass
23
- except Exception as e:
24
- print(f"Cleanup error: {e}")
25
-
26
- def _client_from_token(token: Optional[str]) -> InferenceClient:
27
- if not token:
28
- raise gr.Error("Please sign in first. This app requires your Hugging Face login.")
29
- # IMPORTANT: do not set bill_to when using user OAuth tokens
30
- return InferenceClient(
31
- provider="fal-ai",
32
- api_key=token,
33
- )
34
-
35
- def _save_bytes_as_temp_mp4(data: bytes) -> str:
36
- temp_file = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
37
- try:
38
- temp_file.write(data)
39
- temp_file.flush()
40
- return temp_file.name
41
- finally:
42
- temp_file.close()
43
-
44
- def text_to_video(prompt, token: gr.OAuthToken | None, duration=5, aspect_ratio="16:9", resolution="720p", *_):
45
  """Generate video from text prompt"""
46
  try:
47
- if token is None or not getattr(token, "token", None):
48
- return None, "❌ Sign in with Hugging Face to continue. This app uses your inference provider credits."
49
 
50
  if not prompt or prompt.strip() == "":
51
  return None, "Please enter a text prompt"
52
 
53
- cleanup_temp_files()
54
-
55
- # Create client with user's token
56
- client = _client_from_token(token.token)
57
-
58
  # Generate video from text
59
- try:
60
- video = client.text_to_video(
61
- prompt,
62
- model="akhaliq/veo3.1-fast",
63
- )
64
- except Exception as e:
65
- import requests
66
- if isinstance(e, requests.HTTPError) and getattr(e.response, "status_code", None) == 403:
67
- return None, "❌ Access denied by provider (403). Make sure your HF account has credits/permission for provider 'fal-ai' and model 'akhaliq/veo3.1-fast'."
68
- raise
69
 
70
  # Save the video to a temporary file
71
- video_path = _save_bytes_as_temp_mp4(video)
 
 
72
 
73
  return video_path, f"✅ Video generated successfully from prompt: '{prompt[:50]}...'"
74
 
75
- except gr.Error as e:
76
- return None, f"❌ {str(e)}"
77
  except Exception as e:
78
- return None, f"❌ Generation failed. If this keeps happening, check your provider quota or try again later."
79
 
80
- def image_to_video(image, prompt, token: gr.OAuthToken | None, duration=5, aspect_ratio="16:9", resolution="720p", *_):
81
  """Generate video from image and prompt"""
82
  try:
83
- if token is None or not getattr(token, "token", None):
84
- return None, "❌ Sign in with Hugging Face to continue. This app uses your inference provider credits."
85
 
86
  if image is None:
87
  return None, "Please upload an image"
@@ -89,8 +49,6 @@ def image_to_video(image, prompt, token: gr.OAuthToken | None, duration=5, aspec
89
  if not prompt or prompt.strip() == "":
90
  return None, "Please enter a prompt describing the motion"
91
 
92
- cleanup_temp_files()
93
-
94
  # Read the image file
95
  if isinstance(image, str):
96
  # If image is a file path
@@ -113,31 +71,22 @@ def image_to_video(image, prompt, token: gr.OAuthToken | None, duration=5, aspec
113
  pil_image.save(buffer, format='PNG')
114
  input_image = buffer.getvalue()
115
 
116
- # Create client with user's token
117
- client = _client_from_token(token.token)
118
-
119
  # Generate video from image
120
- try:
121
- video = client.image_to_video(
122
- input_image,
123
- prompt=prompt,
124
- model="akhaliq/veo3.1-fast-image-to-video",
125
- )
126
- except Exception as e:
127
- import requests
128
- if isinstance(e, requests.HTTPError) and getattr(e.response, "status_code", None) == 403:
129
- return None, "❌ Access denied by provider (403). Make sure your HF account has credits/permission for provider 'fal-ai' and model 'akhaliq/veo3.1-fast-image-to-video'."
130
- raise
131
 
132
  # Save the video to a temporary file
133
- video_path = _save_bytes_as_temp_mp4(video)
 
 
134
 
135
  return video_path, f"✅ Video generated successfully with motion: '{prompt[:50]}...'"
136
 
137
- except gr.Error as e:
138
- return None, f"❌ {str(e)}"
139
  except Exception as e:
140
- return None, f"❌ Generation failed. If this keeps happening, check your provider quota or try again later."
141
 
142
  def clear_text_tab():
143
  """Clear text-to-video tab"""
@@ -166,15 +115,14 @@ custom_css = """
166
  border-radius: 5px;
167
  margin-top: 10px;
168
  }
169
- .notice {
170
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
171
- color: white;
172
- padding: 14px 16px;
173
- border-radius: 12px;
174
- margin: 18px auto 6px;
175
- max-width: 860px;
176
  text-align: center;
177
- font-size: 0.98rem;
 
 
 
178
  }
179
  .mobile-link-container {
180
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@@ -208,22 +156,12 @@ custom_css = """
208
  """
209
 
210
  # Create the Gradio interface
211
- with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator (Paid)") as demo:
212
-
213
- gr.HTML(
214
  """
215
- <div style="text-align:center; max-width:900px; margin:0 auto;">
216
- <h1 style="font-size:2.2em; margin-bottom:6px;">Veo 3.1 Fast</h1>
217
- <p style="color:#777; margin:0 0 8px;">Generate videos via the Hugging Face Inference Providers</p>
218
- <div class="notice">
219
- <b>Heads up:</b> This is a paid app that uses <b>your</b> inference provider credits when you run generations.
220
- Free users get <b>$0.10 in included credits</b>. <b>PRO users</b> get <b>$2 in included credits</b>
221
- and can continue using beyond that (with billing).
222
- <a href='http://huggingface.co/subscribe/pro?source=veo3' target='_blank' style='color:#fff; text-decoration:underline; font-weight:bold;'>Subscribe to PRO</a>
223
- for more credits. Please sign in with your Hugging Face account to continue.
224
- <br><a href='https://huggingface.co/settings/inference-providers/overview' target='_blank' style='color:#fff; text-decoration:underline; font-weight:bold;'>Check your billing usage here</a>
225
- </div>
226
- </div>
227
  """
228
  )
229
 
@@ -241,14 +179,14 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator
241
 
242
  gr.HTML(
243
  """
244
- <p style="text-align: center; font-size: 0.9em; color: #999; margin-top: 10px;">
245
- Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color:#667eea; text-decoration:underline;">anycoder</a>
246
- </p>
247
  """
248
  )
249
 
250
  # Add login button - required for OAuth
251
- login_btn = gr.LoginButton("Sign in with Hugging Face")
252
 
253
  with gr.Tabs() as tabs:
254
  # Text-to-Video Tab
@@ -378,7 +316,7 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator
378
  # Event handlers
379
  text_generate_btn.click(
380
  fn=text_to_video,
381
- inputs=[text_prompt, login_btn],
382
  outputs=[text_video_output, text_status],
383
  show_progress="full",
384
  queue=False,
@@ -395,7 +333,7 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator
395
 
396
  image_generate_btn.click(
397
  fn=image_to_video,
398
- inputs=[image_input, image_prompt, login_btn],
399
  outputs=[image_video_output, image_status],
400
  show_progress="full",
401
  queue=False,
@@ -412,14 +350,6 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator
412
 
413
  # Launch the app
414
  if __name__ == "__main__":
415
- try:
416
- cleanup_temp_files()
417
- if os.path.exists("gradio_cached_examples"):
418
- shutil.rmtree("gradio_cached_examples", ignore_errors=True)
419
- except Exception as e:
420
- print(f"Initial cleanup error: {e}")
421
-
422
- demo.queue(status_update_rate="auto", api_open=False, default_concurrency_limit=None)
423
  demo.launch(
424
  show_api=False,
425
  share=False,
 
4
  import tempfile
5
  import shutil
6
  from pathlib import Path
 
 
7
 
8
+ # Initialize the client
9
+ client = InferenceClient(
10
+ provider="fal-ai",
11
+ api_key=os.environ.get("HF_TOKEN"),
12
+ bill_to="huggingface",
13
+ )
14
 
15
+ def text_to_video(prompt, duration=5, aspect_ratio="16:9", resolution="720p", profile: gr.OAuthProfile | None = None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  """Generate video from text prompt"""
17
  try:
18
+ if profile is None:
19
+ return None, "❌ Click Sign in with Hugging Face button to use this app for free"
20
 
21
  if not prompt or prompt.strip() == "":
22
  return None, "Please enter a text prompt"
23
 
 
 
 
 
 
24
  # Generate video from text
25
+ video = client.text_to_video(
26
+ prompt,
27
+ model="akhaliq/veo3.1-fast",
28
+ )
 
 
 
 
 
 
29
 
30
  # Save the video to a temporary file
31
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_file:
32
+ tmp_file.write(video)
33
+ video_path = tmp_file.name
34
 
35
  return video_path, f"✅ Video generated successfully from prompt: '{prompt[:50]}...'"
36
 
 
 
37
  except Exception as e:
38
+ return None, f"❌ Error generating video: {str(e)}"
39
 
40
+ def image_to_video(image, prompt, duration=5, aspect_ratio="16:9", resolution="720p", profile: gr.OAuthProfile | None = None):
41
  """Generate video from image and prompt"""
42
  try:
43
+ if profile is None:
44
+ return None, "❌ Click Sign in with Hugging Face button to use this app for free"
45
 
46
  if image is None:
47
  return None, "Please upload an image"
 
49
  if not prompt or prompt.strip() == "":
50
  return None, "Please enter a prompt describing the motion"
51
 
 
 
52
  # Read the image file
53
  if isinstance(image, str):
54
  # If image is a file path
 
71
  pil_image.save(buffer, format='PNG')
72
  input_image = buffer.getvalue()
73
 
 
 
 
74
  # Generate video from image
75
+ video = client.image_to_video(
76
+ input_image,
77
+ prompt=prompt,
78
+ model="akhaliq/veo3.1-fast-image-to-video",
79
+ )
 
 
 
 
 
 
80
 
81
  # Save the video to a temporary file
82
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_file:
83
+ tmp_file.write(video)
84
+ video_path = tmp_file.name
85
 
86
  return video_path, f"✅ Video generated successfully with motion: '{prompt[:50]}...'"
87
 
 
 
88
  except Exception as e:
89
+ return None, f"❌ Error generating video: {str(e)}"
90
 
91
  def clear_text_tab():
92
  """Clear text-to-video tab"""
 
115
  border-radius: 5px;
116
  margin-top: 10px;
117
  }
118
+ .auth-warning {
119
+ color: #ff6b00;
120
+ font-weight: bold;
 
 
 
 
121
  text-align: center;
122
+ margin: 1em 0;
123
+ padding: 1em;
124
+ background-color: #fff3e0;
125
+ border-radius: 5px;
126
  }
127
  .mobile-link-container {
128
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
156
  """
157
 
158
  # Create the Gradio interface
159
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator") as demo:
160
+ gr.Markdown(
 
161
  """
162
+ # 🎬 AI Video Generator
163
+ ### Generate stunning videos from text or animate your images with AI
164
+ #### Powered by VEO 3.1 Fast Model | [Built with anycoder](https://huggingface.co/spaces/akhaliq/anycoder)
 
 
 
 
 
 
 
 
 
165
  """
166
  )
167
 
 
179
 
180
  gr.HTML(
181
  """
182
+ <div class="auth-warning">
183
+ ⚠️ You must Sign in with Hugging Face using the button below to use this app.
184
+ </div>
185
  """
186
  )
187
 
188
  # Add login button - required for OAuth
189
+ gr.LoginButton()
190
 
191
  with gr.Tabs() as tabs:
192
  # Text-to-Video Tab
 
316
  # Event handlers
317
  text_generate_btn.click(
318
  fn=text_to_video,
319
+ inputs=[text_prompt],
320
  outputs=[text_video_output, text_status],
321
  show_progress="full",
322
  queue=False,
 
333
 
334
  image_generate_btn.click(
335
  fn=image_to_video,
336
+ inputs=[image_input, image_prompt],
337
  outputs=[image_video_output, image_status],
338
  show_progress="full",
339
  queue=False,
 
350
 
351
  # Launch the app
352
  if __name__ == "__main__":
 
 
 
 
 
 
 
 
353
  demo.launch(
354
  show_api=False,
355
  share=False,