import streamlit as st import pandas as pd import plotly.express as px from datetime import datetime from data_processor import DataProcessor # Configure page st.set_page_config( page_title="Label Dashboard", page_icon="📊", layout="wide", initial_sidebar_state="expanded" ) # Initialize data processor @st.cache_resource def get_data_processor(): return DataProcessor() # Load and cache data @st.cache_data(ttl=300) # Cache for 5 minutes def load_annotation_data(): processor = get_data_processor() return processor.process_annotations() @st.cache_data(ttl=300) def load_annotations_dataframe(): processor = get_data_processor() return processor.get_annotations_dataframe() # Add cache clearing functionality def clear_cache(): st.cache_data.clear() st.cache_resource.clear() def main(): st.title("📊 Label Dashboard") st.markdown("---") # Add cache clear button in sidebar with st.sidebar: if st.button("Clear Cache & Reload"): clear_cache() st.rerun() # Load data with st.spinner("Loading annotation data..."): try: metrics = load_annotation_data() df = load_annotations_dataframe() if metrics.total_annotations == 0: st.warning("No annotation data found. Please check your environment configuration.") return except Exception as e: st.error(f"Error loading data: {e}") st.error("Try clicking 'Clear Cache & Reload' in the sidebar if this persists") return # Main dashboard tabs tab1, tab2, tab3, tab4 = st.tabs(["📈 Overview", "🎯 Accuracy", "👥 Productivity", "📅 Timeline"]) # Overview Tab with tab1: st.header("Project Overview") # Key metrics row col1, col2, col3, col4 = st.columns(4) with col1: st.metric( "Total Annotations", metrics.total_annotations, help="Total number of annotations processed" ) with col2: st.metric( "Prediction Accuracy", f"{metrics.prediction_accuracy:.1%}", help="Percentage of predictions that were not corrected" ) with col3: st.metric( "Avg Lead Time", f"{metrics.avg_lead_time:.1f}s", help="Average time to complete an annotation" ) with col4: st.metric( "Correction Rate", f"{metrics.correction_rate:.1%}", help="Percentage of predictions that were corrected" ) # Label distribution st.subheader("Label Distribution") if metrics.label_distribution: label_df = pd.DataFrame( list(metrics.label_distribution.items()), columns=['Label', 'Count'] ) fig = px.pie( label_df, values='Count', names='Label', title="Distribution of Labels" ) st.plotly_chart(fig, use_container_width=True) else: st.info("No label data available.") # Accuracy Tab with tab2: st.header("Prediction Accuracy Analysis") # Accuracy metrics col1, col2 = st.columns(2) with col1: # Accuracy pie chart accuracy_data = pd.DataFrame({ 'Status': ['Correct Predictions', 'Corrected Predictions'], 'Count': [ metrics.prediction_accuracy * metrics.total_annotations, metrics.correction_rate * metrics.total_annotations ] }) fig = px.pie( accuracy_data, values='Count', names='Status', title="Prediction Accuracy Breakdown", color_discrete_map={ 'Correct Predictions': '#2E8B57', 'Corrected Predictions': '#CD5C5C' } ) st.plotly_chart(fig, use_container_width=True) with col2: # Accuracy by user if not df.empty: user_accuracy = df.groupby('user_email')['origin'].apply( lambda x: (x == 'prediction').mean() ).reset_index() user_accuracy.columns = ['User', 'Accuracy'] user_accuracy['Accuracy'] = user_accuracy['Accuracy'] * 100 fig = px.bar( user_accuracy, x='User', y='Accuracy', title="Prediction Accuracy by User", labels={'Accuracy': 'Accuracy (%)'} ) fig.update_xaxes(tickangle=45) st.plotly_chart(fig, use_container_width=True) # Productivity Tab with tab3: st.header("User Productivity") # User productivity metrics if metrics.annotations_per_user: col1, col2 = st.columns(2) with col1: # Annotations per user user_df = pd.DataFrame( list(metrics.annotations_per_user.items()), columns=['User', 'Annotations'] ) fig = px.bar( user_df, x='User', y='Annotations', title="Annotations per User" ) fig.update_xaxes(tickangle=45) st.plotly_chart(fig, use_container_width=True) with col2: # Average lead time by user if not df.empty: user_leadtime = df.groupby('user_email')['lead_time'].mean().reset_index() user_leadtime.columns = ['User', 'Avg Lead Time'] fig = px.bar( user_leadtime, x='User', y='Avg Lead Time', title="Average Lead Time by User", labels={'Avg Lead Time': 'Lead Time (seconds)'} ) fig.update_xaxes(tickangle=45) st.plotly_chart(fig, use_container_width=True) # Detailed user table st.subheader("User Statistics") if not df.empty: user_stats = df.groupby('user_email').agg({ 'id': 'count', 'lead_time': 'mean', 'origin': lambda x: (x == 'prediction').mean() }).reset_index() user_stats.columns = ['User', 'Total Annotations', 'Avg Lead Time', 'Accuracy'] user_stats['Accuracy'] = user_stats['Accuracy'] * 100 user_stats = user_stats.round(2) st.dataframe(user_stats, use_container_width=True) # Timeline Tab with tab4: st.header("Timeline Analysis") # Daily throughput if metrics.throughput_by_date: throughput_df = pd.DataFrame( list(metrics.throughput_by_date.items()), columns=['Date', 'Annotations'] ) throughput_df['Date'] = pd.to_datetime(throughput_df['Date']) throughput_df = throughput_df.sort_values('Date') fig = px.line( throughput_df, x='Date', y='Annotations', title="Daily Annotation Throughput", markers=True ) st.plotly_chart(fig, use_container_width=True) # Show throughput statistics col1, col2, col3 = st.columns(3) with col1: st.metric( "Peak Day", int(throughput_df.loc[throughput_df['Annotations'].idxmax(), 'Annotations']), help="Highest number of annotations in a single day" ) with col2: st.metric( "Average Daily", f"{throughput_df['Annotations'].mean():.1f}", help="Average annotations per day" ) with col3: st.metric( "Active Days", len(throughput_df), help="Number of days with annotation activity" ) # Timeline with filters st.subheader("Detailed Timeline") if not df.empty: # Date range filter col1, col2 = st.columns(2) with col1: start_date = st.date_input( "Start Date", value=df['created_at'].min().date() if 'created_at' in df.columns else datetime.now().date() ) with col2: end_date = st.date_input( "End Date", value=df['created_at'].max().date() if 'created_at' in df.columns else datetime.now().date() ) # Filter data if 'created_at' in df.columns: filtered_df = df[ (df['created_at'].dt.date >= start_date) & (df['created_at'].dt.date <= end_date) ] if not filtered_df.empty: # Show filtered timeline daily_stats = filtered_df.groupby(filtered_df['created_at'].dt.date).agg({ 'id': 'count', 'lead_time': 'mean', 'origin': lambda x: (x == 'prediction').mean() }).reset_index() daily_stats.columns = ['Date', 'Count', 'Avg Lead Time', 'Accuracy'] daily_stats['Accuracy'] = daily_stats['Accuracy'] * 100 st.dataframe(daily_stats, use_container_width=True) if __name__ == "__main__": main()