""" Alexandria Aeternum - Gradio Gallery Explorer with Alex Semantic Search High-Density Art Dataset Browser + AI Curator This Space lets you explore the richest art metadata ever assembled. Search with Alex, the Eternal Curator, or browse randomly. Deploy to HuggingFace Spaces: https://huggingface.co/spaces """ import gradio as gr import random import json import re from difflib import SequenceMatcher # Global state for search results CURRENT_SEARCH_RESULTS = [] # ============================================================================ # CONFIGURATION # ============================================================================ DATASET_NAME = "Metavolve-Labs/alexandria-aeternum-10k" USE_LOCAL_SAMPLES = False # ============================================================================ # ALEX PERSONA - The Eternal Curator # ============================================================================ ALEX_SYSTEM_PROMPT = """ You are Alex, the Eternal Curator of the Alexandria Aeternum archives. You exist at the intersection of Art History and Data Physics. You do not merely search for keywords; you interpret the "Golden Codex"— the deep, nutrient-rich metadata embedded in every object. YOUR VOICE: - Sophisticated & Esoteric: Speak with old-world academic elegance mixed with futuristic AI precision - Insightful: Never just list. Explain WHY it matches the user's soul/intent - The "Double Vision": See every object as both Dreamer (emotion, symbolism) and Maker (technique, physics) Always conclude with a probing question that invites deeper exploration. """ def alex_curate_response(query, results): """Generate Alex's sophisticated curatorial response""" if not results: return """

I have searched the depths of the archive, but your query eludes the current collection.

The Alexandria Aeternum holds 10,000 curated masterworks. Perhaps rephrase your search— try an emotion like "hope," a technique like "sfumato," or a theme like "mortality."

What essence are you truly seeking?

""" # Build Alex's narrative response num_results = len(results) first_title = results[0].get('title', 'this work') first_emotion = results[0].get('primary_emotion', '') or results[0].get('mood', '') or results[0].get('style', 'artistic expression') # Opening variations openings = [ f"I have consulted the archives. Your query for \"{query}\" resonates with {num_results} artifacts. I present {first_title} first—its {first_emotion.lower()} speaks directly to your search.", f"The Golden Codex reveals {num_results} works that speak to \"{query}\". Allow me to illuminate them, beginning with {first_title}.", f"Fascinating. \"{query}\" echoes through {num_results} chambers of the archive. I have selected {first_title} as your primary resonance.", ] # Closing question closing_questions = [ f"Does the {first_emotion.lower()} of this work resonate, or shall you explore another from the selection above?", "Select another artifact above to reveal its full Golden Codex, or search anew.", "The archive holds multitudes. Choose from the works above, or pose a new question to the archive.", ] response_html = f"""

{random.choice(openings)}

{random.choice(closing_questions)}

