Spaces:
Runtime error
Runtime error
| """ | |
| Dispatch AI — Daily AI Image Drop | |
| Auto-generates a new AI art piece daily. Shows date, prompt used, image. | |
| Archive of past 30 days. Uses FLUX.1-schnell. | |
| """ | |
| import os | |
| import io | |
| import json | |
| import datetime | |
| import hashlib | |
| import gradio as gr | |
| from huggingface_hub import InferenceClient | |
| from PIL import Image, ImageDraw | |
| # --- Configuration ----------------------------------------------------------- | |
| HF_TOKEN = os.environ.get("HF_TOKEN", None) | |
| MODEL_ID = "black-forest-labs/FLUX.1-schnell" | |
| client = InferenceClient(model=MODEL_ID, token=HF_TOKEN) | |
| BG_COLOR = "#0A0F1A" | |
| ACCENT = "#1FE0E6" | |
| # Directory for archive | |
| ARCHIVE_DIR = os.path.join(os.getcwd(), "archive") | |
| os.makedirs(ARCHIVE_DIR, exist_ok=True) | |
| # Daily prompts — 30 curated art prompts cycling through the month | |
| DAILY_PROMPTS = [ | |
| "A majestic falcon soaring over the Dubai skyline at golden hour, Burj Khalifa in the background, cinematic, ultra detailed", | |
| "An ancient pearl diver in the Arabian Gulf, traditional dhow boat, underwater scene with pearls glowing, ethereal lighting", | |
| "Bedouin camp under a starry desert sky, campfire glowing, camels resting, Milky Way overhead, peaceful atmosphere", | |
| "Modern Dubai at night from above, neon-lit skyscrapers, flying cars, cyberpunk meets Arabian luxury, blade runner style", | |
| "Traditional Arabian wind tower (barjeel) architecture, old Dubai district, warm sunlight, golden hour, detailed stonework", | |
| "A majestic falcon perched on a gloved hand in the desert, piercing eyes, feather detail, warm sunset, wildlife photography", | |
| "Underwater pearl diving scene, traditional Emirati diver holding an oyster shell, bioluminescent water, dreamlike", | |
| "A caravan of camels crossing the Empty Quarter desert at dawn, long shadows on sand dunes, golden light", | |
| "Dubai Marina at blue hour, luxury yachts, modern architecture, reflections on water, ultra detailed cityscape", | |
| "An old souk in Dubai, spices and textiles hanging, warm lantern light, bustling atmosphere, orientalist painting style", | |
| "Arabian stallion galloping through the desert at sunset, dust kicking up, dramatic lighting, powerful, ultra detailed", | |
| "A traditional Emirati coffee ceremony (gahwa), dallah pot pouring into finjan, dates on a brass tray, warm intimate lighting", | |
| "Sheikh Zayed Grand Mosque at night, illuminated domes and minarets, reflecting pool, serene and majestic", | |
| "Falconry scene in the UAE desert, falcon taking off from handler's wrist, motion blur, golden hour", | |
| "Al Ain oasis with date palms and aflaj water channels, lush green in the desert, peaceful, golden afternoon light", | |
| "Abu Dhabi Corniche at sunset, modern skyline, calm sea, families walking, warm and inviting atmosphere", | |
| "Henna being applied in intricate patterns, close-up of hands, traditional Emirati setting, warm lighting, detailed", | |
| "A dhow race in the Dubai Creek, traditional boats with white sails, dramatic sky, action shot", | |
| "The Burj Al Arab sail-shaped hotel at sunset, glowing pink and gold sky, calm sea reflections, luxury aesthetic", | |
| "Emirati women in traditional abayas and burqas walking through a date palm plantation, warm sunlight filtering through palms", | |
| "Liwa desert sand dunes at sunrise, wind-rippled sand, golden orange glow, minimalist composition, fine art photography", | |
| "Old Dubai wind tower district (Bastakiya), narrow alleyways, traditional courtyard, warm and inviting", | |
| "Arabian oryx in the desert, elegant white antelope, pristine landscape, wildlife photography, golden hour", | |
| "Dubai Frame at night, glowing golden frame structure, old and new city visible through it, dramatic", | |
| "A traditional Emirati wedding celebration, henna, dancing, warm lantern light, joyous atmosphere, orientalist style", | |
| "Sharjah's King Faisal Mosque at dawn, soft blue light, call to prayer atmosphere, peaceful and serene", | |
| "Jebel Jais mountain range at sunrise, mist in the valleys, dramatic rock formations, cool blue tones", | |
| "Arabic coffee (gahwa) and dates on a traditional rug in the desert, campfire, stars, intimate and warm", | |
| "The UAE flag waving proudly against a clear blue sky, on top of a mountain, dramatic and patriotic", | |
| "Sunset over the Empty Quarter, endless sand dunes, purple and orange sky, lone camel caravan, epic", | |
| ] | |
| def get_daily_prompt(date_str=None): | |
| """Get the prompt for a specific date (or today).""" | |
| if date_str is None: | |
| date_str = datetime.date.today().isoformat() | |
| # Use date to deterministically pick a prompt | |
| day_hash = int(hashlib.md5(date_str.encode()).hexdigest(), 16) | |
| return DAILY_PROMPTS[day_hash % len(DAILY_PROMPTS)] | |
| def get_today_image(): | |
| """Generate or load today's image.""" | |
| today = datetime.date.today().isoformat() | |
| archive_path = os.path.join(ARCHIVE_DIR, f"{today}.png") | |
| meta_path = os.path.join(ARCHIVE_DIR, f"{today}.json") | |
| # If already generated, load from archive | |
| if os.path.exists(archive_path) and os.path.exists(meta_path): | |
| try: | |
| img = Image.open(archive_path) | |
| with open(meta_path) as f: | |
| meta = json.load(f) | |
| prompt = meta.get("prompt", "") | |
| return img, f"📅 {today}", prompt, "✅ Loaded from archive" | |
| except Exception: | |
| pass | |
| # Generate new | |
| prompt = get_daily_prompt(today) | |
| w, h = 1024, 1024 | |
| try: | |
| image = client.text_to_image(prompt, width=w, height=h) | |
| if not isinstance(image, Image.Image): | |
| image = Image.open(io.BytesIO(image)) if hasattr(image, "read") else Image.open(image) | |
| # Save to archive | |
| image.save(archive_path) | |
| with open(meta_path, "w") as f: | |
| json.dump({"date": today, "prompt": prompt}, f, indent=2) | |
| return image, f"📅 {today}", prompt, "✅ Today's image generated!" | |
| except Exception as e: | |
| img = Image.new("RGB", (w, h), BG_COLOR) | |
| d = ImageDraw.Draw(img) | |
| d.text((w // 4, h // 2), f"Error: {str(e)[:50]}", fill=ACCENT) | |
| return img, f"📅 {today}", prompt, f"❌ Error: {str(e)}" | |
| def get_archive(): | |
| """Load all archived images.""" | |
| archives = [] | |
| if os.path.exists(ARCHIVE_DIR): | |
| for f in sorted(os.listdir(ARCHIVE_DIR), reverse=True): | |
| if f.endswith(".png"): | |
| date_str = f.replace(".png", "") | |
| meta_path = os.path.join(ARCHIVE_DIR, f"{date_str}.json") | |
| prompt = "" | |
| if os.path.exists(meta_path): | |
| try: | |
| with open(meta_path) as mf: | |
| meta = json.load(mf) | |
| prompt = meta.get("prompt", "")[:80] + "..." if len(meta.get("prompt", "")) > 80 else meta.get("prompt", "") | |
| except Exception: | |
| pass | |
| archives.append({ | |
| "date": date_str, | |
| "prompt": prompt, | |
| "image_path": os.path.join(ARCHIVE_DIR, f), | |
| }) | |
| return archives[:30] # Last 30 | |
| def build_archive_gallery(): | |
| """Build gallery data for the archive tab.""" | |
| archives = get_archive() | |
| if not archives: | |
| return [], "No archived images yet. Click 'Generate Today's Image' first." | |
| gallery_items = [(a["image_path"], a["date"]) for a in archives] | |
| summary = f"### 📚 Archive — {len(archives)} image(s)\n\n" | |
| for a in archives[:10]: | |
| summary += f"- **{a['date']}** — {a['prompt']}\n" | |
| if len(archives) > 10: | |
| summary += f"\n...and {len(archives) - 10} more" | |
| return gallery_items, summary | |
| # --- UI ----------------------------------------------------------------------- | |
| CSS = """ | |
| #dispatch-header h1 { | |
| color: #FFFFFF; font-size: 2.2rem; margin: 0; | |
| background: linear-gradient(90deg, #1FE0E6 0%, #FFFFFF 60%); | |
| -webkit-background-clip: text; -webkit-text-fill-color: transparent; | |
| } | |
| #dispatch-header p { color: #1FE0E6; font-size: 1.05rem; margin: 6px 0 0 0; } | |
| .dispatch-footer { text-align: center; color: #8A8F9C; font-size: 0.9rem; padding-top: 8px; } | |
| """ | |
| with gr.Blocks( | |
| title="Dispatch AI — Daily AI Image Drop", | |
| theme=gr.themes.Base( | |
| primary_hue="cyan", secondary_hue="cyan", neutral_hue="slate", | |
| font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui"], | |
| ).set( | |
| body_background_fill="#0A0F1A", body_background_fill_dark="#0A0F1A", | |
| body_text_color="#FFFFFF", body_text_color_dark="#FFFFFF", | |
| block_background_fill="#0E1424", block_background_fill_dark="#0E1424", | |
| block_border_color="#1FE0E6", block_border_width="1px", | |
| block_label_text_color="#1FE0E6", block_title_text_color="#1FE0E6", | |
| button_primary_background_fill="#1FE0E6", button_primary_background_fill_dark="#1FE0E6", | |
| button_primary_text_color="#0A0F1A", button_primary_border_color="#1FE0E6", | |
| input_background_fill="#0E1424", input_background_fill_dark="#0E1424", | |
| input_border_color="#1FE0E6", input_border_width="1px", | |
| ), | |
| css=CSS, | |
| ) as demo: | |
| with gr.Column(elem_id="dispatch-header"): | |
| gr.Markdown( | |
| """ | |
| # Dispatch AI — Daily AI Image Drop | |
| A new AI art piece every day · FLUX.1-schnell · Dispatch AI (FZE) · UAE | |
| """ | |
| ) | |
| with gr.Tab("🖼️ Today's Drop"): | |
| with gr.Row(): | |
| generate_btn = gr.Button("🎨 Generate/Load Today's Image", variant="primary") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| today_image = gr.Image(label="Today's Art", type="pil", show_download_button=True) | |
| with gr.Column(scale=1): | |
| date_box = gr.Textbox(label="Date", interactive=False) | |
| prompt_box = gr.Textbox(label="Prompt Used", interactive=False, lines=4) | |
| status_box = gr.Textbox(label="Status", interactive=False) | |
| with gr.Tab("📚 Archive (30 days)"): | |
| with gr.Row(): | |
| refresh_archive_btn = gr.Button("🔄 Refresh Archive", variant="secondary") | |
| archive_gallery = gr.Gallery( | |
| label="Past Art Drops", show_label=True, | |
| columns=4, height=600, object_fit="cover", | |
| ) | |
| archive_summary = gr.Markdown() | |
| # Events | |
| generate_btn.click( | |
| get_today_image, | |
| outputs=[today_image, date_box, prompt_box, status_box], | |
| ) | |
| refresh_archive_btn.click( | |
| build_archive_gallery, | |
| outputs=[archive_gallery, archive_summary], | |
| ) | |
| gr.Markdown( | |
| """ | |
| <div class="dispatch-footer"> | |
| © 2026 Dispatch AI (FZE) · Sharjah, UAE · License 10818 · | |
| Model: FLUX.1-schnell · A new art piece is generated daily and archived for 30 days | |
| </div> | |
| """ | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue() | |
| demo.launch() | |