Spaces:
Sleeping
Sleeping
J-Barrert
Fix: match Gradio 5.20 CSS specificity - duplicate rules with container prefix so dynamic <style> overrides initial css
7a16ed0 | 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) | |