Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import datetime
|
| 3 |
+
import json
|
| 4 |
+
import os
|
| 5 |
+
from transformers import pipeline
|
| 6 |
+
|
| 7 |
+
# Load an emotion detection model
|
| 8 |
+
# top_k=None to get all emotions and their scores
|
| 9 |
+
emotion_pipeline = pipeline("text-classification", model="SamLowe/roberta-base-go_emotions", top_k=None)
|
| 10 |
+
|
| 11 |
+
# Custom motivational responses based on various emotions
|
| 12 |
+
def get_motivation(label):
|
| 13 |
+
messages = {
|
| 14 |
+
"joy": "That's wonderful! Keep embracing that positive energy! π",
|
| 15 |
+
"optimism": "It's great to see your hopeful outlook! Keep believing in yourself! β¨",
|
| 16 |
+
"love": "Feeling the love is a beautiful thing! Cherish these moments. β€οΈ",
|
| 17 |
+
"sadness": "I'm here for you. It's okay to feel sad, and remember that tough times don't last. π§οΈ",
|
| 18 |
+
"anger": "It sounds like you're feeling angry. Acknowledge your feelings, and remember to be kind to yourself. π€",
|
| 19 |
+
"fear": "It's natural to feel scared sometimes. Take a deep breath; you're stronger than you think. π‘οΈ",
|
| 20 |
+
"surprise": "Oh, what an unexpected turn! Hope it's a good one! π²",
|
| 21 |
+
"neutral": "It's okay to have neutral days. Keep going, one step at a time. π±",
|
| 22 |
+
"disappointment": "It's tough when things don't go as planned. Allow yourself to feel it, and remember there's always tomorrow.π",
|
| 23 |
+
"excitement": "Awesome! Your excitement is contagious! Keep that energy flowing! π",
|
| 24 |
+
"gratitude": "Feeling thankful is a wonderful practice. What a lovely perspective! π",
|
| 25 |
+
"desire": "It's good to have aspirations! What steps can you take towards your goals? π ",
|
| 26 |
+
"confusion": "Feeling a bit lost? It's okay to not have all the answers. Take your time to figure things out. π€",
|
| 27 |
+
"admiration": "It's inspiring to look up to someone! What qualities do you admire most? π€©",
|
| 28 |
+
"amusement": "Laughter is the best medicine! Glad to hear you're finding joy. π"
|
| 29 |
+
}
|
| 30 |
+
return messages.get(label.lower(), "Thanks for sharing. Keep expressing yourself. π¬")
|
| 31 |
+
|
| 32 |
+
# Function to get suggestions based on emotion
|
| 33 |
+
def get_suggestions(emotion_label):
|
| 34 |
+
suggestions = {
|
| 35 |
+
"sadness": [
|
| 36 |
+
"Relax and listen to calming music.",
|
| 37 |
+
"Take a warm bath or shower.",
|
| 38 |
+
"Connect with a trusted friend or family member.",
|
| 39 |
+
"Go for a gentle walk in nature.",
|
| 40 |
+
"Watch a comforting movie or read a book.",
|
| 41 |
+
"Allow yourself to cry if you need to, it can be a healthy release.",
|
| 42 |
+
"Engage in a favorite hobby that brings you a sense of calm."
|
| 43 |
+
],
|
| 44 |
+
"anger": [
|
| 45 |
+
"Take a few deep breaths to calm your nervous system.",
|
| 46 |
+
"Step away from the situation if possible.",
|
| 47 |
+
"Engage in physical activity, like a brisk walk or some stretches, to release tension.",
|
| 48 |
+
"Express your feelings in a non-confrontational way, perhaps by writing them down.",
|
| 49 |
+
"Listen to music that helps you relax or channel your energy.",
|
| 50 |
+
"Squeeze a stress ball or do something with your hands like crafting."
|
| 51 |
+
],
|
| 52 |
+
"fear": [
|
| 53 |
+
"Practice deep breathing exercises (e.g., 4-7-8 breathing).",
|
| 54 |
+
"Identify 5 things you can see, 4 you can touch, 3 you can hear, 2 you can smell, and 1 you can taste (grounding technique).",
|
| 55 |
+
"Talk to someone you trust about your worries.",
|
| 56 |
+
"Engage in a calming activity like meditation or gentle yoga.",
|
| 57 |
+
"Remind yourself that fear is a natural emotion and it will pass.",
|
| 58 |
+
"Challenge anxious thoughts by asking if they are truly factual."
|
| 59 |
+
],
|
| 60 |
+
"joy": [
|
| 61 |
+
"Savor the moment and appreciate what made you feel this way.",
|
| 62 |
+
"Share your happiness with loved ones.",
|
| 63 |
+
"Engage in activities that bring you more joy, like a favorite hobby.",
|
| 64 |
+
"Practice gratitude: list things you are thankful for.",
|
| 65 |
+
"Help someone else β giving back can amplify joyful feelings.",
|
| 66 |
+
"Capture the moment (e.g., take a photo, write it down) to revisit later."
|
| 67 |
+
],
|
| 68 |
+
"optimism": [
|
| 69 |
+
"Keep focusing on your goals and take small steps towards them.",
|
| 70 |
+
"Share your positive outlook with others to inspire them.",
|
| 71 |
+
"Continue practicing gratitude to reinforce positive thinking.",
|
| 72 |
+
"Reflect on your strengths and past successes.",
|
| 73 |
+
"Consider setting new positive intentions for your future."
|
| 74 |
+
],
|
| 75 |
+
"disappointment": [
|
| 76 |
+
"Acknowledge your feelings and allow yourself to feel disappointed.",
|
| 77 |
+
"Reflect on what you can learn from the situation.",
|
| 78 |
+
"Focus on what you can control moving forward.",
|
| 79 |
+
"Talk to someone supportive about how you feel.",
|
| 80 |
+
"Engage in a self-care activity to uplift your spirits.",
|
| 81 |
+
"Remember that it's okay for things not to go as planned sometimes."
|
| 82 |
+
],
|
| 83 |
+
"gratitude": [
|
| 84 |
+
"Keep a gratitude journal to consistently note things you're thankful for.",
|
| 85 |
+
"Express your thanks to someone in your life.",
|
| 86 |
+
"Perform a random act of kindness for someone else.",
|
| 87 |
+
"Mindfully appreciate the small blessings in your day.",
|
| 88 |
+
"Reflect on how far you've come and what you've overcome."
|
| 89 |
+
],
|
| 90 |
+
# Add more emotions and their corresponding suggestions here
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
# Default suggestions if no specific emotion is matched or for neutral
|
| 94 |
+
default_suggestions = [
|
| 95 |
+
"Take a moment to reflect on your day.",
|
| 96 |
+
"Engage in a relaxing activity like reading or listening to music.",
|
| 97 |
+
"Practice deep breathing exercises.",
|
| 98 |
+
"Connect with a friend or family member.",
|
| 99 |
+
"Consider going for a short walk.",
|
| 100 |
+
"Hydrate and consider a healthy snack."
|
| 101 |
+
]
|
| 102 |
+
|
| 103 |
+
chosen_suggestions = suggestions.get(emotion_label.lower(), default_suggestions)
|
| 104 |
+
|
| 105 |
+
return chosen_suggestions
|
| 106 |
+
|
| 107 |
+
# Main journaling function
|
| 108 |
+
def analyze_journal(entry, confidence_threshold=0.1): # Added confidence_threshold
|
| 109 |
+
if not entry.strip():
|
| 110 |
+
# When clearing the input, also clear the suggestions output and state
|
| 111 |
+
return "Please write something in your journal entry.", "I'm ready to listen when you are!", "", []
|
| 112 |
+
|
| 113 |
+
results = emotion_pipeline(entry)
|
| 114 |
+
|
| 115 |
+
detected_emotions_display = ""
|
| 116 |
+
suggestions_output_list = []
|
| 117 |
+
|
| 118 |
+
# Sort results by score in descending order
|
| 119 |
+
# results is typically a list containing a list of dictionaries, so results[0]
|
| 120 |
+
if not results or not results[0]: # Handle case where results might be empty
|
| 121 |
+
detected_emotions_display = "No emotions detected."
|
| 122 |
+
suggestions_output_list.extend(get_suggestions("neutral"))
|
| 123 |
+
return f"π§ Detected Emotions:\n{detected_emotions_display}", "Thanks for sharing. Keep expressing yourself. π¬", \
|
| 124 |
+
"\n\n**π‘ Here are some suggestions for you:**\n" + "\n".join([f"- {s}" for s in suggestions_output_list]), \
|
| 125 |
+
suggestions_output_list
|
| 126 |
+
|
| 127 |
+
sorted_results = sorted(results[0], key=lambda x: x['score'], reverse=True)
|
| 128 |
+
|
| 129 |
+
for emotion_data in sorted_results:
|
| 130 |
+
emotion_label = emotion_data['label']
|
| 131 |
+
emotion_score = emotion_data['score']
|
| 132 |
+
|
| 133 |
+
if emotion_score >= confidence_threshold:
|
| 134 |
+
detected_emotions_display += f"- **{emotion_label.replace('_', ' ').title()}** (Confidence: {emotion_score:.2f})\n"
|
| 135 |
+
suggestions_output_list.extend(get_suggestions(emotion_label))
|
| 136 |
+
|
| 137 |
+
if not detected_emotions_display:
|
| 138 |
+
detected_emotions_display = "No specific emotions detected with high confidence."
|
| 139 |
+
suggestions_output_list.extend(get_suggestions("neutral")) # Fallback to neutral suggestions
|
| 140 |
+
|
| 141 |
+
# Remove duplicates from suggestions while preserving order
|
| 142 |
+
unique_suggestions = []
|
| 143 |
+
seen = set()
|
| 144 |
+
for suggestion in suggestions_output_list:
|
| 145 |
+
if suggestion not in seen:
|
| 146 |
+
unique_suggestions.append(suggestion)
|
| 147 |
+
seen.add(suggestion)
|
| 148 |
+
|
| 149 |
+
suggestion_text = "\n\n**π‘ Here are some suggestions for you:**\n"
|
| 150 |
+
if unique_suggestions:
|
| 151 |
+
for suggestion in unique_suggestions:
|
| 152 |
+
suggestion_text += f"- {suggestion}\n"
|
| 153 |
+
else:
|
| 154 |
+
suggestion_text += "No specific suggestions generated based on your entry."
|
| 155 |
+
|
| 156 |
+
# Get a primary emotion for the motivational response (e.g., the top one)
|
| 157 |
+
primary_emotion = sorted_results[0]['label'] if sorted_results else "neutral"
|
| 158 |
+
response = get_motivation(primary_emotion)
|
| 159 |
+
|
| 160 |
+
return f"π§ Detected Emotions:\n{detected_emotions_display}", response, suggestion_text, unique_suggestions
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
# --- Calendar To-Do List Feature Setup ---
|
| 164 |
+
TASKS_FILE = "calendar_tasks.json"
|
| 165 |
+
|
| 166 |
+
def load_calendar_tasks():
|
| 167 |
+
if os.path.exists(TASKS_FILE):
|
| 168 |
+
try:
|
| 169 |
+
with open(TASKS_FILE, 'r') as f:
|
| 170 |
+
return json.load(f)
|
| 171 |
+
except json.JSONDecodeError:
|
| 172 |
+
print(f"Warning: {TASKS_FILE} is corrupted or empty. Starting with empty tasks.")
|
| 173 |
+
return {}
|
| 174 |
+
return {} # { "YYYY-MM-DD": [{"item": "...", "completed": False}, ...] }
|
| 175 |
+
|
| 176 |
+
def save_calendar_tasks(tasks_data):
|
| 177 |
+
with open(TASKS_FILE, 'w') as f:
|
| 178 |
+
json.dump(tasks_data, f, indent=4)
|
| 179 |
+
|
| 180 |
+
# Load tasks when the app starts
|
| 181 |
+
global_calendar_tasks = load_calendar_tasks()
|
| 182 |
+
|
| 183 |
+
def format_date_input(selected_date):
|
| 184 |
+
"""Ensures the date is in "YYYY-MM-DD" format from various Gradio date inputs."""
|
| 185 |
+
if isinstance(selected_date, datetime.date):
|
| 186 |
+
return selected_date.strftime("%Y-%m-%d")
|
| 187 |
+
elif isinstance(selected_date, datetime.datetime):
|
| 188 |
+
return selected_date.strftime("%Y-%m-%d")
|
| 189 |
+
elif isinstance(selected_date, str):
|
| 190 |
+
try:
|
| 191 |
+
# Handle potential ISO format strings from gr.DateTime
|
| 192 |
+
# Gradio's gr.DateTime often returns ISO formatted strings like "YYYY-MM-DDTHH:MM:SS.sssZ"
|
| 193 |
+
dt_obj = datetime.datetime.fromisoformat(selected_date.replace('Z', '+00:00'))
|
| 194 |
+
return dt_obj.strftime("%Y-%m-%d")
|
| 195 |
+
except ValueError:
|
| 196 |
+
# Assume it's already "YYYY-MM-DD" if other conversions fail
|
| 197 |
+
return selected_date
|
| 198 |
+
return datetime.date.today().strftime("%Y-%m-%d") # Default fallback
|
| 199 |
+
|
| 200 |
+
def get_tasks_for_date(selected_date):
|
| 201 |
+
selected_date_str = format_date_input(selected_date)
|
| 202 |
+
return global_calendar_tasks.get(selected_date_str, [])
|
| 203 |
+
|
| 204 |
+
def display_calendar_tasks(selected_date):
|
| 205 |
+
selected_date_str = format_date_input(selected_date)
|
| 206 |
+
tasks = get_tasks_for_date(selected_date_str)
|
| 207 |
+
|
| 208 |
+
display_title = f"### To-Do List for {selected_date_str}:"
|
| 209 |
+
if not tasks:
|
| 210 |
+
display_title += "\nNo tasks for this date. Add one!"
|
| 211 |
+
|
| 212 |
+
# We will no longer generate HTML directly.
|
| 213 |
+
# Instead, we will configure the CheckboxGroup to reflect the current tasks and their completion status.
|
| 214 |
+
|
| 215 |
+
task_labels = [task['item'] for task in tasks]
|
| 216 |
+
completed_task_labels = [task['item'] for task in tasks if task['completed']]
|
| 217 |
+
|
| 218 |
+
# The CheckboxGroup's choices are all task items.
|
| 219 |
+
# Its value is the list of items that are completed.
|
| 220 |
+
return (
|
| 221 |
+
display_title,
|
| 222 |
+
gr.CheckboxGroup(choices=task_labels, value=completed_task_labels, visible=True, label="Tasks"),
|
| 223 |
+
"" # Clear the new item textbox
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
def add_calendar_todo_item(selected_date, item):
|
| 228 |
+
selected_date_str = format_date_input(selected_date)
|
| 229 |
+
|
| 230 |
+
if not item.strip():
|
| 231 |
+
# Re-display tasks without adding empty item, clear input
|
| 232 |
+
title, checkbox_group_output, _ = display_calendar_tasks(selected_date_str)
|
| 233 |
+
return title, checkbox_group_output, "" # Clear input
|
| 234 |
+
|
| 235 |
+
tasks_for_today = global_calendar_tasks.get(selected_date_str, [])
|
| 236 |
+
# Check if the item already exists to prevent duplicates if you want to.
|
| 237 |
+
# For now, we'll allow duplicates to simplify.
|
| 238 |
+
|
| 239 |
+
tasks_for_today.append({"item": item.strip(), "completed": False})
|
| 240 |
+
global_calendar_tasks[selected_date_str] = tasks_for_today
|
| 241 |
+
save_calendar_tasks(global_calendar_tasks)
|
| 242 |
+
|
| 243 |
+
# Re-display tasks and clear input
|
| 244 |
+
title, checkbox_group_output, _ = display_calendar_tasks(selected_date_str)
|
| 245 |
+
return title, checkbox_group_output, "" # Clear input
|
| 246 |
+
|
| 247 |
+
def toggle_calendar_todo_item(selected_date, selected_tasks_labels_from_checkbox_group):
|
| 248 |
+
selected_date_str = format_date_input(selected_date)
|
| 249 |
+
tasks = global_calendar_tasks.get(selected_date_str, [])
|
| 250 |
+
|
| 251 |
+
# Update the completed status for each task based on the CheckboxGroup's value
|
| 252 |
+
for task in tasks:
|
| 253 |
+
task["completed"] = (task["item"] in selected_tasks_labels_from_checkbox_group)
|
| 254 |
+
|
| 255 |
+
save_calendar_tasks(global_calendar_tasks)
|
| 256 |
+
|
| 257 |
+
# Re-display the tasks to update the visual representation (e.g., strikethrough)
|
| 258 |
+
# The display_calendar_tasks function will now return a new gr.CheckboxGroup
|
| 259 |
+
# with updated choices and values.
|
| 260 |
+
return display_calendar_tasks(selected_date)
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
def clear_completed_tasks_today(selected_date):
|
| 264 |
+
selected_date_str = format_date_input(selected_date)
|
| 265 |
+
|
| 266 |
+
if selected_date_str in global_calendar_tasks:
|
| 267 |
+
# Filter out completed tasks
|
| 268 |
+
global_calendar_tasks[selected_date_str] = [
|
| 269 |
+
task for task in global_calendar_tasks[selected_date_str] if not task['completed']
|
| 270 |
+
]
|
| 271 |
+
save_calendar_tasks(global_calendar_tasks)
|
| 272 |
+
|
| 273 |
+
# Re-display the tasks for today after clearing completed ones
|
| 274 |
+
# This will now correctly return a new gr.CheckboxGroup with fewer items if tasks were cleared
|
| 275 |
+
return display_calendar_tasks(selected_date)
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
# This function is called to update the choices of the gr.Radio component
|
| 279 |
+
def populate_suggestions_radio(suggestions_list):
|
| 280 |
+
"""
|
| 281 |
+
Populates the gr.Radio component with suggestions.
|
| 282 |
+
This function should be directly mapped to the outputs of an event.
|
| 283 |
+
"""
|
| 284 |
+
if suggestions_list:
|
| 285 |
+
# If there are suggestions, make it visible and populate choices
|
| 286 |
+
return gr.Radio(choices=suggestions_list, value=None, visible=True)
|
| 287 |
+
else:
|
| 288 |
+
# If no suggestions, ensure choices are empty and it's hidden
|
| 289 |
+
return gr.Radio(choices=[], value=None, visible=False)
|
| 290 |
+
|
| 291 |
+
def add_suggestion_to_todo(selected_date, suggestion_to_add):
|
| 292 |
+
if suggestion_to_add:
|
| 293 |
+
# Call the existing add_calendar_todo_item function
|
| 294 |
+
title, checkbox_group_output, new_item_textbox_val = add_calendar_todo_item(selected_date, suggestion_to_add)
|
| 295 |
+
# Clear the selected radio button after adding
|
| 296 |
+
return title, checkbox_group_output, new_item_textbox_val, gr.Radio(value=None, visible=True) # Reset radio selection
|
| 297 |
+
else:
|
| 298 |
+
# If no suggestion selected, just refresh the display and clear input field
|
| 299 |
+
title, checkbox_group_output, _ = display_calendar_tasks(selected_date)
|
| 300 |
+
return title, checkbox_group_output, gr.Textbox(value="", interactive=True), gr.Radio(value=None, visible=True)
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
# --- Combined Gradio Interface (All in one frame) ---
|
| 304 |
+
with gr.Blocks(title="β¨ Your Multi-purpose AI Companion") as demo:
|
| 305 |
+
gr.Markdown("# β¨ Your Multi-purpose AI Companion")
|
| 306 |
+
gr.Markdown("Welcome! This AI buddy offers journaling and a to-do list all in one place.")
|
| 307 |
+
|
| 308 |
+
# --- Journal Buddy Section ---
|
| 309 |
+
gr.HTML("<hr>")
|
| 310 |
+
gr.Markdown("## π Journal Buddy")
|
| 311 |
+
gr.Markdown("Reflect, vent, or write freely. Get feedback based on your emotional tone.")
|
| 312 |
+
with gr.Column():
|
| 313 |
+
journal_input = gr.Textbox(label="Your Journal Entry", placeholder="Write how your day went or what's on your mind...", lines=5)
|
| 314 |
+
journal_analyze_button = gr.Button("Analyze Journal")
|
| 315 |
+
journal_output_mood = gr.Markdown(label="Detected Mood")
|
| 316 |
+
journal_output_response = gr.Text(label="Journal Buddy's Response")
|
| 317 |
+
journal_output_suggestions_markdown = gr.Markdown(label="Suggestions for You") # Markdown for display
|
| 318 |
+
|
| 319 |
+
# Hidden state to pass suggestions to the calendar tab
|
| 320 |
+
journal_suggestions_list_state = gr.State(value=[])
|
| 321 |
+
|
| 322 |
+
journal_analyze_result = journal_analyze_button.click( # Store the event object
|
| 323 |
+
fn=analyze_journal,
|
| 324 |
+
inputs=journal_input,
|
| 325 |
+
outputs=[
|
| 326 |
+
journal_output_mood,
|
| 327 |
+
journal_output_response,
|
| 328 |
+
journal_output_suggestions_markdown,
|
| 329 |
+
journal_suggestions_list_state # This updates the gr.State
|
| 330 |
+
]
|
| 331 |
+
)
|
| 332 |
+
gr.Examples(
|
| 333 |
+
examples=[
|
| 334 |
+
["I had a fantastic day, everything went perfectly and I feel so happy!"],
|
| 335 |
+
["I'm really struggling today, nothing seems to be going right and I feel so sad and frustrated."],
|
| 336 |
+
["I'm so angry about what happened at work, I can't believe it. I also feel a bit disappointed."],
|
| 337 |
+
["Today was just a regular day, nothing special happened."],
|
| 338 |
+
["I am so grateful for the sunny weather and a good cup of coffee this morning. Feeling very content."]
|
| 339 |
+
],
|
| 340 |
+
inputs=journal_input
|
| 341 |
+
)
|
| 342 |
+
|
| 343 |
+
# --- Calendar To-Do List Section ---
|
| 344 |
+
gr.HTML("<hr>")
|
| 345 |
+
gr.Markdown("## π
Calendar To-Do List")
|
| 346 |
+
gr.Markdown("This To-Do list is automatically set to today's date.")
|
| 347 |
+
|
| 348 |
+
with gr.Tabs() as calendar_tabs: # Use gr.Tabs for multiple sections within the To-Do list
|
| 349 |
+
with gr.TabItem("Manage To-Dos", id="manage_todos_tab"): # Added ID for clarity
|
| 350 |
+
with gr.Column():
|
| 351 |
+
# Automatically set to today's date and make it non-interactive
|
| 352 |
+
calendar_date_picker = gr.DateTime(
|
| 353 |
+
label="Today's Date",
|
| 354 |
+
value=datetime.datetime.now(),
|
| 355 |
+
type="date",
|
| 356 |
+
info="Tasks are managed for today's date.",
|
| 357 |
+
interactive=False # Key change: Make it non-interactive
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
calendar_todo_title = gr.Markdown() # To display the date title
|
| 361 |
+
|
| 362 |
+
# IMPORTANT CHANGE: Use gr.CheckboxGroup directly for displaying tasks
|
| 363 |
+
calendar_todo_checkboxes_display = gr.CheckboxGroup(
|
| 364 |
+
label="Your Tasks",
|
| 365 |
+
choices=[], # Will be populated by display_calendar_tasks
|
| 366 |
+
value=[], # Will be populated by display_calendar_tasks
|
| 367 |
+
interactive=True # Allow users to check/uncheck
|
| 368 |
+
)
|
| 369 |
+
|
| 370 |
+
with gr.Row():
|
| 371 |
+
new_item_textbox_calendar = gr.Textbox(label="New To-Do Item", placeholder="e.g., Team meeting", scale=4)
|
| 372 |
+
add_button_calendar = gr.Button("Add Item", scale=1)
|
| 373 |
+
|
| 374 |
+
clear_completed_button_calendar = gr.Button("Clear Done Tasks Today", variant="secondary")
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
# This ensures tasks are displayed when the app initially loads, for today's date
|
| 378 |
+
demo.load(
|
| 379 |
+
fn=lambda: display_calendar_tasks(datetime.date.today()),
|
| 380 |
+
outputs=[calendar_todo_title, calendar_todo_checkboxes_display, new_item_textbox_calendar]
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
add_button_calendar.click(
|
| 384 |
+
fn=add_calendar_todo_item,
|
| 385 |
+
inputs=[calendar_date_picker, new_item_textbox_calendar],
|
| 386 |
+
outputs=[calendar_todo_title, calendar_todo_checkboxes_display, new_item_textbox_calendar]
|
| 387 |
+
)
|
| 388 |
+
|
| 389 |
+
# IMPORTANT CHANGE: Wire the `change` event of the visible CheckboxGroup
|
| 390 |
+
calendar_todo_checkboxes_display.change(
|
| 391 |
+
fn=toggle_calendar_todo_item,
|
| 392 |
+
inputs=[calendar_date_picker, calendar_todo_checkboxes_display],
|
| 393 |
+
outputs=[calendar_todo_title, calendar_todo_checkboxes_display, new_item_textbox_calendar] # Ensure all outputs are updated
|
| 394 |
+
)
|
| 395 |
+
|
| 396 |
+
clear_completed_button_calendar.click(
|
| 397 |
+
fn=clear_completed_tasks_today,
|
| 398 |
+
inputs=calendar_date_picker,
|
| 399 |
+
outputs=[calendar_todo_title, calendar_todo_checkboxes_display, new_item_textbox_calendar]
|
| 400 |
+
)
|
| 401 |
+
|
| 402 |
+
with gr.TabItem("AI Suggestions", id="ai_suggestions_tab"): # Added ID for clarity
|
| 403 |
+
gr.Markdown("### Add Journal Suggestions to your To-Do List")
|
| 404 |
+
gr.Markdown("Select a suggestion from your last journal entry to add it directly to the To-Do list for today.")
|
| 405 |
+
|
| 406 |
+
# Display suggestions as radio buttons for selection
|
| 407 |
+
ai_suggestions_radio = gr.Radio(label="Choose a suggestion to add:", choices=[], value=None, visible=False)
|
| 408 |
+
add_suggestion_button = gr.Button("Add Selected Suggestion to To-Do List")
|
| 409 |
+
|
| 410 |
+
# Corrected logic: Use the .then() method to ensure sequential updates
|
| 411 |
+
# First, analyze journal and update state. Then, use the state to populate the radio.
|
| 412 |
+
journal_analyze_result.then( # Use the stored event object from journal_analyze_button.click
|
| 413 |
+
fn=populate_suggestions_radio,
|
| 414 |
+
inputs=journal_suggestions_list_state, # Input the state that was just updated
|
| 415 |
+
outputs=ai_suggestions_radio # Output to the radio button to update its choices
|
| 416 |
+
).then( # Chain another .then() to switch tabs
|
| 417 |
+
fn=lambda: gr.Tabs(selected="ai_suggestions_tab"),
|
| 418 |
+
outputs=calendar_tabs
|
| 419 |
+
)
|
| 420 |
+
|
| 421 |
+
# Action to add selected suggestion to the to-do list
|
| 422 |
+
add_suggestion_button.click(
|
| 423 |
+
fn=add_suggestion_to_todo,
|
| 424 |
+
inputs=[calendar_date_picker, ai_suggestions_radio],
|
| 425 |
+
outputs=[calendar_todo_title, calendar_todo_checkboxes_display, new_item_textbox_calendar, ai_suggestions_radio]
|
| 426 |
+
)
|
| 427 |
+
|
| 428 |
+
# Clear suggestions when switching back to the "Manage To-Dos" tab
|
| 429 |
+
# We don't need to clear suggestions on date_picker.change since it's non-interactive
|
| 430 |
+
calendar_tabs.select(
|
| 431 |
+
fn=lambda selected_tab: gr.Radio(choices=[], value=None, visible=False) if selected_tab == "manage_todos_tab" else gr.Noop(),
|
| 432 |
+
inputs=calendar_tabs,
|
| 433 |
+
outputs=ai_suggestions_radio
|
| 434 |
+
)
|
| 435 |
+
|
| 436 |
+
demo.launch()
|