J-Barrert
Fix: match Gradio 5.20 CSS specificity - duplicate rules with container prefix so dynamic <style> overrides initial css
7a16ed0
Raw
History Blame Contribute Delete
5.62 kB
import os
import gradio as gr
import rag_engine as rag
print("Loading RAG engine...")
RETRIEVER = rag.build_retriever()
print(f"Loaded {len(RETRIEVER['texts'])} FAQ entries.")
API_KEY = os.environ.get("OPENROUTER_API_KEY", "")
DEFAULT_ACCENT = "#667eea"
DEFAULT_BOT_NAME = "FlowBar Support"
DEFAULT_TAGLINE = "Ask me anything about FlowBar -- account setup, features, billing, or troubleshooting."
PRESET_COLORS = [
("Violet", "#667eea"),
("Teal", "#0d9488"),
("Blue", "#3b82f6"),
("Green", "#22c55e"),
("Orange", "#f97316"),
("Pink", "#ec4899"),
("Red", "#ef4444"),
("Gold", "#eab308"),
("Gray", "#6b7280"),
]
def respond(message, history):
if not message.strip():
return "Please enter a question."
results = rag.search(RETRIEVER, message, top_k=3)
if not results:
return "I could not find relevant info. Try rephrasing."
if API_KEY:
text, _ = rag.generate_response(message, results, API_KEY)
else:
text, _ = rag.generate_response_light(message, results)
return text
def _is_dark_color(hex_color):
"""Returns True if accent is dark (text needs to be white for contrast)."""
hex_color = hex_color.lstrip("#")
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
return luminance < 0.5
def make_custom_css(accent):
"""Return full CSS with accent color applied to visible elements."""
text_color = "#ffffff" if _is_dark_color(accent) else "#1a1a2e"
# Gradio 5.20 wraps every CSS rule with high-specificity container prefix,
# so we duplicate each rule with the same prefix to match specificity.
# With equal specificity, the later rule (our dynamic injection) wins.
p = ".gradio-container.gradio-container-5-20-0 .contain"
return f"""
.gradio-container {{ max-width: 800px !important; margin: 0 auto; min-height: 600px; }}
.bot-row {{ background: #2d2d3d !important; }}
{p} .bot-row {{ background: #2d2d3d !important; }}
footer {{ display: none !important; }}
{p} footer {{ display: none !important; }}
/* --- Accent: header text --- */
h1 {{ color: {accent} !important; text-align: center; margin-bottom: 4px; }}
{p} h1 {{ color: {accent} !important; text-align: center; margin-bottom: 4px; }}
/* --- Accent: send button --- */
.submit-button, button.primary {{
background: {accent} !important;
border-color: {accent} !important;
color: {text_color} !important;
}}
{p} .submit-button, {p} button.primary {{
background: {accent} !important;
border-color: {accent} !important;
color: {text_color} !important;
}}
.submit-button:hover, button.primary:hover {{
filter: brightness(1.15) !important;
}}
{p} .submit-button:hover, {p} button.primary:hover {{
filter: brightness(1.15) !important;
}}
/* --- Accent: example buttons --- */
button.example {{
border-color: {accent}66 !important;
color: {accent} !important;
}}
{p} button.example {{
border-color: {accent}66 !important;
color: {accent} !important;
}}
button.example:hover {{
background: {accent}22 !important;
border-color: {accent} !important;
}}
{p} button.example:hover {{
background: {accent}22 !important;
border-color: {accent} !important;
}}
/* --- Accent: user chat bubbles --- */
.user-row {{
background: {accent} !important;
color: {text_color} !important;
border-radius: 18px 18px 4px 18px !important;
}}
{p} .user-row {{
background: {accent} !important;
color: {text_color} !important;
border-radius: 18px 18px 4px 18px !important;
}}
/* --- Accent: accordion toggle text --- */
.label-wrap {{
color: {accent} !important;
}}
{p} .label-wrap {{
color: {accent} !important;
}}
/* --- Accent: accordion open state --- */
.label-wrap.open {{
border-color: {accent} !important;
}}
{p} .label-wrap.open {{
border-color: {accent} !important;
}}
"""
def make_header(name, tagline, accent):
return f"""
<div style="text-align:center;border-bottom:3px solid {accent};padding-bottom:12px;margin-bottom:4px;">
<h1 style="color:{accent};margin-bottom:2px;">{name}</h1>
<p style="color:#aaaaaa;margin-top:4px;">{tagline}</p>
</div>
"""
def update_all(name, tagline, accent):
h = make_header(name, tagline, accent)
css = f"<style>{make_custom_css(accent)}</style>"
return h, css
with gr.Blocks(
css=make_custom_css(DEFAULT_ACCENT),
theme=gr.themes.Soft(primary_hue="violet", neutral_hue="slate"),
) as demo:
header = gr.HTML(make_header(DEFAULT_BOT_NAME, DEFAULT_TAGLINE, DEFAULT_ACCENT))
css_holder = gr.HTML("")
chatbot = gr.ChatInterface(
respond,
examples=[
"How do I sign up for FlowBar?",
"Can I cancel anytime?",
"What's the free plan include?",
"How do I create a task?",
"Do you have a mobile app?",
],
cache_examples=False,
)
with gr.Accordion("Customize Your Bot", open=False):
name_input = gr.Textbox(label="Bot Name", value=DEFAULT_BOT_NAME)
tagline_input = gr.Textbox(label="Tagline", value=DEFAULT_TAGLINE, lines=2)
color_input = gr.Dropdown(
label="Accent Color",
choices=PRESET_COLORS,
value=DEFAULT_ACCENT,
)
apply_btn = gr.Button("Apply", variant="primary", size="sm")
apply_btn.click(
update_all,
inputs=[name_input, tagline_input, color_input],
outputs=[header, css_holder],
)
demo.launch(server_name="0.0.0.0", server_port=7860)