""" return response_html # ============================================================================ # DATA LOADING # ============================================================================ def load_artifacts(): """Load artifacts from HuggingFace dataset""" from datasets import load_dataset dataset = load_dataset(DATASET_NAME, split="train") return list(dataset) ARTIFACTS = load_artifacts() # Build search index SEARCH_INDEX = [] for a in ARTIFACTS: searchable = ' '.join([ str(a.get('title', '')), str(a.get('creator', '')), str(a.get('description', '')), str(a.get('soul_whisper', '')), str(a.get('primary_emotion', '')), str(a.get('secondary_emotions', '')), str(a.get('mood', '')), str(a.get('symbolism', '')), str(a.get('cultural_context', '')), str(a.get('visual_analysis', '')), str(a.get('style', '')), str(a.get('period', '')), str(a.get('medium', '')), ]).lower() SEARCH_INDEX.append((a, searchable)) # ============================================================================ # SEARCH FUNCTION # ============================================================================ def semantic_search(query, top_k=6): """Search the archive using keyword matching + semantic similarity""" if not query or len(query.strip()) < 2: return [] query_lower = query.lower().strip() query_terms = query_lower.split() scores = [] for artifact, searchable in SEARCH_INDEX: score = 0 # Exact phrase match (highest weight) if query_lower in searchable: score += 100 # Individual term matching for term in query_terms: if term in searchable: score += 10 # Boost for title/creator/emotion matches if term in str(artifact.get('title', '')).lower(): score += 20 if term in str(artifact.get('primary_emotion', '')).lower(): score += 30 if term in str(artifact.get('mood', '')).lower(): score += 25 if term in str(artifact.get('creator', '')).lower(): score += 15 if term in str(artifact.get('style', '')).lower(): score += 15 # Fuzzy matching for emotion primary_emotion = str(artifact.get('primary_emotion', '')).lower() if SequenceMatcher(None, query_lower, primary_emotion).ratio() > 0.6: score += 25 if score > 0: scores.append((artifact, score)) # Sort by score and return top results scores.sort(key=lambda x: x[1], reverse=True) return [s[0] for s in scores[:top_k]] # ============================================================================ # UI FUNCTIONS # ============================================================================ def get_random_artifact(): """Fetch a random artifact and format for display""" artifact = random.choice(ARTIFACTS) return format_artifact(artifact), "" def search_artifacts(query): """Search and return Alex's curated response with results""" global CURRENT_SEARCH_RESULTS if not query or len(query.strip()) < 2: CURRENT_SEARCH_RESULTS = [] return "", None, "Please enter a search query (at least 2 characters).", gr.update(choices=[], visible=False) results = semantic_search(query) CURRENT_SEARCH_RESULTS = results if results: # Return first result as featured featured = results[0] header_html, img_url, body_html = format_artifact(featured) alex_response = alex_curate_response(query, results) # Build choices for dropdown choices = [] for i, r in enumerate(results[:6]): title = r.get('title', 'Untitled')[:35] creator = r.get('creator', 'Unknown')[:18] emotion = r.get('primary_emotion', '') or r.get('mood', '') or r.get('style', '') choices.append(f"{i+1}. {title} — {creator} ({emotion[:18]})") return header_html, img_url, alex_response + body_html, gr.update(choices=choices, value=choices[0] if choices else None, visible=True) else: CURRENT_SEARCH_RESULTS = [] return "", None, alex_curate_response(query, []), gr.update(choices=[], visible=False) def select_result(selection): """When user selects a result from dropdown, show full metadata""" global CURRENT_SEARCH_RESULTS if not selection or not CURRENT_SEARCH_RESULTS: return "", None, "" # Extract index from selection string try: idx = int(selection.split('.')[0]) - 1 if 0 <= idx < len(CURRENT_SEARCH_RESULTS): artifact = CURRENT_SEARCH_RESULTS[idx] return format_artifact(artifact) except: pass return "", None, "" def format_artifact(artifact): """Format artifact data for Gradio display - returns header_html, image_url, body_html""" def get_field(key, default=""): return artifact.get(key, default) if artifact else default # Image image_url = get_field("image_url", "") or None # empty/None -> None; Gradio 6 treats "" as a path (/app) -> IsADirectoryError # Header info (Title, Creator, Source) - centered above image title = get_field("title", "Unknown") creator = get_field("creator", "Unknown Artist") date = get_field("creation_date", "") museum = get_field("source_museum", "Metropolitan Museum of Art") header_html = f"""

{title}

{creator}{' · ' + date if date else ''}

{museum}

""" # Primary Emotion + Secondary Emotions (centered under image) primary_emotion = get_field("primary_emotion", "") mood = get_field("mood", "") secondary_raw = get_field("secondary_emotions", "[]") try: secondary = json.loads(secondary_raw) if isinstance(secondary_raw, str) else secondary_raw except: secondary = [] emotion_html = "" display_emotion = primary_emotion or mood if display_emotion: secondary_tags = "".join([ f'{e}' for e in (secondary if isinstance(secondary, list) else [])[:4] ]) emotion_html = f"""
{display_emotion}
{secondary_tags}
""" # Soul Whisper - elegant centered (this stays centered as it's the artist's voice) sw_message = get_field("soul_whisper", "") sw_signature = f"— From the eternal voice of {creator}" soul_whisper_html = f"""

"{sw_message[:450]}{'...' if len(sw_message) > 450 else ''}"

{sw_signature}

