import gradio as gr import datetime import random import time from typing import Dict, List, Any, Union, Optional import os import json # Import utilities from utils.storage import load_data, save_data, safe_get from utils.state import generate_id, get_timestamp, record_activity from utils.config import FILE_PATHS from utils.logging import setup_logger from utils.error_handling import handle_exceptions # Initialize logger logger = setup_logger(__name__) @handle_exceptions def create_settings_page(state: Dict[str, Any]) -> None: """ Create the Settings page with options to customize the application Args: state: Application state """ logger.info("Creating settings page") # Initialize settings if not present if "settings" not in state: state["settings"] = load_data(FILE_PATHS["settings"], { "appearance": { "theme": "light", "accent_color": "#4CAF50", "font_size": "medium", "sidebar_position": "left" }, "notifications": { "enabled": True, "task_reminders": True, "goal_updates": True, "daily_summary": True, "sound_enabled": True }, "ai_preferences": { "suggestions_enabled": True, "suggestion_frequency": "medium", "preferred_models": { "text_generation": "microsoft/DialoGPT-medium", "question_answering": "distilbert-base-uncased-distilled-squad", "image_analysis": "Salesforce/blip-image-captioning-base", "speech_to_text": "openai/whisper-small", "translation": "Helsinki-NLP/opus-mt-en-de", "sentiment": "cardiffnlp/twitter-roberta-base-sentiment-latest", "summarization": "facebook/bart-large-cnn", "code_generation": "microsoft/CodeBERT-base" } }, "data_management": { "auto_backup": True, "backup_frequency": "weekly", "data_retention": "1 year" }, "user_profile": { "name": "", "email": "", "timezone": "UTC", "language": "English" } }) # Create the settings page layout with gr.Column(elem_id="settings-page"): gr.Markdown("# ⚙️ Settings") gr.Markdown("*Customize your Mona experience*") # Settings saved notification settings_notification = gr.Markdown( "", elem_id="settings-notification", visible=False ) # Main tabs for different settings categories with gr.Tabs(): # Appearance Tab with gr.TabItem("Appearance"): with gr.Group(): gr.Markdown("### Theme & Colors") theme = gr.Radio( choices=["light", "dark", "system"], value=safe_get(state, ["settings", "appearance", "theme"], "light"), label="Theme" ) accent_color = gr.ColorPicker( value=safe_get(state, ["settings", "appearance", "accent_color"], "#4CAF50"), label="Accent Color" ) font_size = gr.Dropdown( choices=["small", "medium", "large"], value=safe_get(state, ["settings", "appearance", "font_size"], "medium"), label="Font Size" ) sidebar_position = gr.Radio( choices=["left", "right"], value=safe_get(state, ["settings", "appearance", "sidebar_position"], "left"), label="Sidebar Position" ) # Function to update appearance settings @handle_exceptions def update_appearance( theme_value: str, color_value: str, size_value: str, position_value: str ) -> str: """Update appearance settings""" logger.info("Updating appearance settings") state["settings"]["appearance"].update({ "theme": theme_value, "accent_color": color_value, "font_size": size_value, "sidebar_position": position_value }) save_data(FILE_PATHS["settings"], state["settings"]) record_activity(state, "Updated Appearance Settings", { "theme": theme_value, "accent_color": color_value, "font_size": size_value, "sidebar_position": position_value }) return "✅ Appearance settings saved!" # Connect appearance settings to update function gr.Button("Save Appearance").click( update_appearance, inputs=[theme, accent_color, font_size, sidebar_position], outputs=[settings_notification] ) # Notifications Tab with gr.TabItem("Notifications"): with gr.Group(): gr.Markdown("### Notification Settings") notifications_enabled = gr.Checkbox( value=safe_get(state, ["settings", "notifications", "enabled"], True), label="Enable Notifications" ) task_reminders = gr.Checkbox( value=safe_get(state, ["settings", "notifications", "task_reminders"], True), label="Task Reminders" ) goal_updates = gr.Checkbox( value=safe_get(state, ["settings", "notifications", "goal_updates"], True), label="Goal Updates" ) daily_summary = gr.Checkbox( value=safe_get(state, ["settings", "notifications", "daily_summary"], True), label="Daily Summary" ) sound_enabled = gr.Checkbox( value=safe_get(state, ["settings", "notifications", "sound_enabled"], True), label="Enable Sound" ) # Function to update notification settings @handle_exceptions def update_notifications( enabled: bool, reminders: bool, updates: bool, summary: bool, sound: bool ) -> str: """Update notification settings""" logger.info("Updating notification settings") state["settings"]["notifications"].update({ "enabled": enabled, "task_reminders": reminders, "goal_updates": updates, "daily_summary": summary, "sound_enabled": sound }) save_data(FILE_PATHS["settings"], state["settings"]) record_activity(state, "Updated Notification Settings", { "enabled": enabled, "task_reminders": reminders, "goal_updates": updates, "daily_summary": summary, "sound_enabled": sound }) return "✅ Notification settings saved!" # Connect notification settings to update function gr.Button("Save Notifications").click( update_notifications, inputs=[ notifications_enabled, task_reminders, goal_updates, daily_summary, sound_enabled ], outputs=[settings_notification] ) # AI Preferences Tab with gr.TabItem("AI Preferences"): with gr.Group(): gr.Markdown("### AI Assistant Settings") suggestions_enabled = gr.Checkbox( value=safe_get(state, ["settings", "ai_preferences", "suggestions_enabled"], True), label="Enable AI Suggestions" ) suggestion_frequency = gr.Radio( choices=["low", "medium", "high"], value=safe_get(state, ["settings", "ai_preferences", "suggestion_frequency"], "medium"), label="Suggestion Frequency" ) # Model selection dropdowns text_model = gr.Dropdown( choices=["microsoft/DialoGPT-small", "microsoft/DialoGPT-medium", "microsoft/DialoGPT-large"], value=safe_get(state, ["settings", "ai_preferences", "preferred_models", "text_generation"], "microsoft/DialoGPT-medium"), label="Text Generation Model" ) qa_model = gr.Dropdown( choices=["distilbert-base-uncased-distilled-squad", "bert-large-uncased-whole-word-masking-finetuned-squad"], value=safe_get(state, ["settings", "ai_preferences", "preferred_models", "question_answering"], "distilbert-base-uncased-distilled-squad"), label="Question Answering Model" ) # Function to update AI preferences @handle_exceptions def update_ai_preferences( enabled: bool, frequency: str, text_model_value: str, qa_model_value: str ) -> str: """Update AI preferences""" logger.info("Updating AI preferences") state["settings"]["ai_preferences"].update({ "suggestions_enabled": enabled, "suggestion_frequency": frequency, "preferred_models": { **state["settings"]["ai_preferences"]["preferred_models"], "text_generation": text_model_value, "question_answering": qa_model_value } }) save_data(FILE_PATHS["settings"], state["settings"]) record_activity(state, "Updated AI Preferences", { "suggestions_enabled": enabled, "suggestion_frequency": frequency, "text_model": text_model_value, "qa_model": qa_model_value }) return "✅ AI preferences saved!" # Connect AI preferences to update function gr.Button("Save AI Preferences").click( update_ai_preferences, inputs=[suggestions_enabled, suggestion_frequency, text_model, qa_model], outputs=[settings_notification] ) # Data Management Tab with gr.TabItem("Data Management"): with gr.Group(): gr.Markdown("### Data Management Settings") auto_backup = gr.Checkbox( value=safe_get(state, ["settings", "data_management", "auto_backup"], True), label="Enable Auto-Backup" ) backup_frequency = gr.Radio( choices=["daily", "weekly", "monthly"], value=safe_get(state, ["settings", "data_management", "backup_frequency"], "weekly"), label="Backup Frequency" ) data_retention = gr.Dropdown( choices=["1 month", "3 months", "6 months", "1 year", "forever"], value=safe_get(state, ["settings", "data_management", "data_retention"], "1 year"), label="Data Retention Period" ) # Function to update data management settings @handle_exceptions def update_data_management( backup_enabled: bool, frequency: str, retention: str ) -> str: """Update data management settings""" logger.info("Updating data management settings") state["settings"]["data_management"].update({ "auto_backup": backup_enabled, "backup_frequency": frequency, "data_retention": retention }) save_data(FILE_PATHS["settings"], state["settings"]) record_activity(state, "Updated Data Management Settings", { "auto_backup": backup_enabled, "backup_frequency": frequency, "data_retention": retention }) return "✅ Data management settings saved!" # Connect data management settings to update function gr.Button("Save Data Management").click( update_data_management, inputs=[auto_backup, backup_frequency, data_retention], outputs=[settings_notification] ) # User Profile Tab with gr.TabItem("User Profile"): with gr.Group(): gr.Markdown("### User Profile Settings") name = gr.Textbox( value=safe_get(state, ["settings", "user_profile", "name"], ""), label="Name" ) email = gr.Textbox( value=safe_get(state, ["settings", "user_profile", "email"], ""), label="Email" ) timezone = gr.Dropdown( choices=["UTC", "US/Eastern", "US/Central", "US/Mountain", "US/Pacific"], value=safe_get(state, ["settings", "user_profile", "timezone"], "UTC"), label="Timezone" ) language = gr.Dropdown( choices=["English", "Spanish", "French", "German", "Chinese", "Japanese"], value=safe_get(state, ["settings", "user_profile", "language"], "English"), label="Language" ) # Function to update user profile @handle_exceptions def update_user_profile( name_value: str, email_value: str, timezone_value: str, language_value: str ) -> str: """Update user profile settings""" logger.info("Updating user profile") state["settings"]["user_profile"].update({ "name": name_value, "email": email_value, "timezone": timezone_value, "language": language_value }) save_data(FILE_PATHS["settings"], state["settings"]) record_activity(state, "Updated User Profile", { "name": name_value, "email": email_value, "timezone": timezone_value, "language": language_value }) return "✅ User profile saved!" # Connect user profile to update function gr.Button("Save Profile").click( update_user_profile, inputs=[name, email, timezone, language], outputs=[settings_notification] ) # API Keys Tab with gr.TabItem("API Keys"): with gr.Group(): gr.Markdown("### API Keys Management") gr.Markdown("Enter your API keys for various services. These keys will be securely stored and used for integrations.") # Create a dropdown to select the service service_selector = gr.Dropdown( choices=[ "OpenWeatherMap", "GitHub", "Google Calendar", "Telegram", "News API", "Crypto API" ], label="Select Service", value="OpenWeatherMap" ) # API key input api_key_input = gr.Textbox( value=safe_get(state, ["settings", "api_keys", "OpenWeatherMap"], ""), label="API Key", placeholder="Enter your API key here", type="password" ) # Function to update the API key input when service is changed def update_api_key_input(service): """Update API key input when service is changed""" return gr.update( value=safe_get(state, ["settings", "api_keys", service], ""), label=f"{service} API Key" ) # Connect service selector to update function service_selector.change( update_api_key_input, inputs=[service_selector], outputs=[api_key_input] ) # Function to save API key @handle_exceptions def save_api_key(service, api_key): """Save API key for selected service""" logger.info(f"Saving API key for {service}") # Initialize api_keys dict if it doesn't exist if "api_keys" not in state["settings"]: state["settings"]["api_keys"] = {} # Save the API key state["settings"]["api_keys"][service] = api_key # Save settings save_data(FILE_PATHS["settings"], state["settings"]) # Record activity record_activity(state, f"Updated API key for {service}") return f"✅ API key for {service} saved!" # Connect save button to save function gr.Button("Save API Key").click( save_api_key, inputs=[service_selector, api_key_input], outputs=[settings_notification] ) # Function to test API key @handle_exceptions def test_api_key(service, api_key): """Test API key for selected service""" logger.info(f"Testing API key for {service}") if not api_key: return "❌ Please enter an API key first" # Test the API key based on the service try: if service == "OpenWeatherMap": from utils.integrations.weather import WeatherIntegration weather = WeatherIntegration(api_key=api_key) if weather.test_connection(): return "✅ API key is valid!" else: return "❌ API key is invalid or connection failed" # Add more services as needed else: return "⚠️ Testing not implemented for this service yet" except Exception as e: logger.error(f"Error testing API key: {str(e)}") return f"❌ Error: {str(e)}" # Connect test button to test function gr.Button("Test API Key").click( test_api_key, inputs=[service_selector, api_key_input], outputs=[settings_notification] ) # Display current API keys gr.Markdown("### Current API Keys") # Function to render current API keys def render_api_keys(): """Render current API keys as HTML""" api_keys = safe_get(state, ["settings", "api_keys"], {}) if not api_keys: return "

No API keys configured yet.

" html = "
" for service, key in api_keys.items(): # Mask the API key for display masked_key = "*" * (len(key) - 4) + key[-4:] if key else "" html += f"""
{service}
{masked_key}
""" html += "
" return html api_keys_display = gr.HTML(render_api_keys()) # Function to delete API key @handle_exceptions def delete_api_key(service): """Delete API key for selected service""" logger.info(f"Deleting API key for {service}") if "api_keys" in state["settings"] and service in state["settings"]["api_keys"]: del state["settings"]["api_keys"][service] # Save settings save_data(FILE_PATHS["settings"], state["settings"]) # Record activity record_activity(state, f"Deleted API key for {service}") return render_api_keys(), f"✅ API key for {service} deleted!" return render_api_keys(), f"⚠️ No API key found for {service}" # Refresh button to update the API keys display gr.Button("Refresh API Keys").click( lambda: render_api_keys(), outputs=[api_keys_display] ) # Record page visit in activity record_activity(state, "Viewed Settings Page")