isa-model 0.3.91__py3-none-any.whl → 0.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- isa_model/client.py +1166 -584
- isa_model/core/cache/redis_cache.py +410 -0
- isa_model/core/config/config_manager.py +282 -12
- isa_model/core/config.py +91 -1
- isa_model/core/database/__init__.py +1 -0
- isa_model/core/database/direct_db_client.py +114 -0
- isa_model/core/database/migration_manager.py +563 -0
- isa_model/core/database/migrations.py +297 -0
- isa_model/core/database/supabase_client.py +258 -0
- isa_model/core/dependencies.py +316 -0
- isa_model/core/discovery/__init__.py +19 -0
- isa_model/core/discovery/consul_discovery.py +190 -0
- isa_model/core/logging/__init__.py +54 -0
- isa_model/core/logging/influx_logger.py +523 -0
- isa_model/core/logging/loki_logger.py +160 -0
- isa_model/core/models/__init__.py +46 -0
- isa_model/core/models/config_models.py +625 -0
- isa_model/core/models/deployment_billing_tracker.py +430 -0
- isa_model/core/models/model_billing_tracker.py +60 -88
- isa_model/core/models/model_manager.py +66 -25
- isa_model/core/models/model_metadata.py +690 -0
- isa_model/core/models/model_repo.py +217 -55
- isa_model/core/models/model_statistics_tracker.py +234 -0
- isa_model/core/models/model_storage.py +0 -1
- isa_model/core/models/model_version_manager.py +959 -0
- isa_model/core/models/system_models.py +857 -0
- isa_model/core/pricing_manager.py +2 -249
- isa_model/core/repositories/__init__.py +9 -0
- isa_model/core/repositories/config_repository.py +912 -0
- isa_model/core/resilience/circuit_breaker.py +366 -0
- isa_model/core/security/secrets.py +358 -0
- isa_model/core/services/__init__.py +2 -4
- isa_model/core/services/intelligent_model_selector.py +479 -370
- isa_model/core/storage/hf_storage.py +2 -2
- isa_model/core/types.py +8 -0
- isa_model/deployment/__init__.py +5 -48
- isa_model/deployment/core/__init__.py +2 -31
- isa_model/deployment/core/deployment_manager.py +1278 -368
- isa_model/deployment/local/__init__.py +31 -0
- isa_model/deployment/local/config.py +248 -0
- isa_model/deployment/local/gpu_gateway.py +607 -0
- isa_model/deployment/local/health_checker.py +428 -0
- isa_model/deployment/local/provider.py +586 -0
- isa_model/deployment/local/tensorrt_service.py +621 -0
- isa_model/deployment/local/transformers_service.py +644 -0
- isa_model/deployment/local/vllm_service.py +527 -0
- isa_model/deployment/modal/__init__.py +8 -0
- isa_model/deployment/modal/config.py +136 -0
- isa_model/deployment/modal/deployer.py +894 -0
- isa_model/deployment/modal/services/__init__.py +3 -0
- isa_model/deployment/modal/services/audio/__init__.py +1 -0
- isa_model/deployment/modal/services/audio/isa_audio_chatTTS_service.py +520 -0
- isa_model/deployment/modal/services/audio/isa_audio_openvoice_service.py +758 -0
- isa_model/deployment/modal/services/audio/isa_audio_service_v2.py +1044 -0
- isa_model/deployment/modal/services/embedding/__init__.py +1 -0
- isa_model/deployment/modal/services/embedding/isa_embed_rerank_service.py +296 -0
- isa_model/deployment/modal/services/llm/__init__.py +1 -0
- isa_model/deployment/modal/services/llm/isa_llm_service.py +424 -0
- isa_model/deployment/modal/services/video/__init__.py +1 -0
- isa_model/deployment/modal/services/video/isa_video_hunyuan_service.py +423 -0
- isa_model/deployment/modal/services/vision/__init__.py +1 -0
- isa_model/deployment/modal/services/vision/isa_vision_ocr_service.py +519 -0
- isa_model/deployment/modal/services/vision/isa_vision_qwen25_service.py +709 -0
- isa_model/deployment/modal/services/vision/isa_vision_table_service.py +676 -0
- isa_model/deployment/modal/services/vision/isa_vision_ui_service.py +833 -0
- isa_model/deployment/modal/services/vision/isa_vision_ui_service_optimized.py +660 -0
- isa_model/deployment/models/org-org-acme-corp-tenant-a-service-llm-20250825-225822/tenant-a-service_modal_service.py +48 -0
- isa_model/deployment/models/org-test-org-123-prefix-test-service-llm-20250825-225822/prefix-test-service_modal_service.py +48 -0
- isa_model/deployment/models/test-llm-service-llm-20250825-204442/test-llm-service_modal_service.py +48 -0
- isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-212906/test-monitoring-gpt2_modal_service.py +48 -0
- isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-213009/test-monitoring-gpt2_modal_service.py +48 -0
- isa_model/deployment/storage/__init__.py +5 -0
- isa_model/deployment/storage/deployment_repository.py +824 -0
- isa_model/deployment/triton/__init__.py +10 -0
- isa_model/deployment/triton/config.py +196 -0
- isa_model/deployment/triton/configs/__init__.py +1 -0
- isa_model/deployment/triton/provider.py +512 -0
- isa_model/deployment/triton/scripts/__init__.py +1 -0
- isa_model/deployment/triton/templates/__init__.py +1 -0
- isa_model/inference/__init__.py +47 -1
- isa_model/inference/ai_factory.py +179 -16
- isa_model/inference/legacy_services/__init__.py +21 -0
- isa_model/inference/legacy_services/model_evaluation.py +637 -0
- isa_model/inference/legacy_services/model_service.py +573 -0
- isa_model/inference/legacy_services/model_serving.py +717 -0
- isa_model/inference/legacy_services/model_training.py +561 -0
- isa_model/inference/models/__init__.py +21 -0
- isa_model/inference/models/inference_config.py +551 -0
- isa_model/inference/models/inference_record.py +675 -0
- isa_model/inference/models/performance_models.py +714 -0
- isa_model/inference/repositories/__init__.py +9 -0
- isa_model/inference/repositories/inference_repository.py +828 -0
- isa_model/inference/services/audio/__init__.py +21 -0
- isa_model/inference/services/audio/base_realtime_service.py +225 -0
- isa_model/inference/services/audio/base_stt_service.py +184 -11
- isa_model/inference/services/audio/isa_tts_service.py +0 -0
- isa_model/inference/services/audio/openai_realtime_service.py +320 -124
- isa_model/inference/services/audio/openai_stt_service.py +53 -11
- isa_model/inference/services/base_service.py +17 -1
- isa_model/inference/services/custom_model_manager.py +277 -0
- isa_model/inference/services/embedding/__init__.py +13 -0
- isa_model/inference/services/embedding/base_embed_service.py +111 -8
- isa_model/inference/services/embedding/isa_embed_service.py +305 -0
- isa_model/inference/services/embedding/ollama_embed_service.py +15 -3
- isa_model/inference/services/embedding/openai_embed_service.py +2 -4
- isa_model/inference/services/embedding/resilient_embed_service.py +285 -0
- isa_model/inference/services/embedding/tests/test_embedding.py +222 -0
- isa_model/inference/services/img/__init__.py +2 -2
- isa_model/inference/services/img/base_image_gen_service.py +24 -7
- isa_model/inference/services/img/replicate_image_gen_service.py +84 -422
- isa_model/inference/services/img/services/replicate_face_swap.py +193 -0
- isa_model/inference/services/img/services/replicate_flux.py +226 -0
- isa_model/inference/services/img/services/replicate_flux_kontext.py +219 -0
- isa_model/inference/services/img/services/replicate_sticker_maker.py +249 -0
- isa_model/inference/services/img/tests/test_img_client.py +297 -0
- isa_model/inference/services/llm/__init__.py +10 -2
- isa_model/inference/services/llm/base_llm_service.py +361 -26
- isa_model/inference/services/llm/cerebras_llm_service.py +628 -0
- isa_model/inference/services/llm/helpers/llm_adapter.py +71 -12
- isa_model/inference/services/llm/helpers/llm_prompts.py +342 -0
- isa_model/inference/services/llm/helpers/llm_utils.py +321 -23
- isa_model/inference/services/llm/huggingface_llm_service.py +581 -0
- isa_model/inference/services/llm/local_llm_service.py +747 -0
- isa_model/inference/services/llm/ollama_llm_service.py +11 -3
- isa_model/inference/services/llm/openai_llm_service.py +670 -56
- isa_model/inference/services/llm/yyds_llm_service.py +10 -3
- isa_model/inference/services/vision/__init__.py +27 -6
- isa_model/inference/services/vision/base_vision_service.py +118 -185
- isa_model/inference/services/vision/blip_vision_service.py +359 -0
- isa_model/inference/services/vision/helpers/image_utils.py +19 -10
- isa_model/inference/services/vision/isa_vision_service.py +634 -0
- isa_model/inference/services/vision/openai_vision_service.py +19 -10
- isa_model/inference/services/vision/tests/test_ocr_client.py +284 -0
- isa_model/inference/services/vision/vgg16_vision_service.py +257 -0
- isa_model/serving/api/cache_manager.py +245 -0
- isa_model/serving/api/dependencies/__init__.py +1 -0
- isa_model/serving/api/dependencies/auth.py +194 -0
- isa_model/serving/api/dependencies/database.py +139 -0
- isa_model/serving/api/error_handlers.py +284 -0
- isa_model/serving/api/fastapi_server.py +240 -18
- isa_model/serving/api/middleware/auth.py +317 -0
- isa_model/serving/api/middleware/security.py +268 -0
- isa_model/serving/api/middleware/tenant_context.py +414 -0
- isa_model/serving/api/routes/analytics.py +489 -0
- isa_model/serving/api/routes/config.py +645 -0
- isa_model/serving/api/routes/deployment_billing.py +315 -0
- isa_model/serving/api/routes/deployments.py +475 -0
- isa_model/serving/api/routes/gpu_gateway.py +440 -0
- isa_model/serving/api/routes/health.py +32 -12
- isa_model/serving/api/routes/inference_monitoring.py +486 -0
- isa_model/serving/api/routes/local_deployments.py +448 -0
- isa_model/serving/api/routes/logs.py +430 -0
- isa_model/serving/api/routes/settings.py +582 -0
- isa_model/serving/api/routes/tenants.py +575 -0
- isa_model/serving/api/routes/unified.py +992 -171
- isa_model/serving/api/routes/webhooks.py +479 -0
- isa_model/serving/api/startup.py +318 -0
- isa_model/serving/modal_proxy_server.py +249 -0
- isa_model/utils/gpu_utils.py +311 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/METADATA +76 -22
- isa_model-0.4.3.dist-info/RECORD +193 -0
- isa_model/deployment/cloud/__init__.py +0 -9
- isa_model/deployment/cloud/modal/__init__.py +0 -10
- isa_model/deployment/cloud/modal/isa_vision_doc_service.py +0 -766
- isa_model/deployment/cloud/modal/isa_vision_table_service.py +0 -532
- isa_model/deployment/cloud/modal/isa_vision_ui_service.py +0 -406
- isa_model/deployment/cloud/modal/register_models.py +0 -321
- isa_model/deployment/core/deployment_config.py +0 -356
- isa_model/deployment/core/isa_deployment_service.py +0 -401
- isa_model/deployment/gpu_int8_ds8/app/server.py +0 -66
- isa_model/deployment/gpu_int8_ds8/scripts/test_client.py +0 -43
- isa_model/deployment/gpu_int8_ds8/scripts/test_client_os.py +0 -35
- isa_model/deployment/runtime/deployed_service.py +0 -338
- isa_model/deployment/services/__init__.py +0 -9
- isa_model/deployment/services/auto_deploy_vision_service.py +0 -538
- isa_model/deployment/services/model_service.py +0 -332
- isa_model/deployment/services/service_monitor.py +0 -356
- isa_model/deployment/services/service_registry.py +0 -527
- isa_model/eval/__init__.py +0 -92
- isa_model/eval/benchmarks.py +0 -469
- isa_model/eval/config/__init__.py +0 -10
- isa_model/eval/config/evaluation_config.py +0 -108
- isa_model/eval/evaluators/__init__.py +0 -18
- isa_model/eval/evaluators/base_evaluator.py +0 -503
- isa_model/eval/evaluators/llm_evaluator.py +0 -472
- isa_model/eval/factory.py +0 -531
- isa_model/eval/infrastructure/__init__.py +0 -24
- isa_model/eval/infrastructure/experiment_tracker.py +0 -466
- isa_model/eval/metrics.py +0 -798
- isa_model/inference/adapter/unified_api.py +0 -248
- isa_model/inference/services/helpers/stacked_config.py +0 -148
- isa_model/inference/services/img/flux_professional_service.py +0 -603
- isa_model/inference/services/img/helpers/base_stacked_service.py +0 -274
- isa_model/inference/services/others/table_transformer_service.py +0 -61
- isa_model/inference/services/vision/doc_analysis_service.py +0 -640
- isa_model/inference/services/vision/helpers/base_stacked_service.py +0 -274
- isa_model/inference/services/vision/ui_analysis_service.py +0 -823
- isa_model/scripts/inference_tracker.py +0 -283
- isa_model/scripts/mlflow_manager.py +0 -379
- isa_model/scripts/model_registry.py +0 -465
- isa_model/scripts/register_models.py +0 -370
- isa_model/scripts/register_models_with_embeddings.py +0 -510
- isa_model/scripts/start_mlflow.py +0 -95
- isa_model/scripts/training_tracker.py +0 -257
- isa_model/training/__init__.py +0 -74
- isa_model/training/annotation/annotation_schema.py +0 -47
- isa_model/training/annotation/processors/annotation_processor.py +0 -126
- isa_model/training/annotation/storage/dataset_manager.py +0 -131
- isa_model/training/annotation/storage/dataset_schema.py +0 -44
- isa_model/training/annotation/tests/test_annotation_flow.py +0 -109
- isa_model/training/annotation/tests/test_minio copy.py +0 -113
- isa_model/training/annotation/tests/test_minio_upload.py +0 -43
- isa_model/training/annotation/views/annotation_controller.py +0 -158
- isa_model/training/cloud/__init__.py +0 -22
- isa_model/training/cloud/job_orchestrator.py +0 -402
- isa_model/training/cloud/runpod_trainer.py +0 -454
- isa_model/training/cloud/storage_manager.py +0 -482
- isa_model/training/core/__init__.py +0 -23
- isa_model/training/core/config.py +0 -181
- isa_model/training/core/dataset.py +0 -222
- isa_model/training/core/trainer.py +0 -720
- isa_model/training/core/utils.py +0 -213
- isa_model/training/factory.py +0 -424
- isa_model-0.3.91.dist-info/RECORD +0 -138
- /isa_model/{core/storage/minio_storage.py → deployment/modal/services/audio/isa_audio_fish_service.py} +0 -0
- /isa_model/deployment/{services → modal/services/vision}/simple_auto_deploy_vision_service.py +0 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/WHEEL +0 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/top_level.txt +0 -0
@@ -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
|
+
}
|