| | """ |
| | 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) |