|
|
import gradio as gr |
|
|
import datetime |
|
|
import random |
|
|
import time |
|
|
from typing import Dict, List, Any, Union, Optional |
|
|
import os |
|
|
import json |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
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" |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
with gr.Column(elem_id="settings-page"): |
|
|
gr.Markdown("# βοΈ Settings") |
|
|
gr.Markdown("*Customize your Mona experience*") |
|
|
|
|
|
|
|
|
settings_notification = gr.Markdown( |
|
|
"", |
|
|
elem_id="settings-notification", |
|
|
visible=False |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Tabs(): |
|
|
|
|
|
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" |
|
|
) |
|
|
|
|
|
|
|
|
@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!" |
|
|
|
|
|
|
|
|
gr.Button("Save Appearance").click( |
|
|
update_appearance, |
|
|
inputs=[theme, accent_color, font_size, sidebar_position], |
|
|
outputs=[settings_notification] |
|
|
) |
|
|
|
|
|
|
|
|
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" |
|
|
) |
|
|
|
|
|
|
|
|
@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!" |
|
|
|
|
|
|
|
|
gr.Button("Save Notifications").click( |
|
|
update_notifications, |
|
|
inputs=[ |
|
|
notifications_enabled, |
|
|
task_reminders, |
|
|
goal_updates, |
|
|
daily_summary, |
|
|
sound_enabled |
|
|
], |
|
|
outputs=[settings_notification] |
|
|
) |
|
|
|
|
|
|
|
|
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" |
|
|
) |
|
|
|
|
|
|
|
|
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" |
|
|
) |
|
|
|
|
|
|
|
|
@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!" |
|
|
|
|
|
|
|
|
gr.Button("Save AI Preferences").click( |
|
|
update_ai_preferences, |
|
|
inputs=[suggestions_enabled, suggestion_frequency, text_model, qa_model], |
|
|
outputs=[settings_notification] |
|
|
) |
|
|
|
|
|
|
|
|
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" |
|
|
) |
|
|
|
|
|
|
|
|
@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!" |
|
|
|
|
|
|
|
|
gr.Button("Save Data Management").click( |
|
|
update_data_management, |
|
|
inputs=[auto_backup, backup_frequency, data_retention], |
|
|
outputs=[settings_notification] |
|
|
) |
|
|
|
|
|
|
|
|
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" |
|
|
) |
|
|
|
|
|
|
|
|
@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!" |
|
|
|
|
|
|
|
|
gr.Button("Save Profile").click( |
|
|
update_user_profile, |
|
|
inputs=[name, email, timezone, language], |
|
|
outputs=[settings_notification] |
|
|
) |
|
|
|
|
|
|
|
|
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.") |
|
|
|
|
|
|
|
|
service_selector = gr.Dropdown( |
|
|
choices=[ |
|
|
"OpenWeatherMap", |
|
|
"GitHub", |
|
|
"Google Calendar", |
|
|
"Telegram", |
|
|
"News API", |
|
|
"Crypto API" |
|
|
], |
|
|
label="Select Service", |
|
|
value="OpenWeatherMap" |
|
|
) |
|
|
|
|
|
|
|
|
api_key_input = gr.Textbox( |
|
|
value=safe_get(state, ["settings", "api_keys", "OpenWeatherMap"], ""), |
|
|
label="API Key", |
|
|
placeholder="Enter your API key here", |
|
|
type="password" |
|
|
) |
|
|
|
|
|
|
|
|
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" |
|
|
) |
|
|
|
|
|
|
|
|
service_selector.change( |
|
|
update_api_key_input, |
|
|
inputs=[service_selector], |
|
|
outputs=[api_key_input] |
|
|
) |
|
|
|
|
|
|
|
|
@handle_exceptions |
|
|
def save_api_key(service, api_key): |
|
|
"""Save API key for selected service""" |
|
|
logger.info(f"Saving API key for {service}") |
|
|
|
|
|
|
|
|
if "api_keys" not in state["settings"]: |
|
|
state["settings"]["api_keys"] = {} |
|
|
|
|
|
|
|
|
state["settings"]["api_keys"][service] = api_key |
|
|
|
|
|
|
|
|
save_data(FILE_PATHS["settings"], state["settings"]) |
|
|
|
|
|
|
|
|
record_activity(state, f"Updated API key for {service}") |
|
|
|
|
|
return f"β
API key for {service} saved!" |
|
|
|
|
|
|
|
|
gr.Button("Save API Key").click( |
|
|
save_api_key, |
|
|
inputs=[service_selector, api_key_input], |
|
|
outputs=[settings_notification] |
|
|
) |
|
|
|
|
|
|
|
|
@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" |
|
|
|
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
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)}" |
|
|
|
|
|
|
|
|
gr.Button("Test API Key").click( |
|
|
test_api_key, |
|
|
inputs=[service_selector, api_key_input], |
|
|
outputs=[settings_notification] |
|
|
) |
|
|
|
|
|
|
|
|
gr.Markdown("### 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 "<p>No API keys configured yet.</p>" |
|
|
|
|
|
html = "<div class='api-keys-list'>" |
|
|
for service, key in api_keys.items(): |
|
|
|
|
|
masked_key = "*" * (len(key) - 4) + key[-4:] if key else "" |
|
|
|
|
|
html += f""" |
|
|
<div class='api-key-item'> |
|
|
<div class='api-key-service'>{service}</div> |
|
|
<div class='api-key-value'>{masked_key}</div> |
|
|
<div class='api-key-actions'> |
|
|
<button class='delete-api-key' data-service='{service}'>Delete</button> |
|
|
</div> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
html += "</div>" |
|
|
return html |
|
|
|
|
|
api_keys_display = gr.HTML(render_api_keys()) |
|
|
|
|
|
|
|
|
@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_data(FILE_PATHS["settings"], state["settings"]) |
|
|
|
|
|
|
|
|
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}" |
|
|
|
|
|
|
|
|
gr.Button("Refresh API Keys").click( |
|
|
lambda: render_api_keys(), |
|
|
outputs=[api_keys_display] |
|
|
) |
|
|
|
|
|
|
|
|
record_activity(state, "Viewed Settings Page") |