import gradio as gr import datetime import json import os from transformers import pipeline # Load an emotion detection model # top_k=None to get all emotions and their scores emotion_pipeline = pipeline("text-classification", model="SamLowe/roberta-base-go_emotions", top_k=None) # Custom motivational responses based on various emotions def get_motivation(label): messages = { "joy": "That's wonderful! Keep embracing that positive energy! 🌟", "optimism": "It's great to see your hopeful outlook! Keep believing in yourself! ✨", "love": "Feeling the love is a beautiful thing! Cherish these moments. ❤️", "sadness": "I'm here for you. It's okay to feel sad, and remember that tough times don't last. 🌧️", "anger": "It sounds like you're feeling angry. Acknowledge your feelings, and remember to be kind to yourself. 😤", "fear": "It's natural to feel scared sometimes. Take a deep breath; you're stronger than you think. 🛡️", "surprise": "Oh, what an unexpected turn! Hope it's a good one! 😲", "neutral": "It's okay to have neutral days. Keep going, one step at a time. 🌱", "disappointment": "It's tough when things don't go as planned. Allow yourself to feel it, and remember there's always tomorrow.😔", "excitement": "Awesome! Your excitement is contagious! Keep that energy flowing! 🎉", "gratitude": "Feeling thankful is a wonderful practice. What a lovely perspective! 🙏", "desire": "It's good to have aspirations! What steps can you take towards your goals? 🌠", "confusion": "Feeling a bit lost? It's okay to not have all the answers. Take your time to figure things out. 🤔", "admiration": "It's inspiring to look up to someone! What qualities do you admire most? 🤩", "amusement": "Laughter is the best medicine! Glad to hear you're finding joy. 😂" } return messages.get(label.lower(), "Thanks for sharing. Keep expressing yourself. 💬") # Function to get suggestions based on emotion def get_suggestions(emotion_label): suggestions = { "sadness": [ "Relax and listen to calming music.", "Take a warm bath or shower.", "Connect with a trusted friend or family member.", "Go for a gentle walk in nature.", "Watch a comforting movie or read a book.", "Allow yourself to cry if you need to, it can be a healthy release.", "Engage in a favorite hobby that brings you a sense of calm." ], "anger": [ "Take a few deep breaths to calm your nervous system.", "Step away from the situation if possible.", "Engage in physical activity, like a brisk walk or some stretches, to release tension.", "Express your feelings in a non-confrontational way, perhaps by writing them down.", "Listen to music that helps you relax or channel your energy.", "Squeeze a stress ball or do something with your hands like crafting." ], "fear": [ "Practice deep breathing exercises (e.g., 4-7-8 breathing).", "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).", "Talk to someone you trust about your worries.", "Engage in a calming activity like meditation or gentle yoga.", "Remind yourself that fear is a natural emotion and it will pass.", "Challenge anxious thoughts by asking if they are truly factual." ], "joy": [ "Savor the moment and appreciate what made you feel this way.", "Share your happiness with loved ones.", "Engage in activities that bring you more joy, like a favorite hobby.", "Practice gratitude: list things you are thankful for.", "Help someone else – giving back can amplify joyful feelings.", "Capture the moment (e.g., take a photo, write it down) to revisit later." ], "optimism": [ "Keep focusing on your goals and take small steps towards them.", "Share your positive outlook with others to inspire them.", "Continue practicing gratitude to reinforce positive thinking.", "Reflect on your strengths and past successes.", "Consider setting new positive intentions for your future." ], "disappointment": [ "Acknowledge your feelings and allow yourself to feel disappointed.", "Reflect on what you can learn from the situation.", "Focus on what you can control moving forward.", "Talk to someone supportive about how you feel.", "Engage in a self-care activity to uplift your spirits.", "Remember that it's okay for things not to go as planned sometimes." ], "gratitude": [ "Keep a gratitude journal to consistently note things you're thankful for.", "Express your thanks to someone in your life.", "Perform a random act of kindness for someone else.", "Mindfully appreciate the small blessings in your day.", "Reflect on how far you've come and what you've overcome." ], # Add more emotions and their corresponding suggestions here } # Default suggestions if no specific emotion is matched or for neutral default_suggestions = [ "Take a moment to reflect on your day.", "Engage in a relaxing activity like reading or listening to music.", "Practice deep breathing exercises.", "Connect with a friend or family member.", "Consider going for a short walk.", "Hydrate and consider a healthy snack." ] chosen_suggestions = suggestions.get(emotion_label.lower(), default_suggestions) return chosen_suggestions # Main journaling function def analyze_journal(entry, confidence_threshold=0.1): # Added confidence_threshold if not entry.strip(): # When clearing the input, also clear the suggestions output and state return "Please write something in your journal entry.", "I'm ready to listen when you are!", "", [] results = emotion_pipeline(entry) detected_emotions_display = "" suggestions_output_list = [] # Sort results by score in descending order # results is typically a list containing a list of dictionaries, so results[0] if not results or not results[0]: # Handle case where results might be empty detected_emotions_display = "No emotions detected." suggestions_output_list.extend(get_suggestions("neutral")) return f"🧠 Detected Emotions:\n{detected_emotions_display}", "Thanks for sharing. Keep expressing yourself. 💬", \ "\n\n**💡 Here are some suggestions for you:**\n" + "\n".join([f"- {s}" for s in suggestions_output_list]), \ suggestions_output_list sorted_results = sorted(results[0], key=lambda x: x['score'], reverse=True) for emotion_data in sorted_results: emotion_label = emotion_data['label'] emotion_score = emotion_data['score'] if emotion_score >= confidence_threshold: detected_emotions_display += f"- **{emotion_label.replace('_', ' ').title()}** (Confidence: {emotion_score:.2f})\n" suggestions_output_list.extend(get_suggestions(emotion_label)) if not detected_emotions_display: detected_emotions_display = "No specific emotions detected with high confidence." suggestions_output_list.extend(get_suggestions("neutral")) # Fallback to neutral suggestions # Remove duplicates from suggestions while preserving order unique_suggestions = [] seen = set() for suggestion in suggestions_output_list: if suggestion not in seen: unique_suggestions.append(suggestion) seen.add(suggestion) suggestion_text = "\n\n**💡 Here are some suggestions for you:**\n" if unique_suggestions: for suggestion in unique_suggestions: suggestion_text += f"- {suggestion}\n" else: suggestion_text += "No specific suggestions generated based on your entry." # Get a primary emotion for the motivational response (e.g., the top one) primary_emotion = sorted_results[0]['label'] if sorted_results else "neutral" response = get_motivation(primary_emotion) return f"🧠 Detected Emotions:\n{detected_emotions_display}", response, suggestion_text, unique_suggestions # --- Calendar To-Do List Feature Setup --- TASKS_FILE = "calendar_tasks.json" def load_calendar_tasks(): if os.path.exists(TASKS_FILE): try: with open(TASKS_FILE, 'r') as f: return json.load(f) except json.JSONDecodeError: print(f"Warning: {TASKS_FILE} is corrupted or empty. Starting with empty tasks.") return {} return {} # { "YYYY-MM-DD": [{"item": "...", "completed": False}, ...] } def save_calendar_tasks(tasks_data): with open(TASKS_FILE, 'w') as f: json.dump(tasks_data, f, indent=4) # Load tasks when the app starts global_calendar_tasks = load_calendar_tasks() def format_date_input(selected_date): """Ensures the date is in "YYYY-MM-DD" format from various Gradio date inputs.""" if isinstance(selected_date, datetime.date): return selected_date.strftime("%Y-%m-%d") elif isinstance(selected_date, datetime.datetime): return selected_date.strftime("%Y-%m-%d") elif isinstance(selected_date, str): try: # Handle potential ISO format strings from gr.DateTime # Gradio's gr.DateTime often returns ISO formatted strings like "YYYY-MM-DDTHH:MM:SS.sssZ" dt_obj = datetime.datetime.fromisoformat(selected_date.replace('Z', '+00:00')) return dt_obj.strftime("%Y-%m-%d") except ValueError: # Assume it's already "YYYY-MM-DD" if other conversions fail return selected_date return datetime.date.today().strftime("%Y-%m-%d") # Default fallback def get_tasks_for_date(selected_date): selected_date_str = format_date_input(selected_date) return global_calendar_tasks.get(selected_date_str, []) def display_calendar_tasks(selected_date): selected_date_str = format_date_input(selected_date) tasks = get_tasks_for_date(selected_date_str) display_title = f"### To-Do List for {selected_date_str}:" if not tasks: display_title += "\nNo tasks for this date. Add one!" # We will no longer generate HTML directly. # Instead, we will configure the CheckboxGroup to reflect the current tasks and their completion status. task_labels = [task['item'] for task in tasks] completed_task_labels = [task['item'] for task in tasks if task['completed']] # The CheckboxGroup's choices are all task items. # Its value is the list of items that are completed. return ( display_title, gr.CheckboxGroup(choices=task_labels, value=completed_task_labels, visible=True, label="Tasks"), "" # Clear the new item textbox ) def add_calendar_todo_item(selected_date, item): selected_date_str = format_date_input(selected_date) if not item.strip(): # Re-display tasks without adding empty item, clear input title, checkbox_group_output, _ = display_calendar_tasks(selected_date_str) return title, checkbox_group_output, "" # Clear input tasks_for_today = global_calendar_tasks.get(selected_date_str, []) # Check if the item already exists to prevent duplicates if you want to. # For now, we'll allow duplicates to simplify. tasks_for_today.append({"item": item.strip(), "completed": False}) global_calendar_tasks[selected_date_str] = tasks_for_today save_calendar_tasks(global_calendar_tasks) # Re-display tasks and clear input title, checkbox_group_output, _ = display_calendar_tasks(selected_date_str) return title, checkbox_group_output, "" # Clear input def toggle_calendar_todo_item(selected_date, selected_tasks_labels_from_checkbox_group): selected_date_str = format_date_input(selected_date) tasks = global_calendar_tasks.get(selected_date_str, []) # Update the completed status for each task based on the CheckboxGroup's value for task in tasks: task["completed"] = (task["item"] in selected_tasks_labels_from_checkbox_group) save_calendar_tasks(global_calendar_tasks) # Re-display the tasks to update the visual representation (e.g., strikethrough) # The display_calendar_tasks function will now return a new gr.CheckboxGroup # with updated choices and values. return display_calendar_tasks(selected_date) def clear_completed_tasks_today(selected_date): selected_date_str = format_date_input(selected_date) if selected_date_str in global_calendar_tasks: # Filter out completed tasks global_calendar_tasks[selected_date_str] = [ task for task in global_calendar_tasks[selected_date_str] if not task['completed'] ] save_calendar_tasks(global_calendar_tasks) # Re-display the tasks for today after clearing completed ones # This will now correctly return a new gr.CheckboxGroup with fewer items if tasks were cleared return display_calendar_tasks(selected_date) # This function is called to update the choices of the gr.Radio component def populate_suggestions_radio(suggestions_list): """ Populates the gr.Radio component with suggestions. This function should be directly mapped to the outputs of an event. """ if suggestions_list: # If there are suggestions, make it visible and populate choices return gr.Radio(choices=suggestions_list, value=None, visible=True) else: # If no suggestions, ensure choices are empty and it's hidden return gr.Radio(choices=[], value=None, visible=False) def add_suggestion_to_todo(selected_date, suggestion_to_add): if suggestion_to_add: # Call the existing add_calendar_todo_item function title, checkbox_group_output, new_item_textbox_val = add_calendar_todo_item(selected_date, suggestion_to_add) # Clear the selected radio button after adding return title, checkbox_group_output, new_item_textbox_val, gr.Radio(value=None, visible=True) # Reset radio selection else: # If no suggestion selected, just refresh the display and clear input field title, checkbox_group_output, _ = display_calendar_tasks(selected_date) return title, checkbox_group_output, gr.Textbox(value="", interactive=True), gr.Radio(value=None, visible=True) # --- Combined Gradio Interface (All in one frame) --- with gr.Blocks(title="✨ Your Multi-purpose AI Companion") as demo: gr.Markdown("# ✨ Your Multi-purpose AI Companion") gr.Markdown("Welcome! This AI buddy offers journaling and a to-do list all in one place.") # --- Journal Buddy Section --- gr.HTML("