Spaces:
Sleeping
Sleeping
| 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 |