Update utils/config.py
Browse files- utils/config.py +140 -221
utils/config.py
CHANGED
@@ -1,233 +1,152 @@
|
|
1 |
-
"""
|
2 |
-
Configuration module for the MONA application.
|
3 |
-
|
4 |
-
This module centralizes all configuration settings and constants used throughout
|
5 |
-
the application, making it easier to maintain and modify settings in one place.
|
6 |
-
"""
|
7 |
-
|
8 |
import os
|
9 |
-
from
|
|
|
|
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
DATA_DIR = BASE_DIR / "data"
|
14 |
-
EXPORT_DIR = DATA_DIR / "exports"
|
15 |
-
BACKUP_DIR = DATA_DIR / "backups"
|
16 |
|
17 |
-
|
18 |
-
os.makedirs(DATA_DIR, exist_ok=True)
|
19 |
-
os.makedirs(EXPORT_DIR, exist_ok=True)
|
20 |
-
os.makedirs(BACKUP_DIR, exist_ok=True)
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
"
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
-
#
|
37 |
-
|
38 |
-
"text_generation": {
|
39 |
-
"name": "microsoft/DialoGPT-medium",
|
40 |
-
"max_length": 100,
|
41 |
-
"temperature": 0.7,
|
42 |
-
},
|
43 |
-
"question_answering": {
|
44 |
-
"name": "distilbert-base-uncased-distilled-squad",
|
45 |
-
},
|
46 |
-
"image_captioning": {
|
47 |
-
"name": "Salesforce/blip-image-captioning-base",
|
48 |
-
"max_length": 50,
|
49 |
-
},
|
50 |
-
"speech_to_text": {
|
51 |
-
"name": "openai/whisper-small",
|
52 |
-
},
|
53 |
-
"translation": {
|
54 |
-
"name": "Helsinki-NLP/opus-mt-en-de",
|
55 |
-
},
|
56 |
-
"sentiment": {
|
57 |
-
"name": "cardiffnlp/twitter-roberta-base-sentiment-latest",
|
58 |
-
},
|
59 |
-
"summarization": {
|
60 |
-
"name": "facebook/bart-large-cnn",
|
61 |
-
"max_length": 150,
|
62 |
-
"min_length": 30,
|
63 |
-
},
|
64 |
-
"code_generation": {
|
65 |
-
"name": "microsoft/CodeBERT-base",
|
66 |
-
},
|
67 |
-
}
|
68 |
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
"data_retention": "1 year",
|
99 |
-
"auto_archive": True,
|
100 |
-
},
|
101 |
-
"user_profile": {
|
102 |
-
"name": "User",
|
103 |
-
"email": "",
|
104 |
-
"timezone": "UTC",
|
105 |
-
"language": "English",
|
106 |
-
"date_format": "MM/DD/YYYY",
|
107 |
-
"time_format": "12h",
|
108 |
-
},
|
109 |
-
"api_keys": {
|
110 |
-
"OpenWeatherMap": "",
|
111 |
-
"GitHub": "",
|
112 |
-
"Google Calendar": "",
|
113 |
-
"Telegram": "",
|
114 |
-
"News API": "",
|
115 |
-
"Crypto API": "",
|
116 |
-
},
|
117 |
-
}
|
118 |
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
|
|
|
|
128 |
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
"teal": "#1abc9c",
|
138 |
-
"gray": "#95a5a6",
|
139 |
-
"dark": "#34495e",
|
140 |
-
"primary": "#7B68EE",
|
141 |
-
"secondary": "#FF6B6B",
|
142 |
-
"success": "#2ecc71",
|
143 |
-
"warning": "#f1c40f",
|
144 |
-
"danger": "#e74c3c",
|
145 |
-
"info": "#3498db",
|
146 |
-
}
|
147 |
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
"spacing_sm": "0.5rem",
|
162 |
-
"spacing_md": "1rem",
|
163 |
-
"spacing_lg": "1.5rem",
|
164 |
-
"spacing_xl": "2rem",
|
165 |
-
}
|
166 |
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
"
|
173 |
-
|
174 |
-
"enable_analytics": True,
|
175 |
-
}
|
176 |
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
"
|
184 |
-
|
185 |
-
"microsoft_todo": {
|
186 |
-
"enabled": False,
|
187 |
-
"auth_url": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
188 |
-
"token_url": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
189 |
-
"scope": "Tasks.ReadWrite",
|
190 |
-
},
|
191 |
-
"notion": {
|
192 |
-
"enabled": False,
|
193 |
-
"auth_url": "https://api.notion.com/v1/oauth/authorize",
|
194 |
-
"token_url": "https://api.notion.com/v1/oauth/token",
|
195 |
-
},
|
196 |
-
"weather_api": {
|
197 |
-
"enabled": False,
|
198 |
-
"base_url": "https://api.openweathermap.org/data/2.5/weather",
|
199 |
-
"units": "metric",
|
200 |
-
},
|
201 |
-
}
|
202 |
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
"
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
"
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import os
|
2 |
+
from typing import Dict, Any, Optional
|
3 |
+
from dataclasses import dataclass, asdict
|
4 |
+
import streamlit as st
|
5 |
|
6 |
+
from utils.logging import get_logger
|
7 |
+
from utils.error_handling import ConfigError
|
|
|
|
|
|
|
8 |
|
9 |
+
logger = get_logger(__name__)
|
|
|
|
|
|
|
10 |
|
11 |
+
@dataclass
|
12 |
+
class AppConfig:
|
13 |
+
"""Application configuration data class"""
|
14 |
+
app_name: str = "MONA Dashboard"
|
15 |
+
version: str = "1.0.0"
|
16 |
+
debug_mode: bool = False
|
17 |
+
max_data_points: int = 1000
|
18 |
+
refresh_interval: int = 30
|
19 |
+
default_chart_type: str = "line"
|
20 |
+
theme: str = "light"
|
21 |
+
|
22 |
+
# UI Configuration
|
23 |
+
sidebar_width: int = 300
|
24 |
+
chart_height: int = 400
|
25 |
+
table_page_size: int = 50
|
26 |
+
|
27 |
+
# Data Configuration
|
28 |
+
data_cache_timeout: int = 300
|
29 |
+
max_file_size_mb: int = 10
|
30 |
+
supported_file_types: list = None
|
31 |
+
|
32 |
+
def __post_init__(self):
|
33 |
+
if self.supported_file_types is None:
|
34 |
+
self.supported_file_types = ['.csv', '.xlsx', '.json', '.parquet']
|
35 |
|
36 |
+
# Global configuration instance
|
37 |
+
_config = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
+
def load_config() -> AppConfig:
|
40 |
+
"""Load application configuration"""
|
41 |
+
global _config
|
42 |
+
|
43 |
+
if _config is None:
|
44 |
+
try:
|
45 |
+
# Create default config
|
46 |
+
_config = AppConfig()
|
47 |
+
|
48 |
+
# Override with environment variables if available
|
49 |
+
_config.debug_mode = os.getenv('DEBUG', 'False').lower() == 'true'
|
50 |
+
_config.max_data_points = int(os.getenv('MAX_DATA_POINTS', '1000'))
|
51 |
+
_config.refresh_interval = int(os.getenv('REFRESH_INTERVAL', '30'))
|
52 |
+
_config.theme = os.getenv('THEME', 'light')
|
53 |
+
|
54 |
+
# Override with Streamlit session state if available
|
55 |
+
if 'app_config' in st.session_state:
|
56 |
+
session_config = st.session_state.app_config
|
57 |
+
for key, value in session_config.items():
|
58 |
+
if hasattr(_config, key):
|
59 |
+
setattr(_config, key, value)
|
60 |
+
|
61 |
+
logger.info("Configuration loaded successfully")
|
62 |
+
|
63 |
+
except Exception as e:
|
64 |
+
logger.error(f"Failed to load configuration: {str(e)}")
|
65 |
+
raise ConfigError(f"Configuration loading failed: {str(e)}")
|
66 |
+
|
67 |
+
return _config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
|
69 |
+
def save_config(config: AppConfig) -> bool:
|
70 |
+
"""Save configuration to session state"""
|
71 |
+
try:
|
72 |
+
st.session_state.app_config = asdict(config)
|
73 |
+
global _config
|
74 |
+
_config = config
|
75 |
+
logger.info("Configuration saved successfully")
|
76 |
+
return True
|
77 |
+
except Exception as e:
|
78 |
+
logger.error(f"Failed to save configuration: {str(e)}")
|
79 |
+
return False
|
80 |
|
81 |
+
def get_config_value(key: str, default_value: Any = None) -> Any:
|
82 |
+
"""Get a specific configuration value"""
|
83 |
+
try:
|
84 |
+
config = load_config()
|
85 |
+
return getattr(config, key, default_value)
|
86 |
+
except Exception as e:
|
87 |
+
logger.error(f"Failed to get config value for key {key}: {str(e)}")
|
88 |
+
return default_value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
|
90 |
+
def update_config_value(key: str, value: Any) -> bool:
|
91 |
+
"""Update a specific configuration value"""
|
92 |
+
try:
|
93 |
+
config = load_config()
|
94 |
+
if hasattr(config, key):
|
95 |
+
setattr(config, key, value)
|
96 |
+
return save_config(config)
|
97 |
+
else:
|
98 |
+
logger.warning(f"Configuration key '{key}' does not exist")
|
99 |
+
return False
|
100 |
+
except Exception as e:
|
101 |
+
logger.error(f"Failed to update config value for key {key}: {str(e)}")
|
102 |
+
return False
|
|
|
|
|
|
|
|
|
|
|
103 |
|
104 |
+
def reset_config() -> AppConfig:
|
105 |
+
"""Reset configuration to defaults"""
|
106 |
+
global _config
|
107 |
+
_config = AppConfig()
|
108 |
+
save_config(_config)
|
109 |
+
logger.info("Configuration reset to defaults")
|
110 |
+
return _config
|
|
|
|
|
111 |
|
112 |
+
def get_config_dict() -> Dict[str, Any]:
|
113 |
+
"""Get configuration as dictionary"""
|
114 |
+
try:
|
115 |
+
config = load_config()
|
116 |
+
return asdict(config)
|
117 |
+
except Exception as e:
|
118 |
+
logger.error(f"Failed to get configuration dictionary: {str(e)}")
|
119 |
+
return {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
+
def validate_config(config: AppConfig) -> bool:
|
122 |
+
"""Validate configuration values"""
|
123 |
+
try:
|
124 |
+
# Validate numeric values
|
125 |
+
if config.max_data_points <= 0:
|
126 |
+
raise ConfigError("max_data_points must be positive")
|
127 |
+
|
128 |
+
if config.refresh_interval <= 0:
|
129 |
+
raise ConfigError("refresh_interval must be positive")
|
130 |
+
|
131 |
+
if config.sidebar_width <= 0:
|
132 |
+
raise ConfigError("sidebar_width must be positive")
|
133 |
+
|
134 |
+
if config.chart_height <= 0:
|
135 |
+
raise ConfigError("chart_height must be positive")
|
136 |
+
|
137 |
+
# Validate string values
|
138 |
+
if config.theme not in ['light', 'dark']:
|
139 |
+
raise ConfigError("theme must be 'light' or 'dark'")
|
140 |
+
|
141 |
+
if config.default_chart_type not in ['line', 'bar', 'scatter', 'area']:
|
142 |
+
raise ConfigError("invalid default_chart_type")
|
143 |
+
|
144 |
+
logger.info("Configuration validation successful")
|
145 |
+
return True
|
146 |
+
|
147 |
+
except ConfigError as e:
|
148 |
+
logger.error(f"Configuration validation failed: {str(e)}")
|
149 |
+
raise e
|
150 |
+
except Exception as e:
|
151 |
+
logger.error(f"Unexpected error during configuration validation: {str(e)}")
|
152 |
+
raise ConfigError(f"Configuration validation error: {str(e)}")
|