Update pages/settings.py
Browse files- pages/settings.py +312 -553
pages/settings.py
CHANGED
@@ -1,568 +1,327 @@
|
|
1 |
-
import
|
2 |
-
import datetime
|
3 |
-
import random
|
4 |
-
import time
|
5 |
-
from typing import Dict, List, Any, Union, Optional
|
6 |
-
import os
|
7 |
-
import json
|
8 |
|
9 |
-
|
10 |
-
from utils.storage import
|
11 |
-
from utils.
|
12 |
-
from utils.
|
13 |
-
from utils.logging import setup_logger
|
14 |
-
from utils.error_handling import handle_exceptions
|
15 |
|
16 |
-
|
17 |
-
logger = setup_logger(__name__)
|
18 |
|
19 |
-
@
|
20 |
-
def create_settings_page(
|
21 |
-
"""
|
22 |
-
|
|
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
"""
|
27 |
-
logger.info("Creating settings page")
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
state["settings"] = load_data(FILE_PATHS["settings"], {
|
32 |
-
"appearance": {
|
33 |
-
"theme": "light",
|
34 |
-
"accent_color": "#4CAF50",
|
35 |
-
"font_size": "medium",
|
36 |
-
"sidebar_position": "left"
|
37 |
-
},
|
38 |
-
"notifications": {
|
39 |
-
"enabled": True,
|
40 |
-
"task_reminders": True,
|
41 |
-
"goal_updates": True,
|
42 |
-
"daily_summary": True,
|
43 |
-
"sound_enabled": True
|
44 |
-
},
|
45 |
-
"ai_preferences": {
|
46 |
-
"suggestions_enabled": True,
|
47 |
-
"suggestion_frequency": "medium",
|
48 |
-
"preferred_models": {
|
49 |
-
"text_generation": "microsoft/DialoGPT-medium",
|
50 |
-
"question_answering": "distilbert-base-uncased-distilled-squad",
|
51 |
-
"image_analysis": "Salesforce/blip-image-captioning-base",
|
52 |
-
"speech_to_text": "openai/whisper-small",
|
53 |
-
"translation": "Helsinki-NLP/opus-mt-en-de",
|
54 |
-
"sentiment": "cardiffnlp/twitter-roberta-base-sentiment-latest",
|
55 |
-
"summarization": "facebook/bart-large-cnn",
|
56 |
-
"code_generation": "microsoft/CodeBERT-base"
|
57 |
-
}
|
58 |
-
},
|
59 |
-
"data_management": {
|
60 |
-
"auto_backup": True,
|
61 |
-
"backup_frequency": "weekly",
|
62 |
-
"data_retention": "1 year"
|
63 |
-
},
|
64 |
-
"user_profile": {
|
65 |
-
"name": "",
|
66 |
-
"email": "",
|
67 |
-
"timezone": "UTC",
|
68 |
-
"language": "English"
|
69 |
-
}
|
70 |
-
})
|
71 |
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
|
|
82 |
)
|
83 |
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
gr.Markdown("### Theme & Colors")
|
90 |
-
|
91 |
-
theme = gr.Radio(
|
92 |
-
choices=["light", "dark", "system"],
|
93 |
-
value=safe_get(state, ["settings", "appearance", "theme"], "light"),
|
94 |
-
label="Theme"
|
95 |
-
)
|
96 |
-
|
97 |
-
accent_color = gr.ColorPicker(
|
98 |
-
value=safe_get(state, ["settings", "appearance", "accent_color"], "#4CAF50"),
|
99 |
-
label="Accent Color"
|
100 |
-
)
|
101 |
-
|
102 |
-
font_size = gr.Dropdown(
|
103 |
-
choices=["small", "medium", "large"],
|
104 |
-
value=safe_get(state, ["settings", "appearance", "font_size"], "medium"),
|
105 |
-
label="Font Size"
|
106 |
-
)
|
107 |
-
|
108 |
-
sidebar_position = gr.Radio(
|
109 |
-
choices=["left", "right"],
|
110 |
-
value=safe_get(state, ["settings", "appearance", "sidebar_position"], "left"),
|
111 |
-
label="Sidebar Position"
|
112 |
-
)
|
113 |
-
|
114 |
-
# Function to update appearance settings
|
115 |
-
@handle_exceptions
|
116 |
-
def update_appearance(
|
117 |
-
theme_value: str,
|
118 |
-
color_value: str,
|
119 |
-
size_value: str,
|
120 |
-
position_value: str
|
121 |
-
) -> str:
|
122 |
-
"""Update appearance settings"""
|
123 |
-
logger.info("Updating appearance settings")
|
124 |
-
|
125 |
-
state["settings"]["appearance"].update({
|
126 |
-
"theme": theme_value,
|
127 |
-
"accent_color": color_value,
|
128 |
-
"font_size": size_value,
|
129 |
-
"sidebar_position": position_value
|
130 |
-
})
|
131 |
-
|
132 |
-
save_data(FILE_PATHS["settings"], state["settings"])
|
133 |
-
record_activity(state, "Updated Appearance Settings", {
|
134 |
-
"theme": theme_value,
|
135 |
-
"accent_color": color_value,
|
136 |
-
"font_size": size_value,
|
137 |
-
"sidebar_position": position_value
|
138 |
-
})
|
139 |
-
|
140 |
-
return "β
Appearance settings saved!"
|
141 |
-
|
142 |
-
# Connect appearance settings to update function
|
143 |
-
gr.Button("Save Appearance").click(
|
144 |
-
update_appearance,
|
145 |
-
inputs=[theme, accent_color, font_size, sidebar_position],
|
146 |
-
outputs=[settings_notification]
|
147 |
-
)
|
148 |
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
# Connect notification settings to update function
|
211 |
-
gr.Button("Save Notifications").click(
|
212 |
-
update_notifications,
|
213 |
-
inputs=[
|
214 |
-
notifications_enabled,
|
215 |
-
task_reminders,
|
216 |
-
goal_updates,
|
217 |
-
daily_summary,
|
218 |
-
sound_enabled
|
219 |
-
],
|
220 |
-
outputs=[settings_notification]
|
221 |
-
)
|
222 |
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
"text_model": text_model_value,
|
278 |
-
"qa_model": qa_model_value
|
279 |
-
})
|
280 |
-
|
281 |
-
return "β
AI preferences saved!"
|
282 |
-
|
283 |
-
# Connect AI preferences to update function
|
284 |
-
gr.Button("Save AI Preferences").click(
|
285 |
-
update_ai_preferences,
|
286 |
-
inputs=[suggestions_enabled, suggestion_frequency, text_model, qa_model],
|
287 |
-
outputs=[settings_notification]
|
288 |
-
)
|
289 |
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
gr.Markdown("### Data Management Settings")
|
294 |
-
|
295 |
-
auto_backup = gr.Checkbox(
|
296 |
-
value=safe_get(state, ["settings", "data_management", "auto_backup"], True),
|
297 |
-
label="Enable Auto-Backup"
|
298 |
-
)
|
299 |
-
|
300 |
-
backup_frequency = gr.Radio(
|
301 |
-
choices=["daily", "weekly", "monthly"],
|
302 |
-
value=safe_get(state, ["settings", "data_management", "backup_frequency"], "weekly"),
|
303 |
-
label="Backup Frequency"
|
304 |
-
)
|
305 |
-
|
306 |
-
data_retention = gr.Dropdown(
|
307 |
-
choices=["1 month", "3 months", "6 months", "1 year", "forever"],
|
308 |
-
value=safe_get(state, ["settings", "data_management", "data_retention"], "1 year"),
|
309 |
-
label="Data Retention Period"
|
310 |
-
)
|
311 |
-
|
312 |
-
# Function to update data management settings
|
313 |
-
@handle_exceptions
|
314 |
-
def update_data_management(
|
315 |
-
backup_enabled: bool,
|
316 |
-
frequency: str,
|
317 |
-
retention: str
|
318 |
-
) -> str:
|
319 |
-
"""Update data management settings"""
|
320 |
-
logger.info("Updating data management settings")
|
321 |
-
|
322 |
-
state["settings"]["data_management"].update({
|
323 |
-
"auto_backup": backup_enabled,
|
324 |
-
"backup_frequency": frequency,
|
325 |
-
"data_retention": retention
|
326 |
-
})
|
327 |
-
|
328 |
-
save_data(FILE_PATHS["settings"], state["settings"])
|
329 |
-
record_activity(state, "Updated Data Management Settings", {
|
330 |
-
"auto_backup": backup_enabled,
|
331 |
-
"backup_frequency": frequency,
|
332 |
-
"data_retention": retention
|
333 |
-
})
|
334 |
-
|
335 |
-
return "β
Data management settings saved!"
|
336 |
-
|
337 |
-
# Connect data management settings to update function
|
338 |
-
gr.Button("Save Data Management").click(
|
339 |
-
update_data_management,
|
340 |
-
inputs=[auto_backup, backup_frequency, data_retention],
|
341 |
-
outputs=[settings_notification]
|
342 |
-
)
|
343 |
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
timezone = gr.Dropdown(
|
360 |
-
choices=["UTC", "US/Eastern", "US/Central", "US/Mountain", "US/Pacific"],
|
361 |
-
value=safe_get(state, ["settings", "user_profile", "timezone"], "UTC"),
|
362 |
-
label="Timezone"
|
363 |
-
)
|
364 |
-
|
365 |
-
language = gr.Dropdown(
|
366 |
-
choices=["English", "Spanish", "French", "German", "Chinese", "Japanese"],
|
367 |
-
value=safe_get(state, ["settings", "user_profile", "language"], "English"),
|
368 |
-
label="Language"
|
369 |
-
)
|
370 |
-
|
371 |
-
# Function to update user profile
|
372 |
-
@handle_exceptions
|
373 |
-
def update_user_profile(
|
374 |
-
name_value: str,
|
375 |
-
email_value: str,
|
376 |
-
timezone_value: str,
|
377 |
-
language_value: str
|
378 |
-
) -> str:
|
379 |
-
"""Update user profile settings"""
|
380 |
-
logger.info("Updating user profile")
|
381 |
-
|
382 |
-
state["settings"]["user_profile"].update({
|
383 |
-
"name": name_value,
|
384 |
-
"email": email_value,
|
385 |
-
"timezone": timezone_value,
|
386 |
-
"language": language_value
|
387 |
-
})
|
388 |
-
|
389 |
-
save_data(FILE_PATHS["settings"], state["settings"])
|
390 |
-
record_activity(state, "Updated User Profile", {
|
391 |
-
"name": name_value,
|
392 |
-
"email": email_value,
|
393 |
-
"timezone": timezone_value,
|
394 |
-
"language": language_value
|
395 |
-
})
|
396 |
-
|
397 |
-
return "β
User profile saved!"
|
398 |
-
|
399 |
-
# Connect user profile to update function
|
400 |
-
gr.Button("Save Profile").click(
|
401 |
-
update_user_profile,
|
402 |
-
inputs=[name, email, timezone, language],
|
403 |
-
outputs=[settings_notification]
|
404 |
-
)
|
405 |
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
"Google Calendar",
|
418 |
-
"Telegram",
|
419 |
-
"News API",
|
420 |
-
"Crypto API"
|
421 |
-
],
|
422 |
-
label="Select Service",
|
423 |
-
value="OpenWeatherMap"
|
424 |
-
)
|
425 |
-
|
426 |
-
# API key input
|
427 |
-
api_key_input = gr.Textbox(
|
428 |
-
value=safe_get(state, ["settings", "api_keys", "OpenWeatherMap"], ""),
|
429 |
-
label="API Key",
|
430 |
-
placeholder="Enter your API key here",
|
431 |
-
type="password"
|
432 |
-
)
|
433 |
-
|
434 |
-
# Function to update the API key input when service is changed
|
435 |
-
def update_api_key_input(service):
|
436 |
-
"""Update API key input when service is changed"""
|
437 |
-
return gr.update(
|
438 |
-
value=safe_get(state, ["settings", "api_keys", service], ""),
|
439 |
-
label=f"{service} API Key"
|
440 |
-
)
|
441 |
-
|
442 |
-
# Connect service selector to update function
|
443 |
-
service_selector.change(
|
444 |
-
update_api_key_input,
|
445 |
-
inputs=[service_selector],
|
446 |
-
outputs=[api_key_input]
|
447 |
-
)
|
448 |
-
|
449 |
-
# Function to save API key
|
450 |
-
@handle_exceptions
|
451 |
-
def save_api_key(service, api_key):
|
452 |
-
"""Save API key for selected service"""
|
453 |
-
logger.info(f"Saving API key for {service}")
|
454 |
-
|
455 |
-
# Initialize api_keys dict if it doesn't exist
|
456 |
-
if "api_keys" not in state["settings"]:
|
457 |
-
state["settings"]["api_keys"] = {}
|
458 |
-
|
459 |
-
# Save the API key
|
460 |
-
state["settings"]["api_keys"][service] = api_key
|
461 |
-
|
462 |
-
# Save settings
|
463 |
-
save_data(FILE_PATHS["settings"], state["settings"])
|
464 |
-
|
465 |
-
# Record activity
|
466 |
-
record_activity(state, f"Updated API key for {service}")
|
467 |
-
|
468 |
-
return f"β
API key for {service} saved!"
|
469 |
-
|
470 |
-
# Connect save button to save function
|
471 |
-
gr.Button("Save API Key").click(
|
472 |
-
save_api_key,
|
473 |
-
inputs=[service_selector, api_key_input],
|
474 |
-
outputs=[settings_notification]
|
475 |
-
)
|
476 |
-
|
477 |
-
# Function to test API key
|
478 |
-
@handle_exceptions
|
479 |
-
def test_api_key(service, api_key):
|
480 |
-
"""Test API key for selected service"""
|
481 |
-
logger.info(f"Testing API key for {service}")
|
482 |
-
|
483 |
-
if not api_key:
|
484 |
-
return "β Please enter an API key first"
|
485 |
-
|
486 |
-
# Test the API key based on the service
|
487 |
-
try:
|
488 |
-
if service == "OpenWeatherMap":
|
489 |
-
from utils.integrations.weather import WeatherIntegration
|
490 |
-
weather = WeatherIntegration(api_key=api_key)
|
491 |
-
if weather.test_connection():
|
492 |
-
return "β
API key is valid!"
|
493 |
-
else:
|
494 |
-
return "β API key is invalid or connection failed"
|
495 |
-
|
496 |
-
# Add more services as needed
|
497 |
-
else:
|
498 |
-
return "β οΈ Testing not implemented for this service yet"
|
499 |
-
|
500 |
-
except Exception as e:
|
501 |
-
logger.error(f"Error testing API key: {str(e)}")
|
502 |
-
return f"β Error: {str(e)}"
|
503 |
-
|
504 |
-
# Connect test button to test function
|
505 |
-
gr.Button("Test API Key").click(
|
506 |
-
test_api_key,
|
507 |
-
inputs=[service_selector, api_key_input],
|
508 |
-
outputs=[settings_notification]
|
509 |
-
)
|
510 |
-
|
511 |
-
# Display current API keys
|
512 |
-
gr.Markdown("### Current API Keys")
|
513 |
-
|
514 |
-
# Function to render current API keys
|
515 |
-
def render_api_keys():
|
516 |
-
"""Render current API keys as HTML"""
|
517 |
-
api_keys = safe_get(state, ["settings", "api_keys"], {})
|
518 |
-
|
519 |
-
if not api_keys:
|
520 |
-
return "<p>No API keys configured yet.</p>"
|
521 |
-
|
522 |
-
html = "<div class='api-keys-list'>"
|
523 |
-
for service, key in api_keys.items():
|
524 |
-
# Mask the API key for display
|
525 |
-
masked_key = "*" * (len(key) - 4) + key[-4:] if key else ""
|
526 |
-
|
527 |
-
html += f"""
|
528 |
-
<div class='api-key-item'>
|
529 |
-
<div class='api-key-service'>{service}</div>
|
530 |
-
<div class='api-key-value'>{masked_key}</div>
|
531 |
-
<div class='api-key-actions'>
|
532 |
-
<button class='delete-api-key' data-service='{service}'>Delete</button>
|
533 |
-
</div>
|
534 |
-
</div>
|
535 |
-
"""
|
536 |
-
|
537 |
-
html += "</div>"
|
538 |
-
return html
|
539 |
-
|
540 |
-
api_keys_display = gr.HTML(render_api_keys())
|
541 |
-
|
542 |
-
# Function to delete API key
|
543 |
-
@handle_exceptions
|
544 |
-
def delete_api_key(service):
|
545 |
-
"""Delete API key for selected service"""
|
546 |
-
logger.info(f"Deleting API key for {service}")
|
547 |
-
|
548 |
-
if "api_keys" in state["settings"] and service in state["settings"]["api_keys"]:
|
549 |
-
del state["settings"]["api_keys"][service]
|
550 |
-
|
551 |
-
# Save settings
|
552 |
-
save_data(FILE_PATHS["settings"], state["settings"])
|
553 |
-
|
554 |
-
# Record activity
|
555 |
-
record_activity(state, f"Deleted API key for {service}")
|
556 |
-
|
557 |
-
return render_api_keys(), f"β
API key for {service} deleted!"
|
558 |
-
|
559 |
-
return render_api_keys(), f"β οΈ No API key found for {service}"
|
560 |
-
|
561 |
-
# Refresh button to update the API keys display
|
562 |
-
gr.Button("Refresh API Keys").click(
|
563 |
-
lambda: render_api_keys(),
|
564 |
-
outputs=[api_keys_display]
|
565 |
-
)
|
566 |
|
567 |
-
|
568 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
from utils.config import load_config, save_config, reset_config, AppConfig
|
5 |
+
from utils.storage import get_storage_info, clear_storage, list_keys
|
6 |
+
from utils.error_handling import handle_ui_exceptions
|
7 |
+
from utils.logging import get_logger
|
|
|
|
|
8 |
|
9 |
+
logger = get_logger(__name__)
|
|
|
10 |
|
11 |
+
@handle_ui_exceptions
|
12 |
+
def create_settings_page():
|
13 |
+
"""Create the settings page"""
|
14 |
+
st.title("βοΈ Settings")
|
15 |
+
st.write("Configure your MONA dashboard preferences and system settings.")
|
16 |
|
17 |
+
# Create tabs for different settings categories
|
18 |
+
tab1, tab2, tab3, tab4 = st.tabs(["General", "Display", "Data", "System"])
|
|
|
|
|
19 |
|
20 |
+
with tab1:
|
21 |
+
create_general_settings()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
+
with tab2:
|
24 |
+
create_display_settings()
|
25 |
+
|
26 |
+
with tab3:
|
27 |
+
create_data_settings()
|
28 |
+
|
29 |
+
with tab4:
|
30 |
+
create_system_settings()
|
31 |
+
|
32 |
+
@handle_ui_exceptions
|
33 |
+
def create_general_settings():
|
34 |
+
"""Create general settings section"""
|
35 |
+
st.header("π§ General Settings")
|
36 |
+
|
37 |
+
config = load_config()
|
38 |
+
|
39 |
+
# Application settings
|
40 |
+
with st.form("general_settings_form"):
|
41 |
+
st.subheader("Application Configuration")
|
42 |
+
|
43 |
+
app_name = st.text_input("Application Name", value=config.app_name)
|
44 |
+
version = st.text_input("Version", value=config.version, disabled=True)
|
45 |
+
debug_mode = st.checkbox("Debug Mode", value=config.debug_mode)
|
46 |
+
|
47 |
+
st.subheader("Performance Settings")
|
48 |
+
max_data_points = st.number_input(
|
49 |
+
"Maximum Data Points",
|
50 |
+
min_value=100,
|
51 |
+
max_value=10000,
|
52 |
+
value=config.max_data_points,
|
53 |
+
step=100
|
54 |
+
)
|
55 |
|
56 |
+
refresh_interval = st.number_input(
|
57 |
+
"Refresh Interval (seconds)",
|
58 |
+
min_value=1,
|
59 |
+
max_value=300,
|
60 |
+
value=config.refresh_interval,
|
61 |
+
step=1
|
62 |
)
|
63 |
|
64 |
+
if st.form_submit_button("Save General Settings"):
|
65 |
+
config.app_name = app_name
|
66 |
+
config.debug_mode = debug_mode
|
67 |
+
config.max_data_points = max_data_points
|
68 |
+
config.refresh_interval = refresh_interval
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
+
if save_config(config):
|
71 |
+
st.success("General settings saved successfully!")
|
72 |
+
st.rerun()
|
73 |
+
else:
|
74 |
+
st.error("Failed to save general settings.")
|
75 |
+
|
76 |
+
@handle_ui_exceptions
|
77 |
+
def create_display_settings():
|
78 |
+
"""Create display settings section"""
|
79 |
+
st.header("π¨ Display Settings")
|
80 |
+
|
81 |
+
config = load_config()
|
82 |
+
|
83 |
+
with st.form("display_settings_form"):
|
84 |
+
st.subheader("Theme & Appearance")
|
85 |
+
|
86 |
+
theme = st.selectbox(
|
87 |
+
"Theme",
|
88 |
+
options=["light", "dark"],
|
89 |
+
index=0 if config.theme == "light" else 1
|
90 |
+
)
|
91 |
+
|
92 |
+
default_chart_type = st.selectbox(
|
93 |
+
"Default Chart Type",
|
94 |
+
options=["line", "bar", "scatter", "area"],
|
95 |
+
index=["line", "bar", "scatter", "area"].index(config.default_chart_type)
|
96 |
+
)
|
97 |
+
|
98 |
+
st.subheader("Layout Settings")
|
99 |
+
|
100 |
+
sidebar_width = st.slider(
|
101 |
+
"Sidebar Width (px)",
|
102 |
+
min_value=200,
|
103 |
+
max_value=500,
|
104 |
+
value=config.sidebar_width,
|
105 |
+
step=10
|
106 |
+
)
|
107 |
+
|
108 |
+
chart_height = st.slider(
|
109 |
+
"Default Chart Height (px)",
|
110 |
+
min_value=300,
|
111 |
+
max_value=800,
|
112 |
+
value=config.chart_height,
|
113 |
+
step=50
|
114 |
+
)
|
115 |
+
|
116 |
+
table_page_size = st.number_input(
|
117 |
+
"Table Page Size",
|
118 |
+
min_value=10,
|
119 |
+
max_value=200,
|
120 |
+
value=config.table_page_size,
|
121 |
+
step=10
|
122 |
+
)
|
123 |
+
|
124 |
+
if st.form_submit_button("Save Display Settings"):
|
125 |
+
config.theme = theme
|
126 |
+
config.default_chart_type = default_chart_type
|
127 |
+
config.sidebar_width = sidebar_width
|
128 |
+
config.chart_height = chart_height
|
129 |
+
config.table_page_size = table_page_size
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
131 |
+
if save_config(config):
|
132 |
+
st.success("Display settings saved successfully!")
|
133 |
+
st.rerun()
|
134 |
+
else:
|
135 |
+
st.error("Failed to save display settings.")
|
136 |
+
|
137 |
+
@handle_ui_exceptions
|
138 |
+
def create_data_settings():
|
139 |
+
"""Create data settings section"""
|
140 |
+
st.header("π Data Settings")
|
141 |
+
|
142 |
+
config = load_config()
|
143 |
+
|
144 |
+
with st.form("data_settings_form"):
|
145 |
+
st.subheader("Data Processing")
|
146 |
+
|
147 |
+
data_cache_timeout = st.number_input(
|
148 |
+
"Data Cache Timeout (seconds)",
|
149 |
+
min_value=60,
|
150 |
+
max_value=3600,
|
151 |
+
value=config.data_cache_timeout,
|
152 |
+
step=60
|
153 |
+
)
|
154 |
+
|
155 |
+
max_file_size_mb = st.number_input(
|
156 |
+
"Maximum File Size (MB)",
|
157 |
+
min_value=1,
|
158 |
+
max_value=100,
|
159 |
+
value=config.max_file_size_mb,
|
160 |
+
step=1
|
161 |
+
)
|
162 |
+
|
163 |
+
st.subheader("Supported File Types")
|
164 |
+
current_types = config.supported_file_types or ['.csv', '.xlsx', '.json', '.parquet']
|
165 |
+
|
166 |
+
col1, col2 = st.columns(2)
|
167 |
+
with col1:
|
168 |
+
csv_support = st.checkbox("CSV Files (.csv)", value='.csv' in current_types)
|
169 |
+
xlsx_support = st.checkbox("Excel Files (.xlsx)", value='.xlsx' in current_types)
|
170 |
+
|
171 |
+
with col2:
|
172 |
+
json_support = st.checkbox("JSON Files (.json)", value='.json' in current_types)
|
173 |
+
parquet_support = st.checkbox("Parquet Files (.parquet)", value='.parquet' in current_types)
|
174 |
+
|
175 |
+
if st.form_submit_button("Save Data Settings"):
|
176 |
+
supported_types = []
|
177 |
+
if csv_support:
|
178 |
+
supported_types.append('.csv')
|
179 |
+
if xlsx_support:
|
180 |
+
supported_types.append('.xlsx')
|
181 |
+
if json_support:
|
182 |
+
supported_types.append('.json')
|
183 |
+
if parquet_support:
|
184 |
+
supported_types.append('.parquet')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
|
186 |
+
config.data_cache_timeout = data_cache_timeout
|
187 |
+
config.max_file_size_mb = max_file_size_mb
|
188 |
+
config.supported_file_types = supported_types
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
|
190 |
+
if save_config(config):
|
191 |
+
st.success("Data settings saved successfully!")
|
192 |
+
st.rerun()
|
193 |
+
else:
|
194 |
+
st.error("Failed to save data settings.")
|
195 |
+
|
196 |
+
# Data management section
|
197 |
+
st.subheader("π Data Management")
|
198 |
+
|
199 |
+
col1, col2 = st.columns(2)
|
200 |
+
|
201 |
+
with col1:
|
202 |
+
st.write("**Memory Storage**")
|
203 |
+
memory_info = get_storage_info("memory")
|
204 |
+
st.write(f"Keys stored: {memory_info['total_keys']}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
|
206 |
+
if st.button("Clear Memory Storage", type="secondary"):
|
207 |
+
if clear_storage("memory"):
|
208 |
+
st.success("Memory storage cleared!")
|
209 |
+
st.rerun()
|
210 |
+
else:
|
211 |
+
st.error("Failed to clear memory storage.")
|
212 |
+
|
213 |
+
with col2:
|
214 |
+
st.write("**Session Storage**")
|
215 |
+
session_info = get_storage_info("session")
|
216 |
+
st.write(f"Keys stored: {session_info['total_keys']}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
|
218 |
+
if st.button("Clear Session Storage", type="secondary"):
|
219 |
+
if clear_storage("session"):
|
220 |
+
st.success("Session storage cleared!")
|
221 |
+
st.rerun()
|
222 |
+
else:
|
223 |
+
st.error("Failed to clear session storage.")
|
224 |
+
|
225 |
+
# Show stored data keys
|
226 |
+
with st.expander("View Stored Data Keys"):
|
227 |
+
memory_keys = list_keys("memory")
|
228 |
+
session_keys = list_keys("session")
|
229 |
+
|
230 |
+
col1, col2 = st.columns(2)
|
231 |
+
|
232 |
+
with col1:
|
233 |
+
st.write("**Memory Keys:**")
|
234 |
+
for key in memory_keys:
|
235 |
+
st.write(f"- {key}")
|
236 |
+
|
237 |
+
with col2:
|
238 |
+
st.write("**Session Keys:**")
|
239 |
+
for key in session_keys:
|
240 |
+
st.write(f"- {key}")
|
241 |
+
|
242 |
+
@handle_ui_exceptions
|
243 |
+
def create_system_settings():
|
244 |
+
"""Create system settings section"""
|
245 |
+
st.header("π§ System Settings")
|
246 |
+
|
247 |
+
# System information
|
248 |
+
st.subheader("π System Information")
|
249 |
+
|
250 |
+
col1, col2 = st.columns(2)
|
251 |
+
|
252 |
+
with col1:
|
253 |
+
st.write("**Application Info:**")
|
254 |
+
config = load_config()
|
255 |
+
st.write(f"- Name: {config.app_name}")
|
256 |
+
st.write(f"- Version: {config.version}")
|
257 |
+
st.write(f"- Debug Mode: {'Enabled' if config.debug_mode else 'Disabled'}")
|
258 |
+
|
259 |
+
with col2:
|
260 |
+
st.write("**Runtime Info:**")
|
261 |
+
st.write(f"- Current Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
262 |
+
st.write(f"- Streamlit Version: {st.__version__}")
|
263 |
+
st.write("- Python Version: 3.8+")
|
264 |
+
|
265 |
+
# Configuration management
|
266 |
+
st.subheader("βοΈ Configuration Management")
|
267 |
+
|
268 |
+
col1, col2, col3 = st.columns(3)
|
269 |
+
|
270 |
+
with col1:
|
271 |
+
if st.button("Export Configuration", type="secondary"):
|
272 |
+
config_dict = config.__dict__
|
273 |
+
st.download_button(
|
274 |
+
label="Download Config",
|
275 |
+
data=str(config_dict),
|
276 |
+
file_name=f"mona_config_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
|
277 |
+
mime="text/plain"
|
278 |
+
)
|
279 |
+
|
280 |
+
with col2:
|
281 |
+
if st.button("Reset to Defaults", type="secondary"):
|
282 |
+
if st.session_state.get('confirm_reset', False):
|
283 |
+
reset_config()
|
284 |
+
st.success("Configuration reset to defaults!")
|
285 |
+
st.session_state['confirm_reset'] = False
|
286 |
+
st.rerun()
|
287 |
+
else:
|
288 |
+
st.session_state['confirm_reset'] = True
|
289 |
+
st.warning("Click again to confirm reset.")
|
290 |
+
|
291 |
+
with col3:
|
292 |
+
if st.button("Reload Configuration", type="secondary"):
|
293 |
+
# Force reload by clearing the global config
|
294 |
+
from utils.config import _config
|
295 |
+
if '_config' in globals():
|
296 |
+
globals()['_config'] = None
|
297 |
+
st.success("Configuration reloaded!")
|
298 |
+
st.rerun()
|
299 |
+
|
300 |
+
# Advanced settings
|
301 |
+
with st.expander("π§ Advanced Settings"):
|
302 |
+
st.subheader("Developer Options")
|
303 |
+
|
304 |
+
if config.debug_mode:
|
305 |
+
st.write("**Debug Information:**")
|
306 |
+
st.json(config.__dict__)
|
307 |
+
|
308 |
+
if st.button("View Session State"):
|
309 |
+
st.write("**Session State:**")
|
310 |
+
st.json(dict(st.session_state))
|
311 |
+
else:
|
312 |
+
st.info("Enable Debug Mode in General Settings to access developer options.")
|
313 |
+
|
314 |
+
# System actions
|
315 |
+
st.subheader("π System Actions")
|
316 |
+
|
317 |
+
col1, col2 = st.columns(2)
|
318 |
+
|
319 |
+
with col1:
|
320 |
+
if st.button("Clear All Cache", type="secondary"):
|
321 |
+
st.cache_data.clear()
|
322 |
+
st.success("All cache cleared!")
|
323 |
+
|
324 |
+
with col2:
|
325 |
+
if st.button("Restart Application", type="primary"):
|
326 |
+
st.info("Application will restart...")
|
327 |
+
st.rerun()
|