Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| import time | |
| from pathlib import Path | |
| from PIL import Image | |
| import base64 | |
| from io import BytesIO | |
| # --- Setup --- | |
| # Create a directory to store uploaded images | |
| IMAGE_DIR = Path("gallery_images") | |
| IMAGE_DIR.mkdir(exist_ok=True) | |
| # --- Backend Functions --- | |
| def cleanup_old_images(): | |
| """Deletes images older than 60 minutes to save space.""" | |
| now = time.time() | |
| for f in IMAGE_DIR.iterdir(): | |
| if f.is_file(): | |
| # Check if file is older than 3600 seconds (60 minutes) | |
| if now - f.stat().st_mtime > 3600: | |
| print(f"Cleaning up old image: {f.name}") | |
| f.unlink() | |
| def show_gallery(): | |
| """ | |
| Cleans up old files and returns a sorted list of all current image paths. | |
| This is called by the frontend to refresh the gallery view. | |
| """ | |
| cleanup_old_images() | |
| # Sort files by creation time, newest first | |
| files = sorted(IMAGE_DIR.iterdir(), key=os.path.getmtime, reverse=True) | |
| return [str(f) for f in files] | |
| def clear_gallery(): | |
| """Deletes all files in the image directory.""" | |
| if IMAGE_DIR.exists(): | |
| for file_path in IMAGE_DIR.iterdir(): | |
| if file_path.is_file(): | |
| file_path.unlink() # Deletes the file | |
| print("Gallery cleared successfully.") | |
| # Return an empty list to update the gallery UI | |
| return [] | |
| def upload_via_ui(image_from_ui): | |
| """ | |
| Handles image uploads directly from the Gradio UI interface. | |
| The 'image_from_ui' is a PIL Image object. | |
| """ | |
| if image_from_ui is not None: | |
| timestamp = int(time.time()) | |
| filename = f"ui_{timestamp}.png" | |
| path = IMAGE_DIR / filename | |
| image_from_ui.save(path) | |
| print(f"Image saved from UI to {path}") | |
| return show_gallery() | |
| def upload_via_data_url(data_url_string): | |
| """ | |
| Handles image uploads from our JavaScript frontend. | |
| The 'data_url_string' is a base64 encoded string. | |
| """ | |
| if not data_url_string: | |
| raise gr.Error("No image data received.") | |
| try: | |
| # The string is "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..." | |
| # We need to strip the header to get just the base64 part. | |
| header, encoded = data_url_string.split(",", 1) | |
| # Decode the base64 string | |
| img_data = base64.b64decode(encoded) | |
| # Open the image using Pillow | |
| image = Image.open(BytesIO(img_data)) | |
| # Generate a unique filename | |
| timestamp = int(time.time()) | |
| filename = f"capture_{timestamp}.jpeg" | |
| path = IMAGE_DIR / filename | |
| # Save the image | |
| image.save(path, "JPEG") | |
| print(f"Image saved from camera to {path}") | |
| except Exception as e: | |
| print(f"Error processing image: {e}") | |
| raise gr.Error("Server failed to process image.") | |
| # After saving, return the updated list of all images | |
| return show_gallery() | |
| # --- Gradio UI & API --- | |
| with gr.Blocks(title="Shekar's Portfolio Gallery") as demo: | |
| gr.Markdown("## 📸 Portfolio Image Gallery") | |
| # Main gallery display | |
| gallery = gr.Gallery( | |
| label="Uploaded Images", | |
| show_label=False, | |
| elem_id="gallery_component", # Use a unique elem_id | |
| columns=4, | |
| height="auto" | |
| ) | |
| # --- Section for manual uploads via the Gradio UI --- | |
| with gr.Accordion("Manual Upload (for testing)", open=False): | |
| image_input = gr.Image(type="pil", label="Upload an Image") | |
| upload_button = gr.Button("Upload from UI") | |
| upload_button.click( | |
| fn=upload_via_ui, | |
| inputs=image_input, | |
| outputs=gallery | |
| ) | |
| with gr.Accordion("Admin Controls", open=False): | |
| clear_btn = gr.Button("⚠️ Clear All Gallery Images") | |
| # --- Hidden components to create the API endpoints --- | |
| with gr.Row(visible=False): | |
| # Textbox to receive the base64 data URL from the JS client | |
| data_url_input = gr.Textbox() | |
| # The upload function will output the new gallery list to our main gallery component | |
| # This creates the /upload_via_data_url endpoint | |
| data_url_input.submit( | |
| fn=upload_via_data_url, | |
| inputs=data_url_input, | |
| outputs=gallery, | |
| api_name="upload_via_data_url" | |
| ) | |
| clear_btn.click(fn=clear_gallery, inputs=None, outputs=gallery) | |
| # Load and refresh the gallery when the app starts. | |
| # This also creates the /show_gallery endpoint for the JS client. | |
| demo.load( | |
| fn=show_gallery, | |
| inputs=None, | |
| outputs=gallery, | |
| api_name="show_gallery" | |
| ) | |
| # --- Launch the App --- | |
| demo.launch() |