Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import os | |
| from langgraphagenticai.ui.uiconfigfile import Config | |
| class LoadStreamlitUI: | |
| def __init__(self): | |
| self.config = Config() | |
| self.user_controls = {} | |
| def _inject_custom_css(self): | |
| """Inject custom CSS with light purple-green background and white fonts""" | |
| st.markdown(""" | |
| <style> | |
| /* Main container styling - light purple to light green gradient */ | |
| .main { | |
| background: linear-gradient(135deg, #e9d5ff 0%, #ddd6fe 25%, #c4b5fd 40%, #d1fae5 60%, #a7f3d0 80%, #6ee7b7 100%); | |
| background-attachment: fixed; | |
| } | |
| /* Header styling - dark elegant background with main topic in gradient color */ | |
| .custom-header { | |
| background: linear-gradient(135deg, #1e293b 0%, #334155 100%); | |
| padding: 2.5rem 3rem 2rem 3rem; | |
| border-radius: 16px; | |
| box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); | |
| margin-bottom: 2.5rem; | |
| text-align: center; | |
| border: 1px solid rgba(100, 116, 139, 0.3); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .custom-header::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| height: 2px; | |
| background: linear-gradient(90deg, transparent, #a78bfa, #6ee7b7, transparent); | |
| opacity: 0.8; | |
| } | |
| .custom-header h1 { | |
| font-size: 2.4rem; | |
| font-weight: 600; | |
| margin: 0 0 0.5rem 0; | |
| letter-spacing: 0.3px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 0.5rem; | |
| } | |
| .header-text { | |
| background: linear-gradient(135deg, #a78bfa 0%, #8b5cf6 30%, #6ee7b7 70%, #34d399 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| /* Built by Sachin text styling - like the reference image */ | |
| .built-by { | |
| color: #94a3b8; | |
| font-size: 0.8rem; | |
| font-weight: 400; | |
| letter-spacing: 0.3px; | |
| margin-top: 0.5rem; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 0.4rem; | |
| } | |
| .built-by .sparkle { | |
| font-size: 0.9rem; | |
| color: #a78bfa; | |
| } | |
| /* Robot emoji animation - UP AND DOWN (floating) */ | |
| @keyframes float { | |
| 0%, 100% { | |
| transform: translateY(0px); | |
| } | |
| 50% { | |
| transform: translateY(-10px); | |
| } | |
| } | |
| .robot-icon { | |
| display: inline-block; | |
| animation: float 2s ease-in-out infinite; | |
| font-size: 2.2rem; | |
| } | |
| /* Chatbot icon styling with animation */ | |
| .chatbot-icon { | |
| position: fixed; | |
| bottom: 2rem; | |
| right: 2rem; | |
| width: 60px; | |
| height: 60px; | |
| background: linear-gradient(135deg, #7c3aed 0%, #8b5cf6 100%); | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 2rem; | |
| box-shadow: 0 4px 20px rgba(124, 58, 237, 0.4); | |
| cursor: pointer; | |
| z-index: 1000; | |
| transition: all 0.3s ease; | |
| animation: pulse 2s ease-in-out infinite; | |
| } | |
| .chatbot-icon:hover { | |
| transform: scale(1.1); | |
| box-shadow: 0 6px 30px rgba(124, 58, 237, 0.6); | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { | |
| transform: scale(1); | |
| box-shadow: 0 4px 20px rgba(124, 58, 237, 0.4); | |
| } | |
| 50% { | |
| transform: scale(1.05); | |
| box-shadow: 0 6px 25px rgba(124, 58, 237, 0.6); | |
| } | |
| } | |
| /* Sidebar styling - deep dark */ | |
| [data-testid="stSidebar"] { | |
| background: linear-gradient(180deg, #1a1625 0%, #0f0d15 100%); | |
| border-right: 1px solid rgba(167, 139, 250, 0.2); | |
| } | |
| [data-testid="stSidebar"] .css-1d391kg { | |
| padding: 2rem 1rem; | |
| } | |
| /* Selectbox styling - white text */ | |
| .stSelectbox label { | |
| color: #ffffff !important; | |
| font-weight: 500; | |
| font-size: 0.95rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .stSelectbox > div > div { | |
| background-color: #2d2438; | |
| border: 1px solid #4c3d5f; | |
| border-radius: 8px; | |
| color: #ffffff !important; | |
| transition: all 0.3s ease; | |
| } | |
| .stSelectbox > div > div:hover { | |
| border-color: #7c3aed; | |
| background-color: #3d3250; | |
| box-shadow: 0 0 0 1px rgba(167, 139, 250, 0.3); | |
| } | |
| /* Text input styling - white text */ | |
| .stTextInput label { | |
| color: #ffffff !important; | |
| font-weight: 500; | |
| font-size: 0.95rem; | |
| } | |
| .stTextInput > div > div > input { | |
| background-color: #2d2438; | |
| border: 1px solid #4c3d5f; | |
| border-radius: 8px; | |
| color: #ffffff !important; | |
| padding: 0.65rem; | |
| transition: all 0.3s ease; | |
| } | |
| .stTextInput > div > div > input:focus { | |
| border-color: #7c3aed; | |
| background-color: #3d3250; | |
| box-shadow: 0 0 0 2px rgba(167, 139, 250, 0.25); | |
| outline: none; | |
| } | |
| .stTextInput > div > div > input::placeholder { | |
| color: #a78bfa; | |
| opacity: 0.7; | |
| } | |
| /* Warning box styling - white text */ | |
| .stAlert { | |
| background: linear-gradient(135deg, #6d28d9 0%, #7c3aed 100%); | |
| border-radius: 8px; | |
| border: 1px solid #8b5cf6; | |
| padding: 1rem; | |
| color: #ffffff !important; | |
| font-weight: 400; | |
| box-shadow: 0 4px 15px rgba(124, 58, 237, 0.2); | |
| } | |
| /* Link styling - white */ | |
| a { | |
| color: #ffffff !important; | |
| text-decoration: none; | |
| font-weight: 500; | |
| transition: color 0.2s ease; | |
| } | |
| a:hover { | |
| color: #f3f4f6 !important; | |
| text-decoration: underline; | |
| } | |
| /* Clean section dividers */ | |
| .section-divider { | |
| height: 1px; | |
| background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); | |
| margin: 2rem 0; | |
| } | |
| /* Section headers - white */ | |
| .section-header { | |
| color: #ffffff !important; | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| margin-bottom: 1rem; | |
| margin-top: 1.5rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| } | |
| /* Remove extra spacing */ | |
| .stSelectbox, .stTextInput { | |
| margin-bottom: 1.5rem; | |
| } | |
| /* Toggle/Checkbox styling - white */ | |
| .stCheckbox label { | |
| color: #ffffff !important; | |
| } | |
| /* Overall text color - white */ | |
| p, span, div, label { | |
| color: #ffffff !important; | |
| } | |
| /* Dropdown options styling */ | |
| [role="listbox"] { | |
| background-color: #2d2438 !important; | |
| } | |
| [role="option"] { | |
| color: #ffffff !important; | |
| } | |
| /* Button styling */ | |
| .stButton > button { | |
| background: linear-gradient(135deg, #7c3aed 0%, #8b5cf6 100%); | |
| color: #ffffff !important; | |
| border: 1px solid #a78bfa; | |
| border-radius: 8px; | |
| padding: 0.5rem 1.5rem; | |
| font-weight: 500; | |
| transition: all 0.3s ease; | |
| } | |
| .stButton > button:hover { | |
| background: linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%); | |
| box-shadow: 0 0 20px rgba(167, 139, 250, 0.4); | |
| border-color: #c4b5fd; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| def load_streamlit_ui(self): | |
| # Page config | |
| st.set_page_config( | |
| page_title="π€ " + self.config.get_page_title(), | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| st.session_state.timeframe = '' | |
| st.session_state.IsFetchButtonClicked = False | |
| # Inject custom CSS | |
| self._inject_custom_css() | |
| # Custom header with animated robot icon (bouncing up and down) | |
| st.markdown(f""" | |
| <div class="custom-header"> | |
| <h1> | |
| <span class="robot-icon">π€</span> | |
| <span class="header-text">{self.config.get_page_title()}</span> | |
| </h1> | |
| <p class="built-by"><span class="sparkle">β¨</span> Built by Sachin Ranasing</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Animated chatbot icon at bottom right | |
| st.markdown(""" | |
| <div class="chatbot-icon"> | |
| π€ | |
| </div> | |
| """, unsafe_allow_html=True) | |
| with st.sidebar: | |
| # Get options from config | |
| llm_options = self.config.get_llm_options() | |
| usecase_options = self.config.get_usecase_options() | |
| # AI Configuration section header | |
| st.markdown("<div class='section-header'>βοΈ AI Configuration</div>", unsafe_allow_html=True) | |
| # LLM selection | |
| self.user_controls["selected_llm"] = st.selectbox( | |
| "Select LLM", | |
| llm_options, | |
| help="Choose your preferred Language Model" | |
| ) | |
| if self.user_controls["selected_llm"] == 'Groq': | |
| # Model selection | |
| model_options = self.config.get_groq_model_options() | |
| self.user_controls["selected_groq_model"] = st.selectbox( | |
| "Select Model", | |
| model_options, | |
| help="Choose a Groq model variant" | |
| ) | |
| self.user_controls["GROQ_API_KEY"] = st.session_state["GROQ_API_KEY"] = st.text_input( | |
| "API Key", | |
| type="password", | |
| placeholder="Enter your Groq API key" | |
| ) | |
| # Validate API key | |
| if not self.user_controls["GROQ_API_KEY"]: | |
| st.warning("β οΈ Please enter your GROQ API key to proceed. Don't have one? Get it here: [Groq Console](https://console.groq.com/keys)") | |
| # Divider | |
| st.markdown("<div class='section-divider'></div>", unsafe_allow_html=True) | |
| # Use Case section header | |
| st.markdown("<div class='section-header'>π― Use Case</div>", unsafe_allow_html=True) | |
| # Usecase selection | |
| self.user_controls["selected_usecase"] = st.selectbox( | |
| "Select Usecases", | |
| usecase_options, | |
| help="Choose your application use case" | |
| ) | |
| if self.user_controls["selected_usecase"] =="Chatbot with Web Search" or self.user_controls["selected_usecase"] =="AI News": | |
| os.environ["TAVILY_API_KEY"]=self.user_controls["TAVILY_API_KEY"]=st.session_state["TAVILY_API_KEY"]=st.text_input("TAVILY API KEY",type="password", placeholder="Enter your TAVILY API key") | |
| # Validate API key | |
| if not self.user_controls["TAVILY_API_KEY"]: | |
| st.warning("β οΈ Please enter your TAVILY_API_KEY key to proceed. Don't have? refer : https://app.tavily.com/home") | |
| if self.user_controls['selected_usecase']=="AI News": | |
| st.subheader("π° AI News Explorer ") | |
| with st.sidebar: | |
| time_frame = st.selectbox( | |
| "π Select Time Frame", | |
| ["Daily", "Weekly", "Monthly"], | |
| index=0 | |
| ) | |
| if st.button("π Fetch Latest AI News", use_container_width=True): | |
| st.session_state.IsFetchButtonClicked = True | |
| st.session_state.timeframe = time_frame | |
| elif self.user_controls["selected_usecase"] == "Research Assistant": | |
| st.info("π¬ **Research Assistant Features:**\n\n" | |
| "β’ **ArXiv Search**: Access academic papers and research\n" | |
| "β’ **Web Search**: Complement research with general web results\n" | |
| "β’ **No API Key Required**: ArXiv is free to use\n\n" | |
| "Perfect for literature reviews, academic research, and finding relevant papers!") | |
| # Still need TAVILY for web search component | |
| os.environ["TAVILY_API_KEY"]=self.user_controls["TAVILY_API_KEY"]=st.session_state["TAVILY_API_KEY"]=st.text_input("TAVILY API KEY",type="password", placeholder="Enter your TAVILY API key for web search") | |
| # Validate API key | |
| if not self.user_controls["TAVILY_API_KEY"]: | |
| st.warning("β οΈ Please enter your TAVILY_API_KEY for comprehensive research. Don't have? refer : https://app.tavily.com/home") | |
| return self.user_controls | |