from threading import Thread import gradio as gr from gradio.themes import Base from gradio.themes.utils import colors from transformers import pipeline, TextIteratorStreamer # Custom theme colors based on brand standards class ArtemisiaTheme(Base): def __init__(self, **kwargs): # Configure Gradio's theme system with our colors super().__init__( font=["Segoe UI", "Tahoma", "Geneva", "Verdana", "sans-serif"], primary_hue=colors.indigo, neutral_hue=colors.gray, **kwargs ) # Background settings self.body_background_fill = "#4f008c" self.background_fill_primary = self.neutral_800 self.block_background_fill = "transparent" self.block_label_background_fill = self.neutral_700 # Components self.button_primary_background_fill = self.primary_900 self.button_primary_background_fill_hover = self.primary_700 # Input fields self.input_background_fill = "#000000" self.input_border_color = "transparent" # Text colors self.text_color = "#ffffff" self.error_text_color = "#ff5252" # Custom CSS for exact layout and styling custom_css = """ body { margin: 0; padding: 0; width: 100%; background-color: #4f008c; color: #fff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } .gradio-container { background-color: #4f008c !important; } header { background-color: #4a0082; padding: 10px 20px; display: flex; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); flex-wrap: nowrap; align-items: center; gap: 24px; } .logo-container { display: flex; gap: 0px; flex-direction: row; width: fit-content !important; flex: 0 0 auto !important; min-width: 0 !important; } .nav-divider { width: 1px; height: 24px; background-color: rgba(255, 255, 255, 0.2); margin: 0 10px; } .dashboard-title { font-size: 0.875rem; font-weight: 400; margin: 0; white-space: nowrap; flex: 1 1 0%; min-width: 0; overflow: hidden; text-overflow: ellipsis; } .stc-logo svg { width: 66px; height: 32px; } /* Explicitly ensure STC logo is white */ .stc-logo svg path { fill: #ffffff !important; } .about-section { padding: 12px 20px; background-color: #000; border-bottom: 1px solid #333; } .about-section h2 { color: #ff5252; margin-bottom: 6px; font-size: 1rem; font-weight: 600; } .about-section p { font-size: 0.875rem; line-height: 1.6; } .main-content { display: flex; padding: 0; background-color: #4f008c; gap: 8px; justify-content: space-between; } .chat-container, .results-container { flex: 1; background-color: transparent; border-radius: 15px; padding: 0; display: flex; flex-direction: column; min-height: 550px; max-height: 550px; height: 550px; overflow: hidden; margin: 0; gap: 0 !important; } .section-header { gap: 0; background-color: #120428; border-radius: 15px 15px 0 0; padding: 12px; margin-bottom: 0; } .section-header h2 { margin: 0; padding: 0; font-size: 0.875rem; font-weight: 600; } .section-header p { margin: 0; padding: 4px 0 0 0; color: #ccc; font-size: 0.75rem; } .chat-content { flex: 1; background-color: #0a0013; border-radius: 0 0 15px 15px; padding: 0; margin: 0; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden; } .chat-messages { flex: 1; background: #120428 !important; padding: 10px !important; margin: 0 !important; max-width: 100%; border: none; overflow-y: auto; } .results-content { flex: 1; background-color: #0a0013; border-radius: 0 0 15px 15px; padding: 16px; margin: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } .placeholder-text { color: #aaa; font-size: 0.75rem; max-width: 400px; line-height: 1.6; } /* Updated styles to match the image reference */ .gradio-container { max-width: 100% !important; padding: 0 !important; } .chat-container { padding: 0; margin: 0; } .results-container { padding: 0; margin: 0; min-width: min(50%, 100%) !important; } #component-0 > .gr-form > div:not(.about-section):not(.header) { background-color: #4f008c; } /* Chat messages container adjustments */ .chat-messages { padding: 0 !important; margin: 0 !important; border: none !important; } /* Remove any gaps between elements, but exclude section headers */ .chat-container > div:not(.section-header), .results-container > div:not(.section-header) { margin: 0 !important; padding: 0 !important; } /* Override flex-grow for section headers */ #component-27, .column.section-header, div[id^="component"][class*="column section-header"] { flex-grow: 0 !important; } /* Add more forceful display for chatbot component */ .gradio-chatbot { height: auto !important; min-height: 400px !important; display: block !important; width: 100% !important; overflow-y: auto !important; visibility: visible !important; opacity: 1 !important; } /* Also target the container of the chatbot */ .message-wrap { display: block !important; visibility: visible !important; opacity: 1 !important; } /* Target the messages themselves */ .message { display: block !important; visibility: visible !important; opacity: 1 !important; } /* Ensure chat bubbles have proper max-width */ .bubble-wrap { background: #0A0013; margin: 0 !important; padding: 0 !important; min-width: 100%; border: none !important; } /* Target the chat bubble containers */ .gradio-chatbot .messages-wrapper > div > div { max-width: 70% !important; /* Allow bubbles to be a bit wider */ width: auto !important; /* Let content determine width, up to max-width */ min-width: 30% !important; /* Ensure a minimum width */ } /* Style the individual message bubbles */ .gradio-chatbot .messages-wrapper > div > div > div { width: 100% !important; /* Text fills the bubble */ padding: 10px 15px !important; /* Add more padding for better readability */ border-radius: 12px !important; /* Rounded corners */ } /* Focus on the text content inside bubbles */ .gradio-chatbot .bubble { width: 100% !important; /* Fill the bubble width */ max-width: 100% !important; word-wrap: break-word !important; overflow-wrap: break-word !important; display: block !important; /* Ensure it takes full width */ white-space: normal !important; /* Allow proper wrapping */ } /* Target the actual text paragraphs inside bubbles */ .gradio-chatbot .bubble p, .gradio-chatbot .bubble span, .gradio-chatbot .bubble div { width: 100% !important; display: inline-block !important; word-break: break-word !important; white-space: normal !important; text-align: left !important; } /* Target the first lines of text specifically to ensure they fill the width */ .gradio-chatbot .bubble p:first-child, .gradio-chatbot .bubble span:first-child { width: 100% !important; display: block !important; } /* Specific gradio selector */ .chat-messages [data-testid="chatbot"] .message-wrap > div { max-width: 50% !important; } .chat-input-container { width: 100%; position: relative; border-top: 1px solid rgba(255, 255, 255, 0.1); padding: 16px; background-color: #000000; display: flex; gap: 0 !important; } .chat-input { flex-grow: 1; padding: 0px; background-color: #000000; border: none; border-radius: 8px 0 0 8px; color: #fff; font-size: 0.875rem; width: 100%; margin: 0 !important; } .send-button { width: 50px !important; min-width: 40px !important; max-width: 50px !important; height: 100%; background-color: #993333; border: none !important; border-radius: 0 8px 8px 0; color: white; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background-color 0.2s ease; margin: 0 !important; } .send-button:hover { background-color: #b33c3c; } .container.show_textbox_border { border: none !important; background: transparent !important; box-shadow: none !important; margin: 0 !important; } .input-container { background: transparent !important; border: none !important; margin: 0 !important; } .input-container textarea { background: transparent !important; color: #fff !important; border: none !important; box-shadow: none !important; border-radius: 0 !important; min-width: min(80%, 100%) !important; } span[data-testid="block-info"] { display: none !important; } .chat-input::placeholder { color: #aaa; background-color: #000000; padding: 0px; } /* Paper plane icon styling for the send button */ .send-icon { width: 20px; height: 20px; } .send-button svg { width: 20px; height: 20px; display: block; margin: auto; } .bot, .user { max-width: 70% !important; width: fit-content !important; } """ # SVG icons stc_logo_svg = """""" artemsia_logo_svg = """ """ # Paper plane SVG icon for send button paper_plane_svg = """ """ # Pipeline loading generator = pipeline("text-generation", model="openai-community/gpt2") # Mock data function for chatbot def send_message(message, history): #if not message: # return history #history.append({"role": "user", "content": message}) #history.append({"role": "assistant", "content": f"This is a response about: {message}"}) #return history tokenizer = generator.tokenizer streamer = TextIteratorStreamer(tokenizer, skip_prompt=True) input_ids = tokenizer.encode(message, return_tensors="pt") gen_kwargs = { "inputs": input_ids, "streamer": streamer, "pad_token_id": tokenizer.eos_token_id, "max_length": 8192, "temperature": 0.1, "top_p": 0.8, "repetition_penalty": 1.25, } partial = "" thread = Thread(target=pipeline, kwargs=gen_kwargs) thread.start() #for token in generator(message, max_new_tokens=200): for t in streamer: partial += t#token["generated_text"][len(message):] yield history + [{"role": "assistant", "content": partial}] # Create the dashboard with gr.Blocks(theme=ArtemisiaTheme(), css=custom_css) as demo: # Header with gr.Row(elem_classes="header"): with gr.Row(elem_classes="logo-container"): gr.HTML(stc_logo_svg, elem_classes="stc-logo") gr.HTML('', elem_classes="divider") gr.HTML(artemsia_logo_svg, elem_classes="stc-logo") gr.Markdown("# Risk Insights Dashboard", elem_classes="dashboard-title") # Main content area with gr.Row(elem_classes="main-content"): # Chat column with gr.Column(scale=1, elem_classes="chat-container"): with gr.Column(elem_classes="section-header"): gr.Markdown("## Chat Interface") gr.Markdown("Query your Archer risk data here or ask questions for valuable insights.") with gr.Column(elem_classes="chat-content"): chatbot = gr.Chatbot(value=[ {"role": "assistant", "content": "Welcome to Risk Insights. How can I help you analyze your risk data today?"} ], type='messages', elem_classes="chat-messages", layout="bubble", bubble_full_width=False) with gr.Row(elem_classes="chat-input-container"): chat_input = gr.Textbox(placeholder="Ask about stc Group's risk data", elem_classes="chat-input", label="", scale=1) send_button = gr.Button(value="→", elem_classes="send-button", scale=0) # Results column with gr.Column(scale=1, elem_classes="results-container"): with gr.Column(elem_classes="section-header"): gr.Markdown("## Results & Insights") gr.Markdown("Visualizations and data from your queries") with gr.Column(elem_classes="results-content"): results_placeholder = gr.Markdown("Ask a question in the chat to analyze risk data and see insights here", elem_classes="placeholder-text") # Wire up the chat functionality send_button.click( fn=send_message, inputs=[chat_input, chatbot], outputs=[chatbot] ).then(lambda: "", None, chat_input) chat_input.submit( fn=send_message, inputs=[chat_input, chatbot], outputs=[chatbot] ).then(lambda: "", None, chat_input) # JavaScript for UI enhancements gr.HTML(""" """) # Launch the app #demo.launch(share=True) if __name__ == "__main__": demo.launch()