isa-model 0.3.4__py3-none-any.whl → 0.3.6__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 (100) hide show
  1. isa_model/__init__.py +30 -1
  2. isa_model/client.py +770 -0
  3. isa_model/core/config/__init__.py +16 -0
  4. isa_model/core/config/config_manager.py +514 -0
  5. isa_model/core/config.py +426 -0
  6. isa_model/core/models/model_billing_tracker.py +476 -0
  7. isa_model/core/models/model_manager.py +399 -0
  8. isa_model/core/models/model_repo.py +343 -0
  9. isa_model/core/pricing_manager.py +426 -0
  10. isa_model/core/services/__init__.py +19 -0
  11. isa_model/core/services/intelligent_model_selector.py +547 -0
  12. isa_model/core/types.py +291 -0
  13. isa_model/deployment/__init__.py +2 -0
  14. isa_model/deployment/cloud/__init__.py +9 -0
  15. isa_model/deployment/cloud/modal/__init__.py +10 -0
  16. isa_model/deployment/cloud/modal/isa_vision_doc_service.py +766 -0
  17. isa_model/deployment/cloud/modal/isa_vision_table_service.py +532 -0
  18. isa_model/deployment/cloud/modal/isa_vision_ui_service.py +406 -0
  19. isa_model/deployment/cloud/modal/register_models.py +321 -0
  20. isa_model/deployment/runtime/deployed_service.py +338 -0
  21. isa_model/deployment/services/__init__.py +9 -0
  22. isa_model/deployment/services/auto_deploy_vision_service.py +537 -0
  23. isa_model/deployment/services/model_service.py +332 -0
  24. isa_model/deployment/services/service_monitor.py +356 -0
  25. isa_model/deployment/services/service_registry.py +527 -0
  26. isa_model/eval/__init__.py +80 -44
  27. isa_model/eval/config/__init__.py +10 -0
  28. isa_model/eval/config/evaluation_config.py +108 -0
  29. isa_model/eval/evaluators/__init__.py +18 -0
  30. isa_model/eval/evaluators/base_evaluator.py +503 -0
  31. isa_model/eval/evaluators/llm_evaluator.py +472 -0
  32. isa_model/eval/factory.py +417 -709
  33. isa_model/eval/infrastructure/__init__.py +24 -0
  34. isa_model/eval/infrastructure/experiment_tracker.py +466 -0
  35. isa_model/eval/metrics.py +191 -21
  36. isa_model/inference/ai_factory.py +187 -387
  37. isa_model/inference/providers/modal_provider.py +109 -0
  38. isa_model/inference/providers/yyds_provider.py +108 -0
  39. isa_model/inference/services/__init__.py +2 -1
  40. isa_model/inference/services/audio/base_stt_service.py +65 -1
  41. isa_model/inference/services/audio/base_tts_service.py +75 -1
  42. isa_model/inference/services/audio/openai_stt_service.py +189 -151
  43. isa_model/inference/services/audio/openai_tts_service.py +12 -10
  44. isa_model/inference/services/audio/replicate_tts_service.py +61 -56
  45. isa_model/inference/services/base_service.py +55 -55
  46. isa_model/inference/services/embedding/base_embed_service.py +65 -1
  47. isa_model/inference/services/embedding/ollama_embed_service.py +103 -43
  48. isa_model/inference/services/embedding/openai_embed_service.py +8 -10
  49. isa_model/inference/services/helpers/stacked_config.py +148 -0
  50. isa_model/inference/services/img/__init__.py +18 -0
  51. isa_model/inference/services/{vision → img}/base_image_gen_service.py +80 -35
  52. isa_model/inference/services/img/flux_professional_service.py +603 -0
  53. isa_model/inference/services/img/helpers/base_stacked_service.py +274 -0
  54. isa_model/inference/services/{vision → img}/replicate_image_gen_service.py +210 -69
  55. isa_model/inference/services/llm/__init__.py +3 -3
  56. isa_model/inference/services/llm/base_llm_service.py +519 -35
  57. isa_model/inference/services/llm/{llm_adapter.py → helpers/llm_adapter.py} +40 -0
  58. isa_model/inference/services/llm/helpers/llm_prompts.py +258 -0
  59. isa_model/inference/services/llm/helpers/llm_utils.py +280 -0
  60. isa_model/inference/services/llm/ollama_llm_service.py +150 -15
  61. isa_model/inference/services/llm/openai_llm_service.py +134 -31
  62. isa_model/inference/services/llm/yyds_llm_service.py +255 -0
  63. isa_model/inference/services/vision/__init__.py +38 -4
  64. isa_model/inference/services/vision/base_vision_service.py +241 -96
  65. isa_model/inference/services/vision/disabled/isA_vision_service.py +500 -0
  66. isa_model/inference/services/vision/doc_analysis_service.py +640 -0
  67. isa_model/inference/services/vision/helpers/base_stacked_service.py +274 -0
  68. isa_model/inference/services/vision/helpers/image_utils.py +272 -3
  69. isa_model/inference/services/vision/helpers/vision_prompts.py +297 -0
  70. isa_model/inference/services/vision/openai_vision_service.py +109 -170
  71. isa_model/inference/services/vision/replicate_vision_service.py +508 -0
  72. isa_model/inference/services/vision/ui_analysis_service.py +823 -0
  73. isa_model/scripts/register_models.py +370 -0
  74. isa_model/scripts/register_models_with_embeddings.py +510 -0
  75. isa_model/serving/__init__.py +19 -0
  76. isa_model/serving/api/__init__.py +10 -0
  77. isa_model/serving/api/fastapi_server.py +89 -0
  78. isa_model/serving/api/middleware/__init__.py +9 -0
  79. isa_model/serving/api/middleware/request_logger.py +88 -0
  80. isa_model/serving/api/routes/__init__.py +5 -0
  81. isa_model/serving/api/routes/health.py +82 -0
  82. isa_model/serving/api/routes/llm.py +19 -0
  83. isa_model/serving/api/routes/ui_analysis.py +223 -0
  84. isa_model/serving/api/routes/unified.py +202 -0
  85. isa_model/serving/api/routes/vision.py +19 -0
  86. isa_model/serving/api/schemas/__init__.py +17 -0
  87. isa_model/serving/api/schemas/common.py +33 -0
  88. isa_model/serving/api/schemas/ui_analysis.py +78 -0
  89. {isa_model-0.3.4.dist-info → isa_model-0.3.6.dist-info}/METADATA +4 -1
  90. isa_model-0.3.6.dist-info/RECORD +147 -0
  91. isa_model/core/model_manager.py +0 -208
  92. isa_model/core/model_registry.py +0 -342
  93. isa_model/inference/billing_tracker.py +0 -406
  94. isa_model/inference/services/llm/triton_llm_service.py +0 -481
  95. isa_model/inference/services/vision/ollama_vision_service.py +0 -194
  96. isa_model-0.3.4.dist-info/RECORD +0 -91
  97. /isa_model/core/{model_storage.py → models/model_storage.py} +0 -0
  98. /isa_model/inference/services/{vision → embedding}/helpers/text_splitter.py +0 -0
  99. {isa_model-0.3.4.dist-info → isa_model-0.3.6.dist-info}/WHEEL +0 -0
  100. {isa_model-0.3.4.dist-info → isa_model-0.3.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,343 @@
1
+ """
2
+ Unified Model Registry with Supabase Backend
3
+
4
+ Simplified architecture using only Supabase for model metadata and capabilities.
5
+ No SQLite support - uses unified configuration management.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ import logging
11
+ from typing import Dict, List, Optional, Any
12
+ from enum import Enum
13
+ from datetime import datetime
14
+
15
+ try:
16
+ from supabase import create_client, Client
17
+ SUPABASE_AVAILABLE = True
18
+ except ImportError:
19
+ SUPABASE_AVAILABLE = False
20
+
21
+ from ..config import ConfigManager
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ class ModelCapability(str, Enum):
26
+ """Model capabilities"""
27
+ TEXT_GENERATION = "text_generation"
28
+ CHAT = "chat"
29
+ EMBEDDING = "embedding"
30
+ RERANKING = "reranking"
31
+ REASONING = "reasoning"
32
+ IMAGE_GENERATION = "image_generation"
33
+ IMAGE_ANALYSIS = "image_analysis"
34
+ AUDIO_TRANSCRIPTION = "audio_transcription"
35
+ IMAGE_UNDERSTANDING = "image_understanding"
36
+ UI_DETECTION = "ui_detection"
37
+ OCR = "ocr"
38
+ TABLE_DETECTION = "table_detection"
39
+ TABLE_STRUCTURE_RECOGNITION = "table_structure_recognition"
40
+
41
+ class ModelType(str, Enum):
42
+ """Model types"""
43
+ LLM = "llm"
44
+ EMBEDDING = "embedding"
45
+ RERANK = "rerank"
46
+ IMAGE = "image"
47
+ AUDIO = "audio"
48
+ VIDEO = "video"
49
+ VISION = "vision"
50
+
51
+ class ModelRegistry:
52
+ """Unified Model Registry with Supabase backend"""
53
+
54
+ def __init__(self):
55
+ if not SUPABASE_AVAILABLE:
56
+ raise ImportError("supabase-py is required. Install with: pip install supabase")
57
+
58
+ # Get configuration from unified ConfigManager
59
+ self.config_manager = ConfigManager()
60
+ global_config = self.config_manager.get_global_config()
61
+
62
+ # Get Supabase configuration from database config
63
+ self.supabase_url = global_config.database.supabase_url or os.getenv("SUPABASE_URL")
64
+ self.supabase_key = global_config.database.supabase_key or os.getenv("SUPABASE_ANON_KEY") or os.getenv("SERVICE_ROLE_KEY")
65
+
66
+ if not self.supabase_url or not self.supabase_key:
67
+ raise ValueError("SUPABASE_URL and SUPABASE_ANON_KEY (or SERVICE_ROLE_KEY) must be configured")
68
+
69
+ # Initialize Supabase client
70
+ self.supabase: Client = create_client(self.supabase_url, self.supabase_key)
71
+
72
+ # Verify connection
73
+ self._ensure_tables()
74
+
75
+ logger.info("Model registry initialized with Supabase backend")
76
+
77
+ def _ensure_tables(self):
78
+ """Ensure required tables exist in Supabase"""
79
+ try:
80
+ # Check if models table exists by trying to query it
81
+ result = self.supabase.table('models').select('model_id').limit(1).execute()
82
+ logger.debug("Models table verified")
83
+ except Exception as e:
84
+ logger.warning(f"Models table might not exist: {e}")
85
+ # In production, tables should be created via Supabase migrations
86
+
87
+ def register_model(self,
88
+ model_id: str,
89
+ model_type: ModelType,
90
+ capabilities: List[ModelCapability],
91
+ metadata: Dict[str, Any]) -> bool:
92
+ """Register a model with its capabilities and metadata"""
93
+ try:
94
+ current_time = datetime.now().isoformat()
95
+
96
+ # Prepare model data
97
+ model_data = {
98
+ 'model_id': model_id,
99
+ 'model_type': model_type.value,
100
+ 'metadata': json.dumps(metadata),
101
+ 'created_at': current_time,
102
+ 'updated_at': current_time
103
+ }
104
+
105
+ # Insert or update model
106
+ result = self.supabase.table('models').upsert(model_data).execute()
107
+
108
+ if not result.data:
109
+ logger.error(f"Failed to insert model {model_id}")
110
+ return False
111
+
112
+ # Delete existing capabilities
113
+ self.supabase.table('model_capabilities').delete().eq('model_id', model_id).execute()
114
+
115
+ # Insert new capabilities
116
+ if capabilities:
117
+ capability_data = [
118
+ {
119
+ 'model_id': model_id,
120
+ 'capability': capability.value,
121
+ 'created_at': current_time
122
+ }
123
+ for capability in capabilities
124
+ ]
125
+
126
+ cap_result = self.supabase.table('model_capabilities').insert(capability_data).execute()
127
+
128
+ if not cap_result.data:
129
+ logger.error(f"Failed to insert capabilities for {model_id}")
130
+ return False
131
+
132
+ logger.info(f"Successfully registered model {model_id} with {len(capabilities)} capabilities")
133
+ return True
134
+
135
+ except Exception as e:
136
+ logger.error(f"Failed to register model {model_id}: {e}")
137
+ return False
138
+
139
+ def unregister_model(self, model_id: str) -> bool:
140
+ """Unregister a model"""
141
+ try:
142
+ # Delete model (capabilities will be cascade deleted)
143
+ result = self.supabase.table('models').delete().eq('model_id', model_id).execute()
144
+
145
+ if result.data:
146
+ logger.info(f"Unregistered model {model_id}")
147
+ return True
148
+ return False
149
+
150
+ except Exception as e:
151
+ logger.error(f"Failed to unregister model {model_id}: {e}")
152
+ return False
153
+
154
+ def get_model_info(self, model_id: str) -> Optional[Dict[str, Any]]:
155
+ """Get model information"""
156
+ try:
157
+ # Get model info
158
+ model_result = self.supabase.table('models').select('*').eq('model_id', model_id).execute()
159
+
160
+ if not model_result.data:
161
+ return None
162
+
163
+ model_row = model_result.data[0]
164
+
165
+ # Get capabilities
166
+ cap_result = self.supabase.table('model_capabilities').select('capability').eq('model_id', model_id).execute()
167
+ capabilities = [cap['capability'] for cap in cap_result.data]
168
+
169
+ model_info = {
170
+ "model_id": model_row["model_id"],
171
+ "type": model_row["model_type"],
172
+ "capabilities": capabilities,
173
+ "metadata": json.loads(model_row["metadata"]) if model_row["metadata"] else {},
174
+ "created_at": model_row["created_at"],
175
+ "updated_at": model_row["updated_at"]
176
+ }
177
+
178
+ return model_info
179
+
180
+ except Exception as e:
181
+ logger.error(f"Failed to get model info for {model_id}: {e}")
182
+ return None
183
+
184
+ def get_models_by_type(self, model_type: ModelType) -> Dict[str, Dict[str, Any]]:
185
+ """Get all models of a specific type"""
186
+ try:
187
+ models_result = self.supabase.table('models').select('*').eq('model_type', model_type.value).execute()
188
+
189
+ result = {}
190
+ for model in models_result.data:
191
+ model_id = model["model_id"]
192
+
193
+ # Get capabilities for this model
194
+ cap_result = self.supabase.table('model_capabilities').select('capability').eq('model_id', model_id).execute()
195
+ capabilities = [cap['capability'] for cap in cap_result.data]
196
+
197
+ result[model_id] = {
198
+ "type": model["model_type"],
199
+ "capabilities": capabilities,
200
+ "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
201
+ "created_at": model["created_at"],
202
+ "updated_at": model["updated_at"]
203
+ }
204
+
205
+ return result
206
+
207
+ except Exception as e:
208
+ logger.error(f"Failed to get models by type {model_type}: {e}")
209
+ return {}
210
+
211
+ def get_models_by_capability(self, capability: ModelCapability) -> Dict[str, Dict[str, Any]]:
212
+ """Get all models with a specific capability"""
213
+ try:
214
+ # Get model IDs with specific capability
215
+ cap_result = self.supabase.table('model_capabilities').select('model_id').eq('capability', capability.value).execute()
216
+ model_ids = [row['model_id'] for row in cap_result.data]
217
+
218
+ if not model_ids:
219
+ return {}
220
+
221
+ # Get model details
222
+ models_result = self.supabase.table('models').select('*').in_('model_id', model_ids).execute()
223
+
224
+ result = {}
225
+ for model in models_result.data:
226
+ model_id = model["model_id"]
227
+
228
+ # Get all capabilities for this model
229
+ all_caps_result = self.supabase.table('model_capabilities').select('capability').eq('model_id', model_id).execute()
230
+ capabilities = [cap['capability'] for cap in all_caps_result.data]
231
+
232
+ result[model_id] = {
233
+ "type": model["model_type"],
234
+ "capabilities": capabilities,
235
+ "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
236
+ "created_at": model["created_at"],
237
+ "updated_at": model["updated_at"]
238
+ }
239
+
240
+ return result
241
+
242
+ except Exception as e:
243
+ logger.error(f"Failed to get models by capability {capability}: {e}")
244
+ return {}
245
+
246
+ def has_capability(self, model_id: str, capability: ModelCapability) -> bool:
247
+ """Check if a model has a specific capability"""
248
+ try:
249
+ result = self.supabase.table('model_capabilities').select('model_id').eq('model_id', model_id).eq('capability', capability.value).execute()
250
+
251
+ return len(result.data) > 0
252
+
253
+ except Exception as e:
254
+ logger.error(f"Failed to check capability for {model_id}: {e}")
255
+ return False
256
+
257
+ def list_models(self) -> Dict[str, Dict[str, Any]]:
258
+ """List all registered models"""
259
+ try:
260
+ models_result = self.supabase.table('models').select('*').order('created_at', desc=True).execute()
261
+
262
+ result = {}
263
+ for model in models_result.data:
264
+ model_id = model["model_id"]
265
+
266
+ # Get capabilities for this model
267
+ cap_result = self.supabase.table('model_capabilities').select('capability').eq('model_id', model_id).execute()
268
+ capabilities = [cap['capability'] for cap in cap_result.data]
269
+
270
+ result[model_id] = {
271
+ "type": model["model_type"],
272
+ "capabilities": capabilities,
273
+ "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
274
+ "created_at": model["created_at"],
275
+ "updated_at": model["updated_at"]
276
+ }
277
+
278
+ return result
279
+
280
+ except Exception as e:
281
+ logger.error(f"Failed to list models: {e}")
282
+ return {}
283
+
284
+ def get_stats(self) -> Dict[str, Any]:
285
+ """Get registry statistics"""
286
+ try:
287
+ # Count total models
288
+ total_result = self.supabase.table('models').select('model_id', count='exact').execute()
289
+ total_models = total_result.count if total_result.count is not None else 0
290
+
291
+ # Count by type (manual aggregation since RPC might not exist)
292
+ models_result = self.supabase.table('models').select('model_type').execute()
293
+ type_counts = {}
294
+ for model in models_result.data:
295
+ model_type = model['model_type']
296
+ type_counts[model_type] = type_counts.get(model_type, 0) + 1
297
+
298
+ # Count by capability
299
+ caps_result = self.supabase.table('model_capabilities').select('capability').execute()
300
+ capability_counts = {}
301
+ for cap in caps_result.data:
302
+ capability = cap['capability']
303
+ capability_counts[capability] = capability_counts.get(capability, 0) + 1
304
+
305
+ return {
306
+ "total_models": total_models,
307
+ "models_by_type": type_counts,
308
+ "models_by_capability": capability_counts
309
+ }
310
+
311
+ except Exception as e:
312
+ logger.error(f"Failed to get stats: {e}")
313
+ return {"total_models": 0, "models_by_type": {}, "models_by_capability": {}}
314
+
315
+ def search_models(self, query: str) -> Dict[str, Dict[str, Any]]:
316
+ """Search models by name or metadata"""
317
+ try:
318
+ # Search in model_id and metadata
319
+ models_result = self.supabase.table('models').select('*').or_(
320
+ f'model_id.ilike.%{query}%,metadata.ilike.%{query}%'
321
+ ).order('created_at', desc=True).execute()
322
+
323
+ result = {}
324
+ for model in models_result.data:
325
+ model_id = model["model_id"]
326
+
327
+ # Get capabilities for this model
328
+ cap_result = self.supabase.table('model_capabilities').select('capability').eq('model_id', model_id).execute()
329
+ capabilities = [cap['capability'] for cap in cap_result.data]
330
+
331
+ result[model_id] = {
332
+ "type": model["model_type"],
333
+ "capabilities": capabilities,
334
+ "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
335
+ "created_at": model["created_at"],
336
+ "updated_at": model["updated_at"]
337
+ }
338
+
339
+ return result
340
+
341
+ except Exception as e:
342
+ logger.error(f"Failed to search models with query '{query}': {e}")
343
+ return {}