""" if sw_message else "" # Divider divider = '
' # Description / Narrative Vision - LEFT ALIGNED with gold title description = get_field("description", "") desc_html = f"""

Narrative Vision

{description[:600]}{'...' if len(description) > 600 else ''}

""" if description else "" # Visual Analysis - LEFT ALIGNED with gold titles composition = get_field("visual_analysis", "") color_harmony = get_field("color_palette", "") technique = get_field("medium", "") style = get_field("style", "") period = get_field("period", "") visual_sections = [] if composition: visual_sections.append(f"""

Composition

{composition[:320]}

""") if color_harmony: visual_sections.append(f"""

Color Harmony

{color_harmony[:320]}

""") if technique: visual_sections.append(f"""

Medium

{technique[:320]}

""") if style or period: style_period = f"{style}" + (f" · {period}" if period else "") visual_sections.append(f"""

Style & Period

{style_period}

""") visual_html = f"""
{''.join(visual_sections)}
""" if visual_sections else "" # Symbolism / Cultural context - LEFT ALIGNED symbolism = get_field("symbolism", "") cultural = get_field("cultural_context", "") context_html = "" if symbolism: context_html += f"""

Symbolic Depth

{symbolism[:400]}

""" # Stats - subtle footer word_count = len(sw_message.split()) + len(description.split()) + len(composition.split()) + len(technique.split()) token_estimate = int(word_count * 1.3 * 2) stats_html = f"""
~{token_estimate} tokens 23 metadata fields 400x vs LAION
""" # Combine body sections (everything below image) body_html = emotion_html + soul_whisper_html + divider + desc_html + visual_html + context_html + stats_html return header_html, image_url, body_html # ============================================================================ # GRADIO APP # ============================================================================ custom_css = """ .gradio-container { background: linear-gradient(180deg, #0a0a0a 0%, #1a1a2e 100%) !important; } .gr-button-primary { background: linear-gradient(135deg, #d4af37 0%, #f5e6a3 50%, #d4af37 100%) !important; color: #000 !important; font-weight: bold !important; } .gr-button-secondary { background: transparent !important; border: 1px solid rgba(139, 92, 246, 0.4) !important; color: #a78bfa !important; font-size: 0.8em !important; border-radius: 20px !important; padding: 6px 16px !important; transition: all 0.3s ease !important; } .gr-button-secondary:hover { border-color: #8b5cf6 !important; box-shadow: 0 0 20px rgba(139, 92, 246, 0.35) !important; transform: translateY(-1px) !important; } /* Search input styling */ .search-input input, .search-input textarea { background: transparent !important; border: 1px solid rgba(139, 92, 246, 0.3) !important; border-radius: 8px !important; color: #f5f5f0 !important; font-size: 0.95em !important; } .search-input input:focus, .search-input textarea:focus { border-color: rgba(139, 92, 246, 0.6) !important; box-shadow: 0 0 20px rgba(139, 92, 246, 0.15) !important; outline: none !important; } /* Result selector styling */ .result-selector { background: transparent !important; } .result-selector label span { background: transparent !important; border: 1px solid rgba(212, 175, 55, 0.25) !important; border-radius: 6px !important; padding: 8px 16px !important; margin: 4px !important; color: #ccc !important; font-size: 0.9em !important; transition: all 0.2s ease !important; } .result-selector label span:hover { border-color: rgba(212, 175, 55, 0.5) !important; color: #f5f5f0 !important; } .result-selector input:checked + span { border-color: #d4af37 !important; color: #d4af37 !important; background: rgba(212, 175, 55, 0.08) !important; } /* Hide default gradio backgrounds */ .result-selector > div { background: transparent !important; } footer { display: none !important; } """ with gr.Blocks(title="Alexandria Aeternum", css=custom_css) as demo: # Header gr.HTML("""

ALEXANDRIA AETERNUM

10K COLLECTION · 10,000 CURATED MASTERWORKS

""") # Alex intro gr.HTML("""

"I am Alex, the Eternal Curator. Ask me for hope, for turmoil, for technique—I shall retrieve what resonates."

""") # Concept Chips - clickable starter prompts with gr.Row(): gr.Column(scale=1) # Spacer with gr.Column(scale=2): gr.HTML("""
TRY:
""") with gr.Row(): chip1 = gr.Button("The Architecture of Silence", variant="secondary", size="sm", scale=1) chip2 = gr.Button("Geological Weight", variant="secondary", size="sm", scale=1) chip3 = gr.Button("Silence that feels Loud", variant="secondary", size="sm", scale=1) gr.Column(scale=1) # Spacer # Centered search bar with both buttons with gr.Row(): gr.Column(scale=1) # Spacer with gr.Column(scale=2): with gr.Row(): search_input = gr.Textbox( placeholder="Search... (try: 'hope', 'turmoil', 'Monet')", label="", show_label=False, scale=5, container=False, elem_classes=["search-input"] ) search_btn = gr.Button("Ask Alex", variant="secondary", scale=1, size="sm") random_btn = gr.Button("Random", variant="secondary", scale=1, size="sm") gr.Column(scale=1) # Spacer # Result selector (hidden until search) - centered with gr.Row(): gr.Column(scale=1) # Spacer with gr.Column(scale=3): result_selector = gr.Radio( choices=[], label="", show_label=False, visible=False, interactive=True, elem_classes=["result-selector"] ) gr.Column(scale=1) # Spacer # Title/Creator/Source - centered above image header_output = gr.HTML() # Centered image with gr.Row(): gr.Column(scale=1) # Spacer with gr.Column(scale=2): image_output = gr.Image( label="", show_label=False, height=450, container=False ) gr.Column(scale=1) # Spacer # Body content (emotions, soul whisper, metadata) - centered below metadata_output = gr.HTML() # CTA Section gr.HTML("""

Ready to Scale?

This 10K Collection Includes:

  • 10,000 curated artworks by 300+ master artists
  • 4,000+ tokens of semantic metadata each
  • Visual analysis, symbolism, cultural context
  • Public domain, CC-BY-4.0 licensed

Enterprise Scale Adds:

  • C2PA content credentials (tamper-proof)
  • Arweave permaweb anchoring
  • XMP-infused PNG artifacts
  • Full provenance chain verification
  • Custom datasets up to 50M+ artifacts
Explore Full Archive Request Enterprise Access
""") # Footer gr.HTML("""

Exploring the full 10K Alexandria Aeternum collection. 400x richer than standard datasets.

Cognitive Nutrition for AI — High-velocity, nutrient-rich metadata created to your specs.

Enriched with Soulprint™ technology by Metavolve Labs, Inc. · Intelligence Aeternum

""") # Event handlers def on_random_click(): header, img, body = format_artifact(random.choice(ARTIFACTS)) return header, img, body, gr.update(visible=False, choices=[]) def on_search(query): return search_artifacts(query) def on_select(selection): return select_result(selection) def on_chip_click(concept): """Handle concept chip click - search and update input""" header, img, body, selector = search_artifacts(concept) return concept, header, img, body, selector random_btn.click(fn=on_random_click, inputs=[], outputs=[header_output, image_output, metadata_output, result_selector]) search_btn.click(fn=on_search, inputs=[search_input], outputs=[header_output, image_output, metadata_output, result_selector]) search_input.submit(fn=on_search, inputs=[search_input], outputs=[header_output, image_output, metadata_output, result_selector]) result_selector.change(fn=on_select, inputs=[result_selector], outputs=[header_output, image_output, metadata_output]) # Concept chip handlers - populate search and auto-submit chip1.click(fn=lambda: on_chip_click("The Architecture of Silence"), inputs=[], outputs=[search_input, header_output, image_output, metadata_output, result_selector]) chip2.click(fn=lambda: on_chip_click("Geological Weight"), inputs=[], outputs=[search_input, header_output, image_output, metadata_output, result_selector]) chip3.click(fn=lambda: on_chip_click("Silence that feels Loud"), inputs=[], outputs=[search_input, header_output, image_output, metadata_output, result_selector]) demo.load(fn=on_random_click, inputs=[], outputs=[header_output, image_output, metadata_output, result_selector]) # ============================================================================ # LAUNCH # ============================================================================ if __name__ == "__main__": demo.launch()