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