isa-model 0.3.91__py3-none-any.whl → 0.4.3__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/client.py +1166 -584
- isa_model/core/cache/redis_cache.py +410 -0
- isa_model/core/config/config_manager.py +282 -12
- isa_model/core/config.py +91 -1
- isa_model/core/database/__init__.py +1 -0
- isa_model/core/database/direct_db_client.py +114 -0
- isa_model/core/database/migration_manager.py +563 -0
- isa_model/core/database/migrations.py +297 -0
- isa_model/core/database/supabase_client.py +258 -0
- isa_model/core/dependencies.py +316 -0
- isa_model/core/discovery/__init__.py +19 -0
- isa_model/core/discovery/consul_discovery.py +190 -0
- isa_model/core/logging/__init__.py +54 -0
- isa_model/core/logging/influx_logger.py +523 -0
- isa_model/core/logging/loki_logger.py +160 -0
- isa_model/core/models/__init__.py +46 -0
- isa_model/core/models/config_models.py +625 -0
- isa_model/core/models/deployment_billing_tracker.py +430 -0
- isa_model/core/models/model_billing_tracker.py +60 -88
- isa_model/core/models/model_manager.py +66 -25
- isa_model/core/models/model_metadata.py +690 -0
- isa_model/core/models/model_repo.py +217 -55
- isa_model/core/models/model_statistics_tracker.py +234 -0
- isa_model/core/models/model_storage.py +0 -1
- isa_model/core/models/model_version_manager.py +959 -0
- isa_model/core/models/system_models.py +857 -0
- isa_model/core/pricing_manager.py +2 -249
- isa_model/core/repositories/__init__.py +9 -0
- isa_model/core/repositories/config_repository.py +912 -0
- isa_model/core/resilience/circuit_breaker.py +366 -0
- isa_model/core/security/secrets.py +358 -0
- isa_model/core/services/__init__.py +2 -4
- isa_model/core/services/intelligent_model_selector.py +479 -370
- isa_model/core/storage/hf_storage.py +2 -2
- isa_model/core/types.py +8 -0
- isa_model/deployment/__init__.py +5 -48
- isa_model/deployment/core/__init__.py +2 -31
- isa_model/deployment/core/deployment_manager.py +1278 -368
- isa_model/deployment/local/__init__.py +31 -0
- isa_model/deployment/local/config.py +248 -0
- isa_model/deployment/local/gpu_gateway.py +607 -0
- isa_model/deployment/local/health_checker.py +428 -0
- isa_model/deployment/local/provider.py +586 -0
- isa_model/deployment/local/tensorrt_service.py +621 -0
- isa_model/deployment/local/transformers_service.py +644 -0
- isa_model/deployment/local/vllm_service.py +527 -0
- isa_model/deployment/modal/__init__.py +8 -0
- isa_model/deployment/modal/config.py +136 -0
- isa_model/deployment/modal/deployer.py +894 -0
- isa_model/deployment/modal/services/__init__.py +3 -0
- isa_model/deployment/modal/services/audio/__init__.py +1 -0
- isa_model/deployment/modal/services/audio/isa_audio_chatTTS_service.py +520 -0
- isa_model/deployment/modal/services/audio/isa_audio_openvoice_service.py +758 -0
- isa_model/deployment/modal/services/audio/isa_audio_service_v2.py +1044 -0
- isa_model/deployment/modal/services/embedding/__init__.py +1 -0
- isa_model/deployment/modal/services/embedding/isa_embed_rerank_service.py +296 -0
- isa_model/deployment/modal/services/llm/__init__.py +1 -0
- isa_model/deployment/modal/services/llm/isa_llm_service.py +424 -0
- isa_model/deployment/modal/services/video/__init__.py +1 -0
- isa_model/deployment/modal/services/video/isa_video_hunyuan_service.py +423 -0
- isa_model/deployment/modal/services/vision/__init__.py +1 -0
- isa_model/deployment/modal/services/vision/isa_vision_ocr_service.py +519 -0
- isa_model/deployment/modal/services/vision/isa_vision_qwen25_service.py +709 -0
- isa_model/deployment/modal/services/vision/isa_vision_table_service.py +676 -0
- isa_model/deployment/modal/services/vision/isa_vision_ui_service.py +833 -0
- isa_model/deployment/modal/services/vision/isa_vision_ui_service_optimized.py +660 -0
- isa_model/deployment/models/org-org-acme-corp-tenant-a-service-llm-20250825-225822/tenant-a-service_modal_service.py +48 -0
- isa_model/deployment/models/org-test-org-123-prefix-test-service-llm-20250825-225822/prefix-test-service_modal_service.py +48 -0
- isa_model/deployment/models/test-llm-service-llm-20250825-204442/test-llm-service_modal_service.py +48 -0
- isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-212906/test-monitoring-gpt2_modal_service.py +48 -0
- isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-213009/test-monitoring-gpt2_modal_service.py +48 -0
- isa_model/deployment/storage/__init__.py +5 -0
- isa_model/deployment/storage/deployment_repository.py +824 -0
- isa_model/deployment/triton/__init__.py +10 -0
- isa_model/deployment/triton/config.py +196 -0
- isa_model/deployment/triton/configs/__init__.py +1 -0
- isa_model/deployment/triton/provider.py +512 -0
- isa_model/deployment/triton/scripts/__init__.py +1 -0
- isa_model/deployment/triton/templates/__init__.py +1 -0
- isa_model/inference/__init__.py +47 -1
- isa_model/inference/ai_factory.py +179 -16
- isa_model/inference/legacy_services/__init__.py +21 -0
- isa_model/inference/legacy_services/model_evaluation.py +637 -0
- isa_model/inference/legacy_services/model_service.py +573 -0
- isa_model/inference/legacy_services/model_serving.py +717 -0
- isa_model/inference/legacy_services/model_training.py +561 -0
- isa_model/inference/models/__init__.py +21 -0
- isa_model/inference/models/inference_config.py +551 -0
- isa_model/inference/models/inference_record.py +675 -0
- isa_model/inference/models/performance_models.py +714 -0
- isa_model/inference/repositories/__init__.py +9 -0
- isa_model/inference/repositories/inference_repository.py +828 -0
- isa_model/inference/services/audio/__init__.py +21 -0
- isa_model/inference/services/audio/base_realtime_service.py +225 -0
- isa_model/inference/services/audio/base_stt_service.py +184 -11
- isa_model/inference/services/audio/isa_tts_service.py +0 -0
- isa_model/inference/services/audio/openai_realtime_service.py +320 -124
- isa_model/inference/services/audio/openai_stt_service.py +53 -11
- isa_model/inference/services/base_service.py +17 -1
- isa_model/inference/services/custom_model_manager.py +277 -0
- isa_model/inference/services/embedding/__init__.py +13 -0
- isa_model/inference/services/embedding/base_embed_service.py +111 -8
- isa_model/inference/services/embedding/isa_embed_service.py +305 -0
- isa_model/inference/services/embedding/ollama_embed_service.py +15 -3
- isa_model/inference/services/embedding/openai_embed_service.py +2 -4
- isa_model/inference/services/embedding/resilient_embed_service.py +285 -0
- isa_model/inference/services/embedding/tests/test_embedding.py +222 -0
- isa_model/inference/services/img/__init__.py +2 -2
- isa_model/inference/services/img/base_image_gen_service.py +24 -7
- isa_model/inference/services/img/replicate_image_gen_service.py +84 -422
- isa_model/inference/services/img/services/replicate_face_swap.py +193 -0
- isa_model/inference/services/img/services/replicate_flux.py +226 -0
- isa_model/inference/services/img/services/replicate_flux_kontext.py +219 -0
- isa_model/inference/services/img/services/replicate_sticker_maker.py +249 -0
- isa_model/inference/services/img/tests/test_img_client.py +297 -0
- isa_model/inference/services/llm/__init__.py +10 -2
- isa_model/inference/services/llm/base_llm_service.py +361 -26
- isa_model/inference/services/llm/cerebras_llm_service.py +628 -0
- isa_model/inference/services/llm/helpers/llm_adapter.py +71 -12
- isa_model/inference/services/llm/helpers/llm_prompts.py +342 -0
- isa_model/inference/services/llm/helpers/llm_utils.py +321 -23
- isa_model/inference/services/llm/huggingface_llm_service.py +581 -0
- isa_model/inference/services/llm/local_llm_service.py +747 -0
- isa_model/inference/services/llm/ollama_llm_service.py +11 -3
- isa_model/inference/services/llm/openai_llm_service.py +670 -56
- isa_model/inference/services/llm/yyds_llm_service.py +10 -3
- isa_model/inference/services/vision/__init__.py +27 -6
- isa_model/inference/services/vision/base_vision_service.py +118 -185
- isa_model/inference/services/vision/blip_vision_service.py +359 -0
- isa_model/inference/services/vision/helpers/image_utils.py +19 -10
- isa_model/inference/services/vision/isa_vision_service.py +634 -0
- isa_model/inference/services/vision/openai_vision_service.py +19 -10
- isa_model/inference/services/vision/tests/test_ocr_client.py +284 -0
- isa_model/inference/services/vision/vgg16_vision_service.py +257 -0
- isa_model/serving/api/cache_manager.py +245 -0
- isa_model/serving/api/dependencies/__init__.py +1 -0
- isa_model/serving/api/dependencies/auth.py +194 -0
- isa_model/serving/api/dependencies/database.py +139 -0
- isa_model/serving/api/error_handlers.py +284 -0
- isa_model/serving/api/fastapi_server.py +240 -18
- isa_model/serving/api/middleware/auth.py +317 -0
- isa_model/serving/api/middleware/security.py +268 -0
- isa_model/serving/api/middleware/tenant_context.py +414 -0
- isa_model/serving/api/routes/analytics.py +489 -0
- isa_model/serving/api/routes/config.py +645 -0
- isa_model/serving/api/routes/deployment_billing.py +315 -0
- isa_model/serving/api/routes/deployments.py +475 -0
- isa_model/serving/api/routes/gpu_gateway.py +440 -0
- isa_model/serving/api/routes/health.py +32 -12
- isa_model/serving/api/routes/inference_monitoring.py +486 -0
- isa_model/serving/api/routes/local_deployments.py +448 -0
- isa_model/serving/api/routes/logs.py +430 -0
- isa_model/serving/api/routes/settings.py +582 -0
- isa_model/serving/api/routes/tenants.py +575 -0
- isa_model/serving/api/routes/unified.py +992 -171
- isa_model/serving/api/routes/webhooks.py +479 -0
- isa_model/serving/api/startup.py +318 -0
- isa_model/serving/modal_proxy_server.py +249 -0
- isa_model/utils/gpu_utils.py +311 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/METADATA +76 -22
- isa_model-0.4.3.dist-info/RECORD +193 -0
- isa_model/deployment/cloud/__init__.py +0 -9
- isa_model/deployment/cloud/modal/__init__.py +0 -10
- isa_model/deployment/cloud/modal/isa_vision_doc_service.py +0 -766
- isa_model/deployment/cloud/modal/isa_vision_table_service.py +0 -532
- isa_model/deployment/cloud/modal/isa_vision_ui_service.py +0 -406
- isa_model/deployment/cloud/modal/register_models.py +0 -321
- isa_model/deployment/core/deployment_config.py +0 -356
- isa_model/deployment/core/isa_deployment_service.py +0 -401
- isa_model/deployment/gpu_int8_ds8/app/server.py +0 -66
- isa_model/deployment/gpu_int8_ds8/scripts/test_client.py +0 -43
- isa_model/deployment/gpu_int8_ds8/scripts/test_client_os.py +0 -35
- isa_model/deployment/runtime/deployed_service.py +0 -338
- isa_model/deployment/services/__init__.py +0 -9
- isa_model/deployment/services/auto_deploy_vision_service.py +0 -538
- isa_model/deployment/services/model_service.py +0 -332
- isa_model/deployment/services/service_monitor.py +0 -356
- isa_model/deployment/services/service_registry.py +0 -527
- isa_model/eval/__init__.py +0 -92
- isa_model/eval/benchmarks.py +0 -469
- isa_model/eval/config/__init__.py +0 -10
- isa_model/eval/config/evaluation_config.py +0 -108
- isa_model/eval/evaluators/__init__.py +0 -18
- isa_model/eval/evaluators/base_evaluator.py +0 -503
- isa_model/eval/evaluators/llm_evaluator.py +0 -472
- isa_model/eval/factory.py +0 -531
- isa_model/eval/infrastructure/__init__.py +0 -24
- isa_model/eval/infrastructure/experiment_tracker.py +0 -466
- isa_model/eval/metrics.py +0 -798
- isa_model/inference/adapter/unified_api.py +0 -248
- isa_model/inference/services/helpers/stacked_config.py +0 -148
- isa_model/inference/services/img/flux_professional_service.py +0 -603
- isa_model/inference/services/img/helpers/base_stacked_service.py +0 -274
- isa_model/inference/services/others/table_transformer_service.py +0 -61
- isa_model/inference/services/vision/doc_analysis_service.py +0 -640
- isa_model/inference/services/vision/helpers/base_stacked_service.py +0 -274
- isa_model/inference/services/vision/ui_analysis_service.py +0 -823
- isa_model/scripts/inference_tracker.py +0 -283
- isa_model/scripts/mlflow_manager.py +0 -379
- isa_model/scripts/model_registry.py +0 -465
- isa_model/scripts/register_models.py +0 -370
- isa_model/scripts/register_models_with_embeddings.py +0 -510
- isa_model/scripts/start_mlflow.py +0 -95
- isa_model/scripts/training_tracker.py +0 -257
- isa_model/training/__init__.py +0 -74
- isa_model/training/annotation/annotation_schema.py +0 -47
- isa_model/training/annotation/processors/annotation_processor.py +0 -126
- isa_model/training/annotation/storage/dataset_manager.py +0 -131
- isa_model/training/annotation/storage/dataset_schema.py +0 -44
- isa_model/training/annotation/tests/test_annotation_flow.py +0 -109
- isa_model/training/annotation/tests/test_minio copy.py +0 -113
- isa_model/training/annotation/tests/test_minio_upload.py +0 -43
- isa_model/training/annotation/views/annotation_controller.py +0 -158
- isa_model/training/cloud/__init__.py +0 -22
- isa_model/training/cloud/job_orchestrator.py +0 -402
- isa_model/training/cloud/runpod_trainer.py +0 -454
- isa_model/training/cloud/storage_manager.py +0 -482
- isa_model/training/core/__init__.py +0 -23
- isa_model/training/core/config.py +0 -181
- isa_model/training/core/dataset.py +0 -222
- isa_model/training/core/trainer.py +0 -720
- isa_model/training/core/utils.py +0 -213
- isa_model/training/factory.py +0 -424
- isa_model-0.3.91.dist-info/RECORD +0 -138
- /isa_model/{core/storage/minio_storage.py → deployment/modal/services/audio/isa_audio_fish_service.py} +0 -0
- /isa_model/deployment/{services → modal/services/vision}/simple_auto_deploy_vision_service.py +0 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/WHEEL +0 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/top_level.txt +0 -0
@@ -41,14 +41,48 @@ class ProviderConfig:
|
|
41
41
|
models: List[Dict[str, Any]] = field(default_factory=list)
|
42
42
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
43
43
|
|
44
|
+
@dataclass
|
45
|
+
class ConsulConfig:
|
46
|
+
"""Consul service discovery configuration"""
|
47
|
+
enabled: bool = True
|
48
|
+
host: str = "localhost"
|
49
|
+
port: int = 8500
|
50
|
+
timeout: int = 10
|
51
|
+
|
52
|
+
@dataclass
|
53
|
+
class ServiceConfig:
|
54
|
+
"""Service endpoint configuration with Consul discovery support"""
|
55
|
+
# Enable Consul discovery
|
56
|
+
use_consul_discovery: bool = True
|
57
|
+
|
58
|
+
# Fallback URLs when Consul is unavailable
|
59
|
+
mcp_base_url: str = "http://localhost:8081"
|
60
|
+
ollama_base_url: str = "http://localhost:11434"
|
61
|
+
influxdb_url: str = "http://localhost:8086"
|
62
|
+
loki_url: str = "http://localhost:3100"
|
63
|
+
minio_endpoint: str = "localhost:9000"
|
64
|
+
redis_url: str = "redis://localhost:6379"
|
65
|
+
api_port: int = 8000
|
66
|
+
redis_port: int = 6379
|
67
|
+
|
68
|
+
# Consul service names for discovery
|
69
|
+
mcp_service_name: str = "mcp"
|
70
|
+
ollama_service_name: str = "ollama"
|
71
|
+
influxdb_service_name: str = "influxdb"
|
72
|
+
loki_service_name: str = "loki"
|
73
|
+
minio_service_name: str = "minio"
|
74
|
+
redis_service_name: str = "redis"
|
75
|
+
|
44
76
|
@dataclass
|
45
77
|
class DatabaseConfig:
|
46
78
|
"""Database configuration"""
|
47
79
|
use_supabase: bool = True
|
48
80
|
supabase_url: Optional[str] = None
|
49
81
|
supabase_key: Optional[str] = None
|
82
|
+
supabase_schema: Optional[str] = None
|
50
83
|
fallback_to_sqlite: bool = False
|
51
84
|
sqlite_path: str = "./isa_model.db"
|
85
|
+
default_database_url: str = "postgresql://postgres:postgres@127.0.0.1:54322/postgres?options=-c%20search_path%3Ddev"
|
52
86
|
connection_pool_size: int = 10
|
53
87
|
max_retries: int = 3
|
54
88
|
|
@@ -109,6 +143,8 @@ class GlobalConfig:
|
|
109
143
|
debug: bool = False
|
110
144
|
|
111
145
|
# Component configurations
|
146
|
+
consul: ConsulConfig = field(default_factory=ConsulConfig)
|
147
|
+
services: ServiceConfig = field(default_factory=ServiceConfig)
|
112
148
|
database: DatabaseConfig = field(default_factory=DatabaseConfig)
|
113
149
|
deployment: DeploymentConfig = field(default_factory=DeploymentConfig)
|
114
150
|
api: APIConfig = field(default_factory=APIConfig)
|
@@ -142,8 +178,10 @@ class ConfigManager:
|
|
142
178
|
self.global_config: Optional[GlobalConfig] = None
|
143
179
|
self.provider_configs: Dict[str, ProviderConfig] = {}
|
144
180
|
self.model_definitions: Dict[str, Dict[str, Any]] = {}
|
181
|
+
self._consul_discovery = None
|
145
182
|
|
146
183
|
self._load_configuration()
|
184
|
+
self._initialize_consul_discovery()
|
147
185
|
ConfigManager._initialized = True
|
148
186
|
|
149
187
|
def _load_configuration(self):
|
@@ -177,13 +215,15 @@ class ConfigManager:
|
|
177
215
|
logger.info(f"Configuration loaded for environment: {environment}")
|
178
216
|
|
179
217
|
def _load_env_files(self):
|
180
|
-
"""Load environment variables from
|
181
|
-
# Load from
|
218
|
+
"""Load environment variables from deployment environment files"""
|
219
|
+
# Load from deployment environment directories only
|
182
220
|
project_root = self._find_project_root()
|
221
|
+
|
222
|
+
# Check environment-specific deployment directories
|
183
223
|
env_files = [
|
184
|
-
project_root / ".env",
|
185
|
-
project_root / ".env.
|
186
|
-
|
224
|
+
project_root / "deployment" / "dev" / ".env",
|
225
|
+
project_root / "deployment" / "staging" / "env" / ".env.staging",
|
226
|
+
project_root / "deployment" / "production" / "env" / ".env.production",
|
187
227
|
]
|
188
228
|
|
189
229
|
for env_file in env_files:
|
@@ -217,6 +257,8 @@ class ConfigManager:
|
|
217
257
|
self.global_config = GlobalConfig(
|
218
258
|
environment=environment,
|
219
259
|
debug=env_data.get('debug', False),
|
260
|
+
consul=ConsulConfig(**env_data.get('consul', {})),
|
261
|
+
services=ServiceConfig(**env_data.get('services', {})),
|
220
262
|
database=DatabaseConfig(**env_data.get('database', {})),
|
221
263
|
deployment=DeploymentConfig(**env_data.get('deployment', {})),
|
222
264
|
api=APIConfig(**env_data.get('api', {})),
|
@@ -262,6 +304,10 @@ class ConfigManager:
|
|
262
304
|
"api_key": ["YYDS_API_KEY"],
|
263
305
|
"api_base_url": ["YYDS_API_BASE", "YYDS_BASE_URL"],
|
264
306
|
},
|
307
|
+
Provider.CEREBRAS: {
|
308
|
+
"api_key": ["CEREBRAS_API_KEY"],
|
309
|
+
"api_base_url": ["CEREBRAS_API_BASE", "CEREBRAS_BASE_URL"],
|
310
|
+
},
|
265
311
|
}
|
266
312
|
|
267
313
|
for provider, env_vars in provider_env_mapping.items():
|
@@ -341,7 +387,9 @@ class ConfigManager:
|
|
341
387
|
# This can be enhanced later with deployment-specific YAML files
|
342
388
|
deployment_env_mapping = {
|
343
389
|
DeploymentPlatform.MODAL: {
|
344
|
-
"
|
390
|
+
"token_id": ["MODAL_TOKEN_ID"],
|
391
|
+
"token_secret": ["MODAL_TOKEN_SECRET"],
|
392
|
+
"environment": ["MODAL_ENVIRONMENT"],
|
345
393
|
"endpoint": ["MODAL_ENDPOINT"],
|
346
394
|
},
|
347
395
|
DeploymentPlatform.RUNPOD: {
|
@@ -384,22 +432,150 @@ class ConfigManager:
|
|
384
432
|
|
385
433
|
logger.info(f"Loaded {len(self.model_definitions)} model definitions")
|
386
434
|
|
435
|
+
def _configure_database_for_environment(self):
|
436
|
+
"""Configure database settings based on environment"""
|
437
|
+
if not self.global_config:
|
438
|
+
return
|
439
|
+
|
440
|
+
env = self.global_config.environment.value
|
441
|
+
|
442
|
+
if env in ["development", "testing"]:
|
443
|
+
# Local Supabase with schema isolation
|
444
|
+
supabase_url = os.getenv("SUPABASE_LOCAL_URL")
|
445
|
+
supabase_key = os.getenv("SUPABASE_LOCAL_ANON_KEY") or os.getenv("SUPABASE_LOCAL_SERVICE_ROLE_KEY")
|
446
|
+
schema = "dev" if env == "development" else "test"
|
447
|
+
|
448
|
+
elif env == "staging":
|
449
|
+
# Supabase Cloud staging
|
450
|
+
supabase_url = os.getenv("SUPABASE_STAGING_URL") or os.getenv("SUPABASE_URL")
|
451
|
+
supabase_key = os.getenv("SUPABASE_STAGING_KEY") or os.getenv("SUPABASE_ANON_KEY")
|
452
|
+
schema = "staging"
|
453
|
+
|
454
|
+
elif env == "production":
|
455
|
+
# Supabase Cloud production
|
456
|
+
supabase_url = os.getenv("SUPABASE_URL")
|
457
|
+
supabase_key = os.getenv("SUPABASE_ANON_KEY") or os.getenv("SERVICE_ROLE_KEY")
|
458
|
+
schema = "public" # or "production" if using schema isolation
|
459
|
+
|
460
|
+
else:
|
461
|
+
logger.warning(f"Unknown environment '{env}', using default configuration")
|
462
|
+
supabase_url = os.getenv("SUPABASE_URL")
|
463
|
+
supabase_key = os.getenv("SUPABASE_ANON_KEY")
|
464
|
+
schema = "public"
|
465
|
+
|
466
|
+
# Apply configuration
|
467
|
+
if supabase_url:
|
468
|
+
self.global_config.database.supabase_url = supabase_url
|
469
|
+
if supabase_key:
|
470
|
+
self.global_config.database.supabase_key = supabase_key
|
471
|
+
if schema:
|
472
|
+
self.global_config.database.supabase_schema = schema
|
473
|
+
|
474
|
+
logger.debug(f"Database configured for {env}: schema={schema}, url={supabase_url}")
|
475
|
+
|
476
|
+
def _initialize_consul_discovery(self):
|
477
|
+
"""Initialize Consul service discovery client"""
|
478
|
+
if not self.global_config or not self.global_config.consul.enabled:
|
479
|
+
logger.info("Consul discovery disabled")
|
480
|
+
return
|
481
|
+
|
482
|
+
try:
|
483
|
+
from ..discovery.consul_discovery import ConsulServiceDiscovery
|
484
|
+
self._consul_discovery = ConsulServiceDiscovery(
|
485
|
+
consul_host=self.global_config.consul.host,
|
486
|
+
consul_port=self.global_config.consul.port
|
487
|
+
)
|
488
|
+
|
489
|
+
if self._consul_discovery.is_available():
|
490
|
+
logger.info("Consul service discovery initialized successfully")
|
491
|
+
else:
|
492
|
+
logger.warning("Consul not available, using fallback URLs")
|
493
|
+
self._consul_discovery = None
|
494
|
+
|
495
|
+
except ImportError as e:
|
496
|
+
logger.warning(f"Consul discovery not available: {e}")
|
497
|
+
self._consul_discovery = None
|
498
|
+
except Exception as e:
|
499
|
+
logger.error(f"Failed to initialize Consul discovery: {e}")
|
500
|
+
self._consul_discovery = None
|
501
|
+
|
502
|
+
def _apply_service_env_overrides(self):
|
503
|
+
"""Apply service endpoint environment variable overrides"""
|
504
|
+
if not self.global_config:
|
505
|
+
return
|
506
|
+
|
507
|
+
# Consul configuration overrides
|
508
|
+
consul_env_mapping = {
|
509
|
+
"enabled": ["CONSUL_ENABLED"],
|
510
|
+
"host": ["CONSUL_HOST"],
|
511
|
+
"port": ["CONSUL_PORT"],
|
512
|
+
}
|
513
|
+
|
514
|
+
for setting, env_vars in consul_env_mapping.items():
|
515
|
+
for env_var in env_vars:
|
516
|
+
value = os.getenv(env_var)
|
517
|
+
if value:
|
518
|
+
if setting == "enabled":
|
519
|
+
setattr(self.global_config.consul, setting, value.lower() == "true")
|
520
|
+
elif setting == "port":
|
521
|
+
try:
|
522
|
+
setattr(self.global_config.consul, setting, int(value))
|
523
|
+
except ValueError:
|
524
|
+
continue
|
525
|
+
else:
|
526
|
+
setattr(self.global_config.consul, setting, value)
|
527
|
+
break
|
528
|
+
|
529
|
+
# Service endpoint overrides
|
530
|
+
service_env_mapping = {
|
531
|
+
"use_consul_discovery": ["USE_CONSUL_DISCOVERY"],
|
532
|
+
"mcp_base_url": ["MCP_BASE_URL", "MCP_URL"],
|
533
|
+
"ollama_base_url": ["OLLAMA_BASE_URL", "OLLAMA_URL"],
|
534
|
+
"influxdb_url": ["INFLUXDB_URL", "INFLUX_URL"],
|
535
|
+
"loki_url": ["LOKI_URL"],
|
536
|
+
"minio_endpoint": ["MINIO_ENDPOINT", "MINIO_HOST"],
|
537
|
+
"redis_url": ["REDIS_URL"],
|
538
|
+
"redis_port": ["REDIS_PORT"],
|
539
|
+
"mcp_service_name": ["MCP_SERVICE_NAME"],
|
540
|
+
"ollama_service_name": ["OLLAMA_SERVICE_NAME"],
|
541
|
+
"influxdb_service_name": ["INFLUXDB_SERVICE_NAME"],
|
542
|
+
"loki_service_name": ["LOKI_SERVICE_NAME"],
|
543
|
+
"minio_service_name": ["MINIO_SERVICE_NAME"],
|
544
|
+
"redis_service_name": ["REDIS_SERVICE_NAME"],
|
545
|
+
}
|
546
|
+
|
547
|
+
for setting, env_vars in service_env_mapping.items():
|
548
|
+
for env_var in env_vars:
|
549
|
+
value = os.getenv(env_var)
|
550
|
+
if value:
|
551
|
+
if setting == "use_consul_discovery":
|
552
|
+
setattr(self.global_config.services, setting, value.lower() == "true")
|
553
|
+
elif setting in ["redis_port"]:
|
554
|
+
try:
|
555
|
+
setattr(self.global_config.services, setting, int(value))
|
556
|
+
except ValueError:
|
557
|
+
continue
|
558
|
+
else:
|
559
|
+
setattr(self.global_config.services, setting, value)
|
560
|
+
break
|
561
|
+
|
387
562
|
def _apply_env_overrides(self):
|
388
563
|
"""Apply environment variable overrides"""
|
389
564
|
if not self.global_config:
|
390
565
|
return
|
391
566
|
|
392
|
-
#
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
567
|
+
# Environment-based database configuration
|
568
|
+
self._configure_database_for_environment()
|
569
|
+
|
570
|
+
# Service configuration overrides
|
571
|
+
self._apply_service_env_overrides()
|
397
572
|
|
398
573
|
# Serving overrides
|
399
|
-
port_env = os.getenv("PORT")
|
574
|
+
port_env = os.getenv("PORT") or os.getenv("API_PORT")
|
400
575
|
if port_env:
|
401
576
|
try:
|
402
577
|
self.global_config.serving.port = int(port_env)
|
578
|
+
self.global_config.services.api_port = int(port_env)
|
403
579
|
except ValueError:
|
404
580
|
pass
|
405
581
|
|
@@ -415,6 +591,100 @@ class ConfigManager:
|
|
415
591
|
raise RuntimeError("Configuration not loaded")
|
416
592
|
return self.global_config
|
417
593
|
|
594
|
+
def get_service_config(self) -> ServiceConfig:
|
595
|
+
"""Get service configuration"""
|
596
|
+
if not self.global_config:
|
597
|
+
raise RuntimeError("Configuration not loaded")
|
598
|
+
return self.global_config.services
|
599
|
+
|
600
|
+
def get_consul_config(self) -> ConsulConfig:
|
601
|
+
"""Get Consul configuration"""
|
602
|
+
if not self.global_config:
|
603
|
+
raise RuntimeError("Configuration not loaded")
|
604
|
+
return self.global_config.consul
|
605
|
+
|
606
|
+
def discover_service_url(self, service_name: str, fallback_url: Optional[str] = None) -> str:
|
607
|
+
"""Discover service URL using Consul or return fallback"""
|
608
|
+
if not self.global_config or not self.global_config.services.use_consul_discovery:
|
609
|
+
return fallback_url or self._get_fallback_service_url(service_name)
|
610
|
+
|
611
|
+
if not self._consul_discovery or not self._consul_discovery.is_available():
|
612
|
+
logger.debug(f"Consul not available, using fallback for {service_name}")
|
613
|
+
return fallback_url or self._get_fallback_service_url(service_name)
|
614
|
+
|
615
|
+
try:
|
616
|
+
discovered_url = self._consul_discovery.get_service_url(
|
617
|
+
service_name,
|
618
|
+
fallback_url or self._get_fallback_service_url(service_name)
|
619
|
+
)
|
620
|
+
return discovered_url
|
621
|
+
except Exception as e:
|
622
|
+
logger.warning(f"Failed to discover {service_name}: {e}")
|
623
|
+
return fallback_url or self._get_fallback_service_url(service_name)
|
624
|
+
|
625
|
+
def _get_fallback_service_url(self, service_name: str) -> str:
|
626
|
+
"""Get fallback URL for service based on service name"""
|
627
|
+
if not self.global_config:
|
628
|
+
raise RuntimeError("Configuration not loaded")
|
629
|
+
|
630
|
+
service_config = self.global_config.services
|
631
|
+
|
632
|
+
# Map service names to fallback URLs
|
633
|
+
service_mapping = {
|
634
|
+
service_config.mcp_service_name: service_config.mcp_base_url,
|
635
|
+
service_config.ollama_service_name: service_config.ollama_base_url,
|
636
|
+
service_config.influxdb_service_name: service_config.influxdb_url,
|
637
|
+
service_config.loki_service_name: service_config.loki_url,
|
638
|
+
service_config.minio_service_name: f"http://{service_config.minio_endpoint}",
|
639
|
+
service_config.redis_service_name: service_config.redis_url,
|
640
|
+
}
|
641
|
+
|
642
|
+
return service_mapping.get(service_name, f"http://localhost:8080")
|
643
|
+
|
644
|
+
def get_mcp_url(self) -> str:
|
645
|
+
"""Get MCP service URL (Consul discovery + fallback)"""
|
646
|
+
service_name = self.global_config.services.mcp_service_name
|
647
|
+
return self.discover_service_url(service_name, self.global_config.services.mcp_base_url)
|
648
|
+
|
649
|
+
def get_ollama_url(self) -> str:
|
650
|
+
"""Get Ollama service URL (Consul discovery + fallback)"""
|
651
|
+
service_name = self.global_config.services.ollama_service_name
|
652
|
+
return self.discover_service_url(service_name, self.global_config.services.ollama_base_url)
|
653
|
+
|
654
|
+
def get_influxdb_url(self) -> str:
|
655
|
+
"""Get InfluxDB service URL (Consul discovery + fallback)"""
|
656
|
+
service_name = self.global_config.services.influxdb_service_name
|
657
|
+
return self.discover_service_url(service_name, self.global_config.services.influxdb_url)
|
658
|
+
|
659
|
+
def get_loki_url(self) -> str:
|
660
|
+
"""Get Loki service URL (Consul discovery + fallback)"""
|
661
|
+
service_name = self.global_config.services.loki_service_name
|
662
|
+
return self.discover_service_url(service_name, self.global_config.services.loki_url)
|
663
|
+
|
664
|
+
def get_minio_url(self) -> str:
|
665
|
+
"""Get MinIO service URL (Consul discovery + fallback)"""
|
666
|
+
service_name = self.global_config.services.minio_service_name
|
667
|
+
fallback = f"http://{self.global_config.services.minio_endpoint}"
|
668
|
+
return self.discover_service_url(service_name, fallback)
|
669
|
+
|
670
|
+
def get_redis_url(self) -> str:
|
671
|
+
"""Get Redis service URL (Consul discovery + fallback)"""
|
672
|
+
service_name = self.global_config.services.redis_service_name
|
673
|
+
return self.discover_service_url(service_name, self.global_config.services.redis_url)
|
674
|
+
|
675
|
+
def resolve_consul_url(self, url: str) -> str:
|
676
|
+
"""Resolve consul:// URLs to actual service addresses"""
|
677
|
+
if not url or not url.startswith("consul://"):
|
678
|
+
return url
|
679
|
+
|
680
|
+
if not self._consul_discovery:
|
681
|
+
# If Consul not available, try to extract service name and use fallback
|
682
|
+
parts = url.replace("consul://", "").split("/", 1)
|
683
|
+
service_name = parts[0]
|
684
|
+
return self._get_fallback_service_url(service_name)
|
685
|
+
|
686
|
+
return self._consul_discovery.resolve_service_url(url)
|
687
|
+
|
418
688
|
def get_provider_config(self, provider: str) -> Optional[ProviderConfig]:
|
419
689
|
"""Get provider configuration"""
|
420
690
|
return self.provider_configs.get(provider)
|
isa_model/core/config.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""
|
1
|
+
z"""
|
2
2
|
Centralized Configuration Management for ISA Model SDK
|
3
3
|
|
4
4
|
This module provides unified configuration management across all modules:
|
@@ -48,6 +48,35 @@ class DeploymentConfig:
|
|
48
48
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
49
49
|
|
50
50
|
|
51
|
+
@dataclass
|
52
|
+
class LocalGPUGlobalConfig:
|
53
|
+
"""Global configuration for local GPU deployment"""
|
54
|
+
enable_local_gpu: bool = True
|
55
|
+
auto_detect_gpu: bool = True
|
56
|
+
workspace_dir: str = "./local_deployments"
|
57
|
+
preferred_backend: str = "transformers" # vllm, tensorrt_llm, transformers
|
58
|
+
|
59
|
+
# Default resource settings
|
60
|
+
default_gpu_memory_fraction: float = 0.9
|
61
|
+
default_max_batch_size: int = 8
|
62
|
+
default_max_model_len: int = 2048
|
63
|
+
default_precision: str = "float16"
|
64
|
+
|
65
|
+
# Health monitoring
|
66
|
+
health_check_interval: int = 30 # seconds
|
67
|
+
auto_restart_unhealthy: bool = True
|
68
|
+
max_consecutive_failures: int = 3
|
69
|
+
|
70
|
+
# Service limits
|
71
|
+
max_concurrent_services: int = 3
|
72
|
+
max_services_per_gpu: int = 2
|
73
|
+
|
74
|
+
# Performance settings
|
75
|
+
enable_model_compilation: bool = True
|
76
|
+
enable_memory_optimization: bool = True
|
77
|
+
cleanup_on_shutdown: bool = True
|
78
|
+
|
79
|
+
|
51
80
|
@dataclass
|
52
81
|
class GlobalConfig:
|
53
82
|
"""Global configuration settings"""
|
@@ -79,6 +108,18 @@ class GlobalConfig:
|
|
79
108
|
enable_model_cache: bool = True
|
80
109
|
cache_size_gb: int = 50
|
81
110
|
cache_cleanup_interval: int = 3600 # 1 hour
|
111
|
+
|
112
|
+
# Local GPU settings
|
113
|
+
enable_local_gpu: bool = True
|
114
|
+
local_gpu_memory_fraction: float = 0.9
|
115
|
+
local_workspace_dir: str = "./local_deployments"
|
116
|
+
auto_detect_gpu: bool = True
|
117
|
+
preferred_local_backend: str = "transformers" # vllm, tensorrt_llm, transformers
|
118
|
+
|
119
|
+
# Local service defaults
|
120
|
+
local_health_check_interval: int = 30 # seconds
|
121
|
+
local_auto_restart_unhealthy: bool = True
|
122
|
+
local_max_concurrent_services: int = 3
|
82
123
|
|
83
124
|
|
84
125
|
class ConfigManager:
|
@@ -121,6 +162,7 @@ class ConfigManager:
|
|
121
162
|
"""Initialize configuration manager"""
|
122
163
|
if not self._initialized:
|
123
164
|
self.global_config = GlobalConfig()
|
165
|
+
self.local_gpu_config = LocalGPUGlobalConfig()
|
124
166
|
self.provider_configs: Dict[str, ProviderConfig] = {}
|
125
167
|
self.deployment_configs: Dict[str, DeploymentConfig] = {}
|
126
168
|
|
@@ -153,6 +195,7 @@ class ConfigManager:
|
|
153
195
|
env_files = [
|
154
196
|
project_root / ".env",
|
155
197
|
project_root / ".env.local",
|
198
|
+
project_root / "deployment" / "dev" / ".env",
|
156
199
|
Path.cwd() / ".env",
|
157
200
|
]
|
158
201
|
|
@@ -197,6 +240,38 @@ class ConfigManager:
|
|
197
240
|
for key, value in global_settings.items():
|
198
241
|
if hasattr(self.global_config, key):
|
199
242
|
setattr(self.global_config, key, value)
|
243
|
+
|
244
|
+
# Load database configuration from environment
|
245
|
+
# Check multiple possible environment variable names for compatibility
|
246
|
+
supabase_url = os.getenv("SUPABASE_URL") or os.getenv("SUPABASE_LOCAL_URL")
|
247
|
+
supabase_key = os.getenv("SUPABASE_ANON_KEY") or os.getenv("SUPABASE_LOCAL_ANON_KEY")
|
248
|
+
|
249
|
+
if supabase_url and supabase_key:
|
250
|
+
self.global_config.use_supabase = True
|
251
|
+
self.global_config.supabase_url = supabase_url
|
252
|
+
self.global_config.supabase_key = supabase_key
|
253
|
+
logger.debug(f"Supabase configured: URL={supabase_url[:30]}...")
|
254
|
+
else:
|
255
|
+
# Check if explicitly disabled
|
256
|
+
use_supabase_env = os.getenv("ISA_USE_SUPABASE", "").lower()
|
257
|
+
if use_supabase_env == "false":
|
258
|
+
self.global_config.use_supabase = False
|
259
|
+
logger.debug("Supabase not configured, using default storage")
|
260
|
+
|
261
|
+
# Load local GPU configuration
|
262
|
+
local_gpu_settings = {
|
263
|
+
"enable_local_gpu": os.getenv("ISA_ENABLE_LOCAL_GPU", "true").lower() == "true",
|
264
|
+
"auto_detect_gpu": os.getenv("ISA_AUTO_DETECT_GPU", "true").lower() == "true",
|
265
|
+
"workspace_dir": os.getenv("ISA_LOCAL_WORKSPACE_DIR", "./local_deployments"),
|
266
|
+
"preferred_backend": os.getenv("ISA_PREFERRED_LOCAL_BACKEND", "transformers"),
|
267
|
+
"default_gpu_memory_fraction": float(os.getenv("ISA_GPU_MEMORY_FRACTION", "0.9")),
|
268
|
+
"health_check_interval": int(os.getenv("ISA_LOCAL_HEALTH_CHECK_INTERVAL", "30")),
|
269
|
+
"max_concurrent_services": int(os.getenv("ISA_MAX_CONCURRENT_SERVICES", "3")),
|
270
|
+
}
|
271
|
+
|
272
|
+
for key, value in local_gpu_settings.items():
|
273
|
+
if hasattr(self.local_gpu_config, key):
|
274
|
+
setattr(self.local_gpu_config, key, value)
|
200
275
|
|
201
276
|
def _load_provider_configs(self):
|
202
277
|
"""Load provider configurations from environment"""
|
@@ -310,6 +385,21 @@ class ConfigManager:
|
|
310
385
|
"""Get configuration for a specific deployment platform"""
|
311
386
|
return self.deployment_configs.get(platform.value)
|
312
387
|
|
388
|
+
def get_local_gpu_config(self) -> LocalGPUGlobalConfig:
|
389
|
+
"""Get local GPU global configuration"""
|
390
|
+
return self.local_gpu_config
|
391
|
+
|
392
|
+
def is_local_gpu_enabled(self) -> bool:
|
393
|
+
"""Check if local GPU deployment is enabled and available"""
|
394
|
+
if not self.local_gpu_config.enable_local_gpu:
|
395
|
+
return False
|
396
|
+
|
397
|
+
try:
|
398
|
+
from ..utils.gpu_utils import check_cuda_availability
|
399
|
+
return check_cuda_availability()
|
400
|
+
except ImportError:
|
401
|
+
return False
|
402
|
+
|
313
403
|
def is_provider_enabled(self, provider: Provider) -> bool:
|
314
404
|
"""Check if a provider is enabled and configured"""
|
315
405
|
config = self.get_provider_config(provider)
|
@@ -0,0 +1 @@
|
|
1
|
+
# Database package
|
@@ -0,0 +1,114 @@
|
|
1
|
+
"""
|
2
|
+
Direct Database Client for Migrations
|
3
|
+
|
4
|
+
Uses direct PostgreSQL connection for database operations like migrations.
|
5
|
+
This bypasses Supabase API and connects directly to PostgreSQL for admin operations.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import logging
|
9
|
+
import asyncio
|
10
|
+
from typing import Dict, List, Optional, Any, Tuple
|
11
|
+
import asyncpg
|
12
|
+
import os
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
class DirectDBClient:
|
17
|
+
"""
|
18
|
+
Direct PostgreSQL client for database administration operations
|
19
|
+
"""
|
20
|
+
|
21
|
+
def __init__(self, database_url: Optional[str] = None):
|
22
|
+
"""Initialize direct database client"""
|
23
|
+
self.database_url = database_url or os.getenv("DATABASE_URL")
|
24
|
+
if not self.database_url:
|
25
|
+
# Fallback to individual components
|
26
|
+
host = os.getenv("DB_HOST", "127.0.0.1")
|
27
|
+
port = os.getenv("DB_PORT", "54322")
|
28
|
+
database = os.getenv("DB_NAME", "postgres")
|
29
|
+
user = os.getenv("DB_USER", "postgres")
|
30
|
+
password = os.getenv("DB_PASSWORD", "postgres")
|
31
|
+
self.database_url = f"postgresql://{user}:{password}@{host}:{port}/{database}"
|
32
|
+
|
33
|
+
self.connection = None
|
34
|
+
|
35
|
+
async def connect(self) -> bool:
|
36
|
+
"""Establish database connection"""
|
37
|
+
try:
|
38
|
+
self.connection = await asyncpg.connect(self.database_url)
|
39
|
+
logger.info("Direct database connection established")
|
40
|
+
return True
|
41
|
+
except Exception as e:
|
42
|
+
logger.error(f"Failed to connect to database: {e}")
|
43
|
+
return False
|
44
|
+
|
45
|
+
async def disconnect(self):
|
46
|
+
"""Close database connection"""
|
47
|
+
if self.connection:
|
48
|
+
await self.connection.close()
|
49
|
+
self.connection = None
|
50
|
+
|
51
|
+
async def execute_sql(self, sql: str) -> Dict[str, Any]:
|
52
|
+
"""Execute raw SQL command"""
|
53
|
+
if not self.connection:
|
54
|
+
if not await self.connect():
|
55
|
+
return {"success": False, "error": "Failed to connect to database"}
|
56
|
+
|
57
|
+
try:
|
58
|
+
await self.connection.execute(sql)
|
59
|
+
return {"success": True}
|
60
|
+
except Exception as e:
|
61
|
+
logger.error(f"SQL execution failed: {e}")
|
62
|
+
return {"success": False, "error": str(e)}
|
63
|
+
|
64
|
+
async def execute_query(self, query: str, params: tuple = None) -> Dict[str, Any]:
|
65
|
+
"""Execute SQL query with parameters and return results"""
|
66
|
+
if not self.connection:
|
67
|
+
if not await self.connect():
|
68
|
+
return {"success": False, "error": "Failed to connect to database"}
|
69
|
+
|
70
|
+
try:
|
71
|
+
if params:
|
72
|
+
result = await self.connection.fetch(query, *params)
|
73
|
+
else:
|
74
|
+
result = await self.connection.fetch(query)
|
75
|
+
|
76
|
+
# Convert asyncpg records to dicts
|
77
|
+
data = [dict(record) for record in result]
|
78
|
+
return {"success": True, "data": data}
|
79
|
+
except Exception as e:
|
80
|
+
logger.error(f"Query execution failed: {e}")
|
81
|
+
return {"success": False, "error": str(e)}
|
82
|
+
|
83
|
+
async def execute_transaction(self, sql_commands: List[str]) -> Dict[str, Any]:
|
84
|
+
"""Execute multiple SQL commands in a transaction"""
|
85
|
+
if not self.connection:
|
86
|
+
if not await self.connect():
|
87
|
+
return {"success": False, "error": "Failed to connect to database"}
|
88
|
+
|
89
|
+
try:
|
90
|
+
async with self.connection.transaction():
|
91
|
+
for sql in sql_commands:
|
92
|
+
await self.connection.execute(sql)
|
93
|
+
return {"success": True}
|
94
|
+
except Exception as e:
|
95
|
+
logger.error(f"Transaction failed: {e}")
|
96
|
+
return {"success": False, "error": str(e)}
|
97
|
+
|
98
|
+
async def test_connection(self) -> bool:
|
99
|
+
"""Test database connection"""
|
100
|
+
try:
|
101
|
+
if not self.connection:
|
102
|
+
if not await self.connect():
|
103
|
+
return False
|
104
|
+
|
105
|
+
await self.connection.fetchval("SELECT 1")
|
106
|
+
return True
|
107
|
+
except Exception as e:
|
108
|
+
logger.error(f"Connection test failed: {e}")
|
109
|
+
return False
|
110
|
+
|
111
|
+
# Factory function
|
112
|
+
def create_direct_db_client(database_url: Optional[str] = None) -> DirectDBClient:
|
113
|
+
"""Create a direct database client"""
|
114
|
+
return DirectDBClient(database_url)
|