Spaces:
Runtime error
Runtime error
| # frontend/app.py | |
| import streamlit as st | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| import sys | |
| import os | |
| # Add the parent directory of 'backend' to the Python path | |
| # This allows importing 'backend' as a package | |
| # os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) points to 'sentilyze/' | |
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) | |
| # Import functions directly from the 'backend' package | |
| # The __init__.py in backend handles the individual imports | |
| from backend import analyze_sentiment, process_csv_for_dashboard, detect_sarcasm_and_highlight | |
| # --- Streamlit App Configuration --- | |
| st.set_page_config( | |
| page_title="Sentilyze - Sentiment & Sarcasm Analyzer", | |
| page_icon="✨", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # --- Custom CSS for better aesthetics --- | |
| st.markdown(""" | |
| <style> | |
| .main-header { | |
| font-size: 3em; | |
| font-weight: bold; | |
| color: #4CAF50; | |
| text-align: center; | |
| margin-bottom: 30px; | |
| text-shadow: 2px 2px 4px #aaaaaa; | |
| } | |
| .stButton>button { | |
| background-color: #4CAF50; | |
| color: white; | |
| border-radius: 12px; | |
| padding: 10px 24px; | |
| font-size: 18px; | |
| border: none; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); | |
| } | |
| .stButton>button:hover { | |
| background-color: #45a049; | |
| box-shadow: 0 6px 12px 0 rgba(0,0,0,0.3); | |
| transform: translateY(-2px); | |
| } | |
| .stTextInput>div>div>input { | |
| border-radius: 12px; | |
| border: 1px solid #ccc; | |
| padding: 10px; | |
| box-shadow: inset 0 1px 3px rgba(0,0,0,0.1); | |
| } | |
| .stFileUploader>div>div>button { | |
| background-color: #2196F3; | |
| color: white; | |
| border-radius: 12px; | |
| padding: 10px 24px; | |
| font-size: 18px; | |
| border: none; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); | |
| } | |
| .stFileUploader>div>div>button:hover { | |
| background-color: #0b7dda; | |
| box-shadow: 0 6px 12px 0 rgba(0,0,0,0.3); | |
| transform: translateY(-2px); | |
| } | |
| .stAlert { | |
| border-radius: 12px; | |
| } | |
| mark { | |
| background-color: #FFEB3B; /* Yellow highlight */ | |
| padding: 2px 5px; | |
| border-radius: 3px; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # --- Header --- | |
| st.markdown("<h1 class='main-header'>Sentilyze ✨</h1>", unsafe_allow_html=True) | |
| st.write("Analyze sentiment, detect sarcasm, and visualize insights from your text data.") | |
| # --- Navigation (using Streamlit's sidebar for sections) --- | |
| st.sidebar.title("Navigation") | |
| page = st.sidebar.radio("Go to", ["Single Text Analysis", "CSV File Analysis", "About"]) | |
| # --- Single Text Analysis Section --- | |
| if page == "Single Text Analysis": | |
| st.header("Analyze Single Text") | |
| user_input = st.text_area("Enter text here:", "This product is absolutely fantastic!", height=150) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("Analyze Sentiment"): | |
| if user_input: | |
| sentiment_result = analyze_sentiment(user_input) | |
| st.success(f"**Sentiment:** {sentiment_result['class'].capitalize()}") | |
| st.info(f"**Polarity Score:** {sentiment_result['polarity']:.2f} (closer to 1 is positive, -1 is negative)") | |
| else: | |
| st.warning("Please enter some text to analyze sentiment.") | |
| with col2: | |
| if st.button("Detect Sarcasm"): | |
| if user_input: | |
| sarcasm_result = detect_sarcasm_and_highlight(user_input) | |
| st.success(f"**Sarcasm Probability:** {sarcasm_result['sarcasm_percent']:.2f}%") | |
| # FIX: Changed 'predicted_sentiment_label' to 'predicted_sarcasm_label' | |
| st.info(f"**Predicted Sarcasm (Model's view):** {sarcasm_result['predicted_sarcasm_label'].capitalize()}") | |
| st.markdown(f"**Highlighted Text:** {sarcasm_result['highlighted_sentence']}", unsafe_allow_html=True) | |
| if "note" in sarcasm_result: | |
| st.caption(f"Note: {sarcasm_result['note']}") | |
| else: | |
| st.warning("Please enter some text to detect sarcasm.") | |
| # --- CSV File Analysis Section --- | |
| elif page == "CSV File Analysis": | |
| st.header("Analyze CSV File") | |
| st.write("Upload a CSV file containing text data for sentiment analysis and dashboard visualization.") | |
| uploaded_file = st.file_uploader("Choose a CSV file", type="csv") | |
| if uploaded_file is not None: | |
| # Save the uploaded file temporarily to process it with pandas | |
| # In a real app, consider more robust temporary file handling or direct BytesIO | |
| temp_filepath = os.path.join("data", uploaded_file.name) | |
| with open(temp_filepath, "wb") as f: | |
| f.write(uploaded_file.getbuffer()) | |
| df = process_csv_for_dashboard(temp_filepath) | |
| if not df.empty: | |
| st.success("CSV file uploaded and processed successfully!") | |
| st.subheader("Raw Data Preview:") | |
| st.dataframe(df.head()) | |
| # Allow user to select the text column | |
| text_columns = [col for col in df.columns if df[col].dtype == 'object'] # Assuming text is object/string type | |
| if not text_columns: | |
| st.error("No text columns found in the CSV. Please ensure your CSV has columns with review text.") | |
| else: | |
| selected_text_column = st.selectbox( | |
| "Select the column containing text/reviews for analysis:", | |
| text_columns | |
| ) | |
| if st.button(f"Perform Sentiment Analysis on '{selected_text_column}'"): | |
| with st.spinner("Analyzing sentiment... This might take a while for large files."): | |
| # Apply sentiment analysis to the selected column | |
| df['Sentiment'] = df[selected_text_column].astype(str).apply(lambda x: analyze_sentiment(x)['class']) | |
| df['Polarity'] = df[selected_text_column].astype(str).apply(lambda x: analyze_sentiment(x)['polarity']) | |
| st.subheader("Sentiment Analysis Results:") | |
| st.dataframe(df[[selected_text_column, 'Sentiment', 'Polarity']].head()) | |
| st.subheader("Sentiment Distribution:") | |
| sentiment_counts = df['Sentiment'].value_counts() | |
| st.bar_chart(sentiment_counts) | |
| # Interactive Dashboard Elements | |
| st.subheader("Interactive Dashboard") | |
| # Pie chart for sentiment distribution | |
| fig1, ax1 = plt.subplots() | |
| sentiment_counts.plot.pie(autopct='%1.1f%%', startangle=90, ax=ax1, | |
| colors=['#4CAF50', '#FFC107', '#F44336']) # Positive, Neutral, Negative | |
| ax1.set_ylabel('') # Hide the default 'Sentiment' label | |
| ax1.set_title('Overall Sentiment Distribution') | |
| st.pyplot(fig1) | |
| # Histogram of Polarity Scores | |
| fig2, ax2 = plt.subplots() | |
| sns.histplot(df['Polarity'], bins=20, kde=True, ax=ax2, color='#2196F3') | |
| ax2.set_title('Distribution of Polarity Scores') | |
| ax2.set_xlabel('Polarity Score') | |
| ax2.set_ylabel('Frequency') | |
| st.pyplot(fig2) | |
| # Display data by sentiment type | |
| st.subheader("View Data by Sentiment Type") | |
| sentiment_filter = st.selectbox( | |
| "Filter by Sentiment:", | |
| ["All", "positive", "neutral", "negative"] | |
| ) | |
| if sentiment_filter == "All": | |
| st.dataframe(df[[selected_text_column, 'Sentiment', 'Polarity']]) | |
| else: | |
| filtered_df = df[df['Sentiment'] == sentiment_filter] | |
| st.dataframe(filtered_df[[selected_text_column, 'Sentiment', 'Polarity']]) | |
| else: | |
| st.error("Could not process the CSV file. Please check its format.") | |
| # Clean up the temporary file | |
| if os.path.exists(temp_filepath): | |
| os.remove(temp_filepath) | |
| # --- About Section --- | |
| elif page == "About": | |
| st.header("About Sentilyze") | |
| st.write(""" | |
| Sentilyze is a web application designed to help you understand the sentiment and nuances | |
| of text data. It offers: | |
| - **Single Text Analysis:** Quickly determine the sentiment (positive, neutral, negative) | |
| and potential sarcasm of individual pieces of text. | |
| - **CSV File Analysis:** Upload your own datasets (e.g., customer reviews, social media comments) | |
| and get an interactive dashboard showing sentiment distribution and polarity. | |
| - **Sarcasm Detection:** A feature to estimate the sarcasm percentage in a sentence, | |
| with basic highlighting (note: advanced sarcasm highlighting is a complex NLP task). | |
| **Technologies Used:** | |
| - **Backend:** Python, `pandas`, `TextBlob`, `transformers` (Hugging Face) | |
| - **Frontend:** Streamlit | |
| - **Deployment:** Docker, GitHub, (potential platforms like Streamlit Community Cloud, Heroku, Render) | |
| **Developed by:** [Your Name/Team Name Here] | |
| """) | |
| st.markdown("[GitHub Repository (Coming Soon!)](#)", unsafe_allow_html=True) | |
| # --- Footer --- | |
| st.markdown(""" | |
| <hr> | |
| <p style='text-align: center; color: grey;'>Sentilyze © 2023</p> | |
| """, unsafe_allow_html=True) | |