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
@@ -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
+ }