Spaces:
Build error
Build error
| import streamlit as st | |
| import pandas as pd | |
| from typing import Union, List, Dict | |
| from groq import Groq | |
| import os | |
| from duckduckgo_search import DDGS | |
| # Set page configuration with fullscreen layout and custom theme | |
| st.set_page_config( | |
| page_title="Z-Alpha News Analysis", | |
| layout="wide", | |
| initial_sidebar_state="collapsed", | |
| page_icon="π" | |
| ) | |
| # Execute JavaScript to make the app fullscreen on load | |
| st.markdown(""" | |
| <script> | |
| document.addEventListener('DOMContentLoaded', (event) => { | |
| // Request fullscreen on page load | |
| document.documentElement.requestFullscreen().catch(e => { | |
| console.log("Fullscreen request failed: ", e); | |
| }); | |
| }); | |
| </script> | |
| """, unsafe_allow_html=True) | |
| # Enhanced CSS for a more beautiful Google DeepMind-inspired styling with green background | |
| st.markdown(""" | |
| <style> | |
| /* Base styles */ | |
| html, body, .stApp, .main { | |
| background-color: #000000 !important; | |
| color: #ffffff !important; | |
| } | |
| /* Typography */ | |
| h1, h2, h3, h4, h5, h6 { | |
| color: #00ff00 !important; | |
| font-family: 'Courier New', monospace !important; | |
| } | |
| p, div, span { | |
| color: #cccccc !important; | |
| } | |
| /* Cards and containers */ | |
| .card { | |
| background-color: #0a0a0a !important; | |
| border: 1px solid #00ff00 !important; | |
| border-radius: 4px !important; | |
| box-shadow: 0 0 15px rgba(0, 255, 0, 0.2) !important; | |
| } | |
| /* Analysis results */ | |
| .analysis-result { | |
| background-color: #121212 !important; | |
| border-left: 4px solid #00ff00 !important; | |
| color: #ffffff !important; | |
| font-family: 'Courier New', monospace !important; | |
| padding: 1.5rem !important; | |
| } | |
| /* Input fields */ | |
| .stTextInput input { | |
| background-color: #121212 !important; | |
| color: #00ff00 !important; | |
| border: 1px solid #00ff00 !important; | |
| border-radius: 0 !important; | |
| } | |
| /* Buttons */ | |
| .stButton > button { | |
| background: linear-gradient(45deg, #00ff00, #003300) !important; | |
| color: #000000 !important; | |
| border: none !important; | |
| border-radius: 0 !important; | |
| font-family: 'Courier New', monospace !important; | |
| font-weight: bold !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| .stButton > button:hover { | |
| box-shadow: 0 0 20px #00ff00 !important; | |
| transform: scale(1.05) !important; | |
| } | |
| /* Source items */ | |
| .source-item { | |
| border-bottom: 1px solid #333333 !important; | |
| padding: 1rem 0 !important; | |
| } | |
| .source-title { | |
| color: #00ff00 !important; | |
| font-family: 'Courier New', monospace !important; | |
| } | |
| /* Links */ | |
| a { | |
| color: #00ff00 !important; | |
| text-decoration: underline !important; | |
| } | |
| a:hover { | |
| color: #99ff99 !important; | |
| } | |
| /* Status indicators */ | |
| .status-badge { | |
| background-color: #002200 !important; | |
| color: #00ff00 !important; | |
| border: 1px solid #00ff00 !important; | |
| } | |
| /* Tabs */ | |
| .stTabs [aria-selected="true"] { | |
| background-color: #121212 !important; | |
| color: #00ff00 !important; | |
| border-bottom: 2px solid #00ff00 !important; | |
| } | |
| /* Logo styling */ | |
| .logo-text { | |
| background: linear-gradient(90deg, #00ff00, #99ff99) !important; | |
| -webkit-background-clip: text !important; | |
| -webkit-text-fill-color: transparent !important; | |
| text-shadow: 0 0 10px rgba(0, 255, 0, 0.5) !important; | |
| } | |
| /* Icons */ | |
| .float-icon svg { | |
| filter: drop-shadow(0 0 5px #00ff00); | |
| } | |
| /* Scrollbar styling */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: #000000; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #00ff00; | |
| border-radius: 4px; | |
| } | |
| /* Dropdown menus */ | |
| .stSelectbox div[data-baseweb="select"] div { | |
| background-color: #121212 !important; | |
| color: #00ff00 !important; | |
| border: 1px solid #00ff00 !important; | |
| border-radius: 0 !important; | |
| } | |
| /* Sliders */ | |
| .stSlider .thumb { | |
| background-color: #00ff00 !important; | |
| } | |
| .stSlider .track { | |
| background-color: #003300 !important; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| class DuckDuckGoSearch: | |
| """ | |
| Custom DuckDuckGo search implementation with robust error handling and result processing. | |
| Uses the duckduckgo_search library to fetch and format news results. | |
| """ | |
| def __init__(self): | |
| # Initialize the DuckDuckGo search session | |
| self.ddgs = DDGS() | |
| def __call__(self, query: str, max_results: int = 5) -> str: | |
| try: | |
| # Perform the search and get results | |
| # The news method is more appropriate for recent news analysis | |
| search_results = list(self.ddgs.news( | |
| query, | |
| max_results=max_results, | |
| region='wt-wt', # Worldwide results | |
| safesearch='on' | |
| )) | |
| if not search_results: | |
| return "No results found. Try modifying your search query." | |
| # Format the results into a readable string | |
| formatted_results = [] | |
| for idx, result in enumerate(search_results, 1): | |
| # Extract available fields with fallbacks for missing data | |
| title = result.get('title', 'No title available') | |
| snippet = result.get('body', result.get('snippet', 'No description available')) | |
| source = result.get('source', 'Unknown source') | |
| url = result.get('url', result.get('link', 'No link available')) | |
| date = result.get('date', 'Date not available') | |
| # Format each result with available information | |
| formatted_results.append( | |
| f"{idx}. Title: {title}\n" | |
| f" Date: {date}\n" | |
| f" Source: {source}\n" | |
| f" Summary: {snippet}\n" | |
| f" URL: {url}\n" | |
| ) | |
| return "\n".join(formatted_results) | |
| except Exception as e: | |
| # Provide detailed error information for debugging | |
| error_msg = f"Search error: {str(e)}\nTry again with a different search term or check your internet connection." | |
| print(f"DuckDuckGo search error: {str(e)}") # For logging | |
| return error_msg | |
| class GroqLLM: | |
| """ | |
| LLM interface using Groq's LLama model. | |
| Handles API communication and response processing. | |
| """ | |
| def __init__(self, model_name="llama-3.1-8B-Instant"): | |
| self.client = Groq(api_key=os.environ.get("GROQ_API_KEY")) | |
| self.model_name = model_name | |
| def __call__(self, prompt: Union[str, dict, List[Dict]]) -> str: | |
| try: | |
| # Convert prompt to string if it's a complex structure | |
| prompt_str = str(prompt) if isinstance(prompt, (dict, list)) else prompt | |
| # Make API call to Groq | |
| completion = self.client.chat.completions.create( | |
| model=self.model_name, | |
| messages=[{ | |
| "role": "user", | |
| "content": prompt_str | |
| }], | |
| temperature=0.7, | |
| max_tokens=1024, | |
| stream=False | |
| ) | |
| return completion.choices[0].message.content if completion.choices else "Error: No response generated" | |
| except Exception as e: | |
| error_msg = f"Error generating response: {str(e)}" | |
| print(error_msg) # For logging | |
| return error_msg | |
| def create_analysis_prompt(topic: str, search_results: str) -> str: | |
| """ | |
| Creates a detailed prompt for news analysis, structuring the request | |
| to get comprehensive and well-organized results from the LLM. | |
| """ | |
| return f"""Analyze the following news information about {topic}. | |
| Search Results: {search_results} | |
| Please provide a comprehensive analysis including: | |
| 1. Key Points Summary: | |
| - Main events and developments | |
| - Critical updates and changes | |
| 2. Stakeholder Analysis: | |
| - Primary parties involved | |
| - Their roles and positions | |
| 3. Impact Assessment: | |
| - Immediate implications | |
| - Potential long-term effects | |
| - Broader context and significance | |
| 4. Multiple Perspectives: | |
| - Different viewpoints on the issue | |
| - Areas of agreement and contention | |
| 5. Fact Check & Reliability: | |
| - Verification of major claims | |
| - Consistency across sources | |
| - Source credibility assessment | |
| Please format the analysis in a clear, journalistic style with section headers.""" | |
| def log_agent_activity(prompt: str, result: str, agent_name: str): | |
| """ | |
| Creates an expandable log of agent activities in the Streamlit interface | |
| for transparency and debugging purposes. | |
| """ | |
| with st.expander("π View Agent Activity Log"): | |
| st.markdown("<h4>Agent Activity Log</h4>", unsafe_allow_html=True) | |
| st.markdown(f"<p><strong>Agent:</strong> {agent_name}</p>", unsafe_allow_html=True) | |
| st.markdown("<div style='background-color: #f8f9fa; padding: 1rem; border-radius: 8px; margin-bottom: 1rem;'>", unsafe_allow_html=True) | |
| st.markdown("<p><strong>Input Prompt:</strong></p>", unsafe_allow_html=True) | |
| st.code(prompt, language="text") | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| st.markdown("<div style='background-color: #f8f9fa; padding: 1rem; border-radius: 8px;'>", unsafe_allow_html=True) | |
| st.markdown("<p><strong>Analysis Output:</strong></p>", unsafe_allow_html=True) | |
| st.code(result, language="text") | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| # Animated header with branded logo and description | |
| st.markdown(""" | |
| <div class="card" style="padding-bottom: 1.5rem;"> | |
| <div style="display: flex; align-items: center; gap: 1.5rem;"> | |
| <div class="float-icon" style="text-align: center;"> | |
| <svg width="70" height="70" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <path d="M19.5 9.5l-7.5-7.5-7.5 7.5m15 0v8c0 1.1-.9 2-2 2h-11c-1.1 0-2-.9-2-2v-8" stroke="#1a73e8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| <circle cx="12" cy="12" r="3" stroke="#1a73e8" stroke-width="2"/> | |
| <path d="M12 15v3" stroke="#1a73e8" stroke-width="2" stroke-linecap="round"/> | |
| </svg> | |
| </div> | |
| <div style="flex: 1;"> | |
| <span class="logo-text">Z-Agent News Analysis</span> | |
| <p style="color: #5f6368; font-size: 1.1rem; margin-top: 0.5rem;"> | |
| Intelligent news analysis powered by AI. Get comprehensive insights and multiple perspectives on any topic. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Main content area | |
| st.markdown('<div class="card">', unsafe_allow_html=True) | |
| # Initialize the components | |
| try: | |
| # Initialize LLM and search tool | |
| llm = GroqLLM() | |
| search_tool = DuckDuckGoSearch() | |
| # Input section with enhanced design | |
| st.markdown("<h2 style='margin-top: 0;'>News Topic Analysis</h2>", unsafe_allow_html=True) | |
| news_topic = st.text_input( | |
| "What news topic would you like to analyze?", | |
| placeholder="E.g., Recent developments in renewable energy, Tech industry layoffs, Global climate agreements...", | |
| key="news_topic_input" | |
| ) | |
| # Analysis options in a cleaner layout | |
| st.markdown("<div style='margin-top: 1.5rem;'></div>", unsafe_allow_html=True) | |
| st.markdown("<h3 style='margin-bottom: 1rem;'>Analysis Options</h3>", unsafe_allow_html=True) | |
| col1, col2, col3 = st.columns([2, 2, 2]) | |
| with col1: | |
| st.markdown("<div style='background-color: #f8f9fa; padding: 1rem; border-radius: 12px; height: 100%;'>", unsafe_allow_html=True) | |
| st.markdown("<p style='font-weight: 600; color: #202124; margin-bottom: 0.5rem;'>Search Depth</p>", unsafe_allow_html=True) | |
| search_depth = st.slider( | |
| "##", | |
| min_value=3, | |
| max_value=10, | |
| value=5, | |
| help="Number of news sources to analyze", | |
| key="search_depth_slider", | |
| label_visibility="collapsed" | |
| ) | |
| st.markdown("<p style='color: #5f6368; font-size: 0.9rem;'>Number of sources: " + str(search_depth) + "</p>", unsafe_allow_html=True) | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| with col2: | |
| st.markdown("<div style='background-color: #f8f9fa; padding: 1rem; border-radius: 12px; height: 100%;'>", unsafe_allow_html=True) | |
| st.markdown("<p style='font-weight: 600; color: #202124; margin-bottom: 0.5rem;'>Analysis Type</p>", unsafe_allow_html=True) | |
| analysis_type = st.selectbox( | |
| "##", | |
| ["Comprehensive", "Quick Summary", "Technical", "Simplified"], | |
| help="Choose the style and depth of analysis", | |
| key="analysis_type_select", | |
| label_visibility="collapsed" | |
| ) | |
| st.markdown("<p style='color: #5f6368; font-size: 0.9rem;'>Selected: " + analysis_type + "</p>", unsafe_allow_html=True) | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| with col3: | |
| st.markdown("<div style='background-color: #f8f9fa; padding: 1rem; border-radius: 12px; height: 100%;'>", unsafe_allow_html=True) | |
| st.markdown("<p style='font-weight: 600; color: #202124; margin-bottom: 0.5rem;'>Time Period</p>", unsafe_allow_html=True) | |
| time_period = st.selectbox( | |
| "##", | |
| ["Last 7 days", "Last 30 days", "Last 24 hours"], | |
| help="How recent should the news be", | |
| key="time_period_select", | |
| label_visibility="collapsed" | |
| ) | |
| st.markdown("<p style='color: #5f6368; font-size: 0.9rem;'>Selected: " + time_period + "</p>", unsafe_allow_html=True) | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| # Generate analysis button | |
| st.markdown("<div style='margin-top: 2rem;'></div>", unsafe_allow_html=True) | |
| col1, col2, col3 = st.columns([2, 2, 2]) | |
| with col2: | |
| analyze_button = st.button("ANALYZE NEWS") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Results section | |
| if analyze_button and news_topic: | |
| with st.spinner(""): | |
| try: | |
| # Progress indicators with enhanced styling | |
| progress_container = st.container() | |
| progress_container.markdown('<div class="info-box">', unsafe_allow_html=True) | |
| progress_placeholder = progress_container.empty() | |
| progress_placeholder.markdown(""" | |
| <div class="pulsing"> | |
| <div class="status-badge status-searching"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <circle cx="11" cy="11" r="8"></circle> | |
| <line x1="21" y1="21" x2="16.65" y2="16.65"></line> | |
| </svg> | |
| <span>Searching for recent news sources...</span> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Determine time frame from selection | |
| time_map = { | |
| "Last 24 hours": "24h", | |
| "Last 7 days": "7d", | |
| "Last 30 days": "30d" | |
| } | |
| time_frame = time_map.get(time_period, "7d") | |
| # Perform search | |
| search_results = search_tool( | |
| f"Latest news about {news_topic} {time_frame}", | |
| max_results=search_depth | |
| ) | |
| if not search_results.startswith(("Search error", "No results")): | |
| # Update progress | |
| progress_placeholder.markdown(""" | |
| <div class="pulsing"> | |
| <div class="status-badge status-analyzing"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M12 3v3m0 12v3m-9-9H3m3-6l2 2M3 12h3m12 0h3m-3-6l-2 2m9 3h-3m-6 6l-2 2m12 0l-2-2"></path> | |
| </svg> | |
| <span>Analyzing search results and generating insights...</span> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Create analysis prompt | |
| analysis_prompt = create_analysis_prompt(news_topic, search_results) | |
| # Get analysis from LLM | |
| analysis_result = llm(analysis_prompt) | |
| # Clear progress messages | |
| progress_container.empty() | |
| # Display results in tabs for better organization | |
| st.markdown('<div class="card">', unsafe_allow_html=True) | |
| st.markdown(f'<h2>Analysis: {news_topic}</h2>', unsafe_allow_html=True) | |
| tab1, tab2 = st.tabs(["π Analysis", "π° Sources"]) | |
| with tab1: | |
| st.markdown('<div class="analysis-result">', unsafe_allow_html=True) | |
| st.markdown(analysis_result) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| with tab2: | |
| st.markdown("<h3>News Sources Used in Analysis</h3>", unsafe_allow_html=True) | |
| # Parse and display sources in a more structured way | |
| sources = search_results.split("\n\n") | |
| for source in sources: | |
| lines = source.strip().split("\n") | |
| if len(lines) >= 5: # Ensure we have enough lines | |
| title_line = lines[0].replace("1. Title: ", "").replace("2. Title: ", "").replace("3. Title: ", "").replace("4. Title: ", "").replace("5. Title: ", "") | |
| date_line = lines[1].replace(" Date: ", "") | |
| source_line = lines[2].replace(" Source: ", "") | |
| url_line = lines[4].replace(" URL: ", "") | |
| st.markdown(f""" | |
| <div class="source-item"> | |
| <p class="source-title">{title_line}</p> | |
| <div class="source-meta"> | |
| <span>{source_line}</span> | |
| <span class="source-meta-dot"></span> | |
| <span>{date_line}</span> | |
| </div> | |
| <a href="{url_line}" class="read-link" target="_blank"> | |
| Read original article | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"></path> | |
| <path d="M15 3h6v6"></path> | |
| <path d="M10 14L21 3"></path> | |
| </svg> | |
| </a> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Log the activity | |
| log_agent_activity( | |
| analysis_prompt, | |
| analysis_result, | |
| "News Analysis Agent" | |
| ) | |
| else: | |
| progress_container.empty() | |
| st.error(f""" | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#FF5252" stroke-width="2"> | |
| <circle cx="12" cy="12" r="10"></circle> | |
| <line x1="12" y1="8" x2="12" y2="12"></line> | |
| <line x1="12" y1="16" x2="12.01" y2="16"></line> | |
| </svg> | |
| <span>{search_results}</span> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| except Exception as e: | |
| st.error(f""" | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#FF5252" stroke-width="2"> | |
| <circle cx="12" cy="12" r="10"></circle> | |
| <line x1="12" y1="8" x2="12" y2="12"></line> | |
| <line x1="12" y1="16" x2="12.01" y2="16"></line> | |
| </svg> | |
| <span>An error occurred during analysis: {str(e)}</span> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| elif analyze_button: | |
| # This handles the case when analyze button is clicked but no topic is entered | |
| st.warning(""" | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#FFA726" stroke-width="2"> | |
| <path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"></path> | |
| <line x1="12" y1="9" x2="12" y2="13"></line> | |
| <line x1="12" y1="17" x2="12.01" y2="17"></line> | |
| </svg> | |
| <span>Please enter a news topic to analyze.</span> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Tips and usage guidance section - displayed when no analysis is in progress | |
| if not analyze_button or not news_topic: | |
| st.markdown('<div class="card">', unsafe_allow_html=True) | |
| st.markdown("<h2 style='margin-top: 0;'>Tips for Better Results</h2>", unsafe_allow_html=True) | |
| st.markdown(""" | |
| <div class="tip-item"> | |
| <div class="tip-icon">π‘</div> | |
| <div class="tip-text"> | |
| <strong>Be specific with your topic.</strong> Instead of "climate change", try "recent climate legislation in the EU". | |
| </div> | |
| </div> | |
| <div class="tip-item"> | |
| <div class="tip-icon">π</div> | |
| <div class="tip-text"> | |
| <strong>Adjust search depth</strong> to find the right balance between comprehensive coverage and analysis speed. | |
| </div> | |
| </div> | |
| <div class="tip-item"> | |
| <div class="tip-icon">π</div> | |
| <div class="tip-text"> | |
| <strong>Choose the right analysis type</strong> based on your needs: | |
| <ul> | |
| <li><strong>Comprehensive:</strong> Full analysis with multiple perspectives</li> | |
| <li><strong>Quick Summary:</strong> Brief overview of key points</li> | |
| <li><strong>Technical:</strong> Detailed analysis with industry-specific terminology</li> | |
| <li><strong>Simplified:</strong> Easy-to-understand breakdown of complex topics</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="tip-item"> | |
| <div class="tip-icon">β±οΈ</div> | |
| <div class="tip-text"> | |
| <strong>Select an appropriate time period</strong> based on how recent you want the news to be. | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Example topics for quick selection | |
| st.markdown('<div class="card">', unsafe_allow_html=True) | |
| st.markdown("<h2 style='margin-top: 0;'>Try These Topics</h2>", unsafe_allow_html=True) | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| if st.button("π Climate Change Policies"): | |
| st.session_state.news_topic_input = "Recent climate change policies and agreements" | |
| st.experimental_rerun() | |
| with col2: | |
| if st.button("π° Cryptocurrency Trends"): | |
| st.session_state.news_topic_input = "Latest developments in cryptocurrency markets" | |
| st.experimental_rerun() | |
| with col3: | |
| if st.button("π¬ AI Research Breakthroughs"): | |
| st.session_state.news_topic_input = "Recent breakthroughs in artificial intelligence research" | |
| st.experimental_rerun() | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Footer with attribution and version info | |
| st.markdown(""" | |
| <footer> | |
| <div style="display: flex; justify-content: space-between; align-items: center;"> | |
| <div>Z-Agent News Analysis v1.0.1</div> | |
| <div></div> | |
| </div> | |
| </footer> | |
| """, unsafe_allow_html=True) | |
| except Exception as e: | |
| # Global error handling to catch any unforeseen issues | |
| st.error(f""" | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#FF5252" stroke-width="2"> | |
| <circle cx="12" cy="12" r="10"></circle> | |
| <line x1="12" y1="8" x2="12" y2="12"></line> | |
| <line x1="12" y1="16" x2="12.01" y2="16"></line> | |
| </svg> | |
| <span>Application Error: {str(e)}</span> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" | |
| <div style="background-color: #F8F9FA; padding: 1rem; border-radius: 8px; margin-top: 1rem;"> | |
| <p><strong>Troubleshooting Tips:</strong></p> | |
| <ul> | |
| <li>Check your API keys for Groq LLM in environment variables</li> | |
| <li>Ensure you have internet connection for DuckDuckGo searches</li> | |
| <li>Try refreshing the page or restarting the application</li> | |
| </ul> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Add a hidden feature to reset the application state | |
| if st.sidebar.button("Reset Application", key="reset_app"): | |
| for key in st.session_state.keys(): | |
| del st.session_state[key] | |
| st.experimental_rerun() | |
| # Optional: Add a feedback mechanism | |
| with st.sidebar: | |
| st.markdown("### Feedback") | |
| feedback = st.text_area("Share your thoughts or report issues", placeholder="Your feedback helps us improve...") | |
| if st.button("Submit Feedback"): | |
| st.success("Thank you for your feedback!") | |
| # In a production app, you would save this feedback to a database |