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.
Files changed (228) hide show
  1. isa_model/client.py +1166 -584
  2. isa_model/core/cache/redis_cache.py +410 -0
  3. isa_model/core/config/config_manager.py +282 -12
  4. isa_model/core/config.py +91 -1
  5. isa_model/core/database/__init__.py +1 -0
  6. isa_model/core/database/direct_db_client.py +114 -0
  7. isa_model/core/database/migration_manager.py +563 -0
  8. isa_model/core/database/migrations.py +297 -0
  9. isa_model/core/database/supabase_client.py +258 -0
  10. isa_model/core/dependencies.py +316 -0
  11. isa_model/core/discovery/__init__.py +19 -0
  12. isa_model/core/discovery/consul_discovery.py +190 -0
  13. isa_model/core/logging/__init__.py +54 -0
  14. isa_model/core/logging/influx_logger.py +523 -0
  15. isa_model/core/logging/loki_logger.py +160 -0
  16. isa_model/core/models/__init__.py +46 -0
  17. isa_model/core/models/config_models.py +625 -0
  18. isa_model/core/models/deployment_billing_tracker.py +430 -0
  19. isa_model/core/models/model_billing_tracker.py +60 -88
  20. isa_model/core/models/model_manager.py +66 -25
  21. isa_model/core/models/model_metadata.py +690 -0
  22. isa_model/core/models/model_repo.py +217 -55
  23. isa_model/core/models/model_statistics_tracker.py +234 -0
  24. isa_model/core/models/model_storage.py +0 -1
  25. isa_model/core/models/model_version_manager.py +959 -0
  26. isa_model/core/models/system_models.py +857 -0
  27. isa_model/core/pricing_manager.py +2 -249
  28. isa_model/core/repositories/__init__.py +9 -0
  29. isa_model/core/repositories/config_repository.py +912 -0
  30. isa_model/core/resilience/circuit_breaker.py +366 -0
  31. isa_model/core/security/secrets.py +358 -0
  32. isa_model/core/services/__init__.py +2 -4
  33. isa_model/core/services/intelligent_model_selector.py +479 -370
  34. isa_model/core/storage/hf_storage.py +2 -2
  35. isa_model/core/types.py +8 -0
  36. isa_model/deployment/__init__.py +5 -48
  37. isa_model/deployment/core/__init__.py +2 -31
  38. isa_model/deployment/core/deployment_manager.py +1278 -368
  39. isa_model/deployment/local/__init__.py +31 -0
  40. isa_model/deployment/local/config.py +248 -0
  41. isa_model/deployment/local/gpu_gateway.py +607 -0
  42. isa_model/deployment/local/health_checker.py +428 -0
  43. isa_model/deployment/local/provider.py +586 -0
  44. isa_model/deployment/local/tensorrt_service.py +621 -0
  45. isa_model/deployment/local/transformers_service.py +644 -0
  46. isa_model/deployment/local/vllm_service.py +527 -0
  47. isa_model/deployment/modal/__init__.py +8 -0
  48. isa_model/deployment/modal/config.py +136 -0
  49. isa_model/deployment/modal/deployer.py +894 -0
  50. isa_model/deployment/modal/services/__init__.py +3 -0
  51. isa_model/deployment/modal/services/audio/__init__.py +1 -0
  52. isa_model/deployment/modal/services/audio/isa_audio_chatTTS_service.py +520 -0
  53. isa_model/deployment/modal/services/audio/isa_audio_openvoice_service.py +758 -0
  54. isa_model/deployment/modal/services/audio/isa_audio_service_v2.py +1044 -0
  55. isa_model/deployment/modal/services/embedding/__init__.py +1 -0
  56. isa_model/deployment/modal/services/embedding/isa_embed_rerank_service.py +296 -0
  57. isa_model/deployment/modal/services/llm/__init__.py +1 -0
  58. isa_model/deployment/modal/services/llm/isa_llm_service.py +424 -0
  59. isa_model/deployment/modal/services/video/__init__.py +1 -0
  60. isa_model/deployment/modal/services/video/isa_video_hunyuan_service.py +423 -0
  61. isa_model/deployment/modal/services/vision/__init__.py +1 -0
  62. isa_model/deployment/modal/services/vision/isa_vision_ocr_service.py +519 -0
  63. isa_model/deployment/modal/services/vision/isa_vision_qwen25_service.py +709 -0
  64. isa_model/deployment/modal/services/vision/isa_vision_table_service.py +676 -0
  65. isa_model/deployment/modal/services/vision/isa_vision_ui_service.py +833 -0
  66. isa_model/deployment/modal/services/vision/isa_vision_ui_service_optimized.py +660 -0
  67. isa_model/deployment/models/org-org-acme-corp-tenant-a-service-llm-20250825-225822/tenant-a-service_modal_service.py +48 -0
  68. isa_model/deployment/models/org-test-org-123-prefix-test-service-llm-20250825-225822/prefix-test-service_modal_service.py +48 -0
  69. isa_model/deployment/models/test-llm-service-llm-20250825-204442/test-llm-service_modal_service.py +48 -0
  70. isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-212906/test-monitoring-gpt2_modal_service.py +48 -0
  71. isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-213009/test-monitoring-gpt2_modal_service.py +48 -0
  72. isa_model/deployment/storage/__init__.py +5 -0
  73. isa_model/deployment/storage/deployment_repository.py +824 -0
  74. isa_model/deployment/triton/__init__.py +10 -0
  75. isa_model/deployment/triton/config.py +196 -0
  76. isa_model/deployment/triton/configs/__init__.py +1 -0
  77. isa_model/deployment/triton/provider.py +512 -0
  78. isa_model/deployment/triton/scripts/__init__.py +1 -0
  79. isa_model/deployment/triton/templates/__init__.py +1 -0
  80. isa_model/inference/__init__.py +47 -1
  81. isa_model/inference/ai_factory.py +179 -16
  82. isa_model/inference/legacy_services/__init__.py +21 -0
  83. isa_model/inference/legacy_services/model_evaluation.py +637 -0
  84. isa_model/inference/legacy_services/model_service.py +573 -0
  85. isa_model/inference/legacy_services/model_serving.py +717 -0
  86. isa_model/inference/legacy_services/model_training.py +561 -0
  87. isa_model/inference/models/__init__.py +21 -0
  88. isa_model/inference/models/inference_config.py +551 -0
  89. isa_model/inference/models/inference_record.py +675 -0
  90. isa_model/inference/models/performance_models.py +714 -0
  91. isa_model/inference/repositories/__init__.py +9 -0
  92. isa_model/inference/repositories/inference_repository.py +828 -0
  93. isa_model/inference/services/audio/__init__.py +21 -0
  94. isa_model/inference/services/audio/base_realtime_service.py +225 -0
  95. isa_model/inference/services/audio/base_stt_service.py +184 -11
  96. isa_model/inference/services/audio/isa_tts_service.py +0 -0
  97. isa_model/inference/services/audio/openai_realtime_service.py +320 -124
  98. isa_model/inference/services/audio/openai_stt_service.py +53 -11
  99. isa_model/inference/services/base_service.py +17 -1
  100. isa_model/inference/services/custom_model_manager.py +277 -0
  101. isa_model/inference/services/embedding/__init__.py +13 -0
  102. isa_model/inference/services/embedding/base_embed_service.py +111 -8
  103. isa_model/inference/services/embedding/isa_embed_service.py +305 -0
  104. isa_model/inference/services/embedding/ollama_embed_service.py +15 -3
  105. isa_model/inference/services/embedding/openai_embed_service.py +2 -4
  106. isa_model/inference/services/embedding/resilient_embed_service.py +285 -0
  107. isa_model/inference/services/embedding/tests/test_embedding.py +222 -0
  108. isa_model/inference/services/img/__init__.py +2 -2
  109. isa_model/inference/services/img/base_image_gen_service.py +24 -7
  110. isa_model/inference/services/img/replicate_image_gen_service.py +84 -422
  111. isa_model/inference/services/img/services/replicate_face_swap.py +193 -0
  112. isa_model/inference/services/img/services/replicate_flux.py +226 -0
  113. isa_model/inference/services/img/services/replicate_flux_kontext.py +219 -0
  114. isa_model/inference/services/img/services/replicate_sticker_maker.py +249 -0
  115. isa_model/inference/services/img/tests/test_img_client.py +297 -0
  116. isa_model/inference/services/llm/__init__.py +10 -2
  117. isa_model/inference/services/llm/base_llm_service.py +361 -26
  118. isa_model/inference/services/llm/cerebras_llm_service.py +628 -0
  119. isa_model/inference/services/llm/helpers/llm_adapter.py +71 -12
  120. isa_model/inference/services/llm/helpers/llm_prompts.py +342 -0
  121. isa_model/inference/services/llm/helpers/llm_utils.py +321 -23
  122. isa_model/inference/services/llm/huggingface_llm_service.py +581 -0
  123. isa_model/inference/services/llm/local_llm_service.py +747 -0
  124. isa_model/inference/services/llm/ollama_llm_service.py +11 -3
  125. isa_model/inference/services/llm/openai_llm_service.py +670 -56
  126. isa_model/inference/services/llm/yyds_llm_service.py +10 -3
  127. isa_model/inference/services/vision/__init__.py +27 -6
  128. isa_model/inference/services/vision/base_vision_service.py +118 -185
  129. isa_model/inference/services/vision/blip_vision_service.py +359 -0
  130. isa_model/inference/services/vision/helpers/image_utils.py +19 -10
  131. isa_model/inference/services/vision/isa_vision_service.py +634 -0
  132. isa_model/inference/services/vision/openai_vision_service.py +19 -10
  133. isa_model/inference/services/vision/tests/test_ocr_client.py +284 -0
  134. isa_model/inference/services/vision/vgg16_vision_service.py +257 -0
  135. isa_model/serving/api/cache_manager.py +245 -0
  136. isa_model/serving/api/dependencies/__init__.py +1 -0
  137. isa_model/serving/api/dependencies/auth.py +194 -0
  138. isa_model/serving/api/dependencies/database.py +139 -0
  139. isa_model/serving/api/error_handlers.py +284 -0
  140. isa_model/serving/api/fastapi_server.py +240 -18
  141. isa_model/serving/api/middleware/auth.py +317 -0
  142. isa_model/serving/api/middleware/security.py +268 -0
  143. isa_model/serving/api/middleware/tenant_context.py +414 -0
  144. isa_model/serving/api/routes/analytics.py +489 -0
  145. isa_model/serving/api/routes/config.py +645 -0
  146. isa_model/serving/api/routes/deployment_billing.py +315 -0
  147. isa_model/serving/api/routes/deployments.py +475 -0
  148. isa_model/serving/api/routes/gpu_gateway.py +440 -0
  149. isa_model/serving/api/routes/health.py +32 -12
  150. isa_model/serving/api/routes/inference_monitoring.py +486 -0
  151. isa_model/serving/api/routes/local_deployments.py +448 -0
  152. isa_model/serving/api/routes/logs.py +430 -0
  153. isa_model/serving/api/routes/settings.py +582 -0
  154. isa_model/serving/api/routes/tenants.py +575 -0
  155. isa_model/serving/api/routes/unified.py +992 -171
  156. isa_model/serving/api/routes/webhooks.py +479 -0
  157. isa_model/serving/api/startup.py +318 -0
  158. isa_model/serving/modal_proxy_server.py +249 -0
  159. isa_model/utils/gpu_utils.py +311 -0
  160. {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/METADATA +76 -22
  161. isa_model-0.4.3.dist-info/RECORD +193 -0
  162. isa_model/deployment/cloud/__init__.py +0 -9
  163. isa_model/deployment/cloud/modal/__init__.py +0 -10
  164. isa_model/deployment/cloud/modal/isa_vision_doc_service.py +0 -766
  165. isa_model/deployment/cloud/modal/isa_vision_table_service.py +0 -532
  166. isa_model/deployment/cloud/modal/isa_vision_ui_service.py +0 -406
  167. isa_model/deployment/cloud/modal/register_models.py +0 -321
  168. isa_model/deployment/core/deployment_config.py +0 -356
  169. isa_model/deployment/core/isa_deployment_service.py +0 -401
  170. isa_model/deployment/gpu_int8_ds8/app/server.py +0 -66
  171. isa_model/deployment/gpu_int8_ds8/scripts/test_client.py +0 -43
  172. isa_model/deployment/gpu_int8_ds8/scripts/test_client_os.py +0 -35
  173. isa_model/deployment/runtime/deployed_service.py +0 -338
  174. isa_model/deployment/services/__init__.py +0 -9
  175. isa_model/deployment/services/auto_deploy_vision_service.py +0 -538
  176. isa_model/deployment/services/model_service.py +0 -332
  177. isa_model/deployment/services/service_monitor.py +0 -356
  178. isa_model/deployment/services/service_registry.py +0 -527
  179. isa_model/eval/__init__.py +0 -92
  180. isa_model/eval/benchmarks.py +0 -469
  181. isa_model/eval/config/__init__.py +0 -10
  182. isa_model/eval/config/evaluation_config.py +0 -108
  183. isa_model/eval/evaluators/__init__.py +0 -18
  184. isa_model/eval/evaluators/base_evaluator.py +0 -503
  185. isa_model/eval/evaluators/llm_evaluator.py +0 -472
  186. isa_model/eval/factory.py +0 -531
  187. isa_model/eval/infrastructure/__init__.py +0 -24
  188. isa_model/eval/infrastructure/experiment_tracker.py +0 -466
  189. isa_model/eval/metrics.py +0 -798
  190. isa_model/inference/adapter/unified_api.py +0 -248
  191. isa_model/inference/services/helpers/stacked_config.py +0 -148
  192. isa_model/inference/services/img/flux_professional_service.py +0 -603
  193. isa_model/inference/services/img/helpers/base_stacked_service.py +0 -274
  194. isa_model/inference/services/others/table_transformer_service.py +0 -61
  195. isa_model/inference/services/vision/doc_analysis_service.py +0 -640
  196. isa_model/inference/services/vision/helpers/base_stacked_service.py +0 -274
  197. isa_model/inference/services/vision/ui_analysis_service.py +0 -823
  198. isa_model/scripts/inference_tracker.py +0 -283
  199. isa_model/scripts/mlflow_manager.py +0 -379
  200. isa_model/scripts/model_registry.py +0 -465
  201. isa_model/scripts/register_models.py +0 -370
  202. isa_model/scripts/register_models_with_embeddings.py +0 -510
  203. isa_model/scripts/start_mlflow.py +0 -95
  204. isa_model/scripts/training_tracker.py +0 -257
  205. isa_model/training/__init__.py +0 -74
  206. isa_model/training/annotation/annotation_schema.py +0 -47
  207. isa_model/training/annotation/processors/annotation_processor.py +0 -126
  208. isa_model/training/annotation/storage/dataset_manager.py +0 -131
  209. isa_model/training/annotation/storage/dataset_schema.py +0 -44
  210. isa_model/training/annotation/tests/test_annotation_flow.py +0 -109
  211. isa_model/training/annotation/tests/test_minio copy.py +0 -113
  212. isa_model/training/annotation/tests/test_minio_upload.py +0 -43
  213. isa_model/training/annotation/views/annotation_controller.py +0 -158
  214. isa_model/training/cloud/__init__.py +0 -22
  215. isa_model/training/cloud/job_orchestrator.py +0 -402
  216. isa_model/training/cloud/runpod_trainer.py +0 -454
  217. isa_model/training/cloud/storage_manager.py +0 -482
  218. isa_model/training/core/__init__.py +0 -23
  219. isa_model/training/core/config.py +0 -181
  220. isa_model/training/core/dataset.py +0 -222
  221. isa_model/training/core/trainer.py +0 -720
  222. isa_model/training/core/utils.py +0 -213
  223. isa_model/training/factory.py +0 -424
  224. isa_model-0.3.91.dist-info/RECORD +0 -138
  225. /isa_model/{core/storage/minio_storage.py → deployment/modal/services/audio/isa_audio_fish_service.py} +0 -0
  226. /isa_model/deployment/{services → modal/services/vision}/simple_auto_deploy_vision_service.py +0 -0
  227. {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/WHEEL +0 -0
  228. {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/top_level.txt +0 -0
@@ -15,7 +15,6 @@ from datetime import datetime, timedelta
15
15
  from dataclasses import dataclass, field
16
16
 
17
17
  from .types import Provider
18
- from .config import config_manager
19
18
 
20
19
  logger = logging.getLogger(__name__)
21
20
 
@@ -78,17 +77,7 @@ class PricingManager:
78
77
 
79
78
  def _load_pricing_data(self):
80
79
  """Load pricing data from configuration files"""
81
- # Try to load from Supabase first
82
- if self._load_from_supabase():
83
- logger.info("Loaded pricing data from Supabase")
84
- return
85
-
86
- # Try to load from provider configurations
87
- if self._load_from_provider_configs():
88
- logger.info("Loaded pricing data from provider configurations")
89
- return
90
-
91
- # Try to load from specified config path
80
+ # Try to load from specified config path first
92
81
  if self.config_path and self.config_path.exists():
93
82
  self._load_from_file(self.config_path)
94
83
  return
@@ -168,7 +157,7 @@ class PricingManager:
168
157
  """Load default pricing data as fallback"""
169
158
  default_pricing = {
170
159
  "openai": {
171
- "gpt-4o-mini": {"input": 0.000000150, "output": 0.000000600, "unit_type": "token"},
160
+ "gpt-4o-mini": {"input": 0.00000015, "output": 0.0000006, "unit_type": "token"},
172
161
  "gpt-4o": {"input": 0.000005, "output": 0.000015, "unit_type": "token"},
173
162
  "gpt-4-turbo": {"input": 0.00001, "output": 0.00003, "unit_type": "token"},
174
163
  "gpt-4": {"input": 0.00003, "output": 0.00006, "unit_type": "token"},
@@ -198,242 +187,6 @@ class PricingManager:
198
187
  self._parse_pricing_data({"providers": default_pricing})
199
188
  logger.info("Loaded default pricing data")
200
189
 
201
- def _load_from_supabase(self) -> bool:
202
- """Try to load pricing data from Supabase models table"""
203
- try:
204
- global_config = config_manager.get_global_config()
205
- if not global_config.use_supabase:
206
- return False
207
-
208
- # Import Supabase client
209
- try:
210
- from supabase import create_client, Client
211
- except ImportError:
212
- logger.debug("Supabase library not available")
213
- return False
214
-
215
- # Get Supabase credentials
216
- supabase_url = global_config.supabase_url or os.getenv('SUPABASE_URL')
217
- supabase_key = global_config.supabase_key or os.getenv('SUPABASE_ANON_KEY')
218
-
219
- if not supabase_url or not supabase_key:
220
- logger.debug("Supabase credentials not configured")
221
- return False
222
-
223
- # Create Supabase client
224
- supabase: Client = create_client(supabase_url, supabase_key)
225
-
226
- # Query models table for pricing information
227
- result = supabase.table('models').select('model_id, provider, metadata').execute()
228
-
229
- if not result.data:
230
- logger.debug("No models found in Supabase")
231
- return False
232
-
233
- self.pricing_data = {}
234
- loaded_count = 0
235
-
236
- for model_record in result.data:
237
- model_id = model_record.get('model_id')
238
- provider = model_record.get('provider')
239
- metadata = model_record.get('metadata', {})
240
-
241
- if not model_id or not provider:
242
- continue
243
-
244
- # Extract pricing from metadata
245
- pricing = self._extract_pricing_from_supabase_metadata(metadata, provider, model_id)
246
- if pricing:
247
- if provider not in self.pricing_data:
248
- self.pricing_data[provider] = {}
249
- self.pricing_data[provider][model_id] = pricing
250
- loaded_count += 1
251
-
252
- if loaded_count > 0:
253
- logger.info(f"Loaded pricing for {loaded_count} models from Supabase")
254
- return True
255
- else:
256
- logger.debug("No pricing data found in Supabase models")
257
- return False
258
-
259
- except Exception as e:
260
- logger.debug(f"Failed to load pricing from Supabase: {e}")
261
- return False
262
-
263
- def _load_from_provider_configs(self) -> bool:
264
- """Load pricing data from provider configuration files"""
265
- try:
266
- providers_dir = self._find_project_root() / "isa_model" / "core" / "config" / "providers"
267
- if not providers_dir.exists():
268
- return False
269
-
270
- self.pricing_data = {}
271
- loaded_any = False
272
-
273
- # Load all provider config files
274
- for config_file in providers_dir.glob("*.yaml"):
275
- if self._load_provider_config_file(config_file):
276
- loaded_any = True
277
-
278
- return loaded_any
279
-
280
- except Exception as e:
281
- logger.error(f"Failed to load pricing from provider configs: {e}")
282
- return False
283
-
284
- def _load_provider_config_file(self, config_file: Path) -> bool:
285
- """Load pricing data from a single provider config file"""
286
- try:
287
- with open(config_file, 'r') as f:
288
- provider_data = yaml.safe_load(f)
289
-
290
- provider_name = provider_data.get("provider")
291
- if not provider_name:
292
- return False
293
-
294
- models = provider_data.get("models", [])
295
- if not models:
296
- return False
297
-
298
- self.pricing_data[provider_name] = {}
299
-
300
- for model in models:
301
- model_id = model.get("model_id")
302
- metadata = model.get("metadata", {})
303
-
304
- if not model_id:
305
- continue
306
-
307
- # Extract pricing information from metadata
308
- pricing = self._extract_pricing_from_metadata(metadata, provider_name, model_id)
309
- if pricing:
310
- self.pricing_data[provider_name][model_id] = pricing
311
-
312
- logger.debug(f"Loaded pricing for {len(self.pricing_data[provider_name])} models from {provider_name}")
313
- return True
314
-
315
- except Exception as e:
316
- logger.error(f"Failed to load provider config {config_file}: {e}")
317
- return False
318
-
319
- def _extract_pricing_from_metadata(self, metadata: Dict[str, Any], provider: str, model_name: str) -> Optional[ModelPricing]:
320
- """Extract pricing information from model metadata"""
321
- try:
322
- # Map different pricing field formats to our standard format
323
- pricing_fields = {
324
- "cost_per_1000_chars": ("character", 1000),
325
- "cost_per_1000_tokens": ("token", 1000000), # Convert to cost per 1M tokens
326
- "cost_per_minute": ("minute", 1),
327
- "cost_per_image": ("image", 1),
328
- "cost_per_request": ("request", 1),
329
- }
330
-
331
- input_cost = 0.0
332
- output_cost = 0.0
333
- unit_type = "token"
334
- base_cost = 0.0
335
-
336
- for field, (unit, multiplier) in pricing_fields.items():
337
- if field in metadata:
338
- cost = float(metadata[field])
339
- if unit == "character":
340
- # Convert cost per 1K chars to cost per 1K chars
341
- input_cost = cost
342
- unit_type = "character"
343
- elif unit == "token":
344
- # Cost per 1M tokens
345
- input_cost = cost
346
- unit_type = "token"
347
- elif unit == "minute":
348
- input_cost = cost
349
- unit_type = "minute"
350
- elif unit == "image":
351
- input_cost = cost
352
- unit_type = "image"
353
- elif unit == "request":
354
- base_cost = cost
355
- break
356
-
357
- # If no pricing found, skip this model
358
- if input_cost == 0.0 and base_cost == 0.0:
359
- return None
360
-
361
- return ModelPricing(
362
- provider=provider,
363
- model_name=model_name,
364
- input_cost=input_cost,
365
- output_cost=output_cost,
366
- unit_type=unit_type,
367
- base_cost=base_cost,
368
- last_updated=datetime.now()
369
- )
370
-
371
- except Exception as e:
372
- logger.warning(f"Failed to extract pricing for {provider}/{model_name}: {e}")
373
- return None
374
-
375
- def _extract_pricing_from_supabase_metadata(self, metadata: Dict[str, Any], provider: str, model_name: str) -> Optional[ModelPricing]:
376
- """Extract pricing information from Supabase model metadata"""
377
- try:
378
- # Check for pricing information in metadata
379
- pricing_info = metadata.get('pricing', {})
380
-
381
- # If no pricing object, look for direct pricing fields
382
- if not pricing_info:
383
- # Look for various pricing field formats in metadata
384
- pricing_fields = [
385
- 'cost_per_1000_chars', 'cost_per_1000_tokens', 'cost_per_minute',
386
- 'cost_per_image', 'cost_per_request', 'input_cost', 'output_cost',
387
- 'cost_per_1k_tokens', 'cost_per_1k_chars'
388
- ]
389
-
390
- for field in pricing_fields:
391
- if field in metadata:
392
- # Create a pricing object from the field
393
- if 'char' in field:
394
- pricing_info = {'input': metadata[field], 'unit_type': 'character'}
395
- elif 'token' in field:
396
- pricing_info = {'input': metadata[field], 'unit_type': 'token'}
397
- elif 'minute' in field:
398
- pricing_info = {'input': metadata[field], 'unit_type': 'minute'}
399
- elif 'image' in field:
400
- pricing_info = {'input': metadata[field], 'unit_type': 'image'}
401
- elif 'request' in field:
402
- pricing_info = {'base_cost': metadata[field], 'unit_type': 'request'}
403
- break
404
-
405
- if not pricing_info:
406
- return None
407
-
408
- # Extract standard pricing fields
409
- input_cost = float(pricing_info.get('input', pricing_info.get('input_cost', 0.0)))
410
- output_cost = float(pricing_info.get('output', pricing_info.get('output_cost', 0.0)))
411
- unit_type = pricing_info.get('unit_type', 'token')
412
- base_cost = float(pricing_info.get('base_cost', 0.0))
413
- infrastructure_cost_per_hour = float(pricing_info.get('infrastructure_cost_per_hour', 0.0))
414
- currency = pricing_info.get('currency', 'USD')
415
-
416
- # If no pricing found, skip this model
417
- if input_cost == 0.0 and output_cost == 0.0 and base_cost == 0.0:
418
- return None
419
-
420
- return ModelPricing(
421
- provider=provider,
422
- model_name=model_name,
423
- input_cost=input_cost,
424
- output_cost=output_cost,
425
- unit_type=unit_type,
426
- base_cost=base_cost,
427
- infrastructure_cost_per_hour=infrastructure_cost_per_hour,
428
- currency=currency,
429
- last_updated=datetime.now(),
430
- metadata=pricing_info
431
- )
432
-
433
- except Exception as e:
434
- logger.warning(f"Failed to extract pricing from Supabase metadata for {provider}/{model_name}: {e}")
435
- return None
436
-
437
190
  def get_model_pricing(self, provider: str, model_name: str) -> Optional[ModelPricing]:
438
191
  """Get pricing information for a specific model"""
439
192
  self._refresh_if_needed()
@@ -0,0 +1,9 @@
1
+ """
2
+ Core Repository Layer
3
+
4
+ Provides data persistence and retrieval for core operations.
5
+ """
6
+
7
+ from .config_repository import ConfigRepository
8
+
9
+ __all__ = ["ConfigRepository"]