isa-model 0.3.9__py3-none-any.whl → 0.4.0__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 (124) hide show
  1. isa_model/__init__.py +1 -1
  2. isa_model/client.py +732 -565
  3. isa_model/core/cache/redis_cache.py +401 -0
  4. isa_model/core/config/config_manager.py +53 -10
  5. isa_model/core/config.py +1 -1
  6. isa_model/core/database/__init__.py +1 -0
  7. isa_model/core/database/migrations.py +277 -0
  8. isa_model/core/database/supabase_client.py +123 -0
  9. isa_model/core/models/__init__.py +37 -0
  10. isa_model/core/models/model_billing_tracker.py +60 -88
  11. isa_model/core/models/model_manager.py +36 -18
  12. isa_model/core/models/model_repo.py +44 -38
  13. isa_model/core/models/model_statistics_tracker.py +234 -0
  14. isa_model/core/models/model_storage.py +0 -1
  15. isa_model/core/models/model_version_manager.py +959 -0
  16. isa_model/core/pricing_manager.py +2 -249
  17. isa_model/core/resilience/circuit_breaker.py +366 -0
  18. isa_model/core/security/secrets.py +358 -0
  19. isa_model/core/services/__init__.py +2 -4
  20. isa_model/core/services/intelligent_model_selector.py +101 -370
  21. isa_model/core/storage/hf_storage.py +1 -1
  22. isa_model/core/types.py +7 -0
  23. isa_model/deployment/cloud/modal/isa_audio_chatTTS_service.py +520 -0
  24. isa_model/deployment/cloud/modal/isa_audio_fish_service.py +0 -0
  25. isa_model/deployment/cloud/modal/isa_audio_openvoice_service.py +758 -0
  26. isa_model/deployment/cloud/modal/isa_audio_service_v2.py +1044 -0
  27. isa_model/deployment/cloud/modal/isa_embed_rerank_service.py +296 -0
  28. isa_model/deployment/cloud/modal/isa_video_hunyuan_service.py +423 -0
  29. isa_model/deployment/cloud/modal/isa_vision_ocr_service.py +519 -0
  30. isa_model/deployment/cloud/modal/isa_vision_qwen25_service.py +709 -0
  31. isa_model/deployment/cloud/modal/isa_vision_table_service.py +467 -323
  32. isa_model/deployment/cloud/modal/isa_vision_ui_service.py +607 -180
  33. isa_model/deployment/cloud/modal/isa_vision_ui_service_optimized.py +660 -0
  34. isa_model/deployment/core/deployment_manager.py +6 -4
  35. isa_model/deployment/services/auto_hf_modal_deployer.py +894 -0
  36. isa_model/eval/benchmarks/__init__.py +27 -0
  37. isa_model/eval/benchmarks/multimodal_datasets.py +460 -0
  38. isa_model/eval/benchmarks.py +244 -12
  39. isa_model/eval/evaluators/__init__.py +8 -2
  40. isa_model/eval/evaluators/audio_evaluator.py +727 -0
  41. isa_model/eval/evaluators/embedding_evaluator.py +742 -0
  42. isa_model/eval/evaluators/vision_evaluator.py +564 -0
  43. isa_model/eval/example_evaluation.py +395 -0
  44. isa_model/eval/factory.py +272 -5
  45. isa_model/eval/isa_benchmarks.py +700 -0
  46. isa_model/eval/isa_integration.py +582 -0
  47. isa_model/eval/metrics.py +159 -6
  48. isa_model/eval/tests/unit/test_basic.py +396 -0
  49. isa_model/inference/ai_factory.py +44 -8
  50. isa_model/inference/services/audio/__init__.py +21 -0
  51. isa_model/inference/services/audio/base_realtime_service.py +225 -0
  52. isa_model/inference/services/audio/isa_tts_service.py +0 -0
  53. isa_model/inference/services/audio/openai_realtime_service.py +320 -124
  54. isa_model/inference/services/audio/openai_stt_service.py +32 -6
  55. isa_model/inference/services/base_service.py +17 -1
  56. isa_model/inference/services/embedding/__init__.py +13 -0
  57. isa_model/inference/services/embedding/base_embed_service.py +111 -8
  58. isa_model/inference/services/embedding/isa_embed_service.py +305 -0
  59. isa_model/inference/services/embedding/openai_embed_service.py +2 -4
  60. isa_model/inference/services/embedding/tests/test_embedding.py +222 -0
  61. isa_model/inference/services/img/__init__.py +2 -2
  62. isa_model/inference/services/img/base_image_gen_service.py +24 -7
  63. isa_model/inference/services/img/replicate_image_gen_service.py +84 -422
  64. isa_model/inference/services/img/services/replicate_face_swap.py +193 -0
  65. isa_model/inference/services/img/services/replicate_flux.py +226 -0
  66. isa_model/inference/services/img/services/replicate_flux_kontext.py +219 -0
  67. isa_model/inference/services/img/services/replicate_sticker_maker.py +249 -0
  68. isa_model/inference/services/img/tests/test_img_client.py +297 -0
  69. isa_model/inference/services/llm/base_llm_service.py +30 -6
  70. isa_model/inference/services/llm/helpers/llm_adapter.py +63 -9
  71. isa_model/inference/services/llm/ollama_llm_service.py +2 -1
  72. isa_model/inference/services/llm/openai_llm_service.py +652 -55
  73. isa_model/inference/services/llm/yyds_llm_service.py +2 -1
  74. isa_model/inference/services/vision/__init__.py +5 -5
  75. isa_model/inference/services/vision/base_vision_service.py +118 -185
  76. isa_model/inference/services/vision/helpers/image_utils.py +11 -5
  77. isa_model/inference/services/vision/isa_vision_service.py +573 -0
  78. isa_model/inference/services/vision/tests/test_ocr_client.py +284 -0
  79. isa_model/serving/api/fastapi_server.py +88 -16
  80. isa_model/serving/api/middleware/auth.py +311 -0
  81. isa_model/serving/api/middleware/security.py +278 -0
  82. isa_model/serving/api/routes/analytics.py +486 -0
  83. isa_model/serving/api/routes/deployments.py +339 -0
  84. isa_model/serving/api/routes/evaluations.py +579 -0
  85. isa_model/serving/api/routes/logs.py +430 -0
  86. isa_model/serving/api/routes/settings.py +582 -0
  87. isa_model/serving/api/routes/unified.py +324 -165
  88. isa_model/serving/api/startup.py +304 -0
  89. isa_model/serving/modal_proxy_server.py +249 -0
  90. isa_model/training/__init__.py +100 -6
  91. isa_model/training/core/__init__.py +4 -1
  92. isa_model/training/examples/intelligent_training_example.py +281 -0
  93. isa_model/training/intelligent/__init__.py +25 -0
  94. isa_model/training/intelligent/decision_engine.py +643 -0
  95. isa_model/training/intelligent/intelligent_factory.py +888 -0
  96. isa_model/training/intelligent/knowledge_base.py +751 -0
  97. isa_model/training/intelligent/resource_optimizer.py +839 -0
  98. isa_model/training/intelligent/task_classifier.py +576 -0
  99. isa_model/training/storage/__init__.py +24 -0
  100. isa_model/training/storage/core_integration.py +439 -0
  101. isa_model/training/storage/training_repository.py +552 -0
  102. isa_model/training/storage/training_storage.py +628 -0
  103. {isa_model-0.3.9.dist-info → isa_model-0.4.0.dist-info}/METADATA +13 -1
  104. isa_model-0.4.0.dist-info/RECORD +182 -0
  105. isa_model/deployment/cloud/modal/isa_vision_doc_service.py +0 -766
  106. isa_model/deployment/cloud/modal/register_models.py +0 -321
  107. isa_model/inference/adapter/unified_api.py +0 -248
  108. isa_model/inference/services/helpers/stacked_config.py +0 -148
  109. isa_model/inference/services/img/flux_professional_service.py +0 -603
  110. isa_model/inference/services/img/helpers/base_stacked_service.py +0 -274
  111. isa_model/inference/services/others/table_transformer_service.py +0 -61
  112. isa_model/inference/services/vision/doc_analysis_service.py +0 -640
  113. isa_model/inference/services/vision/helpers/base_stacked_service.py +0 -274
  114. isa_model/inference/services/vision/ui_analysis_service.py +0 -823
  115. isa_model/scripts/inference_tracker.py +0 -283
  116. isa_model/scripts/mlflow_manager.py +0 -379
  117. isa_model/scripts/model_registry.py +0 -465
  118. isa_model/scripts/register_models.py +0 -370
  119. isa_model/scripts/register_models_with_embeddings.py +0 -510
  120. isa_model/scripts/start_mlflow.py +0 -95
  121. isa_model/scripts/training_tracker.py +0 -257
  122. isa_model-0.3.9.dist-info/RECORD +0 -138
  123. {isa_model-0.3.9.dist-info → isa_model-0.4.0.dist-info}/WHEEL +0 -0
  124. {isa_model-0.3.9.dist-info → isa_model-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,430 @@
1
+ """
2
+ Logs API Routes
3
+
4
+ Handles log retrieval, filtering, and streaming for the ISA Model Platform
5
+ """
6
+
7
+ from fastapi import APIRouter, Query, HTTPException
8
+ from pydantic import BaseModel
9
+ from typing import Optional, List, Dict, Any, Union
10
+ import logging
11
+ import time
12
+ import json
13
+ from datetime import datetime, timedelta
14
+ from collections import defaultdict
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ router = APIRouter()
19
+
20
+ # In-memory log storage (in production, use a proper logging system like ELK, Grafana Loki, etc.)
21
+ logs_storage = []
22
+ max_logs = 10000 # Limit logs in memory
23
+
24
+ class LogEntry(BaseModel):
25
+ timestamp: float
26
+ level: str
27
+ service: str
28
+ component: Optional[str] = None
29
+ message: str
30
+ request_id: Optional[str] = None
31
+ duration: Optional[float] = None
32
+ details: Optional[Dict[str, Any]] = None
33
+ stack_trace: Optional[str] = None
34
+
35
+ class LogFilter(BaseModel):
36
+ level: Optional[str] = None
37
+ service: Optional[str] = None
38
+ component: Optional[str] = None
39
+ time_range: Optional[str] = "24h"
40
+ since: Optional[float] = None
41
+ limit: Optional[int] = 1000
42
+ search: Optional[str] = None
43
+
44
+ def add_log_entry(
45
+ level: str,
46
+ service: str,
47
+ message: str,
48
+ component: Optional[str] = None,
49
+ request_id: Optional[str] = None,
50
+ duration: Optional[float] = None,
51
+ details: Optional[Dict[str, Any]] = None,
52
+ stack_trace: Optional[str] = None
53
+ ):
54
+ """Add a log entry to the storage"""
55
+ global logs_storage
56
+
57
+ log_entry = {
58
+ "timestamp": time.time() * 1000, # Convert to milliseconds
59
+ "level": level,
60
+ "service": service,
61
+ "component": component,
62
+ "message": message,
63
+ "request_id": request_id,
64
+ "duration": duration,
65
+ "details": details,
66
+ "stack_trace": stack_trace
67
+ }
68
+
69
+ # Add to beginning of list (newest first)
70
+ logs_storage.insert(0, log_entry)
71
+
72
+ # Limit storage size
73
+ if len(logs_storage) > max_logs:
74
+ logs_storage = logs_storage[:max_logs]
75
+
76
+ def get_time_range_timestamp(time_range: str) -> float:
77
+ """Convert time range string to timestamp"""
78
+ now = time.time() * 1000
79
+
80
+ time_ranges = {
81
+ "1h": now - (1 * 60 * 60 * 1000),
82
+ "6h": now - (6 * 60 * 60 * 1000),
83
+ "24h": now - (24 * 60 * 60 * 1000),
84
+ "7d": now - (7 * 24 * 60 * 60 * 1000),
85
+ "30d": now - (30 * 24 * 60 * 60 * 1000)
86
+ }
87
+
88
+ return time_ranges.get(time_range, now - (24 * 60 * 60 * 1000))
89
+
90
+ def filter_logs(logs: List[Dict], filters: LogFilter) -> List[Dict]:
91
+ """Apply filters to log list"""
92
+ filtered_logs = logs
93
+
94
+ # Time range filter
95
+ if filters.time_range:
96
+ since_timestamp = get_time_range_timestamp(filters.time_range)
97
+ filtered_logs = [log for log in filtered_logs if log["timestamp"] >= since_timestamp]
98
+
99
+ # Since timestamp filter (for streaming)
100
+ if filters.since:
101
+ filtered_logs = [log for log in filtered_logs if log["timestamp"] > filters.since]
102
+
103
+ # Level filter
104
+ if filters.level:
105
+ filtered_logs = [log for log in filtered_logs if log["level"] == filters.level]
106
+
107
+ # Service filter
108
+ if filters.service:
109
+ filtered_logs = [log for log in filtered_logs if log["service"] == filters.service]
110
+
111
+ # Component filter
112
+ if filters.component:
113
+ filtered_logs = [log for log in filtered_logs if log.get("component") == filters.component]
114
+
115
+ # Search filter
116
+ if filters.search:
117
+ search_term = filters.search.lower()
118
+ filtered_logs = [
119
+ log for log in filtered_logs
120
+ if search_term in log["message"].lower() or
121
+ search_term in log["service"].lower() or
122
+ (log.get("component") and search_term in log["component"].lower())
123
+ ]
124
+
125
+ # Limit results
126
+ if filters.limit:
127
+ filtered_logs = filtered_logs[:filters.limit]
128
+
129
+ return filtered_logs
130
+
131
+ @router.get("/")
132
+ async def get_logs(
133
+ level: Optional[str] = Query(None, description="Filter by log level"),
134
+ service: Optional[str] = Query(None, description="Filter by service"),
135
+ component: Optional[str] = Query(None, description="Filter by component"),
136
+ time_range: Optional[str] = Query("24h", description="Time range (1h, 6h, 24h, 7d, 30d)"),
137
+ limit: Optional[int] = Query(1000, description="Maximum number of logs"),
138
+ search: Optional[str] = Query(None, description="Search term")
139
+ ):
140
+ """
141
+ Get filtered logs
142
+ """
143
+ try:
144
+ filters = LogFilter(
145
+ level=level,
146
+ service=service,
147
+ component=component,
148
+ time_range=time_range,
149
+ limit=limit,
150
+ search=search
151
+ )
152
+
153
+ # If no logs in storage, generate some sample logs
154
+ if not logs_storage:
155
+ populate_sample_logs()
156
+
157
+ filtered_logs = filter_logs(logs_storage, filters)
158
+
159
+ return {
160
+ "logs": filtered_logs,
161
+ "total": len(logs_storage),
162
+ "filtered": len(filtered_logs),
163
+ "filters": filters.dict()
164
+ }
165
+
166
+ except Exception as e:
167
+ logger.error(f"Error retrieving logs: {e}")
168
+ raise HTTPException(status_code=500, detail=f"Failed to retrieve logs: {str(e)}")
169
+
170
+ @router.get("/stream")
171
+ async def get_logs_stream(
172
+ since: Optional[float] = Query(None, description="Get logs since timestamp"),
173
+ level: Optional[str] = Query(None, description="Filter by log level"),
174
+ service: Optional[str] = Query(None, description="Filter by service"),
175
+ limit: Optional[int] = Query(50, description="Maximum number of logs")
176
+ ):
177
+ """
178
+ Get new logs for streaming (since a specific timestamp)
179
+ """
180
+ try:
181
+ filters = LogFilter(
182
+ level=level,
183
+ service=service,
184
+ since=since,
185
+ limit=limit
186
+ )
187
+
188
+ # Generate some new sample logs periodically
189
+ if len(logs_storage) < 20:
190
+ add_sample_log()
191
+
192
+ filtered_logs = filter_logs(logs_storage, filters)
193
+
194
+ return filtered_logs
195
+
196
+ except Exception as e:
197
+ logger.error(f"Error streaming logs: {e}")
198
+ raise HTTPException(status_code=500, detail=f"Failed to stream logs: {str(e)}")
199
+
200
+ @router.post("/")
201
+ async def add_log(log_entry: LogEntry):
202
+ """
203
+ Add a new log entry
204
+ """
205
+ try:
206
+ add_log_entry(
207
+ level=log_entry.level,
208
+ service=log_entry.service,
209
+ message=log_entry.message,
210
+ component=log_entry.component,
211
+ request_id=log_entry.request_id,
212
+ duration=log_entry.duration,
213
+ details=log_entry.details,
214
+ stack_trace=log_entry.stack_trace
215
+ )
216
+
217
+ return {"success": True, "message": "Log entry added"}
218
+
219
+ except Exception as e:
220
+ logger.error(f"Error adding log entry: {e}")
221
+ raise HTTPException(status_code=500, detail=f"Failed to add log entry: {str(e)}")
222
+
223
+ @router.get("/stats")
224
+ async def get_log_stats():
225
+ """
226
+ Get log statistics
227
+ """
228
+ try:
229
+ if not logs_storage:
230
+ populate_sample_logs()
231
+
232
+ # Calculate statistics
233
+ one_hour_ago = time.time() * 1000 - (60 * 60 * 1000)
234
+
235
+ stats = {
236
+ "total_logs": len(logs_storage),
237
+ "logs_last_hour": len([log for log in logs_storage if log["timestamp"] > one_hour_ago]),
238
+ "by_level": defaultdict(int),
239
+ "by_service": defaultdict(int),
240
+ "errors_last_hour": 0,
241
+ "warnings_last_hour": 0
242
+ }
243
+
244
+ for log in logs_storage:
245
+ stats["by_level"][log["level"]] += 1
246
+ stats["by_service"][log["service"]] += 1
247
+
248
+ if log["timestamp"] > one_hour_ago:
249
+ if log["level"] == "ERROR":
250
+ stats["errors_last_hour"] += 1
251
+ elif log["level"] == "WARNING":
252
+ stats["warnings_last_hour"] += 1
253
+
254
+ # Convert defaultdict to regular dict for JSON serialization
255
+ stats["by_level"] = dict(stats["by_level"])
256
+ stats["by_service"] = dict(stats["by_service"])
257
+
258
+ return stats
259
+
260
+ except Exception as e:
261
+ logger.error(f"Error getting log stats: {e}")
262
+ raise HTTPException(status_code=500, detail=f"Failed to get log stats: {str(e)}")
263
+
264
+ @router.delete("/")
265
+ async def clear_logs():
266
+ """
267
+ Clear all logs
268
+ """
269
+ try:
270
+ global logs_storage
271
+ logs_storage = []
272
+
273
+ return {"success": True, "message": "All logs cleared"}
274
+
275
+ except Exception as e:
276
+ logger.error(f"Error clearing logs: {e}")
277
+ raise HTTPException(status_code=500, detail=f"Failed to clear logs: {str(e)}")
278
+
279
+ def populate_sample_logs():
280
+ """Populate storage with sample logs for demonstration"""
281
+ sample_logs = [
282
+ {
283
+ "level": "INFO",
284
+ "service": "api",
285
+ "component": "fastapi",
286
+ "message": "FastAPI server started successfully",
287
+ "request_id": "req_001",
288
+ "duration": 125
289
+ },
290
+ {
291
+ "level": "INFO",
292
+ "service": "deployments",
293
+ "component": "deployer",
294
+ "message": "HuggingFace model analysis completed for microsoft/DialoGPT-medium",
295
+ "request_id": "dep_001",
296
+ "details": {
297
+ "model_id": "microsoft/DialoGPT-medium",
298
+ "model_type": "text",
299
+ "gpu_requirements": "A10G",
300
+ "estimated_cost": 1.20
301
+ }
302
+ },
303
+ {
304
+ "level": "WARNING",
305
+ "service": "api",
306
+ "component": "middleware",
307
+ "message": "High request rate detected from client 192.168.1.100",
308
+ "request_id": "req_002",
309
+ "details": {
310
+ "client_ip": "192.168.1.100",
311
+ "requests_per_minute": 120,
312
+ "threshold": 100
313
+ }
314
+ },
315
+ {
316
+ "level": "ERROR",
317
+ "service": "deployments",
318
+ "component": "modal",
319
+ "message": "Failed to deploy model: insufficient GPU resources",
320
+ "request_id": "dep_002",
321
+ "details": {
322
+ "model_id": "meta-llama/Llama-2-70b-chat-hf",
323
+ "required_gpu": "A100-80GB",
324
+ "available_gpu": "A10G-24GB"
325
+ },
326
+ "stack_trace": "Traceback (most recent call last):\n File \"modal_deployer.py\", line 45, in deploy\n raise InsufficientResourcesError(\"GPU resources unavailable\")\nInsufficientResourcesError: GPU resources unavailable"
327
+ },
328
+ {
329
+ "level": "INFO",
330
+ "service": "models",
331
+ "component": "registry",
332
+ "message": "Model registry updated with 3 new models",
333
+ "request_id": "mod_001",
334
+ "details": {
335
+ "new_models": ["Qwen/Qwen2-VL-7B-Instruct", "BAAI/bge-base-en-v1.5", "openai/whisper-large-v3"],
336
+ "total_models": 156
337
+ }
338
+ },
339
+ {
340
+ "level": "DEBUG",
341
+ "service": "api",
342
+ "component": "auth",
343
+ "message": "User authentication successful",
344
+ "request_id": "auth_001",
345
+ "details": {
346
+ "user_id": "user_123",
347
+ "method": "api_key",
348
+ "permissions": ["read", "deploy"]
349
+ }
350
+ },
351
+ {
352
+ "level": "INFO",
353
+ "service": "api",
354
+ "component": "models",
355
+ "message": "Model inference request completed",
356
+ "request_id": "inf_001",
357
+ "duration": 245,
358
+ "details": {
359
+ "model": "gpt-4-turbo",
360
+ "tokens": 150,
361
+ "cost": 0.003
362
+ }
363
+ },
364
+ {
365
+ "level": "WARNING",
366
+ "service": "system",
367
+ "component": "monitoring",
368
+ "message": "High memory usage detected",
369
+ "details": {
370
+ "memory_usage": "85%",
371
+ "threshold": "80%",
372
+ "service": "deployments"
373
+ }
374
+ }
375
+ ]
376
+
377
+ current_time = time.time() * 1000
378
+
379
+ for i, log in enumerate(sample_logs):
380
+ add_log_entry(
381
+ level=log["level"],
382
+ service=log["service"],
383
+ message=log["message"],
384
+ component=log.get("component"),
385
+ request_id=log.get("request_id"),
386
+ duration=log.get("duration"),
387
+ details=log.get("details"),
388
+ stack_trace=log.get("stack_trace")
389
+ )
390
+
391
+ # Adjust timestamps to be recent
392
+ logs_storage[i]["timestamp"] = current_time - (i * 5000) # 5 seconds apart
393
+
394
+ def add_sample_log():
395
+ """Add a new sample log entry for live streaming demo"""
396
+ import random
397
+
398
+ sample_messages = [
399
+ ("INFO", "api", "HTTP request processed", "fastapi", {"status": 200, "path": "/api/v1/models"}),
400
+ ("INFO", "deployments", "Model deployment started", "deployer", {"model": "BAAI/bge-base-en-v1.5"}),
401
+ ("WARNING", "api", "Rate limiting applied", "middleware", {"client": "192.168.1.50", "rate": 105}),
402
+ ("DEBUG", "models", "Model cache hit", "registry", {"model": "gpt-4-turbo", "cache_size": "2.1GB"}),
403
+ ("INFO", "system", "Health check completed", "monitor", {"status": "healthy", "services": 5}),
404
+ ("ERROR", "deployments", "Model loading failed", "loader", {"model": "invalid/model-id", "error": "not found"}),
405
+ ]
406
+
407
+ level, service, message, component, details = random.choice(sample_messages)
408
+ request_id = f"req_{random.randint(1000, 9999)}"
409
+ duration = random.randint(50, 500) if level == "INFO" else None
410
+
411
+ add_log_entry(
412
+ level=level,
413
+ service=service,
414
+ message=message,
415
+ component=component,
416
+ request_id=request_id,
417
+ duration=duration,
418
+ details=details
419
+ )
420
+
421
+ # Health check for logs service
422
+ @router.get("/health")
423
+ async def logs_health():
424
+ """Health check for logs service"""
425
+ return {
426
+ "status": "healthy",
427
+ "service": "logs",
428
+ "total_logs": len(logs_storage),
429
+ "memory_usage": f"{len(logs_storage)}/{max_logs} logs"
430
+ }