akhaliq HF Staff commited on
Commit
b78c4e1
Β·
verified Β·
1 Parent(s): 6b2dd9c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -65
app.py CHANGED
@@ -1,8 +1,8 @@
1
  import gradio as gr
2
  import os
3
  import tempfile
4
- from typing import Optional, Tuple
5
- from huggingface_hub import InferenceClient
6
 
7
  # Initialize Hugging Face Inference Client with fal-ai provider
8
  client = InferenceClient(
@@ -11,6 +11,28 @@ client = InferenceClient(
11
  bill_to="huggingface",
12
  )
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def generate_video(
15
  prompt: str,
16
  duration: int = 8,
@@ -52,85 +74,218 @@ def generate_video(
52
  error_msg = f"❌ Error generating video: {str(e)}"
53
  return None, error_msg
54
 
55
- def simple_generate(prompt: str) -> Optional[str]:
56
- """Simplified wrapper for generate_video that only takes prompt and returns video."""
 
 
 
 
 
 
 
 
 
 
57
  if not prompt or prompt.strip() == "":
58
- return None
59
 
60
- video_path, status = generate_video(prompt, duration=8, size="1280x720", api_key=None)
 
61
 
62
- # If there's an error, you might want to handle it
63
- if video_path is None:
64
- print(f"Generation failed: {status}")
 
 
 
 
65
 
66
- return video_path
67
 
68
- def generate_with_auth(prompt: str, profile: gr.OAuthProfile | None) -> Optional[str]:
69
- """
70
- Wrapper function that checks if user is logged in before generating video.
71
- """
72
- if profile is None:
73
- raise gr.Error("Click Sign in with Hugging Face button to use this app for free")
74
 
75
- # User is logged in, proceed with video generation
76
- return simple_generate(prompt)
77
 
78
  def create_ui():
79
- """Create the Gradio interface."""
80
- with gr.Blocks(title="Sora-2 Text-to-Video Generator", theme=gr.themes.Soft()) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  gr.HTML("""
82
- <div style="text-align: center; max-width: 700px; margin: 0 auto;">
83
- <h1>🎬 Sora-2 Text-to-Video Generator</h1>
84
- <p>Generate videos using Sora-2 model hosted by FAL AI.</p>
85
- <p style='color: orange;'>⚠️ You must Sign in with Hugging Face using the button to use this app.</p>
86
- <p>Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></p>
 
 
 
 
 
87
  </div>
88
  """)
89
 
90
- # Add login button - required for OAuth
91
  gr.LoginButton()
92
 
93
- with gr.Row():
94
- with gr.Column(scale=1):
95
- prompt_input = gr.Textbox(
96
- label="Enter your prompt",
97
- placeholder="Describe the video you want to create...",
98
- lines=4
99
- )
100
- generate_btn = gr.Button("πŸŽ₯ Generate Video", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
- with gr.Column(scale=1):
103
- video_output = gr.Video(
104
- label="Generated Video",
105
- height=400,
106
- interactive=False,
107
- show_download_button=True
108
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
- # Event handler - note the function now takes OAuthProfile
111
- generate_btn.click(
112
- fn=generate_with_auth,
113
- inputs=[prompt_input],
114
- outputs=video_output,
115
- queue=False,
116
- api_name=False,
117
- show_api=False,
118
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
- # Example usage guidance with queue features disabled
121
- gr.Examples(
122
- examples=[
123
- "A serene beach at sunset with waves gently rolling onto the shore",
124
- "A butterfly emerging from its chrysalis in slow motion",
125
- "Northern lights dancing across a starry night sky",
126
- "A bustling city street transitioning from day to night in timelapse"
127
- ],
128
- inputs=prompt_input,
129
- outputs=video_output,
130
- fn=simple_generate, # Examples use the simple function without auth
131
- cache_examples=False,
132
- api_name=False,
133
- show_api=False,
134
  )
135
 
136
  return demo
@@ -138,7 +293,7 @@ def create_ui():
138
  # Launch the application
139
  if __name__ == "__main__":
140
  app = create_ui()
141
- # Launch without special auth parameters
142
  # OAuth is enabled via Space metadata (hf_oauth: true in README.md)
143
  app.launch(
144
  show_api=False,
 
1
  import gradio as gr
2
  import os
3
  import tempfile
4
+ from typing import Optional, Tuple, Union
5
+ from huggingface_hub import InferenceClient, whoami
6
 
7
  # Initialize Hugging Face Inference Client with fal-ai provider
8
  client = InferenceClient(
 
11
  bill_to="huggingface",
12
  )
13
 
14
+ def verify_pro_status(token: Optional[Union[gr.OAuthToken, str]]) -> bool:
15
+ """Verifies if the user is a Hugging Face PRO user or part of an enterprise org."""
16
+ if not token:
17
+ return False
18
+
19
+ if isinstance(token, gr.OAuthToken):
20
+ token_str = token.token
21
+ elif isinstance(token, str):
22
+ token_str = token
23
+ else:
24
+ return False
25
+
26
+ try:
27
+ user_info = whoami(token=token_str)
28
+ return (
29
+ user_info.get("isPro", False) or
30
+ any(org.get("isEnterprise", False) for org in user_info.get("orgs", []))
31
+ )
32
+ except Exception as e:
33
+ print(f"Could not verify user's PRO/Enterprise status: {e}")
34
+ return False
35
+
36
  def generate_video(
37
  prompt: str,
38
  duration: int = 8,
 
74
  error_msg = f"❌ Error generating video: {str(e)}"
75
  return None, error_msg
76
 
77
+ def generate_with_pro_auth(
78
+ prompt: str,
79
+ manual_token: str,
80
+ oauth_token: Optional[gr.OAuthToken] = None
81
+ ) -> Tuple[Optional[str], str]:
82
+ """
83
+ Wrapper function that checks if user is PRO before generating video.
84
+ """
85
+ # Check if user is PRO (either through OAuth or manual token)
86
+ if not (verify_pro_status(oauth_token) or verify_pro_status(manual_token)):
87
+ raise gr.Error("Access Denied. This app is exclusively for Hugging Face PRO users. Please subscribe to PRO to use this app.")
88
+
89
  if not prompt or prompt.strip() == "":
90
+ return None, "❌ Please enter a prompt"
91
 
92
+ # Use the oauth token if available, otherwise manual token
93
+ token_to_use = oauth_token.token if oauth_token else manual_token
94
 
95
+ # Generate video with the PRO user's token
96
+ video_path, status = generate_video(
97
+ prompt,
98
+ duration=8,
99
+ size="1280x720",
100
+ api_key=token_to_use
101
+ )
102
 
103
+ return video_path, status
104
 
105
+ def simple_generate(prompt: str) -> Optional[str]:
106
+ """Simplified wrapper for examples that only returns video."""
107
+ if not prompt or prompt.strip() == "":
108
+ return None
 
 
109
 
110
+ video_path, _ = generate_video(prompt, duration=8, size="1280x720", api_key=None)
111
+ return video_path
112
 
113
  def create_ui():
114
+ """Create the Gradio interface with PRO verification."""
115
+
116
+ css = '''
117
+ .logo-dark{display: none}
118
+ .dark .logo-dark{display: block !important}
119
+ .dark .logo-light{display: none}
120
+ #sub_title{margin-top: -20px !important}
121
+ .pro-badge{
122
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
123
+ color: white;
124
+ padding: 4px 12px;
125
+ border-radius: 20px;
126
+ font-size: 0.9em;
127
+ font-weight: bold;
128
+ display: inline-block;
129
+ margin-left: 8px;
130
+ }
131
+ '''
132
+
133
+ with gr.Blocks(title="Sora-2 Text-to-Video Generator", theme=gr.themes.Soft(), css=css) as demo:
134
  gr.HTML("""
135
+ <div style="text-align: center; max-width: 800px; margin: 0 auto;">
136
+ <h1 style="font-size: 2.5em; margin-bottom: 0.5em;">
137
+ 🎬 Sora-2 Text-to-Video Generator
138
+ <span class="pro-badge">PRO</span>
139
+ </h1>
140
+ <p style="font-size: 1.1em; color: #666;">Generate stunning videos using OpenAI's Sora-2 model</p>
141
+ <p id="sub_title" style="font-size: 1em; margin-top: 10px;">
142
+ <strong>Exclusive access for Hugging Face PRO users.</strong>
143
+ <a href="http://huggingface.co/subscribe/pro?source=sora2_video" target="_blank" style="color: #667eea;">Subscribe to PRO β†’</a>
144
+ </p>
145
  </div>
146
  """)
147
 
148
+ # Login button for OAuth
149
  gr.LoginButton()
150
 
151
+ # PRO message for non-PRO users
152
+ pro_message = gr.Markdown(visible=False)
153
+
154
+ # Main interface (hidden by default)
155
+ main_interface = gr.Column(visible=False)
156
+
157
+ with main_interface:
158
+ gr.HTML("""
159
+ <div style="text-align: center; margin: 20px 0;">
160
+ <p style="color: #28a745; font-weight: bold;">✨ Welcome PRO User! You have full access to Sora-2.</p>
161
+ </div>
162
+ """)
163
+
164
+ with gr.Row():
165
+ with gr.Column(scale=1):
166
+ prompt_input = gr.Textbox(
167
+ label="Enter your prompt",
168
+ placeholder="Describe the video you want to create...",
169
+ lines=4
170
+ )
171
+
172
+ with gr.Accordion("Advanced Settings", open=False):
173
+ gr.Markdown("*Coming soon: Duration and resolution controls*")
174
+
175
+ generate_btn = gr.Button("πŸŽ₯ Generate Video", variant="primary", size="lg")
176
+
177
+ with gr.Column(scale=1):
178
+ video_output = gr.Video(
179
+ label="Generated Video",
180
+ height=400,
181
+ interactive=False,
182
+ show_download_button=True
183
+ )
184
+ status_output = gr.Textbox(
185
+ label="Status",
186
+ interactive=False,
187
+ visible=True
188
+ )
189
 
190
+ # Hidden manual token input (for API usage)
191
+ manual_token = gr.Textbox(
192
+ label="Manual Token (for API usage)",
193
+ placeholder="Paste your HF token here if using the API",
194
+ type="password",
195
+ visible=False
196
+ )
197
+
198
+ # Examples section with queue disabled
199
+ gr.Examples(
200
+ examples=[
201
+ "A serene beach at sunset with waves gently rolling onto the shore",
202
+ "A butterfly emerging from its chrysalis in slow motion",
203
+ "Northern lights dancing across a starry night sky",
204
+ "A bustling city street transitioning from day to night in timelapse",
205
+ "A close-up of coffee being poured into a cup with steam rising",
206
+ "Cherry blossoms falling in slow motion in a Japanese garden"
207
+ ],
208
+ inputs=prompt_input,
209
+ outputs=video_output,
210
+ fn=simple_generate, # Examples use simplified function
211
+ cache_examples=False,
212
+ api_name=False,
213
+ show_api=False,
214
+ )
215
+
216
+ # Event handler for generation with queue disabled
217
+ generate_btn.click(
218
+ fn=generate_with_pro_auth,
219
+ inputs=[prompt_input, manual_token],
220
+ outputs=[video_output, status_output],
221
+ queue=False,
222
+ api_name=False,
223
+ show_api=False,
224
+ )
225
+
226
+ # Footer
227
+ gr.HTML("""
228
+ <div style="text-align: center; margin-top: 40px; padding: 20px; border-top: 1px solid #e0e0e0;">
229
+ <h3 style="color: #667eea;">Thank you for being a PRO user! πŸ€—</h3>
230
+ <p>Built with ❀️ using <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></p>
231
+ </div>
232
+ """)
233
 
234
+ def control_access(profile: Optional[gr.OAuthProfile] = None, oauth_token: Optional[gr.OAuthToken] = None):
235
+ """Control interface visibility based on PRO status."""
236
+ if not profile:
237
+ # User not logged in
238
+ return gr.update(visible=False), gr.update(visible=False)
239
+
240
+ if verify_pro_status(oauth_token):
241
+ # User is PRO - show main interface
242
+ return gr.update(visible=True), gr.update(visible=False)
243
+ else:
244
+ # User is not PRO - show upgrade message
245
+ message = """
246
+ ## ✨ Exclusive Access for PRO Users
247
+
248
+ Thank you for your interest in the Sora-2 Text-to-Video Generator!
249
+
250
+ This advanced AI video generation tool is available exclusively for Hugging Face **PRO** members.
251
+
252
+ ### What you get with PRO:
253
+ - βœ… Unlimited access to Sora-2 video generation
254
+ - βœ… High-quality video outputs up to 1280x720
255
+ - βœ… Fast generation times with priority queue
256
+ - βœ… Access to other exclusive PRO Spaces
257
+ - βœ… Support the development of cutting-edge AI tools
258
+
259
+ ### Ready to create amazing videos?
260
+
261
+ <div style="text-align: center; margin: 30px 0;">
262
+ <a href="http://huggingface.co/subscribe/pro?source=sora2_video" target="_blank" style="
263
+ display: inline-block;
264
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
265
+ color: white;
266
+ padding: 12px 30px;
267
+ border-radius: 25px;
268
+ text-decoration: none;
269
+ font-weight: bold;
270
+ font-size: 1.1em;
271
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
272
+ transition: transform 0.2s;
273
+ ">
274
+ πŸš€ Become a PRO Today!
275
+ </a>
276
+ </div>
277
+
278
+ <p style="text-align: center; color: #666; margin-top: 20px;">
279
+ Join thousands of creators who are already using PRO tools to bring their ideas to life.
280
+ </p>
281
+ """
282
+ return gr.update(visible=False), gr.update(visible=True, value=message)
283
 
284
+ # Check access on load
285
+ demo.load(
286
+ control_access,
287
+ inputs=None,
288
+ outputs=[main_interface, pro_message]
 
 
 
 
 
 
 
 
 
289
  )
290
 
291
  return demo
 
293
  # Launch the application
294
  if __name__ == "__main__":
295
  app = create_ui()
296
+ # Launch without special auth parameters and no queue
297
  # OAuth is enabled via Space metadata (hf_oauth: true in README.md)
298
  app.launch(
299
  show_api=False,