isa-model 0.3.5__py3-none-any.whl → 0.3.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- isa_model/__init__.py +30 -1
- isa_model/client.py +937 -0
- isa_model/core/config/__init__.py +16 -0
- isa_model/core/config/config_manager.py +514 -0
- isa_model/core/config.py +426 -0
- isa_model/core/models/model_billing_tracker.py +476 -0
- isa_model/core/models/model_manager.py +399 -0
- isa_model/core/{storage/supabase_storage.py → models/model_repo.py} +72 -73
- isa_model/core/pricing_manager.py +426 -0
- isa_model/core/services/__init__.py +19 -0
- isa_model/core/services/intelligent_model_selector.py +547 -0
- isa_model/core/types.py +291 -0
- isa_model/deployment/__init__.py +2 -0
- isa_model/deployment/cloud/modal/isa_vision_doc_service.py +157 -3
- isa_model/deployment/cloud/modal/isa_vision_table_service.py +532 -0
- isa_model/deployment/cloud/modal/isa_vision_ui_service.py +104 -3
- isa_model/deployment/cloud/modal/register_models.py +321 -0
- isa_model/deployment/runtime/deployed_service.py +338 -0
- isa_model/deployment/services/__init__.py +9 -0
- isa_model/deployment/services/auto_deploy_vision_service.py +538 -0
- isa_model/deployment/services/model_service.py +332 -0
- isa_model/deployment/services/service_monitor.py +356 -0
- isa_model/deployment/services/service_registry.py +527 -0
- isa_model/deployment/services/simple_auto_deploy_vision_service.py +275 -0
- isa_model/eval/__init__.py +80 -44
- isa_model/eval/config/__init__.py +10 -0
- isa_model/eval/config/evaluation_config.py +108 -0
- isa_model/eval/evaluators/__init__.py +18 -0
- isa_model/eval/evaluators/base_evaluator.py +503 -0
- isa_model/eval/evaluators/llm_evaluator.py +472 -0
- isa_model/eval/factory.py +417 -709
- isa_model/eval/infrastructure/__init__.py +24 -0
- isa_model/eval/infrastructure/experiment_tracker.py +466 -0
- isa_model/eval/metrics.py +191 -21
- isa_model/inference/ai_factory.py +257 -601
- isa_model/inference/services/audio/base_stt_service.py +65 -1
- isa_model/inference/services/audio/base_tts_service.py +75 -1
- isa_model/inference/services/audio/openai_stt_service.py +189 -151
- isa_model/inference/services/audio/openai_tts_service.py +12 -10
- isa_model/inference/services/audio/replicate_tts_service.py +61 -56
- isa_model/inference/services/base_service.py +55 -17
- isa_model/inference/services/embedding/base_embed_service.py +65 -1
- isa_model/inference/services/embedding/ollama_embed_service.py +103 -43
- isa_model/inference/services/embedding/openai_embed_service.py +8 -10
- isa_model/inference/services/helpers/stacked_config.py +148 -0
- isa_model/inference/services/img/__init__.py +18 -0
- isa_model/inference/services/{vision → img}/base_image_gen_service.py +80 -1
- isa_model/inference/services/{stacked → img}/flux_professional_service.py +25 -1
- isa_model/inference/services/{stacked → img/helpers}/base_stacked_service.py +40 -35
- isa_model/inference/services/{vision → img}/replicate_image_gen_service.py +44 -31
- isa_model/inference/services/llm/__init__.py +3 -3
- isa_model/inference/services/llm/base_llm_service.py +492 -40
- isa_model/inference/services/llm/helpers/llm_prompts.py +258 -0
- isa_model/inference/services/llm/helpers/llm_utils.py +280 -0
- isa_model/inference/services/llm/ollama_llm_service.py +51 -17
- isa_model/inference/services/llm/openai_llm_service.py +70 -19
- isa_model/inference/services/llm/yyds_llm_service.py +24 -23
- isa_model/inference/services/vision/__init__.py +38 -4
- isa_model/inference/services/vision/base_vision_service.py +218 -117
- isa_model/inference/services/vision/{isA_vision_service.py → disabled/isA_vision_service.py} +98 -0
- isa_model/inference/services/{stacked → vision}/doc_analysis_service.py +1 -1
- isa_model/inference/services/vision/helpers/base_stacked_service.py +274 -0
- isa_model/inference/services/vision/helpers/image_utils.py +272 -3
- isa_model/inference/services/vision/helpers/vision_prompts.py +297 -0
- isa_model/inference/services/vision/openai_vision_service.py +104 -307
- isa_model/inference/services/vision/replicate_vision_service.py +140 -325
- isa_model/inference/services/{stacked → vision}/ui_analysis_service.py +2 -498
- isa_model/scripts/register_models.py +370 -0
- isa_model/scripts/register_models_with_embeddings.py +510 -0
- isa_model/serving/api/fastapi_server.py +6 -1
- isa_model/serving/api/routes/unified.py +274 -0
- {isa_model-0.3.5.dist-info → isa_model-0.3.7.dist-info}/METADATA +4 -1
- {isa_model-0.3.5.dist-info → isa_model-0.3.7.dist-info}/RECORD +78 -53
- isa_model/config/__init__.py +0 -9
- isa_model/config/config_manager.py +0 -213
- isa_model/core/model_manager.py +0 -213
- isa_model/core/model_registry.py +0 -375
- isa_model/core/vision_models_init.py +0 -116
- isa_model/inference/billing_tracker.py +0 -406
- isa_model/inference/services/llm/triton_llm_service.py +0 -481
- isa_model/inference/services/stacked/__init__.py +0 -26
- isa_model/inference/services/stacked/config.py +0 -426
- isa_model/inference/services/vision/ollama_vision_service.py +0 -194
- /isa_model/core/{model_storage.py → models/model_storage.py} +0 -0
- /isa_model/inference/services/{vision → embedding}/helpers/text_splitter.py +0 -0
- /isa_model/inference/services/llm/{llm_adapter.py → helpers/llm_adapter.py} +0 -0
- {isa_model-0.3.5.dist-info → isa_model-0.3.7.dist-info}/WHEEL +0 -0
- {isa_model-0.3.5.dist-info → isa_model-0.3.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
"""
|
2
|
+
ISA Model Core Configuration Management
|
3
|
+
|
4
|
+
Centralized configuration system for:
|
5
|
+
- Environment settings (dev, prod, etc.)
|
6
|
+
- Provider API keys and settings
|
7
|
+
- Database configuration and initialization
|
8
|
+
- Model definitions and capabilities
|
9
|
+
- Deployment platform settings
|
10
|
+
"""
|
11
|
+
|
12
|
+
from .config_manager import ConfigManager
|
13
|
+
|
14
|
+
__all__ = [
|
15
|
+
'ConfigManager'
|
16
|
+
]
|
@@ -0,0 +1,514 @@
|
|
1
|
+
"""
|
2
|
+
Unified Configuration Manager for ISA Model Core
|
3
|
+
|
4
|
+
Centralizes all configuration management:
|
5
|
+
- Environment settings (dev, prod, etc.)
|
6
|
+
- Provider API keys and configurations
|
7
|
+
- Database setup and initialization
|
8
|
+
- Model definitions and capabilities
|
9
|
+
- Deployment platform settings
|
10
|
+
"""
|
11
|
+
|
12
|
+
import os
|
13
|
+
import yaml
|
14
|
+
import logging
|
15
|
+
from typing import Dict, Any, Optional, List
|
16
|
+
from pathlib import Path
|
17
|
+
from dataclasses import dataclass, field
|
18
|
+
from enum import Enum
|
19
|
+
from dotenv import load_dotenv
|
20
|
+
|
21
|
+
from ..types import Provider, DeploymentPlatform
|
22
|
+
|
23
|
+
logger = logging.getLogger(__name__)
|
24
|
+
|
25
|
+
class Environment(str, Enum):
|
26
|
+
DEVELOPMENT = "development"
|
27
|
+
STAGING = "staging"
|
28
|
+
PRODUCTION = "production"
|
29
|
+
TESTING = "testing"
|
30
|
+
|
31
|
+
@dataclass
|
32
|
+
class ProviderConfig:
|
33
|
+
"""Configuration for a provider"""
|
34
|
+
name: str
|
35
|
+
api_key: Optional[str] = None
|
36
|
+
api_base_url: Optional[str] = None
|
37
|
+
organization: Optional[str] = None
|
38
|
+
rate_limit_rpm: Optional[int] = None
|
39
|
+
rate_limit_tpm: Optional[int] = None
|
40
|
+
enabled: bool = True
|
41
|
+
models: List[Dict[str, Any]] = field(default_factory=list)
|
42
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
43
|
+
|
44
|
+
@dataclass
|
45
|
+
class DatabaseConfig:
|
46
|
+
"""Database configuration"""
|
47
|
+
use_supabase: bool = True
|
48
|
+
supabase_url: Optional[str] = None
|
49
|
+
supabase_key: Optional[str] = None
|
50
|
+
fallback_to_sqlite: bool = False
|
51
|
+
sqlite_path: str = "./isa_model.db"
|
52
|
+
connection_pool_size: int = 10
|
53
|
+
max_retries: int = 3
|
54
|
+
|
55
|
+
@dataclass
|
56
|
+
class DeploymentConfig:
|
57
|
+
"""Deployment configuration"""
|
58
|
+
platform: str = "local"
|
59
|
+
auto_scaling: bool = False
|
60
|
+
scale_to_zero: bool = False
|
61
|
+
default_gpu: str = "cpu"
|
62
|
+
default_memory_mb: int = 8192
|
63
|
+
keep_warm: int = 0
|
64
|
+
timeout_seconds: int = 300
|
65
|
+
|
66
|
+
@dataclass
|
67
|
+
class APIConfig:
|
68
|
+
"""API configuration"""
|
69
|
+
rate_limit_rpm: int = 100
|
70
|
+
max_file_size_mb: int = 20
|
71
|
+
cache_ttl_seconds: int = 3600
|
72
|
+
enable_auth: bool = False
|
73
|
+
cors_origins: List[str] = field(default_factory=lambda: ["*"])
|
74
|
+
|
75
|
+
@dataclass
|
76
|
+
class ServingConfig:
|
77
|
+
"""Serving configuration"""
|
78
|
+
host: str = "0.0.0.0"
|
79
|
+
port: int = 8000
|
80
|
+
workers: int = 1
|
81
|
+
reload: bool = False
|
82
|
+
log_level: str = "info"
|
83
|
+
|
84
|
+
@dataclass
|
85
|
+
class BillingConfig:
|
86
|
+
"""Billing and cost tracking configuration"""
|
87
|
+
track_costs: bool = True
|
88
|
+
cost_alerts_enabled: bool = True
|
89
|
+
monthly_budget_usd: Optional[float] = None
|
90
|
+
|
91
|
+
@dataclass
|
92
|
+
class HealthConfig:
|
93
|
+
"""Health monitoring configuration"""
|
94
|
+
check_interval_seconds: int = 300
|
95
|
+
timeout_seconds: int = 30
|
96
|
+
enabled: bool = True
|
97
|
+
|
98
|
+
@dataclass
|
99
|
+
class CacheConfig:
|
100
|
+
"""Model caching configuration"""
|
101
|
+
enabled: bool = True
|
102
|
+
size_gb: int = 50
|
103
|
+
cleanup_interval_seconds: int = 3600
|
104
|
+
|
105
|
+
@dataclass
|
106
|
+
class GlobalConfig:
|
107
|
+
"""Complete global configuration"""
|
108
|
+
environment: Environment
|
109
|
+
debug: bool = False
|
110
|
+
|
111
|
+
# Component configurations
|
112
|
+
database: DatabaseConfig = field(default_factory=DatabaseConfig)
|
113
|
+
deployment: DeploymentConfig = field(default_factory=DeploymentConfig)
|
114
|
+
api: APIConfig = field(default_factory=APIConfig)
|
115
|
+
serving: ServingConfig = field(default_factory=ServingConfig)
|
116
|
+
billing: BillingConfig = field(default_factory=BillingConfig)
|
117
|
+
health: HealthConfig = field(default_factory=HealthConfig)
|
118
|
+
cache: CacheConfig = field(default_factory=CacheConfig)
|
119
|
+
|
120
|
+
class ConfigManager:
|
121
|
+
"""
|
122
|
+
Unified Configuration Manager for ISA Model Core
|
123
|
+
|
124
|
+
Manages all configuration from a centralized location:
|
125
|
+
- Environment-specific settings
|
126
|
+
- Provider configurations
|
127
|
+
- Database and deployment settings
|
128
|
+
- Model definitions
|
129
|
+
"""
|
130
|
+
|
131
|
+
_instance = None
|
132
|
+
_initialized = False
|
133
|
+
|
134
|
+
def __new__(cls):
|
135
|
+
if cls._instance is None:
|
136
|
+
cls._instance = super().__new__(cls)
|
137
|
+
return cls._instance
|
138
|
+
|
139
|
+
def __init__(self):
|
140
|
+
if not self._initialized:
|
141
|
+
self.config_dir = Path(__file__).parent
|
142
|
+
self.global_config: Optional[GlobalConfig] = None
|
143
|
+
self.provider_configs: Dict[str, ProviderConfig] = {}
|
144
|
+
self.model_definitions: Dict[str, Dict[str, Any]] = {}
|
145
|
+
|
146
|
+
self._load_configuration()
|
147
|
+
ConfigManager._initialized = True
|
148
|
+
|
149
|
+
def _load_configuration(self):
|
150
|
+
"""Load all configuration from files and environment"""
|
151
|
+
# 0. Load environment variables from .env files
|
152
|
+
self._load_env_files()
|
153
|
+
|
154
|
+
# 1. Determine environment
|
155
|
+
env_name = os.getenv("ISA_ENV", "development")
|
156
|
+
try:
|
157
|
+
environment = Environment(env_name)
|
158
|
+
except ValueError:
|
159
|
+
logger.warning(f"Unknown environment '{env_name}', defaulting to development")
|
160
|
+
environment = Environment.DEVELOPMENT
|
161
|
+
|
162
|
+
# 2. Load environment-specific config
|
163
|
+
self._load_environment_config(environment)
|
164
|
+
|
165
|
+
# 3. Load provider configurations
|
166
|
+
self._load_provider_configs()
|
167
|
+
|
168
|
+
# 4. Load deployment configurations
|
169
|
+
self._load_deployment_configs()
|
170
|
+
|
171
|
+
# 5. Load model definitions
|
172
|
+
self._load_model_definitions()
|
173
|
+
|
174
|
+
# 6. Apply environment variable overrides
|
175
|
+
self._apply_env_overrides()
|
176
|
+
|
177
|
+
logger.info(f"Configuration loaded for environment: {environment}")
|
178
|
+
|
179
|
+
def _load_env_files(self):
|
180
|
+
"""Load environment variables from .env files"""
|
181
|
+
# Load from project root
|
182
|
+
project_root = self._find_project_root()
|
183
|
+
env_files = [
|
184
|
+
project_root / ".env",
|
185
|
+
project_root / ".env.local",
|
186
|
+
Path.cwd() / ".env",
|
187
|
+
]
|
188
|
+
|
189
|
+
for env_file in env_files:
|
190
|
+
if env_file.exists():
|
191
|
+
load_dotenv(env_file)
|
192
|
+
logger.debug(f"Loaded environment from {env_file}")
|
193
|
+
|
194
|
+
def _find_project_root(self) -> Path:
|
195
|
+
"""Find the project root directory"""
|
196
|
+
current = Path(__file__).parent
|
197
|
+
while current != current.parent:
|
198
|
+
if (current / "pyproject.toml").exists() or (current / "setup.py").exists():
|
199
|
+
return current
|
200
|
+
current = current.parent
|
201
|
+
return Path.cwd()
|
202
|
+
|
203
|
+
def _load_environment_config(self, environment: Environment):
|
204
|
+
"""Load environment-specific configuration"""
|
205
|
+
env_file = self.config_dir / "environments" / f"{environment.value}.yaml"
|
206
|
+
|
207
|
+
if not env_file.exists():
|
208
|
+
logger.warning(f"Environment config not found: {env_file}")
|
209
|
+
self.global_config = GlobalConfig(environment=environment)
|
210
|
+
return
|
211
|
+
|
212
|
+
try:
|
213
|
+
with open(env_file, 'r') as f:
|
214
|
+
env_data = yaml.safe_load(f)
|
215
|
+
|
216
|
+
# Build configuration from YAML
|
217
|
+
self.global_config = GlobalConfig(
|
218
|
+
environment=environment,
|
219
|
+
debug=env_data.get('debug', False),
|
220
|
+
database=DatabaseConfig(**env_data.get('database', {})),
|
221
|
+
deployment=DeploymentConfig(**env_data.get('deployment', {})),
|
222
|
+
api=APIConfig(**env_data.get('api', {})),
|
223
|
+
serving=ServingConfig(**env_data.get('serving', {})),
|
224
|
+
billing=BillingConfig(**env_data.get('billing', {})),
|
225
|
+
health=HealthConfig(**env_data.get('health', {})),
|
226
|
+
cache=CacheConfig(**env_data.get('cache', {}))
|
227
|
+
)
|
228
|
+
|
229
|
+
logger.debug(f"Loaded environment config from {env_file}")
|
230
|
+
|
231
|
+
except Exception as e:
|
232
|
+
logger.error(f"Failed to load environment config: {e}")
|
233
|
+
self.global_config = GlobalConfig(environment=environment)
|
234
|
+
|
235
|
+
def _load_provider_configs(self):
|
236
|
+
"""Load provider configurations from YAML files and environment variables"""
|
237
|
+
# First load from environment variables (legacy support)
|
238
|
+
self._load_provider_configs_from_env()
|
239
|
+
|
240
|
+
# Then load from YAML files (enhanced configs)
|
241
|
+
self._load_provider_configs_from_yaml()
|
242
|
+
|
243
|
+
def _load_provider_configs_from_env(self):
|
244
|
+
"""Load provider configurations from environment variables (legacy)"""
|
245
|
+
# Define provider environment variable patterns from original config.py
|
246
|
+
provider_env_mapping = {
|
247
|
+
Provider.OPENAI: {
|
248
|
+
"api_key": ["OPENAI_API_KEY"],
|
249
|
+
"organization": ["OPENAI_ORG_ID", "OPENAI_ORGANIZATION"],
|
250
|
+
"api_base_url": ["OPENAI_API_BASE", "OPENAI_BASE_URL"],
|
251
|
+
},
|
252
|
+
Provider.REPLICATE: {
|
253
|
+
"api_key": ["REPLICATE_API_TOKEN", "REPLICATE_API_KEY"],
|
254
|
+
},
|
255
|
+
Provider.ANTHROPIC: {
|
256
|
+
"api_key": ["ANTHROPIC_API_KEY"],
|
257
|
+
},
|
258
|
+
Provider.GOOGLE: {
|
259
|
+
"api_key": ["GOOGLE_API_KEY", "GEMINI_API_KEY"],
|
260
|
+
},
|
261
|
+
Provider.YYDS: {
|
262
|
+
"api_key": ["YYDS_API_KEY"],
|
263
|
+
"api_base_url": ["YYDS_API_BASE", "YYDS_BASE_URL"],
|
264
|
+
},
|
265
|
+
}
|
266
|
+
|
267
|
+
for provider, env_vars in provider_env_mapping.items():
|
268
|
+
config = ProviderConfig(name=provider.value)
|
269
|
+
|
270
|
+
# Load API key
|
271
|
+
for env_var in env_vars.get("api_key", []):
|
272
|
+
if os.getenv(env_var):
|
273
|
+
config.api_key = os.getenv(env_var)
|
274
|
+
break
|
275
|
+
|
276
|
+
# Load other settings
|
277
|
+
for setting, env_var_list in env_vars.items():
|
278
|
+
if setting == "api_key":
|
279
|
+
continue
|
280
|
+
for env_var in env_var_list:
|
281
|
+
if os.getenv(env_var):
|
282
|
+
setattr(config, setting, os.getenv(env_var))
|
283
|
+
break
|
284
|
+
|
285
|
+
# Check if provider is enabled
|
286
|
+
config.enabled = bool(config.api_key)
|
287
|
+
|
288
|
+
self.provider_configs[provider.value] = config
|
289
|
+
|
290
|
+
def _load_provider_configs_from_yaml(self):
|
291
|
+
"""Load provider configurations from YAML files"""
|
292
|
+
providers_dir = self.config_dir / "providers"
|
293
|
+
|
294
|
+
if not providers_dir.exists():
|
295
|
+
logger.warning(f"Providers directory not found: {providers_dir}")
|
296
|
+
return
|
297
|
+
|
298
|
+
for provider_file in providers_dir.glob("*.yaml"):
|
299
|
+
try:
|
300
|
+
with open(provider_file, 'r') as f:
|
301
|
+
provider_data = yaml.safe_load(f)
|
302
|
+
|
303
|
+
provider_name = provider_data.get('provider')
|
304
|
+
if not provider_name:
|
305
|
+
logger.warning(f"No provider name in {provider_file}")
|
306
|
+
continue
|
307
|
+
|
308
|
+
# Get existing config (from env) or create new one
|
309
|
+
config = self.provider_configs.get(provider_name, ProviderConfig(name=provider_name))
|
310
|
+
|
311
|
+
# Load API configuration
|
312
|
+
api_config = provider_data.get('api', {})
|
313
|
+
api_key_env = api_config.get('api_key_env')
|
314
|
+
org_env = api_config.get('organization_env')
|
315
|
+
|
316
|
+
# Update config with YAML data (environment takes precedence)
|
317
|
+
if not config.api_key and api_key_env:
|
318
|
+
config.api_key = os.getenv(api_key_env)
|
319
|
+
if not config.api_base_url:
|
320
|
+
config.api_base_url = api_config.get('base_url')
|
321
|
+
if not config.organization and org_env:
|
322
|
+
config.organization = os.getenv(org_env)
|
323
|
+
if not config.rate_limit_rpm:
|
324
|
+
config.rate_limit_rpm = api_config.get('rate_limits', {}).get('requests_per_minute')
|
325
|
+
if not config.rate_limit_tpm:
|
326
|
+
config.rate_limit_tpm = api_config.get('rate_limits', {}).get('tokens_per_minute')
|
327
|
+
|
328
|
+
# Enable if API key is available
|
329
|
+
config.enabled = bool(config.api_key)
|
330
|
+
config.models = provider_data.get('models', [])
|
331
|
+
config.metadata = provider_data
|
332
|
+
|
333
|
+
self.provider_configs[provider_name] = config
|
334
|
+
logger.debug(f"Loaded provider config for {provider_name}")
|
335
|
+
|
336
|
+
except Exception as e:
|
337
|
+
logger.error(f"Failed to load provider config from {provider_file}: {e}")
|
338
|
+
|
339
|
+
def _load_deployment_configs(self):
|
340
|
+
"""Load deployment platform configurations"""
|
341
|
+
# This can be enhanced later with deployment-specific YAML files
|
342
|
+
deployment_env_mapping = {
|
343
|
+
DeploymentPlatform.MODAL: {
|
344
|
+
"api_key": ["MODAL_TOKEN"],
|
345
|
+
"endpoint": ["MODAL_ENDPOINT"],
|
346
|
+
},
|
347
|
+
DeploymentPlatform.RUNPOD: {
|
348
|
+
"api_key": ["RUNPOD_API_KEY"],
|
349
|
+
"endpoint": ["RUNPOD_ENDPOINT"],
|
350
|
+
},
|
351
|
+
DeploymentPlatform.KUBERNETES: {
|
352
|
+
"endpoint": ["K8S_ENDPOINT", "KUBERNETES_ENDPOINT"],
|
353
|
+
"api_key": ["K8S_TOKEN", "KUBERNETES_TOKEN"],
|
354
|
+
},
|
355
|
+
}
|
356
|
+
|
357
|
+
# Store deployment configs if needed
|
358
|
+
self.deployment_configs = {}
|
359
|
+
for platform, env_vars in deployment_env_mapping.items():
|
360
|
+
config = {
|
361
|
+
"platform": platform,
|
362
|
+
"enabled": False
|
363
|
+
}
|
364
|
+
|
365
|
+
# Load settings from environment
|
366
|
+
for setting, env_var_list in env_vars.items():
|
367
|
+
for env_var in env_var_list:
|
368
|
+
if os.getenv(env_var):
|
369
|
+
config[setting] = os.getenv(env_var)
|
370
|
+
config["enabled"] = True
|
371
|
+
break
|
372
|
+
|
373
|
+
self.deployment_configs[platform.value] = config
|
374
|
+
|
375
|
+
def _load_model_definitions(self):
|
376
|
+
"""Load model definitions from provider configs"""
|
377
|
+
for provider_name, provider_config in self.provider_configs.items():
|
378
|
+
for model_data in provider_config.models:
|
379
|
+
model_id = model_data.get('model_id')
|
380
|
+
if model_id:
|
381
|
+
# Add provider context to model definition
|
382
|
+
model_data['provider'] = provider_name
|
383
|
+
self.model_definitions[model_id] = model_data
|
384
|
+
|
385
|
+
logger.info(f"Loaded {len(self.model_definitions)} model definitions")
|
386
|
+
|
387
|
+
def _apply_env_overrides(self):
|
388
|
+
"""Apply environment variable overrides"""
|
389
|
+
if not self.global_config:
|
390
|
+
return
|
391
|
+
|
392
|
+
# Database overrides
|
393
|
+
if os.getenv("SUPABASE_URL"):
|
394
|
+
self.global_config.database.supabase_url = os.getenv("SUPABASE_URL")
|
395
|
+
if os.getenv("SUPABASE_ANON_KEY"):
|
396
|
+
self.global_config.database.supabase_key = os.getenv("SUPABASE_ANON_KEY")
|
397
|
+
|
398
|
+
# Serving overrides
|
399
|
+
port_env = os.getenv("PORT")
|
400
|
+
if port_env:
|
401
|
+
try:
|
402
|
+
self.global_config.serving.port = int(port_env)
|
403
|
+
except ValueError:
|
404
|
+
pass
|
405
|
+
|
406
|
+
# Debug override
|
407
|
+
debug_env = os.getenv("DEBUG")
|
408
|
+
if debug_env:
|
409
|
+
self.global_config.debug = debug_env.lower() in ('true', '1', 'yes')
|
410
|
+
|
411
|
+
# Public API
|
412
|
+
def get_global_config(self) -> GlobalConfig:
|
413
|
+
"""Get global configuration"""
|
414
|
+
if not self.global_config:
|
415
|
+
raise RuntimeError("Configuration not loaded")
|
416
|
+
return self.global_config
|
417
|
+
|
418
|
+
def get_provider_config(self, provider: str) -> Optional[ProviderConfig]:
|
419
|
+
"""Get provider configuration"""
|
420
|
+
return self.provider_configs.get(provider)
|
421
|
+
|
422
|
+
def get_provider_api_key(self, provider: str) -> Optional[str]:
|
423
|
+
"""Get API key for provider"""
|
424
|
+
config = self.get_provider_config(provider)
|
425
|
+
return config.api_key if config else None
|
426
|
+
|
427
|
+
def is_provider_enabled(self, provider: str) -> bool:
|
428
|
+
"""Check if provider is enabled"""
|
429
|
+
config = self.get_provider_config(provider)
|
430
|
+
return config is not None and config.enabled and config.api_key is not None
|
431
|
+
|
432
|
+
def get_enabled_providers(self) -> List[str]:
|
433
|
+
"""Get list of enabled providers"""
|
434
|
+
return [name for name, config in self.provider_configs.items() if config.enabled]
|
435
|
+
|
436
|
+
def get_model_definition(self, model_id: str) -> Optional[Dict[str, Any]]:
|
437
|
+
"""Get model definition"""
|
438
|
+
return self.model_definitions.get(model_id)
|
439
|
+
|
440
|
+
def get_models_by_provider(self, provider: str) -> List[Dict[str, Any]]:
|
441
|
+
"""Get all models for a provider"""
|
442
|
+
return [model for model in self.model_definitions.values()
|
443
|
+
if model.get('provider') == provider]
|
444
|
+
|
445
|
+
def get_models_by_capability(self, capability: str) -> List[Dict[str, Any]]:
|
446
|
+
"""Get models that support a specific capability"""
|
447
|
+
return [model for model in self.model_definitions.values()
|
448
|
+
if capability in model.get('capabilities', [])]
|
449
|
+
|
450
|
+
def reload(self):
|
451
|
+
"""Reload configuration"""
|
452
|
+
self._load_configuration()
|
453
|
+
logger.info("Configuration reloaded")
|
454
|
+
|
455
|
+
def get_deployment_config(self, platform: str) -> Optional[Dict[str, Any]]:
|
456
|
+
"""Get deployment platform configuration"""
|
457
|
+
return getattr(self, 'deployment_configs', {}).get(platform)
|
458
|
+
|
459
|
+
def is_deployment_enabled(self, platform: str) -> bool:
|
460
|
+
"""Check if deployment platform is enabled"""
|
461
|
+
config = self.get_deployment_config(platform)
|
462
|
+
return config is not None and config.get("enabled", False)
|
463
|
+
|
464
|
+
def save_config(self, config_file: Optional[Path] = None):
|
465
|
+
"""Save current configuration to YAML file (for compatibility)"""
|
466
|
+
if config_file is None:
|
467
|
+
config_file = Path.cwd() / "isa_model_config.yaml"
|
468
|
+
|
469
|
+
if not self.global_config:
|
470
|
+
logger.error("No configuration to save")
|
471
|
+
return
|
472
|
+
|
473
|
+
config_data = {
|
474
|
+
"environment": self.global_config.environment.value,
|
475
|
+
"debug": self.global_config.debug,
|
476
|
+
"database": {
|
477
|
+
"use_supabase": self.global_config.database.use_supabase,
|
478
|
+
"fallback_to_sqlite": self.global_config.database.fallback_to_sqlite,
|
479
|
+
},
|
480
|
+
"providers": {},
|
481
|
+
}
|
482
|
+
|
483
|
+
# Add provider configs (without API keys for security)
|
484
|
+
for provider_name, config in self.provider_configs.items():
|
485
|
+
config_data["providers"][provider_name] = {
|
486
|
+
"enabled": config.enabled,
|
487
|
+
"rate_limit_rpm": config.rate_limit_rpm,
|
488
|
+
"rate_limit_tpm": config.rate_limit_tpm,
|
489
|
+
"metadata": config.metadata,
|
490
|
+
}
|
491
|
+
|
492
|
+
try:
|
493
|
+
with open(config_file, 'w') as f:
|
494
|
+
yaml.dump(config_data, f, default_flow_style=False)
|
495
|
+
logger.info(f"Configuration saved to {config_file}")
|
496
|
+
except Exception as e:
|
497
|
+
logger.error(f"Failed to save configuration: {e}")
|
498
|
+
|
499
|
+
def get_summary(self) -> Dict[str, Any]:
|
500
|
+
"""Get configuration summary"""
|
501
|
+
enabled_providers = self.get_enabled_providers()
|
502
|
+
configured_deployments = [p for p in getattr(self, 'deployment_configs', {}).keys()]
|
503
|
+
|
504
|
+
return {
|
505
|
+
"environment": self.global_config.environment.value if self.global_config else "unknown",
|
506
|
+
"debug": self.global_config.debug if self.global_config else False,
|
507
|
+
"enabled_providers": enabled_providers,
|
508
|
+
"configured_deployments": configured_deployments,
|
509
|
+
"total_models": len(self.model_definitions),
|
510
|
+
"database_backend": "supabase" if (self.global_config and self.global_config.database.use_supabase) else "sqlite",
|
511
|
+
"deployment_platform": self.global_config.deployment.platform if self.global_config else "unknown",
|
512
|
+
"cost_tracking": self.global_config.billing.track_costs if self.global_config else False,
|
513
|
+
"model_caching": self.global_config.cache.enabled if self.global_config else False,
|
514
|
+
}
|