"""Datology Labs look for the Space, with a light theme (default) and a dark theme. Colors were sampled from the Datology Labs brand film. The light theme follows the film's opening scenes (off-white paper, soft blue glows, navy type); the dark theme follows its night scenes (deep navy, cobalt and teal glows). Both share the cobalt-to-cyan hero, the orange accent and the film grain. A light-bulb button beside the hero switches between them and remembers the choice. Everything visual lives here, so app.py stays the same as the plain version apart from a few imports. """ from __future__ import annotations import inspect import gradio as gr # --------------------------------------------------------------------------- # Palette (sampled from the brand film) # --------------------------------------------------------------------------- # Shared brand colors DEEP_COBALT = "#052d78" COBALT = "#1574eb" ELECTRIC = "#2f8ff0" # primary blue; "kept" in charts CYAN = "#39b0df" ICE = "#a4d9e8" ORANGE = "#e8692a" # the single warm accent; "removed" in charts ORANGE_HI = "#f2894c" EMBER = "#e5b06d" # Dark theme (the night scenes) NIGHT = "#040b18" # deepest background NAVY = "#0a1630" # panels / chart surface NAVY_2 = "#0c2447" # raised surfaces, inputs TEXT = "#f2f6fc" TEXT_MUTED = "#9fb3cf" LINE = "rgba(140, 180, 235, 0.16)" LINE_STRONG = "rgba(140, 180, 235, 0.32)" # Light theme (the opening scenes) PAPER = "#f6f9fd" # page WHITE = "#ffffff" # panels / chart surface PAPER_2 = "#eef3fa" # raised surfaces, inputs INK_NAVY = "#0b1b3a" # body text (navy captions in the film) INK_MUTED = "#4b5e7c" COBALT_TEXT = "#1257c4" # blue that reads as text on white ORANGE_TEXT = "#c9531a" # orange that reads as text on white LINE_L = "rgba(21, 60, 120, 0.12)" LINE_STRONG_L = "rgba(21, 60, 120, 0.24)" FONT = "Hanken Grotesk" FONT_MONO = "JetBrains Mono" # Chart roles. The same two colors pass the palette checks on navy and on white # (CVD ΔE 27, contrast ≥ 3:1), so bars keep their colors in both themes. # Axis text, gridlines and the cutoff line switch with the theme via CSS (see PLOT CSS below). KEPT = ELECTRIC REMOVED = ORANGE INK = TEXT_MUTED GRID = "rgba(159, 179, 207, 0.12)" CUTOFF_LINE = "rgba(242, 246, 252, 0.7)" # --------------------------------------------------------------------------- # Gradio theme: light values for the default, dark values under .dark # --------------------------------------------------------------------------- _SHARED = dict( body_text_weight="400", border_color_accent=ELECTRIC, color_accent=ELECTRIC, shadow_drop="none", shadow_spread="0px", block_border_width="1px", block_radius="16px", container_radius="16px", block_label_background_fill="transparent", block_label_border_width="0px", block_label_text_weight="500", block_title_background_fill="transparent", block_title_border_width="0px", block_title_text_weight="500", block_title_padding="0", panel_background_fill="transparent", input_border_color_focus=ELECTRIC, input_border_width="1px", checkbox_background_color_selected=ELECTRIC, checkbox_border_color_selected=ELECTRIC, checkbox_border_color_focus=ELECTRIC, checkbox_label_border_width="1px", checkbox_label_shadow="none", checkbox_label_text_weight="400", slider_color=ORANGE, loader_color=ORANGE, stat_background_fill=f"linear-gradient(90deg, {COBALT}, {CYAN})", button_primary_background_fill=ORANGE, button_primary_background_fill_hover=ORANGE_HI, button_primary_border_color=ORANGE, button_primary_border_color_hover=ORANGE_HI, button_primary_text_color="#ffffff", button_primary_text_color_hover="#ffffff", button_secondary_border_color_hover=ELECTRIC, button_secondary_shadow="none", ) _DARK = dict( body_background_fill=NIGHT, body_text_color=TEXT, body_text_color_subdued=TEXT_MUTED, background_fill_primary=NAVY, background_fill_secondary=NAVY_2, border_color_primary=LINE, border_color_accent_subdued=LINE_STRONG, color_accent_soft="rgba(47, 143, 240, 0.18)", link_text_color=CYAN, link_text_color_hover=ICE, link_text_color_visited=CYAN, link_text_color_active=ICE, code_background_fill=NIGHT, shadow_drop_lg="0 20px 60px rgba(0, 0, 0, 0.35)", block_background_fill="rgba(10, 22, 48, 0.72)", block_border_color=LINE, block_label_text_color=TEXT_MUTED, block_title_text_color=TEXT, input_background_fill=NAVY_2, input_background_fill_focus=NAVY_2, input_background_fill_hover=NAVY_2, input_border_color=LINE, input_border_color_hover=LINE_STRONG, checkbox_background_color=NIGHT, checkbox_background_color_hover=NIGHT, checkbox_background_color_focus=NIGHT, checkbox_border_color=LINE_STRONG, checkbox_label_background_fill="rgba(12, 36, 71, 0.6)", checkbox_label_background_fill_hover="rgba(21, 116, 235, 0.14)", checkbox_label_background_fill_selected="rgba(21, 116, 235, 0.22)", checkbox_label_border_color=LINE, checkbox_label_border_color_hover=LINE_STRONG, checkbox_label_border_color_selected="rgba(47, 143, 240, 0.65)", checkbox_label_text_color=TEXT, checkbox_label_text_color_selected=TEXT, table_border_color=LINE, table_even_background_fill=NAVY, table_odd_background_fill=NAVY_2, table_row_focus="rgba(21, 116, 235, 0.18)", table_text_color=TEXT, button_primary_shadow="0 0 24px rgba(232, 105, 42, 0.35)", button_primary_shadow_hover="0 0 32px rgba(232, 105, 42, 0.5)", button_secondary_background_fill="rgba(12, 36, 71, 0.6)", button_secondary_background_fill_hover="rgba(21, 116, 235, 0.18)", button_secondary_border_color=LINE_STRONG, button_secondary_text_color=TEXT, button_secondary_text_color_hover=TEXT, ) _LIGHT = dict( body_background_fill=PAPER, body_text_color=INK_NAVY, body_text_color_subdued=INK_MUTED, background_fill_primary=WHITE, background_fill_secondary=PAPER_2, border_color_primary=LINE_L, border_color_accent_subdued=LINE_STRONG_L, color_accent_soft="rgba(21, 116, 235, 0.10)", link_text_color=COBALT_TEXT, link_text_color_hover=COBALT, link_text_color_visited=COBALT_TEXT, link_text_color_active=COBALT, code_background_fill=PAPER, shadow_drop_lg="0 18px 50px rgba(21, 60, 120, 0.10)", block_background_fill="rgba(255, 255, 255, 0.82)", block_border_color=LINE_L, block_label_text_color=INK_MUTED, block_title_text_color=INK_NAVY, input_background_fill=WHITE, input_background_fill_focus=WHITE, input_background_fill_hover=WHITE, input_border_color=LINE_STRONG_L, input_border_color_hover="rgba(21, 60, 120, 0.36)", checkbox_background_color=WHITE, checkbox_background_color_hover=WHITE, checkbox_background_color_focus=WHITE, checkbox_border_color="rgba(21, 60, 120, 0.36)", checkbox_label_background_fill=PAPER_2, checkbox_label_background_fill_hover="rgba(21, 116, 235, 0.08)", checkbox_label_background_fill_selected="rgba(21, 116, 235, 0.10)", checkbox_label_border_color=LINE_L, checkbox_label_border_color_hover=LINE_STRONG_L, checkbox_label_border_color_selected="rgba(21, 116, 235, 0.45)", checkbox_label_text_color=INK_NAVY, checkbox_label_text_color_selected=INK_NAVY, table_border_color=LINE_L, table_even_background_fill=WHITE, table_odd_background_fill=PAPER, table_row_focus="rgba(21, 116, 235, 0.08)", table_text_color=INK_NAVY, button_primary_shadow="0 6px 18px rgba(232, 105, 42, 0.25)", button_primary_shadow_hover="0 8px 24px rgba(232, 105, 42, 0.35)", button_secondary_background_fill=WHITE, button_secondary_background_fill_hover="rgba(21, 116, 235, 0.06)", button_secondary_border_color=LINE_STRONG_L, button_secondary_text_color=INK_NAVY, button_secondary_text_color_hover=INK_NAVY, ) def build_theme() -> gr.themes.Base: theme = gr.themes.Base( primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.orange, neutral_hue=gr.themes.colors.slate, radius_size=gr.themes.sizes.radius_lg, font=[gr.themes.GoogleFont(FONT, weights=(300, 400, 500, 600)), "ui-sans-serif", "system-ui", "sans-serif"], font_mono=[gr.themes.GoogleFont(FONT_MONO), "ui-monospace", "monospace"], ) valid = set(inspect.signature(theme.set).parameters) values = {} for k, v in _SHARED.items(): if k in valid: values[k] = v if f"{k}_dark" in valid: values[f"{k}_dark"] = v for k, v in _LIGHT.items(): if k in valid: values[k] = v for k, v in _DARK.items(): if f"{k}_dark" in valid: values[f"{k}_dark"] = v elif k in valid and k not in _LIGHT: values[k] = v return theme.set(**values) # Opens in light unless the viewer chose dark before (remembered in this browser) or the URL has # ?__theme=dark. Gradio would otherwise follow the system setting, so the class is set explicitly. # The light-bulb button toggles the theme; a click handler on the document survives re-renders. THEME_JS = """ () => { const KEY = 'safetulu-theme'; const sync = (dark) => { const btn = document.getElementById('theme-toggle'); if (!btn) return; const label = dark ? 'Switch to light theme' : 'Switch to dark theme'; btn.setAttribute('aria-label', label); btn.setAttribute('title', label); btn.setAttribute('aria-pressed', String(dark)); }; const apply = (mode) => { const dark = mode === 'dark'; document.body.classList.toggle('dark', dark); document.documentElement.style.colorScheme = dark ? 'dark' : 'light'; sync(dark); }; let saved = null; try { saved = localStorage.getItem(KEY); } catch (e) {} const param = new URLSearchParams(window.location.search).get('__theme'); apply(param === 'dark' || param === 'light' ? param : (saved === 'dark' ? 'dark' : 'light')); document.addEventListener('click', (event) => { if (!event.target.closest('#theme-toggle')) return; const next = document.body.classList.contains('dark') ? 'light' : 'dark'; apply(next); try { localStorage.setItem(KEY, next); } catch (e) {} }); // "Use via API" lives in the footer; hide it there and open it from the hero button instead. const apiBtn = () => Array.from(document.querySelectorAll('footer button, footer a')) .find((el) => /use via api/i.test(el.textContent || '')); const hideFooterApi = () => { const el = apiBtn(); if (!el) return; el.style.display = 'none'; const sep = el.nextElementSibling; if (sep && /^\\s*[·•]\\s*$/.test(sep.textContent || '')) sep.style.display = 'none'; }; hideFooterApi(); new MutationObserver(hideFooterApi).observe(document.body, { childList: true, subtree: true }); document.addEventListener('click', (event) => { if (!event.target.closest('.api-docs-btn')) return; event.preventDefault(); const el = apiBtn(); if (el) el.click(); }); // The hero (and its button) can render after this runs; label it once it exists. const obs = new MutationObserver(() => { if (document.getElementById('theme-toggle')) { sync(document.body.classList.contains('dark')); obs.disconnect(); } }); obs.observe(document.body, { childList: true, subtree: true }); } """ # --------------------------------------------------------------------------- # Brand pieces # --------------------------------------------------------------------------- def _grain(rgb: str) -> str: return ( "url(\"data:image/svg+xml;utf8,\")" ) _GRAIN = _grain("1") # light speckle, for dark surfaces and the hero _GRAIN_DARK = _grain("0.1") # dark speckle, for the light page # Light-bulb icon (Lucide "lightbulb", ISC license). The glass fills in when the light theme is on. _BULB = ( '' ) def hero_html(repo_id: str, n_examples: int, official_pct: float) -> str: return f"""
remove the Tulu 3 data that sits closest to harm, at any threshold you choose