DilBot / src /streamlit_app.py
zainali9091's picture
Update src/streamlit_app.py
c4e745f verified
import streamlit as st
from textblob import TextBlob
import json
import os
import matplotlib.pyplot as plt
# === UI/UX Modifications ===
def set_background_and_styles():
st.markdown(
"""
<style>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Merriweather:wght@300;400;700&display=swap');
.stApp {
background-image: url("https://i.pinimg.com/1200x/f0/ca/71/f0ca7163efb2ecc676426ae5ba1c1723.jpg");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
font-family: 'Montserrat', sans-serif;
color: white; /* Make all general text white */
}
/* Changed all header colors to white, also targeting labels directly */
h1, h2, h3, h4, h5, h6, .stMarkdown, label { /* Added .stMarkdown and label for white text */
font-family: 'Merriweather', serif;
color: white;
}
/* Specific target for the text area label, just in case */
.stTextArea > label {
color: white !important;
}
.stButton>button {
background-color: #4682B4; /* Steel Blue */
color: white;
border-radius: 8px;
border: none;
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
transition: all 0.2s ease-in-out;
}
.stButton>button:hover {
background-color: #5F9EA0; /* Cadet Blue */
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.stTextInput>div>div>input, .stTextArea>div>div>textarea {
border-radius: 8px;
border: 1px solid #B0C4DE; /* LightSteelBlue */
padding: 10px;
background-color: rgba(255, 255, 255, 0.85);
color: #333; /* Input text color should remain dark for readability */
}
.stSelectbox>div>div>div {
border-radius: 8px;
border: 1px solid #B0C4DE;
background-color: rgba(255, 255, 255, 0.85);
color: #333; /* Selectbox text color should remain dark for readability */
}
/* Modified stSuccess and stInfo for white text on darker transparent black background */
.stSuccess {
border-left: 5px solid #28a745;
background-color: rgba(0, 0, 0, 0.6); /* Transparent black */
color: white; /* Make text white */
border-radius: 8px;
padding: 10px;
margin-bottom: 10px;
}
.stInfo {
border-left: 5px solid #17a2b8;
background-color: rgba(0, 0, 0, 0.6); /* Transparent black */
color: white; /* Make text white */
border-radius: 8px;
padding: 10px;
margin-bottom: 10px;
}
.stWarning {
border-left: 5px solid #ffc107;
background-color: rgba(255, 255, 255, 0.9); /* Keep existing light for warning */
color: #333; /* Keep dark for warning */
border-radius: 8px;
padding: 10px;
margin-bottom: 10px;
}
.stError {
border-left: 5px solid #dc3545;
background-color: rgba(255, 255, 255, 0.9); /* Keep existing light for error */
color: #333; /* Keep dark for error */
border-radius: 8px;
padding: 10px;
margin-bottom: 10px;
}
/* Custom container for content with blur background */
.main-content-container {
background-color: rgba(255, 255, 255, 0.7); /* Slightly transparent white */
backdrop-filter: blur(5px); /* Blur effect */
border-radius: 15px;
padding: 30px;
margin: 20px auto; /* Centering the container */
max-width: 550px; /* Significantly less wide */
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
/* Wider layout (adjusted for much less wide) */
.st-emotion-cache-fg4lbf {
max-width: 600px !important; /* Adjusted for less wide */
padding-left: 0 !important;
padding-right: 0 !important;
}
.st-emotion-cache-1d391kg {
padding-top: 2rem;
padding-bottom: 2rem;
}
.block-container { /* Ensure content inside main-content-container respects its max-width */
padding-left: 1rem;
padding-right: 1rem;
color: white; /* Ensure text within block-container is white */
}
/* Center plots */
.st-emotion-cache-1pxazr6 { /* Specific Streamlit container for pyplot */
display: flex;
justify-content: center;
}
/* Hide the top grey bar */
header.st-emotion-cache-1gh8zsi {
display: none !important;
}
div.st-emotion-cache-fis6y8 {
padding-top: 0 !important;
}
div.st-emotion-cache-z5inrg {
display: none !important;
}
</style>
""",
unsafe_allow_html=True
)
# === Load Quotes ===
QUOTES_PATH = os.path.join(os.path.dirname(__file__), "quotes.json")
# Create a dummy quotes.json if it doesn't exist for the script to run locally without error
if not os.path.exists(QUOTES_PATH):
dummy_quotes = {
"positive": ["You are doing great!", "Keep shining!", "Believe in yourself!"],
"negative": ["It's okay to feel down, brighter days are ahead.", "Take a deep breath.", "This too shall pass."],
"neutral": ["Observe your thoughts.", "Find your center.", "Acknowledge your feelings."]
}
with open(QUOTES_PATH, "w") as f:
json.dump(dummy_quotes, f, indent=4)
with open(QUOTES_PATH, "r") as f:
quotes_data = json.load(f)
# === Emotion Detection via TextBlob ===
def detect_emotion(text):
blob = TextBlob(text)
polarity = blob.sentiment.polarity
if polarity > 0.2:
return "positive", polarity
elif polarity < -0.2:
return "negative", polarity
else:
return "neutral", polarity
# === Quotes Retrieval ===
def get_quote(emotion):
if isinstance(quotes_data, dict):
# Return a random quote from the list for the given emotion
import random
return [random.choice(quotes_data.get(emotion, ["Stay strong, you're doing great!"]))]
else:
return ["Stay strong, you're doing great!"]
# === Page Layout ===
st.set_page_config(page_title="DilBot - Emotionally Intelligent AI Companion", layout="centered")
set_background_and_styles()
# This div will act as the centered container
st.markdown('<div class="main-content-container">', unsafe_allow_html=True)
# Motivational quote above title
st.markdown("<p style='text-align: center; font-style: italic; color: white;'>\"The only way to do great work is to love what you do.\"</p>", unsafe_allow_html=True)
st.title("DilBot: Your Emotional Companion")
st.markdown("---")
# === Input Section ===
# Label color is now white via CSS
user_input = st.text_area("How are you feeling today?", height=150, placeholder="Type your thoughts here...")
if st.button("Analyze"):
if user_input.strip():
# Detect Emotion
emotion, polarity = detect_emotion(user_input)
confidence = abs(polarity) * 100
# Display Emotion - now white text on transparent black background
st.subheader("Detected Emotion:")
st.success(f"**{emotion.capitalize()}** with a confidence of **{confidence:.2f}%**")
# Show a personal quote - now white text on transparent black background
st.markdown("### DilBot's Message:")
quote = get_quote(emotion)[0]
st.info(f"_{quote}_")
# === Personal Dashboard ===
st.markdown("### Personal Dashboard")
# Bar & Doughnut Chart
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3), dpi=100)
labels = ['Positive', 'Neutral', 'Negative']
display_values = [0, 0, 0]
if emotion == 'positive':
display_values[0] = confidence
remaining = 100 - confidence
display_values[1] = remaining / 2
display_values[2] = remaining / 2
elif emotion == 'negative':
display_values[2] = confidence
remaining = 100 - confidence
display_values[0] = remaining / 2
display_values[1] = remaining / 2
else: # neutral
display_values[1] = confidence
remaining = 100 - confidence
display_values[0] = remaining / 2
display_values[2] = remaining / 2
# Ensure values sum to 100 for the pie chart
total_sum = sum(display_values)
if total_sum != 0:
display_values = [v * 100 / total_sum for v in display_values]
colors = ['#00cc99', '#b0bec5', '#ff6f61']
# Set chart backgrounds to white
ax1.set_facecolor('white')
ax2.set_facecolor('white')
fig.patch.set_facecolor('white') # Entire figure background white
# Bar Chart
ax1.bar(labels, display_values, color=colors)
ax1.set_title("Confidence by Emotion", color='black')
ax1.set_ylabel("Percentage", color='black')
ax1.tick_params(axis='x', colors='black')
ax1.tick_params(axis='y', colors='black')
ax1.spines['bottom'].set_color('black')
ax1.spines['left'].set_color('black')
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
# Doughnut Chart
if sum(display_values) > 0:
wedges, texts, autotexts = ax2.pie(
display_values, labels=labels, autopct='%1.1f%%',
colors=colors, startangle=90, wedgeprops=dict(width=0.4)
)
ax2.set_title("Emotion Distribution", color='black')
for text_obj in texts:
text_obj.set_color('black')
for autotext_obj in autotexts:
autotext_obj.set_color('black')
else:
ax2.text(0.5, 0.5, 'No data', horizontalalignment='center', verticalalignment='center', transform=ax2.transAxes, color='black')
# Use st.columns to center the plot
col_left, col_center, col_right = st.columns([0.5, 6, 0.5])
with col_center:
st.pyplot(fig)
plt.close(fig)
else:
st.warning("Please write something to analyze.")
st.markdown('</div>', unsafe_allow_html=True) # Close main-content-container