diff --git a/dashboard.py b/dashboard.py index 1994a56..af9f001 100644 --- a/dashboard.py +++ b/dashboard.py @@ -17,11 +17,304 @@ from SPARC import config st.set_page_config( page_title="SPARC Dashboard", - page_icon="đ", + page_icon="âĄ", layout="wide", - initial_sidebar_state="expanded", + initial_sidebar_state="collapsed", ) +# Modern CSS styling +st.markdown(""" + +""", unsafe_allow_html=True) + @st.cache_resource def get_analyzer(): @@ -43,37 +336,44 @@ def get_db_client(): def render_header(): - """Render the dashboard header.""" - st.title("SPARC Dashboard") - st.markdown("**Semiconductor Patent & Analytics Report Core**") - st.markdown("---") + """Render the modern dashboard header.""" + st.markdown(""" +
+ """, unsafe_allow_html=True) -def render_sidebar(): - """Render the sidebar with navigation and controls.""" - st.sidebar.title("Navigation") - page = st.sidebar.radio( - "Select Page", - ["Company Analysis", "Batch Analysis", "Analytics", "About"], - ) - return page +def render_navigation(): + """Render horizontal tab navigation at the top.""" + tabs = st.tabs(["đ Company Analysis", "đĻ Batch Analysis", "đ Analytics", "âšī¸ About"]) + return tabs def render_company_analysis(): """Render single company analysis page.""" - st.header("Company Patent Analysis") + st.markdown('Single Company Analysis
', unsafe_allow_html=True) + st.markdown("Analyze a company's patent portfolio using AI-powered insights.") - col1, col2 = st.columns([2, 1]) + st.markdown("") - with col1: - company_name = st.text_input( - "Company Name", - placeholder="e.g., nvidia, intel, amd", - help="Enter the company name to analyze their patent portfolio", - ) + # Search card + with st.container(): + col1, col2 = st.columns([3, 1]) - with col2: - analyze_btn = st.button("Analyze", type="primary", use_container_width=True) + with col1: + company_name = st.text_input( + "Company Name", + placeholder="Enter company name (e.g., nvidia, intel, amd)", + help="Enter the company name to analyze their patent portfolio", + label_visibility="collapsed", + ) + + with col2: + analyze_btn = st.button("đ Analyze", type="primary", use_container_width=True) if analyze_btn and company_name: with st.spinner(f"Analyzing {company_name}..."): @@ -81,45 +381,57 @@ def render_company_analysis(): result = analyzer._analyze_company_safe(company_name) if result.success: - st.success(f"Analysis complete for {company_name}") + st.success(f"â Analysis complete for {company_name.upper()}") - # Metrics row + st.markdown("") + + # Metrics row with custom styling col1, col2, col3 = st.columns(3) with col1: - st.metric("Patents Analyzed", result.patent_count) + st.metric("Patents Found", result.patent_count) with col2: - st.metric("Status", "Success") + st.metric("Analysis Status", "Complete") with col3: st.metric("Timestamp", result.timestamp.strftime("%H:%M:%S")) - # Analysis content - st.subheader("AI Analysis") - st.markdown(result.analysis) + st.markdown("") + + # Analysis content in a styled container + st.markdown('AI Analysis Results
', unsafe_allow_html=True) + with st.container(): + st.markdown(result.analysis) else: st.error(f"Analysis failed: {result.error}") + elif not company_name and analyze_btn: + st.warning("Please enter a company name to analyze.") + def render_batch_analysis(): """Render batch analysis page.""" - st.header("Batch Company Analysis") + st.markdown('Batch Company Analysis
', unsafe_allow_html=True) + st.markdown("Analyze multiple companies simultaneously for comparative insights.") - st.markdown( - "Analyze multiple companies simultaneously. Enter company names separated by commas or newlines." - ) + st.markdown("") - companies_input = st.text_area( - "Company Names", - placeholder="nvidia\namd\nintel\nqualcomm", - height=150, - ) + # Input section + col1, col2 = st.columns([2, 1]) - col1, col2 = st.columns(2) with col1: - max_workers = st.slider("Concurrent Workers", 1, 5, 3) + companies_input = st.text_area( + "Company Names", + placeholder="Enter company names (one per line or comma-separated):\nnvidia\namd\nintel\nqualcomm", + height=150, + label_visibility="collapsed", + ) + with col2: + st.markdown("**Configuration**") + max_workers = st.slider("Concurrent Workers", 1, 5, 3, help="Number of parallel analysis threads") + st.markdown("") analyze_btn = st.button( - "Run Batch Analysis", type="primary", use_container_width=True + "đ Run Batch Analysis", type="primary", use_container_width=True ) if analyze_btn and companies_input: @@ -134,7 +446,7 @@ def render_batch_analysis(): st.warning("Please enter at least one company name") return - st.info(f"Starting analysis of {len(companies)} companies...") + st.info(f"đ Starting analysis of {len(companies)} companies...") # Progress tracking progress_bar = st.progress(0) @@ -154,10 +466,12 @@ def render_batch_analysis(): ) progress_bar.progress(1.0) - status_text.text("Analysis complete!") + status_text.text("â Analysis complete!") + + st.markdown("") # Summary metrics - st.subheader("Results Summary") + st.markdown('Results Summary
', unsafe_allow_html=True) col1, col2, col3, col4 = st.columns(4) with col1: st.metric("Total Companies", result.total_companies) @@ -178,7 +492,7 @@ def render_batch_analysis(): df = pd.DataFrame( [ { - "Company": r.company_name, + "Company": r.company_name.upper(), "Patents": r.patent_count, "Status": "Success" if r.success else "Failed", } @@ -191,16 +505,34 @@ def render_batch_analysis(): x="Company", y="Patents", color="Status", - color_discrete_map={"Success": "#28a745", "Failed": "#dc3545"}, - title="Patents per Company", + color_discrete_map={"Success": "#10b981", "Failed": "#ef4444"}, + title="", + ) + fig.update_layout( + plot_bgcolor="rgba(0,0,0,0)", + paper_bgcolor="rgba(0,0,0,0)", + font_color="#94a3b8", + legend=dict( + orientation="h", + yanchor="bottom", + y=1.02, + xanchor="right", + x=1 + ), + xaxis=dict(showgrid=False), + yaxis=dict(showgrid=True, gridcolor="rgba(99, 102, 241, 0.1)"), ) st.plotly_chart(fig, use_container_width=True) + st.markdown("") + # Individual results - st.subheader("Individual Results") + st.markdown('Detailed Results
', unsafe_allow_html=True) for r in result.results: + status_icon = "â" if r.success else "â" + status_class = "status-success" if r.success else "status-error" with st.expander( - f"{'â' if r.success else 'â'} {r.company_name} ({r.patent_count} patents)" + f"{status_icon} {r.company_name.upper()} â {r.patent_count} patents" ): if r.success: st.markdown(r.analysis) @@ -210,21 +542,28 @@ def render_batch_analysis(): def render_analytics(): """Render analytics page with database insights.""" - st.header("Analytics Dashboard") + st.markdown('Analytics Dashboard
', unsafe_allow_html=True) + st.markdown("Track historical analysis data and view insights.") db_client = get_db_client() if not db_client: - st.warning( - "Database mode is not enabled. Set USE_DATABASE=true in your .env file to enable analytics." - ) - st.info( - "Analytics features require storing analysis results in PostgreSQL for historical tracking." - ) + st.markdown("") + st.markdown(""" +USE_DATABASE=true in your .env file to enable analytics tracking.
+ Recent Analyses
', unsafe_allow_html=True) messages = db_client.get_messages(limit=10) if messages: for msg in messages: with st.expander( - f"{msg.get('company_name', 'Unknown')} - {msg.get('analysis_type', 'N/A')} ({msg.get('timestamp', 'N/A')})" + f"đ {msg.get('company_name', 'Unknown').upper()} â {msg.get('analysis_type', 'N/A')} ({msg.get('timestamp', 'N/A')})" ): - st.markdown(f"**Model:** {msg.get('model', 'N/A')}") + st.markdown(f"**Model:** `{msg.get('model', 'N/A')}`") if msg.get("response"): st.markdown(msg["response"][:500] + "...") @@ -291,70 +650,127 @@ def render_analytics(): def render_about(): """Render about page.""" - st.header("About SPARC") + st.markdown('About SPARC
', unsafe_allow_html=True) - st.markdown( - """ - **SPARC** (Semiconductor Patent & Analytics Report Core) is a patent analysis - system that estimates company performance by analyzing their patent portfolios - using LLM-powered insights. + col1, col2 = st.columns([2, 1]) - ### Features + with col1: + st.markdown(""" + **SPARC** (Semiconductor Patent & Analytics Report Core) is an AI-powered patent analysis + platform that evaluates company performance by analyzing their patent portfolios + with cutting-edge language models. + """) - - **Patent Retrieval**: Automated collection via SerpAPI's Google Patents engine - - **Intelligent Parsing**: Extracts key sections from patent PDFs - - **AI Analysis**: Uses Claude 3.5 Sonnet for deep analysis - - **Batch Processing**: Analyze multiple companies concurrently - - **REST API**: FastAPI web service for integration - - **Analytics**: Track and visualize analysis history + st.markdown("") + st.markdown("**Key Features**") - ### Technology Stack + features = [ + ("đ", "Patent Retrieval", "Automated collection via SerpAPI's Google Patents"), + ("đ", "Intelligent Parsing", "Extracts key sections from patent documents"), + ("đ¤", "AI Analysis", "Deep analysis powered by Claude 3.5 Sonnet"), + ("âĄ", "Batch Processing", "Analyze multiple companies concurrently"), + ("đ", "REST API", "FastAPI web service for seamless integration"), + ("đ", "Analytics", "Track and visualize historical analysis data"), + ] - - **Backend**: Python, FastAPI - - **AI**: Claude 3.5 Sonnet via OpenRouter - - **Database**: PostgreSQL - - **Dashboard**: Streamlit, Plotly - - **Patent Data**: SerpAPI Google Patents + for icon, title, desc in features: + st.markdown(f""" +System Status
', unsafe_allow_html=True) - col1, col2 = st.columns(2) + col1, col2, col3 = st.columns(3) with col1: db_client = get_db_client() if db_client: - st.success("Database: Connected") + st.markdown(""" +