| """ |
| Musora Sentiment Analysis Dashboard |
| Main Streamlit Application |
| |
| Run with: streamlit run app.py |
| """ |
| import streamlit as st |
| import sys |
| from pathlib import Path |
| import json |
|
|
| |
| parent_dir = Path(__file__).resolve().parent |
| sys.path.append(str(parent_dir)) |
|
|
| from data.data_loader import SentimentDataLoader |
| from components.dashboard import render_dashboard |
| from components.sentiment_analysis import render_sentiment_analysis |
| from components.reply_required import render_reply_required |
|
|
|
|
| |
| config_path = parent_dir / "config" / "viz_config.json" |
| with open(config_path, 'r') as f: |
| config = json.load(f) |
|
|
| |
| st.set_page_config( |
| page_title=config['page_config']['page_title'], |
| page_icon=config['page_config']['page_icon'], |
| layout=config['page_config']['layout'], |
| initial_sidebar_state=config['page_config']['initial_sidebar_state'] |
| ) |
|
|
|
|
| def main(): |
| """ |
| Main application function |
| """ |
| |
| with st.sidebar: |
| st.image("visualization/img/musora.png", use_container_width=True) |
| st.title("Navigation") |
|
|
| |
| page = st.radio( |
| "Select Page", |
| ["π Dashboard", "π Sentiment Analysis", "π¬ Reply Required"], |
| index=0 |
| ) |
|
|
| st.markdown("---") |
|
|
| |
| st.markdown("### π Global Filters") |
|
|
| |
| if 'filters_applied' not in st.session_state: |
| st.session_state.filters_applied = False |
|
|
| |
| with st.spinner("Loading data..."): |
| data_loader = SentimentDataLoader() |
| df = data_loader.load_data() |
|
|
| if df.empty: |
| st.error("No data available. Please check your Snowflake connection.") |
| return |
|
|
| |
| filter_options = data_loader.get_filter_options(df) |
|
|
| |
| selected_platforms = st.multiselect( |
| "Platforms", |
| options=filter_options['platforms'], |
| default=[] |
| ) |
|
|
| |
| selected_brands = st.multiselect( |
| "Brands", |
| options=filter_options['brands'], |
| default=[] |
| ) |
|
|
| |
| selected_sentiments = st.multiselect( |
| "Sentiments", |
| options=filter_options['sentiments'], |
| default=[] |
| ) |
|
|
| |
| if 'comment_timestamp' in df.columns and not df.empty: |
| min_date = df['comment_timestamp'].min().date() |
| max_date = df['comment_timestamp'].max().date() |
|
|
| date_range = st.date_input( |
| "Date Range", |
| value=(min_date, max_date), |
| min_value=min_date, |
| max_value=max_date |
| ) |
| else: |
| date_range = None |
|
|
| |
| if st.button("π Apply Filters", use_container_width=True): |
| st.session_state.filters_applied = True |
|
|
| |
| if st.button("π Reset Filters", use_container_width=True): |
| st.session_state.filters_applied = False |
| st.rerun() |
|
|
| st.markdown("---") |
|
|
| |
| st.markdown("### π Data Management") |
|
|
| if st.button("β»οΈ Reload Data", use_container_width=True): |
| st.cache_data.clear() |
| st.rerun() |
|
|
| |
| st.markdown("---") |
| st.markdown("### βΉοΈ Data Info") |
| st.info(f"**Total Records:** {len(df):,}") |
|
|
| if 'processed_at' in df.columns and not df.empty: |
| last_update = df['processed_at'].max() |
| st.info(f"**Last Updated:** {last_update.strftime('%Y-%m-%d %H:%M')}") |
|
|
| |
| if st.session_state.filters_applied: |
| df = data_loader.apply_filters( |
| df, |
| platforms=selected_platforms if selected_platforms else None, |
| brands=selected_brands if selected_brands else None, |
| sentiments=selected_sentiments if selected_sentiments else None, |
| date_range=date_range if date_range and len(date_range) == 2 else None |
| ) |
|
|
| |
| if df.empty: |
| st.warning("No data matches the selected filters. Please adjust your filters.") |
| return |
| else: |
| st.info(f"Showing {len(df):,} records after applying filters") |
|
|
| |
| if page == "π Dashboard": |
| render_dashboard(df) |
|
|
| elif page == "π Sentiment Analysis": |
| render_sentiment_analysis(df) |
|
|
| elif page == "π¬ Reply Required": |
| render_reply_required(df) |
|
|
| |
| st.markdown("---") |
| st.markdown( |
| """ |
| <div style='text-align: center; color: gray; padding: 20px;'> |
| <p>Musora Sentiment Analysis Dashboard v1.0</p> |
| <p>Powered by Streamlit | Data from Snowflake</p> |
| </div> |
| """, |
| unsafe_allow_html=True |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| try: |
| main() |
| except Exception as e: |
| st.error(f"An error occurred: {str(e)}") |
| st.exception(e) |