Sandipan Haldar commited on
Commit
3221bc5
·
1 Parent(s): 1492cf4

added config

Browse files
Files changed (4) hide show
  1. __init__.py +7 -0
  2. config/__init__.py +7 -0
  3. config/settings.py +270 -0
  4. settings.py +270 -0
__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration package for Smart Auto-Complete
3
+ """
4
+
5
+ from .settings import AppSettings, settings
6
+
7
+ __all__ = ['AppSettings', 'settings']
config/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration package for Smart Auto-Complete
3
+ """
4
+
5
+ from .settings import AppSettings, settings
6
+
7
+ __all__ = ['AppSettings', 'settings']
config/settings.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration Settings for Smart Auto-Complete
3
+ Manages environment variables and application configuration
4
+ """
5
+
6
+ import logging
7
+ import os
8
+ from typing import Any, Dict, Optional
9
+
10
+ from dotenv import load_dotenv
11
+
12
+ # Load environment variables from .env file
13
+ load_dotenv()
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class AppSettings:
19
+ """
20
+ Application settings manager
21
+ Loads configuration from environment variables with sensible defaults
22
+ """
23
+
24
+ def __init__(self):
25
+ """Initialize settings from environment variables"""
26
+
27
+ # API Configuration
28
+ self.OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "").strip()
29
+ self.ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY", "").strip()
30
+ self.DEFAULT_PROVIDER = os.getenv("DEFAULT_PROVIDER", "openai").lower()
31
+
32
+ # Application Settings
33
+ self.MAX_SUGGESTIONS = int(os.getenv("MAX_SUGGESTIONS", "5"))
34
+ self.DEBOUNCE_DELAY = int(os.getenv("DEBOUNCE_DELAY", "300")) # milliseconds
35
+ self.CACHE_TTL = int(os.getenv("CACHE_TTL", "3600")) # seconds
36
+ self.MAX_INPUT_LENGTH = int(os.getenv("MAX_INPUT_LENGTH", "1000"))
37
+
38
+ # Cache Configuration
39
+ self.CACHE_MAX_SIZE = int(os.getenv("CACHE_MAX_SIZE", "1000"))
40
+ self.CACHE_ENABLED = os.getenv("CACHE_ENABLED", "true").lower() == "true"
41
+
42
+ # Logging Configuration
43
+ self.LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
44
+ self.LOG_FORMAT = os.getenv(
45
+ "LOG_FORMAT", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
46
+ )
47
+
48
+ # API Rate Limiting
49
+ self.RATE_LIMIT_REQUESTS_PER_MINUTE = int(
50
+ os.getenv("RATE_LIMIT_REQUESTS_PER_MINUTE", "60")
51
+ )
52
+ self.RATE_LIMIT_ENABLED = (
53
+ os.getenv("RATE_LIMIT_ENABLED", "true").lower() == "true"
54
+ )
55
+
56
+ # Model Configuration
57
+ self.OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-3.5-turbo")
58
+ self.ANTHROPIC_MODEL = os.getenv("ANTHROPIC_MODEL", "claude-3-haiku-20240307")
59
+
60
+ # Temperature settings for different contexts
61
+ self.TEMPERATURE_EMAIL = float(os.getenv("TEMPERATURE_EMAIL", "0.6"))
62
+ self.TEMPERATURE_CREATIVE = float(os.getenv("TEMPERATURE_CREATIVE", "0.8"))
63
+ self.TEMPERATURE_GENERAL = float(os.getenv("TEMPERATURE_GENERAL", "0.7"))
64
+
65
+ # Default token limits for different contexts
66
+ self.DEFAULT_TOKENS_EMAIL = int(os.getenv("DEFAULT_TOKENS_EMAIL", "200"))
67
+ self.DEFAULT_TOKENS_CREATIVE = int(os.getenv("DEFAULT_TOKENS_CREATIVE", "250"))
68
+ self.DEFAULT_TOKENS_GENERAL = int(os.getenv("DEFAULT_TOKENS_GENERAL", "200"))
69
+
70
+ # UI Configuration
71
+ self.UI_THEME = os.getenv("UI_THEME", "soft")
72
+ self.UI_TITLE = os.getenv("UI_TITLE", "🚀 Smart Auto-Complete")
73
+ self.UI_DESCRIPTION = os.getenv(
74
+ "UI_DESCRIPTION", "Intelligent text completion powered by AI"
75
+ )
76
+
77
+ # Server Configuration
78
+ self.SERVER_HOST = os.getenv("SERVER_HOST", "0.0.0.0")
79
+ self.SERVER_PORT = int(os.getenv("SERVER_PORT", "7860"))
80
+ self.SERVER_SHARE = os.getenv("SERVER_SHARE", "false").lower() == "true"
81
+
82
+ # Security Settings
83
+ self.ENABLE_INPUT_SANITIZATION = (
84
+ os.getenv("ENABLE_INPUT_SANITIZATION", "true").lower() == "true"
85
+ )
86
+ self.MAX_CONCURRENT_REQUESTS = int(os.getenv("MAX_CONCURRENT_REQUESTS", "10"))
87
+
88
+ # Development Settings
89
+ self.DEBUG_MODE = os.getenv("DEBUG_MODE", "false").lower() == "true"
90
+ self.ENABLE_ANALYTICS = os.getenv("ENABLE_ANALYTICS", "true").lower() == "true"
91
+
92
+ # Validate settings after initialization
93
+ self._validate_settings()
94
+
95
+ logger.info("Application settings loaded successfully")
96
+
97
+ def _validate_settings(self):
98
+ """Validate configuration settings"""
99
+ errors = []
100
+ warnings = []
101
+
102
+ # Check API keys
103
+ if not self.OPENAI_API_KEY and not self.ANTHROPIC_API_KEY:
104
+ errors.append(
105
+ "No API keys configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY"
106
+ )
107
+
108
+ # Validate provider
109
+ if self.DEFAULT_PROVIDER not in ["openai", "anthropic"]:
110
+ warnings.append(
111
+ f"Invalid DEFAULT_PROVIDER: {self.DEFAULT_PROVIDER}. Using 'openai'"
112
+ )
113
+ self.DEFAULT_PROVIDER = "openai"
114
+
115
+ # Validate numeric ranges
116
+ if not (1 <= self.MAX_SUGGESTIONS <= 20):
117
+ warnings.append(
118
+ f"MAX_SUGGESTIONS should be 1-20, got {self.MAX_SUGGESTIONS}"
119
+ )
120
+ self.MAX_SUGGESTIONS = max(1, min(20, self.MAX_SUGGESTIONS))
121
+
122
+ if not (100 <= self.DEBOUNCE_DELAY <= 2000):
123
+ warnings.append(
124
+ f"DEBOUNCE_DELAY should be 100-2000ms, got {self.DEBOUNCE_DELAY}"
125
+ )
126
+ self.DEBOUNCE_DELAY = max(100, min(2000, self.DEBOUNCE_DELAY))
127
+
128
+ if not (100 <= self.MAX_INPUT_LENGTH <= 10000):
129
+ warnings.append(
130
+ f"MAX_INPUT_LENGTH should be 100-10000, got {self.MAX_INPUT_LENGTH}"
131
+ )
132
+ self.MAX_INPUT_LENGTH = max(100, min(10000, self.MAX_INPUT_LENGTH))
133
+
134
+ # Validate temperature ranges
135
+ for temp_attr in [
136
+ "TEMPERATURE_EMAIL",
137
+ "TEMPERATURE_CREATIVE",
138
+ "TEMPERATURE_GENERAL",
139
+ ]:
140
+ temp_value = getattr(self, temp_attr)
141
+ if not (0.0 <= temp_value <= 2.0):
142
+ warnings.append(f"{temp_attr} should be 0.0-2.0, got {temp_value}")
143
+ setattr(self, temp_attr, max(0.0, min(2.0, temp_value)))
144
+
145
+ # Log validation results
146
+ if errors:
147
+ for error in errors:
148
+ logger.error(f"Configuration error: {error}")
149
+
150
+ if warnings:
151
+ for warning in warnings:
152
+ logger.warning(f"Configuration warning: {warning}")
153
+
154
+ def validate_api_keys(self) -> bool:
155
+ """
156
+ Validate that at least one API key is properly configured
157
+
158
+ Returns:
159
+ True if at least one valid API key is available
160
+ """
161
+ from src.utils import validate_api_key
162
+
163
+ openai_valid = self.OPENAI_API_KEY and validate_api_key(
164
+ self.OPENAI_API_KEY, "openai"
165
+ )
166
+
167
+ anthropic_valid = self.ANTHROPIC_API_KEY and validate_api_key(
168
+ self.ANTHROPIC_API_KEY, "anthropic"
169
+ )
170
+
171
+ return openai_valid or anthropic_valid
172
+
173
+ def get_context_config(self, context: str) -> Dict[str, Any]:
174
+ """
175
+ Get configuration for a specific context
176
+
177
+ Args:
178
+ context: Context name (email, code, creative, general)
179
+
180
+ Returns:
181
+ Dictionary with context-specific configuration
182
+ """
183
+ context_configs = {
184
+ "email": {
185
+ "temperature": self.TEMPERATURE_EMAIL,
186
+ "default_tokens": self.DEFAULT_TOKENS_EMAIL,
187
+ "model_preference": "openai", # Generally better for professional text
188
+ },
189
+ "creative": {
190
+ "temperature": self.TEMPERATURE_CREATIVE,
191
+ "default_tokens": self.DEFAULT_TOKENS_CREATIVE,
192
+ "model_preference": "anthropic", # Often better for creative content
193
+ },
194
+ "general": {
195
+ "temperature": self.TEMPERATURE_GENERAL,
196
+ "default_tokens": self.DEFAULT_TOKENS_GENERAL,
197
+ "model_preference": self.DEFAULT_PROVIDER,
198
+ },
199
+ }
200
+
201
+ return context_configs.get(context, context_configs["general"])
202
+
203
+ def get_model_for_provider(self, provider: str) -> str:
204
+ """
205
+ Get the model name for a specific provider
206
+
207
+ Args:
208
+ provider: Provider name (openai, anthropic)
209
+
210
+ Returns:
211
+ Model name string
212
+ """
213
+ if provider == "openai":
214
+ return self.OPENAI_MODEL
215
+ elif provider == "anthropic":
216
+ return self.ANTHROPIC_MODEL
217
+ else:
218
+ return self.OPENAI_MODEL # Default fallback
219
+
220
+ def to_dict(self) -> Dict[str, Any]:
221
+ """
222
+ Convert settings to dictionary (excluding sensitive data)
223
+
224
+ Returns:
225
+ Dictionary with non-sensitive configuration
226
+ """
227
+ return {
228
+ "max_suggestions": self.MAX_SUGGESTIONS,
229
+ "debounce_delay": self.DEBOUNCE_DELAY,
230
+ "cache_ttl": self.CACHE_TTL,
231
+ "max_input_length": self.MAX_INPUT_LENGTH,
232
+ "cache_enabled": self.CACHE_ENABLED,
233
+ "log_level": self.LOG_LEVEL,
234
+ "rate_limit_enabled": self.RATE_LIMIT_ENABLED,
235
+ "rate_limit_requests_per_minute": self.RATE_LIMIT_REQUESTS_PER_MINUTE,
236
+ "default_provider": self.DEFAULT_PROVIDER,
237
+ "openai_model": self.OPENAI_MODEL,
238
+ "anthropic_model": self.ANTHROPIC_MODEL,
239
+ "ui_theme": self.UI_THEME,
240
+ "ui_title": self.UI_TITLE,
241
+ "server_host": self.SERVER_HOST,
242
+ "server_port": self.SERVER_PORT,
243
+ "debug_mode": self.DEBUG_MODE,
244
+ "has_openai_key": bool(self.OPENAI_API_KEY),
245
+ "has_anthropic_key": bool(self.ANTHROPIC_API_KEY),
246
+ }
247
+
248
+ def update_from_dict(self, config_dict: Dict[str, Any]):
249
+ """
250
+ Update settings from a dictionary
251
+
252
+ Args:
253
+ config_dict: Dictionary with configuration updates
254
+ """
255
+ for key, value in config_dict.items():
256
+ if hasattr(self, key.upper()):
257
+ setattr(self, key.upper(), value)
258
+ logger.info(f"Updated setting {key.upper()} = {value}")
259
+
260
+ # Re-validate after updates
261
+ self._validate_settings()
262
+
263
+ def __str__(self) -> str:
264
+ """String representation of settings (safe for logging)"""
265
+ safe_dict = self.to_dict()
266
+ return f"AppSettings({safe_dict})"
267
+
268
+
269
+ # Global settings instance
270
+ settings = AppSettings()
settings.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration Settings for Smart Auto-Complete
3
+ Manages environment variables and application configuration
4
+ """
5
+
6
+ import logging
7
+ import os
8
+ from typing import Any, Dict, Optional
9
+
10
+ from dotenv import load_dotenv
11
+
12
+ # Load environment variables from .env file
13
+ load_dotenv()
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class AppSettings:
19
+ """
20
+ Application settings manager
21
+ Loads configuration from environment variables with sensible defaults
22
+ """
23
+
24
+ def __init__(self):
25
+ """Initialize settings from environment variables"""
26
+
27
+ # API Configuration
28
+ self.OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "").strip()
29
+ self.ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY", "").strip()
30
+ self.DEFAULT_PROVIDER = os.getenv("DEFAULT_PROVIDER", "openai").lower()
31
+
32
+ # Application Settings
33
+ self.MAX_SUGGESTIONS = int(os.getenv("MAX_SUGGESTIONS", "5"))
34
+ self.DEBOUNCE_DELAY = int(os.getenv("DEBOUNCE_DELAY", "300")) # milliseconds
35
+ self.CACHE_TTL = int(os.getenv("CACHE_TTL", "3600")) # seconds
36
+ self.MAX_INPUT_LENGTH = int(os.getenv("MAX_INPUT_LENGTH", "1000"))
37
+
38
+ # Cache Configuration
39
+ self.CACHE_MAX_SIZE = int(os.getenv("CACHE_MAX_SIZE", "1000"))
40
+ self.CACHE_ENABLED = os.getenv("CACHE_ENABLED", "true").lower() == "true"
41
+
42
+ # Logging Configuration
43
+ self.LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
44
+ self.LOG_FORMAT = os.getenv(
45
+ "LOG_FORMAT", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
46
+ )
47
+
48
+ # API Rate Limiting
49
+ self.RATE_LIMIT_REQUESTS_PER_MINUTE = int(
50
+ os.getenv("RATE_LIMIT_REQUESTS_PER_MINUTE", "60")
51
+ )
52
+ self.RATE_LIMIT_ENABLED = (
53
+ os.getenv("RATE_LIMIT_ENABLED", "true").lower() == "true"
54
+ )
55
+
56
+ # Model Configuration
57
+ self.OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-3.5-turbo")
58
+ self.ANTHROPIC_MODEL = os.getenv("ANTHROPIC_MODEL", "claude-3-haiku-20240307")
59
+
60
+ # Temperature settings for different contexts
61
+ self.TEMPERATURE_EMAIL = float(os.getenv("TEMPERATURE_EMAIL", "0.6"))
62
+ self.TEMPERATURE_CREATIVE = float(os.getenv("TEMPERATURE_CREATIVE", "0.8"))
63
+ self.TEMPERATURE_GENERAL = float(os.getenv("TEMPERATURE_GENERAL", "0.7"))
64
+
65
+ # Default token limits for different contexts
66
+ self.DEFAULT_TOKENS_EMAIL = int(os.getenv("DEFAULT_TOKENS_EMAIL", "200"))
67
+ self.DEFAULT_TOKENS_CREATIVE = int(os.getenv("DEFAULT_TOKENS_CREATIVE", "250"))
68
+ self.DEFAULT_TOKENS_GENERAL = int(os.getenv("DEFAULT_TOKENS_GENERAL", "200"))
69
+
70
+ # UI Configuration
71
+ self.UI_THEME = os.getenv("UI_THEME", "soft")
72
+ self.UI_TITLE = os.getenv("UI_TITLE", "🚀 Smart Auto-Complete")
73
+ self.UI_DESCRIPTION = os.getenv(
74
+ "UI_DESCRIPTION", "Intelligent text completion powered by AI"
75
+ )
76
+
77
+ # Server Configuration
78
+ self.SERVER_HOST = os.getenv("SERVER_HOST", "0.0.0.0")
79
+ self.SERVER_PORT = int(os.getenv("SERVER_PORT", "7860"))
80
+ self.SERVER_SHARE = os.getenv("SERVER_SHARE", "false").lower() == "true"
81
+
82
+ # Security Settings
83
+ self.ENABLE_INPUT_SANITIZATION = (
84
+ os.getenv("ENABLE_INPUT_SANITIZATION", "true").lower() == "true"
85
+ )
86
+ self.MAX_CONCURRENT_REQUESTS = int(os.getenv("MAX_CONCURRENT_REQUESTS", "10"))
87
+
88
+ # Development Settings
89
+ self.DEBUG_MODE = os.getenv("DEBUG_MODE", "false").lower() == "true"
90
+ self.ENABLE_ANALYTICS = os.getenv("ENABLE_ANALYTICS", "true").lower() == "true"
91
+
92
+ # Validate settings after initialization
93
+ self._validate_settings()
94
+
95
+ logger.info("Application settings loaded successfully")
96
+
97
+ def _validate_settings(self):
98
+ """Validate configuration settings"""
99
+ errors = []
100
+ warnings = []
101
+
102
+ # Check API keys
103
+ if not self.OPENAI_API_KEY and not self.ANTHROPIC_API_KEY:
104
+ errors.append(
105
+ "No API keys configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY"
106
+ )
107
+
108
+ # Validate provider
109
+ if self.DEFAULT_PROVIDER not in ["openai", "anthropic"]:
110
+ warnings.append(
111
+ f"Invalid DEFAULT_PROVIDER: {self.DEFAULT_PROVIDER}. Using 'openai'"
112
+ )
113
+ self.DEFAULT_PROVIDER = "openai"
114
+
115
+ # Validate numeric ranges
116
+ if not (1 <= self.MAX_SUGGESTIONS <= 20):
117
+ warnings.append(
118
+ f"MAX_SUGGESTIONS should be 1-20, got {self.MAX_SUGGESTIONS}"
119
+ )
120
+ self.MAX_SUGGESTIONS = max(1, min(20, self.MAX_SUGGESTIONS))
121
+
122
+ if not (100 <= self.DEBOUNCE_DELAY <= 2000):
123
+ warnings.append(
124
+ f"DEBOUNCE_DELAY should be 100-2000ms, got {self.DEBOUNCE_DELAY}"
125
+ )
126
+ self.DEBOUNCE_DELAY = max(100, min(2000, self.DEBOUNCE_DELAY))
127
+
128
+ if not (100 <= self.MAX_INPUT_LENGTH <= 10000):
129
+ warnings.append(
130
+ f"MAX_INPUT_LENGTH should be 100-10000, got {self.MAX_INPUT_LENGTH}"
131
+ )
132
+ self.MAX_INPUT_LENGTH = max(100, min(10000, self.MAX_INPUT_LENGTH))
133
+
134
+ # Validate temperature ranges
135
+ for temp_attr in [
136
+ "TEMPERATURE_EMAIL",
137
+ "TEMPERATURE_CREATIVE",
138
+ "TEMPERATURE_GENERAL",
139
+ ]:
140
+ temp_value = getattr(self, temp_attr)
141
+ if not (0.0 <= temp_value <= 2.0):
142
+ warnings.append(f"{temp_attr} should be 0.0-2.0, got {temp_value}")
143
+ setattr(self, temp_attr, max(0.0, min(2.0, temp_value)))
144
+
145
+ # Log validation results
146
+ if errors:
147
+ for error in errors:
148
+ logger.error(f"Configuration error: {error}")
149
+
150
+ if warnings:
151
+ for warning in warnings:
152
+ logger.warning(f"Configuration warning: {warning}")
153
+
154
+ def validate_api_keys(self) -> bool:
155
+ """
156
+ Validate that at least one API key is properly configured
157
+
158
+ Returns:
159
+ True if at least one valid API key is available
160
+ """
161
+ from src.utils import validate_api_key
162
+
163
+ openai_valid = self.OPENAI_API_KEY and validate_api_key(
164
+ self.OPENAI_API_KEY, "openai"
165
+ )
166
+
167
+ anthropic_valid = self.ANTHROPIC_API_KEY and validate_api_key(
168
+ self.ANTHROPIC_API_KEY, "anthropic"
169
+ )
170
+
171
+ return openai_valid or anthropic_valid
172
+
173
+ def get_context_config(self, context: str) -> Dict[str, Any]:
174
+ """
175
+ Get configuration for a specific context
176
+
177
+ Args:
178
+ context: Context name (email, code, creative, general)
179
+
180
+ Returns:
181
+ Dictionary with context-specific configuration
182
+ """
183
+ context_configs = {
184
+ "email": {
185
+ "temperature": self.TEMPERATURE_EMAIL,
186
+ "default_tokens": self.DEFAULT_TOKENS_EMAIL,
187
+ "model_preference": "openai", # Generally better for professional text
188
+ },
189
+ "creative": {
190
+ "temperature": self.TEMPERATURE_CREATIVE,
191
+ "default_tokens": self.DEFAULT_TOKENS_CREATIVE,
192
+ "model_preference": "anthropic", # Often better for creative content
193
+ },
194
+ "general": {
195
+ "temperature": self.TEMPERATURE_GENERAL,
196
+ "default_tokens": self.DEFAULT_TOKENS_GENERAL,
197
+ "model_preference": self.DEFAULT_PROVIDER,
198
+ },
199
+ }
200
+
201
+ return context_configs.get(context, context_configs["general"])
202
+
203
+ def get_model_for_provider(self, provider: str) -> str:
204
+ """
205
+ Get the model name for a specific provider
206
+
207
+ Args:
208
+ provider: Provider name (openai, anthropic)
209
+
210
+ Returns:
211
+ Model name string
212
+ """
213
+ if provider == "openai":
214
+ return self.OPENAI_MODEL
215
+ elif provider == "anthropic":
216
+ return self.ANTHROPIC_MODEL
217
+ else:
218
+ return self.OPENAI_MODEL # Default fallback
219
+
220
+ def to_dict(self) -> Dict[str, Any]:
221
+ """
222
+ Convert settings to dictionary (excluding sensitive data)
223
+
224
+ Returns:
225
+ Dictionary with non-sensitive configuration
226
+ """
227
+ return {
228
+ "max_suggestions": self.MAX_SUGGESTIONS,
229
+ "debounce_delay": self.DEBOUNCE_DELAY,
230
+ "cache_ttl": self.CACHE_TTL,
231
+ "max_input_length": self.MAX_INPUT_LENGTH,
232
+ "cache_enabled": self.CACHE_ENABLED,
233
+ "log_level": self.LOG_LEVEL,
234
+ "rate_limit_enabled": self.RATE_LIMIT_ENABLED,
235
+ "rate_limit_requests_per_minute": self.RATE_LIMIT_REQUESTS_PER_MINUTE,
236
+ "default_provider": self.DEFAULT_PROVIDER,
237
+ "openai_model": self.OPENAI_MODEL,
238
+ "anthropic_model": self.ANTHROPIC_MODEL,
239
+ "ui_theme": self.UI_THEME,
240
+ "ui_title": self.UI_TITLE,
241
+ "server_host": self.SERVER_HOST,
242
+ "server_port": self.SERVER_PORT,
243
+ "debug_mode": self.DEBUG_MODE,
244
+ "has_openai_key": bool(self.OPENAI_API_KEY),
245
+ "has_anthropic_key": bool(self.ANTHROPIC_API_KEY),
246
+ }
247
+
248
+ def update_from_dict(self, config_dict: Dict[str, Any]):
249
+ """
250
+ Update settings from a dictionary
251
+
252
+ Args:
253
+ config_dict: Dictionary with configuration updates
254
+ """
255
+ for key, value in config_dict.items():
256
+ if hasattr(self, key.upper()):
257
+ setattr(self, key.upper(), value)
258
+ logger.info(f"Updated setting {key.upper()} = {value}")
259
+
260
+ # Re-validate after updates
261
+ self._validate_settings()
262
+
263
+ def __str__(self) -> str:
264
+ """String representation of settings (safe for logging)"""
265
+ safe_dict = self.to_dict()
266
+ return f"AppSettings({safe_dict})"
267
+
268
+
269
+ # Global settings instance
270
+ settings = AppSettings()