Spaces:
				
			
			
	
			
			
					
		Running
		
	
	
	
			
			
	
	
	
	
		
		
					
		Running
		
	Let me try again, I only managed to do it once,,,
#22
by
						
vladimir-68
	
							
						- opened
							
					
    	
        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 | 
            -
             | 
| 12 | 
            -
             | 
|  | |
|  | |
|  | |
| 13 |  | 
| 14 | 
            -
            def  | 
| 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  | 
| 48 | 
            -
                        return None, "❌ Sign in with Hugging Face to  | 
| 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 | 
            -
                     | 
| 60 | 
            -
                         | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 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 | 
            -
                     | 
|  | |
|  | |
| 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"❌  | 
| 79 |  | 
| 80 | 
            -
            def image_to_video(image, prompt,  | 
| 81 | 
             
                """Generate video from image and prompt"""
         | 
| 82 | 
             
                try:
         | 
| 83 | 
            -
                    if  | 
| 84 | 
            -
                        return None, "❌ Sign in with Hugging Face to  | 
| 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 | 
            -
                     | 
| 121 | 
            -
                         | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 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 | 
            -
                     | 
|  | |
|  | |
| 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"❌  | 
| 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 | 
            -
            . | 
| 170 | 
            -
                 | 
| 171 | 
            -
                 | 
| 172 | 
            -
                padding: 14px 16px;
         | 
| 173 | 
            -
                border-radius: 12px;
         | 
| 174 | 
            -
                margin: 18px auto 6px;
         | 
| 175 | 
            -
                max-width: 860px;
         | 
| 176 | 
             
                text-align: center;
         | 
| 177 | 
            -
                 | 
|  | |
|  | |
|  | |
| 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 | 
| 212 | 
            -
                
         | 
| 213 | 
            -
                gr.HTML(
         | 
| 214 | 
             
                    """
         | 
| 215 | 
            -
                     | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 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 | 
            -
                    < | 
| 245 | 
            -
                         | 
| 246 | 
            -
                    </ | 
| 247 | 
             
                    """
         | 
| 248 | 
             
                )
         | 
| 249 |  | 
| 250 | 
             
                # Add login button - required for OAuth
         | 
| 251 | 
            -
                 | 
| 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 | 
| 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 | 
| 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,
         | 
