NeuroBait / ui.py
Haris-Subrata's picture
Upload folder using huggingface_hub
c8c1166 verified
"""NeuroBait UI — hybrid: a standard AI-chat experience (``gr.ChatInterface``,
DeepSeek/Perplexity-ish) carrying NeuroBait's identity.
gradio-only (no torch/spaces) so the UI can be built and smoke-tested without the
model stack. Theme + CSS are applied at ``launch()`` because Gradio 6 moved
``theme``/``css``/``js`` off the Blocks/ChatInterface constructor — see the
deprecation warning we hit in the Space logs.
Dark-only, earthy, calm sage-teal accent (gentler / more sensory-safe for ADHD
than vivid green). The palette is set straight on ``:root`` and mapped onto
Gradio's core CSS vars unconditionally, so the app is dark with no dependence on
JS or HF's ``?__theme``.
"""
from __future__ import annotations
import gradio as gr
MOODS = ["Calm", "Tired", "Anxious", "Focused"]
THEME = gr.themes.Soft(primary_hue="teal", neutral_hue="slate")
TITLE = "🧠 NeuroBait"
DESCRIPTION = (
"A warm space and a gentle boost for your everyday — NeuroBait works *with* "
"your dopamine, not against your willpower. Your brain isn't broken; it's "
"wired for a different kind of focus."
)
PLACEHOLDER = (
"### 🧠 NeuroBait\n"
"Tell me what's on your mind — no need to be tidy, just honest.\n\n"
"*No red pen · no urgency · no streaks.*"
)
EXAMPLES = [
["There's something I've been meaning to get to, and it keeps slipping by.", "Calm"],
["My space feels a bit cluttered today.", "Tired"],
["My mind feels a little foggy right now.", "Anxious"],
]
CSS = """
/* Earthy, always-dark palette on :root (no .dark dependency), with a calm muted
sage-teal accent instead of vivid green. */
:root {
--forest: #6fb6a2;
--sage: #5da894;
--mint: #20362f;
--cream: #1d2128;
--linen: #15181d;
--sand: #2e333b;
--stone: #aeb6bf;
--charcoal: #eef1f4;
--radius: 10px;
--brand-grad: linear-gradient(135deg, #5da894, #4f9582);
}
/* map Gradio core theme vars onto our dark palette so built-in components render
dark even when Gradio's own .dark class is off */
body, .gradio-container, gradio-app, .dark {
--body-background-fill: var(--linen);
--background-fill-primary: var(--cream);
--background-fill-secondary: var(--linen);
--block-background-fill: var(--cream);
--block-label-background-fill: var(--cream);
--block-border-color: var(--sand);
--border-color-primary: var(--sand);
--body-text-color: var(--charcoal);
--body-text-color-subdued: var(--stone);
--input-background-fill: var(--cream);
--input-border-color: var(--sand);
--button-secondary-background-fill: var(--cream);
--button-secondary-text-color: var(--charcoal);
}
body, .gradio-container {
background: var(--linen) !important;
color: var(--charcoal) !important;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji" !important;
}
/* keep the conversation in a comfortable centered column like a modern chat app */
.gradio-container { max-width: 960px !important; margin: 0 auto !important; }
h1 { letter-spacing: -0.5px; font-weight: 800; }
/* user bubble gets the brand accent, assistant stays flat/quiet */
.message.user, [data-testid="user"] {
background: var(--brand-grad) !important; color: #fff !important; border: none !important;
}
.message.bot, [data-testid="bot"] {
background: var(--cream) !important; border: 1px solid var(--sand) !important; color: var(--charcoal) !important;
}
/* rounded, calm input + primary button */
textarea, input[type="text"] {
border-radius: var(--radius) !important; background: var(--cream) !important;
border: 1px solid var(--sand) !important; color: var(--charcoal) !important;
}
button.primary, .submit-button, [variant="primary"] {
background: var(--brand-grad) !important; border: none !important; color: #fff !important;
}
"""
def message_text(content) -> str:
if isinstance(content, str):
return content.strip()
if isinstance(content, list):
parts = []
for item in content:
if isinstance(item, dict):
text = item.get("text")
if isinstance(text, str):
parts.append(text)
return " ".join(part.strip() for part in parts if part.strip()).strip()
return ""
def build_demo(respond_fn):
"""Build the NeuroBait chat. ``respond_fn`` signature (streaming generator ok):
respond_fn(message: str, history: list[dict], mood: str) -> str | generator[str]
"""
mood = gr.Radio(MOODS, value="Calm", label="🌳 How are you feeling?")
chatbot = gr.Chatbot(
height=560,
show_label=False,
placeholder=PLACEHOLDER,
avatar_images=(None, None),
)
return gr.ChatInterface(
fn=respond_fn,
chatbot=chatbot,
additional_inputs=[mood],
additional_inputs_accordion=gr.Accordion("🌳 How are you feeling?", open=True),
title=TITLE,
description=DESCRIPTION,
examples=EXAMPLES,
cache_examples=False,
save_history=True,
fill_height=True,
autoscroll=True,
)