import gradio as gr import requests import os from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from ping import add_ping_route # ===== THEME COLOR VARIABLES ===== PRIMARY_COLOR = "#13406B" # CPA Dark Corporate Blue SECONDARY_COLOR = "#CD9D5B" # CPA Muted Bronze/Tan BACKGROUND_COLOR = "#f8fafc" # Light gray - page background TEXT_COLOR = "#1e293b" # Dark slate - text color # Configuration LANGFLOW_API_URL = os.environ.get("LANGFLOW_API_URL", "") LANGFLOW_API_KEY = os.environ.get("LANGFLOW_API_KEY", "") HF_API_KEY = os.environ.get("HF_API_KEY", "") if not LANGFLOW_API_URL: print("FATAL: LANGFLOW_API_URL secret not found or is empty.") else: print("SUCCESS: LANGFLOW_API_URL loaded securely.") if not LANGFLOW_API_KEY: print("FATAL: LANGFLOW_API_KEY secret not found or is empty.") else: print("SUCCESS: LANGFLOW_API_KEY loaded securely.") if not HF_API_KEY: print("FATAL: HF_API_KEY secret not found or is empty.") else: print("SUCCESS: HF_API_KEY loaded securely.") # Function that calls the LangFlow chat def call_langflow_api(message): """ Call Langflow API and return the response """ headers = { "Content-Type": "application/json", } # Add API keys if HF_API_KEY: headers["Authorization"] = f"Bearer {HF_API_KEY}" if LANGFLOW_API_KEY: headers["x-api-key"] = f"{LANGFLOW_API_KEY}" # Adjust this payload based on your Langflow API structure payload = { "input_value": message, "output_type": "chat", "input_type": "chat", "tweaks": {} } try: response = requests.post( LANGFLOW_API_URL, json=payload, headers=headers, timeout=30 ) response.raise_for_status() # Parse response - adjust based on your API response structure data = response.json() bot_message = data["outputs"][0]["outputs"][0]["results"]["message"]["text"] return bot_message except requests.exceptions.RequestException as e: return f"Error connecting to Langflow: {str(e)}" except (KeyError, IndexError) as e: return f"Error parsing response: {str(e)}\nResponse: {data}" #Create FastAPI App for health check. fastapi_app = FastAPI(title="Chatbot with Ping API") # Optional CORS setup fastapi_app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Add /ping route from ping.py add_ping_route(fastapi_app, call_langflow_api) # Custom CSS using theme variables custom_css = f""" /* Hide footer */ footer {{display: none !important;}} .footer {{display: none !important;}} #footer {{display: none !important;}} .svelte-1p1dq6v {{display: none !important;}} /* Main container background */ .gradio-container {{ background-color: {BACKGROUND_COLOR} !important; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }} /* Chatbot container styling */ #chatbot-window {{ background-color: {BACKGROUND_COLOR} !important; border-radius: 12px !important; box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; border: 2px solid {PRIMARY_COLOR} !important; }} #chatbot-window .placeholder-content {{ background-color: {BACKGROUND_COLOR} !important; }} #chatbot-window .bubble-wrap {{ background-color: {BACKGROUND_COLOR} !important; }} /* Description text */ #descr p{{ color: black !important; font-size: 16px !important; margin-bottom: 20px !important; }} #disclaimer {{ background-color: {PRIMARY_COLOR} !important; color: white !important; font-size: 16px !important; border: 2px solid {SECONDARY_COLOR} !important; border-radius: 8px !important; }} #disclaimer p {{ color: white !important; }} /* User messages */ #chatbot-window .message.user {{ background-color: {SECONDARY_COLOR} !important; color: white !important; border: none !important; }} #chatbot-window .flex-wrap {{ border: none !important; }} #chatbot-window .message.user p{{ color: white !important; }} /* Bot messages */ #chatbot-window .message.bot {{ background-color: {PRIMARY_COLOR} !important; color: white !important; border: none !important; }} #chatbot-window .message.bot p{{ color: white !important; }} /* All text inside bot messages, avoids changes from browser theme */ #chatbot-window .message.bot *, #chatbot-window .message.bot li {{ color: white !important; }} /* Input textbox */ #input-textbox {{ background-color: {BACKGROUND_COLOR} !important; }} /* this gets the text box and send button to align */ #component-4 {{ display: flex; /* ensure it's a flex container */ align-items: center; /* vertically centers children */ gap: 10px; /* optional spacing between textbox & button */ }} /* this removes the text box border that was unnecessary */ div.form {{ --block-border-width: 0px !important; --block-shadow: none !important; --block-radius: 0px !important; padding: 0 !important; }} #input-textbox textarea{{ border: 2px solid {SECONDARY_COLOR} !important; border-radius: 8px !important; font-size: 16px !important; color: {TEXT_COLOR} !important; background-color: {BACKGROUND_COLOR} !important; }} #input-textbox textarea:focus {{ border-color: {PRIMARY_COLOR} !important; box-shadow: 0 0 0 3px rgba(19, 64, 107, 0.1) !important; }} /* Buttons */ button {{ border-radius: 8px !important; font-weight: 600 !important; }} /* Primary buttons (Send) */ #send-button {{ background-color: {PRIMARY_COLOR} !important; color: white !important; border: none !important; }} #send-button:hover {{ background-color: {SECONDARY_COLOR} !important; }} /* Secondary buttons (Clear) */ button.secondary {{ background-color: white !important; color: {PRIMARY_COLOR} !important; border: 2px solid {SECONDARY_COLOR} !important; }} button.secondary:hover {{ background-color: {BACKGROUND_COLOR} !important; }} /* Example buttons */ #example-buttons button {{ background-color: {PRIMARY_COLOR} !important; color: white !important; border: 2px solid {SECONDARY_COLOR} !important; border-radius: 8px !important; font-weight: 500 !important; }} #example-buttons button:hover {{ background-color: {SECONDARY_COLOR} !important; }} /* Example label text */ #example-buttons .label {{ color: {TEXT_COLOR} !important; font-size: 16px !important; }} """ # Create custom Gradio interface with Blocks with gr.Blocks(css=custom_css, analytics_enabled=False) as chatui: # Description gr.Markdown( "Ask Cosmo the cougar questions related to Crown Pointe Academy policies.", elem_classes="description", elem_id="descr" ) #Diclaimer gr.HTML("
I am an AI guide on school policies, not the official source. I may " \ "generate misinformation. Verify all results with official school documents.
", elem_id="disclaimer") # Chatbot component - MUST use type='messages' chatbot = gr.Chatbot( type='messages', height=500, elem_classes="chatbot", elem_id="chatbot-window" ) # Input row with gr.Row(): msg = gr.Textbox( label="", placeholder="Type your question here...", scale=4, show_label=False, elem_id="input-textbox" ) submit = gr.Button( "Send", scale=1, variant="primary", elem_id="send-button" ) # Example buttons gr.Examples( examples=[ "What is the dress code for students?", "How do I report an absence?", "What is the policy on cell phones?" ], inputs=msg, label="Try these examples:", elem_id="example-buttons" ) # Clear button clear = gr.Button("Clear Chat", variant="secondary") # Chat logic for messages format def respond(message, chat_history): if not message.strip(): return "", chat_history # Get bot response bot_message = call_langflow_api(message) # Append messages in the new format chat_history.append({"role": "user", "content": message}) chat_history.append({"role": "assistant", "content": bot_message}) return "", chat_history # Event handlers - mark as non-API to avoid schema issues msg.submit(respond, [msg, chatbot], [msg, chatbot], api_name=False) submit.click(respond, [msg, chatbot], [msg, chatbot], api_name=False) clear.click(lambda: [], None, chatbot, queue=False, api_name=False) # Mount Gradio app to FastAPI at root path app = gr.mount_gradio_app(fastapi_app, chatui, path="/")