import gradio as gr import requests import os import uuid # --- Configuration --- MODAL_BACKEND_URL = os.getenv("MODAL_BACKEND_URL", "").strip() # --- UI Styling --- CUSTOM_CSS = """ body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } .gradio-container { max-width: 800px !important; margin: auto; padding-top: 2rem; } #chatbot { background-color: #F8F9FA; border-radius: 0.5rem; border: 1px solid #DEE2E6; min-height: 450px; } .message { padding: 1rem; border-radius: 0.5rem; } .message.user { background-color: #E9ECEF !important; } .message.bot { background-color: #FFFFFF !important; color: #343a40; /* Ensures text is visible on white background */ } footer { display: none !important; } """ # --- Gradio UI Definition --- with gr.Blocks(theme=gr.themes.Soft(), css=CUSTOM_CSS, title="MediAgent AI") as demo: # --- State Management --- conversation_state = gr.State(value={"history": []}) session_id = gr.State(lambda: str(uuid.uuid4())) # --- Header --- gr.Markdown(""" # 🧬 MediAgent AI (Conversational) _Your Smart, Role-Aware AI Health Navigator_ """) # --- User Role Selection --- user_role = gr.Radio( ["patient", "doctor", "health_worker"], label="👤 Select Your Role", value="patient", info="The AI will adapt its communication style and questions based on your role." ) # --- Chat Interface --- chatbot = gr.Chatbot( label="Conversation", elem_id="chatbot", bubble_full_width=False, avatar_images=(None, "https://i.imgur.com/9k2p4t7.png") ) with gr.Row(): user_textbox = gr.Textbox( scale=4, show_label=False, placeholder="Type your message here...", container=False, ) submit_btn = gr.Button("Send", variant="primary", scale=1, min_width=150) with gr.Row(): clear_btn = gr.ClearButton( value="🔄 Start New Conversation", components=[chatbot, user_textbox, conversation_state] ) # --- Main UI Logic --- def handle_user_turn( user_input: str, chat_history: list, user_role_selection: str, current_state: dict, sid: str ): if not user_input.strip(): return {chatbot: chat_history, conversation_state: current_state} chat_history.append((user_input, None)) yield {chatbot: chat_history} if not MODAL_BACKEND_URL: error_message = "### ❗ Configuration Error\n**Reason**: `MODAL_BACKEND_URL` environment variable is not set. The administrator needs to configure the application." chat_history[-1] = (user_input, error_message) yield {chatbot: chat_history} return headers = {"Content-Type": "application/json"} payload = { "user_input": user_input, "session_id": sid, "user_role": user_role_selection, "conversation_state": current_state } try: response = requests.post(MODAL_BACKEND_URL, headers=headers, json=payload, timeout=300) response.raise_for_status() backend_response = response.json() bot_response_text = backend_response.get("response_text", "Sorry, I received an empty response.") new_state = backend_response.get("conversation_state", current_state) except requests.exceptions.RequestException as e: bot_response_text = f"### ❗ Network Error\n**Reason**: Could not connect to the backend.\n**Details**: {str(e)}" new_state = current_state chat_history[-1] = (user_input, bot_response_text) yield {chatbot: chat_history, conversation_state: new_state} # --- Event Listeners --- submit_event = submit_btn.click( fn=handle_user_turn, inputs=[user_textbox, chatbot, user_role, conversation_state, session_id], outputs=[chatbot, conversation_state], show_progress="hidden" ).then(lambda: gr.update(value=""), outputs=[user_textbox]) textbox_event = user_textbox.submit( fn=handle_user_turn, inputs=[user_textbox, chatbot, user_role, conversation_state, session_id], outputs=[chatbot, conversation_state], show_progress="hidden" ).then(lambda: gr.update(value=""), outputs=[user_textbox]) @clear_btn.click def clear_chat(): return {"history": []} if __name__ == "__main__": print("Gradio App Starting...") if not MODAL_BACKEND_URL: print("\nWARNING: The `MODAL_BACKEND_URL` environment variable is not set.") print("The application will run, but will show a configuration error.\n") demo.queue() demo.launch()