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,676 @@
|
|
1
|
+
"""
|
2
|
+
ISA Vision Table Service
|
3
|
+
|
4
|
+
Specialized service for table detection and structure recognition using Microsoft Table Transformer
|
5
|
+
Combines table detection and structure recognition for comprehensive table processing
|
6
|
+
"""
|
7
|
+
|
8
|
+
import modal
|
9
|
+
import torch
|
10
|
+
import base64
|
11
|
+
import io
|
12
|
+
import numpy as np
|
13
|
+
from PIL import Image
|
14
|
+
from typing import Dict, List, Optional, Any
|
15
|
+
import time
|
16
|
+
import json
|
17
|
+
import os
|
18
|
+
import logging
|
19
|
+
|
20
|
+
# Define Modal application
|
21
|
+
app = modal.App("isa-vision-table")
|
22
|
+
|
23
|
+
# Download Table Transformer models
|
24
|
+
def download_table_transformer_models():
|
25
|
+
"""Download Microsoft Table Transformer models"""
|
26
|
+
from huggingface_hub import snapshot_download
|
27
|
+
|
28
|
+
print("=� Downloading Microsoft Table Transformer models...")
|
29
|
+
os.makedirs("/models", exist_ok=True)
|
30
|
+
|
31
|
+
try:
|
32
|
+
# Download Table Detection model
|
33
|
+
print("<� Downloading Table Transformer Detection model...")
|
34
|
+
snapshot_download(
|
35
|
+
repo_id="microsoft/table-transformer-detection",
|
36
|
+
local_dir="/models/table-transformer-detection",
|
37
|
+
allow_patterns=["**/*.bin", "**/*.json", "**/*.safetensors"]
|
38
|
+
)
|
39
|
+
print(" Table Detection model downloaded")
|
40
|
+
|
41
|
+
# Download Table Structure Recognition model (v1.1)
|
42
|
+
print("=� Downloading Table Transformer Structure Recognition v1.1...")
|
43
|
+
snapshot_download(
|
44
|
+
repo_id="microsoft/table-transformer-structure-recognition-v1.1-all",
|
45
|
+
local_dir="/models/table-transformer-structure",
|
46
|
+
allow_patterns=["**/*.bin", "**/*.json", "**/*.safetensors"]
|
47
|
+
)
|
48
|
+
print(" Table Structure Recognition model downloaded")
|
49
|
+
|
50
|
+
except Exception as e:
|
51
|
+
print(f"� Table Transformer download failed: {e}")
|
52
|
+
# Don't raise - allow service to start with fallback
|
53
|
+
print("� Will use fallback table detection method")
|
54
|
+
|
55
|
+
print(" Table Transformer setup completed")
|
56
|
+
|
57
|
+
# Define Modal container image
|
58
|
+
image = (
|
59
|
+
modal.Image.debian_slim(python_version="3.11")
|
60
|
+
.apt_install([
|
61
|
+
# Graphics libraries for image processing
|
62
|
+
"libgl1-mesa-glx",
|
63
|
+
"libglib2.0-0",
|
64
|
+
"libsm6",
|
65
|
+
"libxext6",
|
66
|
+
"libxrender-dev",
|
67
|
+
"libgomp1",
|
68
|
+
])
|
69
|
+
.pip_install([
|
70
|
+
# Core AI libraries
|
71
|
+
"torch>=2.0.0",
|
72
|
+
"torchvision",
|
73
|
+
"transformers>=4.35.0",
|
74
|
+
"huggingface_hub",
|
75
|
+
"accelerate",
|
76
|
+
|
77
|
+
# Table Transformer specific dependencies
|
78
|
+
"timm", # Required for DETR backbone
|
79
|
+
|
80
|
+
# Image processing
|
81
|
+
"pillow>=10.0.1",
|
82
|
+
"opencv-python-headless",
|
83
|
+
"numpy>=1.24.3",
|
84
|
+
|
85
|
+
# HTTP libraries
|
86
|
+
"httpx>=0.26.0",
|
87
|
+
"requests",
|
88
|
+
|
89
|
+
# Utilities
|
90
|
+
"pydantic>=2.0.0",
|
91
|
+
"python-dotenv",
|
92
|
+
])
|
93
|
+
.run_function(download_table_transformer_models)
|
94
|
+
.env({
|
95
|
+
"TRANSFORMERS_CACHE": "/models",
|
96
|
+
"TORCH_HOME": "/models/torch",
|
97
|
+
"HF_HOME": "/models",
|
98
|
+
})
|
99
|
+
)
|
100
|
+
|
101
|
+
# Table Transformer Service - Optimized for T4 GPU
|
102
|
+
@app.cls(
|
103
|
+
gpu="T4", # T4 4GB GPU - sufficient for Table Transformer
|
104
|
+
image=image,
|
105
|
+
memory=12288, # 12GB RAM for table processing
|
106
|
+
timeout=1800, # 30 minutes
|
107
|
+
scaledown_window=60, # 1 minute idle timeout
|
108
|
+
min_containers=0, # Scale to zero to save costs
|
109
|
+
max_containers=15, # Support up to 15 concurrent containers
|
110
|
+
)
|
111
|
+
class TableTransformerService:
|
112
|
+
"""
|
113
|
+
Microsoft Table Transformer Service
|
114
|
+
|
115
|
+
Provides table detection and structure recognition
|
116
|
+
Cost-effective deployment optimized for document processing
|
117
|
+
"""
|
118
|
+
|
119
|
+
@modal.enter()
|
120
|
+
def load_models(self):
|
121
|
+
"""Load Table Transformer models on container startup"""
|
122
|
+
print("=� Loading Table Transformer models...")
|
123
|
+
start_time = time.time()
|
124
|
+
|
125
|
+
# Initialize instance variables
|
126
|
+
self.detection_model = None
|
127
|
+
self.detection_processor = None
|
128
|
+
self.structure_model = None
|
129
|
+
self.structure_processor = None
|
130
|
+
self.logger = logging.getLogger(__name__)
|
131
|
+
self.request_count = 0
|
132
|
+
self.total_processing_time = 0.0
|
133
|
+
|
134
|
+
try:
|
135
|
+
# Import transformers components
|
136
|
+
from transformers import TableTransformerForObjectDetection, DetrImageProcessor
|
137
|
+
|
138
|
+
print("<� Loading Table Detection model...")
|
139
|
+
self.detection_processor = DetrImageProcessor.from_pretrained(
|
140
|
+
"microsoft/table-transformer-detection"
|
141
|
+
)
|
142
|
+
self.detection_model = TableTransformerForObjectDetection.from_pretrained(
|
143
|
+
"microsoft/table-transformer-detection"
|
144
|
+
)
|
145
|
+
|
146
|
+
print("=� Loading Table Structure Recognition model...")
|
147
|
+
self.structure_processor = DetrImageProcessor.from_pretrained(
|
148
|
+
"microsoft/table-transformer-structure-recognition-v1.1-all"
|
149
|
+
)
|
150
|
+
self.structure_model = TableTransformerForObjectDetection.from_pretrained(
|
151
|
+
"microsoft/table-transformer-structure-recognition-v1.1-all"
|
152
|
+
)
|
153
|
+
|
154
|
+
# Move models to GPU if available
|
155
|
+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
156
|
+
self.detection_model = self.detection_model.to(device)
|
157
|
+
self.structure_model = self.structure_model.to(device)
|
158
|
+
|
159
|
+
# Set to evaluation mode
|
160
|
+
self.detection_model.eval()
|
161
|
+
self.structure_model.eval()
|
162
|
+
|
163
|
+
load_time = time.time() - start_time
|
164
|
+
print(f" Table Transformer models loaded successfully in {load_time:.2f}s")
|
165
|
+
|
166
|
+
except Exception as e:
|
167
|
+
print(f"L Table Transformer model loading failed: {e}")
|
168
|
+
import traceback
|
169
|
+
traceback.print_exc()
|
170
|
+
# Don't raise - allow service to start with fallback
|
171
|
+
print("� Service will use fallback table detection")
|
172
|
+
|
173
|
+
@modal.method()
|
174
|
+
def detect_tables(
|
175
|
+
self,
|
176
|
+
image_b64: str,
|
177
|
+
detection_threshold: float = 0.7
|
178
|
+
) -> Dict[str, Any]:
|
179
|
+
"""
|
180
|
+
Detect tables in document image
|
181
|
+
|
182
|
+
Args:
|
183
|
+
image_b64: Base64 encoded image
|
184
|
+
detection_threshold: Table detection confidence threshold
|
185
|
+
|
186
|
+
Returns:
|
187
|
+
Table detection results with bounding boxes
|
188
|
+
"""
|
189
|
+
start_time = time.time()
|
190
|
+
self.request_count += 1
|
191
|
+
|
192
|
+
try:
|
193
|
+
# Validate models are loaded
|
194
|
+
if not self.detection_model or not self.detection_processor:
|
195
|
+
raise RuntimeError("Table detection model not loaded")
|
196
|
+
|
197
|
+
# Decode and process image
|
198
|
+
image = self._decode_image(image_b64)
|
199
|
+
|
200
|
+
# Run table detection
|
201
|
+
tables = self._detect_tables_impl(image, detection_threshold)
|
202
|
+
|
203
|
+
processing_time = time.time() - start_time
|
204
|
+
self.total_processing_time += processing_time
|
205
|
+
|
206
|
+
# Calculate cost (T4 GPU: ~$0.40/hour)
|
207
|
+
gpu_cost = (processing_time / 3600) * 0.40
|
208
|
+
|
209
|
+
result = {
|
210
|
+
'success': True,
|
211
|
+
'service': 'isa-vision-table',
|
212
|
+
'provider': 'ISA',
|
213
|
+
'tables': tables,
|
214
|
+
'table_count': len(tables),
|
215
|
+
'processing_time': processing_time,
|
216
|
+
'detection_method': 'table-transformer',
|
217
|
+
'billing': {
|
218
|
+
'request_id': f"req_{self.request_count}_{int(time.time())}",
|
219
|
+
'gpu_seconds': processing_time,
|
220
|
+
'estimated_cost_usd': round(gpu_cost, 6),
|
221
|
+
'gpu_type': 'T4'
|
222
|
+
},
|
223
|
+
'model_info': {
|
224
|
+
'model': 'microsoft/table-transformer-detection',
|
225
|
+
'provider': 'ISA',
|
226
|
+
'gpu': 'T4',
|
227
|
+
'container_id': os.environ.get('MODAL_TASK_ID', 'unknown')
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
# Output JSON for client parsing
|
232
|
+
print("=== JSON_RESULT_START ===")
|
233
|
+
print(json.dumps(result, default=str))
|
234
|
+
print("=== JSON_RESULT_END ===")
|
235
|
+
|
236
|
+
return result
|
237
|
+
|
238
|
+
except Exception as e:
|
239
|
+
processing_time = time.time() - start_time
|
240
|
+
self.logger.error(f"Table detection failed: {e}")
|
241
|
+
error_result = {
|
242
|
+
'success': False,
|
243
|
+
'service': 'isa-vision-table',
|
244
|
+
'provider': 'ISA',
|
245
|
+
'error': str(e),
|
246
|
+
'processing_time': processing_time,
|
247
|
+
'billing': {
|
248
|
+
'request_id': f"req_{self.request_count}_{int(time.time())}",
|
249
|
+
'gpu_seconds': processing_time,
|
250
|
+
'estimated_cost_usd': round((processing_time / 3600) * 0.40, 6),
|
251
|
+
'gpu_type': 'T4'
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
print("=== JSON_RESULT_START ===")
|
256
|
+
print(json.dumps(error_result, default=str))
|
257
|
+
print("=== JSON_RESULT_END ===")
|
258
|
+
|
259
|
+
return error_result
|
260
|
+
|
261
|
+
@modal.method()
|
262
|
+
def analyze_table_structure(
|
263
|
+
self,
|
264
|
+
image_b64: str,
|
265
|
+
table_bbox: Optional[List[int]] = None,
|
266
|
+
structure_threshold: float = 0.6
|
267
|
+
) -> Dict[str, Any]:
|
268
|
+
"""
|
269
|
+
Analyze table structure in image or table region
|
270
|
+
|
271
|
+
Args:
|
272
|
+
image_b64: Base64 encoded image
|
273
|
+
table_bbox: Optional table bounding box [x1, y1, x2, y2]
|
274
|
+
structure_threshold: Structure detection confidence threshold
|
275
|
+
|
276
|
+
Returns:
|
277
|
+
Table structure analysis results
|
278
|
+
"""
|
279
|
+
start_time = time.time()
|
280
|
+
|
281
|
+
try:
|
282
|
+
if not self.structure_model or not self.structure_processor:
|
283
|
+
raise RuntimeError("Table structure model not loaded")
|
284
|
+
|
285
|
+
image = self._decode_image(image_b64)
|
286
|
+
|
287
|
+
# Crop to table region if bbox provided
|
288
|
+
if table_bbox:
|
289
|
+
x1, y1, x2, y2 = table_bbox
|
290
|
+
image = image.crop((x1, y1, x2, y2))
|
291
|
+
|
292
|
+
# Analyze table structure
|
293
|
+
structure = self._analyze_table_structure_impl(image, structure_threshold)
|
294
|
+
|
295
|
+
processing_time = time.time() - start_time
|
296
|
+
|
297
|
+
return {
|
298
|
+
'success': True,
|
299
|
+
'service': 'isa-vision-table',
|
300
|
+
'function': 'structure_analysis',
|
301
|
+
'structure': structure,
|
302
|
+
'processing_time': processing_time,
|
303
|
+
'model_info': {
|
304
|
+
'model': 'microsoft/table-transformer-structure-recognition-v1.1-all',
|
305
|
+
'gpu': 'T4'
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
except Exception as e:
|
310
|
+
return {
|
311
|
+
'success': False,
|
312
|
+
'service': 'isa-vision-table',
|
313
|
+
'function': 'structure_analysis',
|
314
|
+
'error': str(e),
|
315
|
+
'processing_time': time.time() - start_time
|
316
|
+
}
|
317
|
+
|
318
|
+
@modal.method()
|
319
|
+
def process_complete_table(
|
320
|
+
self,
|
321
|
+
image_b64: str,
|
322
|
+
detection_threshold: float = 0.7,
|
323
|
+
structure_threshold: float = 0.6
|
324
|
+
) -> Dict[str, Any]:
|
325
|
+
"""
|
326
|
+
Complete table processing: detection + structure analysis
|
327
|
+
|
328
|
+
Args:
|
329
|
+
image_b64: Base64 encoded image
|
330
|
+
detection_threshold: Table detection confidence threshold
|
331
|
+
structure_threshold: Structure analysis confidence threshold
|
332
|
+
|
333
|
+
Returns:
|
334
|
+
Complete table processing results
|
335
|
+
"""
|
336
|
+
start_time = time.time()
|
337
|
+
|
338
|
+
try:
|
339
|
+
image = self._decode_image(image_b64)
|
340
|
+
|
341
|
+
# Step 1: Detect tables
|
342
|
+
tables = self._detect_tables_impl(image, detection_threshold)
|
343
|
+
|
344
|
+
# Step 2: Analyze structure for each detected table
|
345
|
+
for table in tables:
|
346
|
+
if 'bbox' in table:
|
347
|
+
x1, y1, x2, y2 = table['bbox']
|
348
|
+
table_image = image.crop((x1, y1, x2, y2))
|
349
|
+
structure = self._analyze_table_structure_impl(table_image, structure_threshold)
|
350
|
+
table['structure'] = structure
|
351
|
+
|
352
|
+
processing_time = time.time() - start_time
|
353
|
+
|
354
|
+
return {
|
355
|
+
'success': True,
|
356
|
+
'service': 'isa-vision-table',
|
357
|
+
'function': 'complete_processing',
|
358
|
+
'tables': tables,
|
359
|
+
'table_count': len(tables),
|
360
|
+
'processing_time': processing_time,
|
361
|
+
'model_info': {
|
362
|
+
'detection_model': 'microsoft/table-transformer-detection',
|
363
|
+
'structure_model': 'microsoft/table-transformer-structure-recognition-v1.1-all',
|
364
|
+
'gpu': 'T4'
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
except Exception as e:
|
369
|
+
return {
|
370
|
+
'success': False,
|
371
|
+
'service': 'isa-vision-table',
|
372
|
+
'function': 'complete_processing',
|
373
|
+
'error': str(e),
|
374
|
+
'processing_time': time.time() - start_time
|
375
|
+
}
|
376
|
+
|
377
|
+
def _detect_tables_impl(self, image: Image.Image, threshold: float) -> List[Dict[str, Any]]:
|
378
|
+
"""Implementation of table detection using Table Transformer"""
|
379
|
+
print("<� Running Table Transformer detection...")
|
380
|
+
|
381
|
+
try:
|
382
|
+
# Prepare inputs
|
383
|
+
inputs = self.detection_processor(images=image, return_tensors="pt")
|
384
|
+
|
385
|
+
# Move to GPU if available
|
386
|
+
device = next(self.detection_model.parameters()).device
|
387
|
+
inputs = {k: v.to(device) for k, v in inputs.items()}
|
388
|
+
|
389
|
+
# Run inference
|
390
|
+
with torch.no_grad():
|
391
|
+
outputs = self.detection_model(**inputs)
|
392
|
+
|
393
|
+
# Process results
|
394
|
+
target_sizes = torch.tensor([image.size[::-1]]) # (height, width)
|
395
|
+
results = self.detection_processor.post_process_object_detection(
|
396
|
+
outputs, threshold=threshold, target_sizes=target_sizes
|
397
|
+
)[0]
|
398
|
+
|
399
|
+
tables = []
|
400
|
+
for idx, (score, label, box) in enumerate(zip(
|
401
|
+
results["scores"], results["labels"], results["boxes"]
|
402
|
+
)):
|
403
|
+
x1, y1, x2, y2 = box.tolist()
|
404
|
+
|
405
|
+
tables.append({
|
406
|
+
'id': f'table_{idx}',
|
407
|
+
'bbox': [int(x1), int(y1), int(x2), int(y2)],
|
408
|
+
'confidence': float(score),
|
409
|
+
'center': [int((x1 + x2) // 2), int((y1 + y2) // 2)],
|
410
|
+
'label': int(label),
|
411
|
+
'type': 'table'
|
412
|
+
})
|
413
|
+
|
414
|
+
print(f" Table Transformer detected {len(tables)} tables")
|
415
|
+
return tables
|
416
|
+
|
417
|
+
except Exception as e:
|
418
|
+
print(f"L Table detection failed: {e}")
|
419
|
+
import traceback
|
420
|
+
traceback.print_exc()
|
421
|
+
return []
|
422
|
+
|
423
|
+
def _analyze_table_structure_impl(self, image: Image.Image, threshold: float) -> Dict[str, Any]:
|
424
|
+
"""Implementation of table structure analysis using Table Transformer"""
|
425
|
+
print("=� Running Table Transformer structure analysis...")
|
426
|
+
|
427
|
+
try:
|
428
|
+
# Prepare inputs
|
429
|
+
inputs = self.structure_processor(images=image, return_tensors="pt")
|
430
|
+
|
431
|
+
# Move to GPU if available
|
432
|
+
device = next(self.structure_model.parameters()).device
|
433
|
+
inputs = {k: v.to(device) for k, v in inputs.items()}
|
434
|
+
|
435
|
+
# Run inference
|
436
|
+
with torch.no_grad():
|
437
|
+
outputs = self.structure_model(**inputs)
|
438
|
+
|
439
|
+
# Process results
|
440
|
+
target_sizes = torch.tensor([image.size[::-1]]) # (height, width)
|
441
|
+
results = self.structure_processor.post_process_object_detection(
|
442
|
+
outputs, threshold=threshold, target_sizes=target_sizes
|
443
|
+
)[0]
|
444
|
+
|
445
|
+
# Parse structure elements
|
446
|
+
rows = []
|
447
|
+
columns = []
|
448
|
+
cells = []
|
449
|
+
|
450
|
+
for score, label, box in zip(
|
451
|
+
results["scores"], results["labels"], results["boxes"]
|
452
|
+
):
|
453
|
+
x1, y1, x2, y2 = box.tolist()
|
454
|
+
element = {
|
455
|
+
'bbox': [int(x1), int(y1), int(x2), int(y2)],
|
456
|
+
'confidence': float(score),
|
457
|
+
'label': int(label)
|
458
|
+
}
|
459
|
+
|
460
|
+
# Categorize based on label (this may need adjustment based on model output)
|
461
|
+
if label == 0: # Row
|
462
|
+
rows.append(element)
|
463
|
+
elif label == 1: # Column
|
464
|
+
columns.append(element)
|
465
|
+
else: # Cell or other structure
|
466
|
+
cells.append(element)
|
467
|
+
|
468
|
+
structure = {
|
469
|
+
'rows': rows,
|
470
|
+
'columns': columns,
|
471
|
+
'cells': cells,
|
472
|
+
'row_count': len(rows),
|
473
|
+
'column_count': len(columns),
|
474
|
+
'cell_count': len(cells),
|
475
|
+
'confidence_avg': float(torch.mean(results["scores"]).item()) if len(results["scores"]) > 0 else 0.0
|
476
|
+
}
|
477
|
+
|
478
|
+
print(f" Structure analysis: {len(rows)} rows, {len(columns)} columns, {len(cells)} cells")
|
479
|
+
return structure
|
480
|
+
|
481
|
+
except Exception as e:
|
482
|
+
print(f"L Table structure analysis failed: {e}")
|
483
|
+
import traceback
|
484
|
+
traceback.print_exc()
|
485
|
+
return {
|
486
|
+
'rows': [],
|
487
|
+
'columns': [],
|
488
|
+
'cells': [],
|
489
|
+
'row_count': 0,
|
490
|
+
'column_count': 0,
|
491
|
+
'cell_count': 0,
|
492
|
+
'confidence_avg': 0.0,
|
493
|
+
'error': str(e)
|
494
|
+
}
|
495
|
+
|
496
|
+
@modal.method()
|
497
|
+
def health_check(self) -> Dict[str, Any]:
|
498
|
+
"""Health check endpoint"""
|
499
|
+
return {
|
500
|
+
'status': 'healthy',
|
501
|
+
'service': 'isa-vision-table',
|
502
|
+
'provider': 'ISA',
|
503
|
+
'models_loaded': {
|
504
|
+
'detection': self.detection_model is not None,
|
505
|
+
'structure': self.structure_model is not None
|
506
|
+
},
|
507
|
+
'model_names': {
|
508
|
+
'detection': 'microsoft/table-transformer-detection',
|
509
|
+
'structure': 'microsoft/table-transformer-structure-recognition-v1.1-all'
|
510
|
+
},
|
511
|
+
'timestamp': time.time(),
|
512
|
+
'gpu': 'T4',
|
513
|
+
'memory_usage': '12GB',
|
514
|
+
'request_count': self.request_count
|
515
|
+
}
|
516
|
+
|
517
|
+
@modal.method()
|
518
|
+
def get_usage_stats(self) -> Dict[str, Any]:
|
519
|
+
"""Get service usage statistics for billing"""
|
520
|
+
avg_processing_time = (
|
521
|
+
self.total_processing_time / self.request_count
|
522
|
+
if self.request_count > 0 else 0
|
523
|
+
)
|
524
|
+
total_cost = (self.total_processing_time / 3600) * 0.40
|
525
|
+
|
526
|
+
return {
|
527
|
+
'service': 'isa-vision-table',
|
528
|
+
'provider': 'ISA',
|
529
|
+
'stats': {
|
530
|
+
'total_requests': self.request_count,
|
531
|
+
'total_gpu_seconds': round(self.total_processing_time, 3),
|
532
|
+
'avg_processing_time': round(avg_processing_time, 3),
|
533
|
+
'total_cost_usd': round(total_cost, 6),
|
534
|
+
'container_id': os.environ.get('MODAL_TASK_ID', 'unknown')
|
535
|
+
}
|
536
|
+
}
|
537
|
+
|
538
|
+
def _decode_image(self, image_b64: str) -> Image.Image:
|
539
|
+
"""Decode base64 image"""
|
540
|
+
try:
|
541
|
+
# Handle data URL format
|
542
|
+
if image_b64.startswith('data:image'):
|
543
|
+
image_b64 = image_b64.split(',')[1]
|
544
|
+
|
545
|
+
# Clean up base64 string
|
546
|
+
image_b64 = image_b64.strip().replace('\n', '').replace('\r', '').replace(' ', '')
|
547
|
+
|
548
|
+
# Decode base64
|
549
|
+
image_data = base64.b64decode(image_b64)
|
550
|
+
print(f"=
|
551
|
Decoded image size: {len(image_data)} bytes")
|
552
|
+
|
553
|
+
# Open with PIL
|
554
|
+
image = Image.open(io.BytesIO(image_data))
|
555
|
+
print(f"=
|
1
556
|
Image format: {image.format}, size: {image.size}, mode: {image.mode}")
|
557
|
+
|
558
|
+
return image.convert('RGB')
|
559
|
+
|
560
|
+
except Exception as e:
|
561
|
+
print(f"L Image decode error: {e}")
|
562
|
+
raise e
|
563
|
+
|
564
|
+
# Auto-registration function
|
565
|
+
@app.function()
|
566
|
+
async def register_service():
|
567
|
+
"""Auto-register this service in the model registry"""
|
568
|
+
try:
|
569
|
+
import sys
|
570
|
+
from pathlib import Path
|
571
|
+
|
572
|
+
# Add project root to path for imports
|
573
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
574
|
+
sys.path.insert(0, str(project_root))
|
575
|
+
|
576
|
+
try:
|
577
|
+
from isa_model.core.models.model_manager import ModelManager
|
578
|
+
from isa_model.core.models.model_repo import ModelType, ModelCapability
|
579
|
+
except ImportError:
|
580
|
+
print("� Could not import model manager - registration skipped")
|
581
|
+
return {"success": False, "error": "Model manager not available"}
|
582
|
+
|
583
|
+
# Use ModelManager to register this service
|
584
|
+
model_manager = ModelManager()
|
585
|
+
|
586
|
+
# Register the ISA service in the registry
|
587
|
+
success = model_manager.registry.register_model(
|
588
|
+
model_id="isa-table-transformer-service",
|
589
|
+
model_type=ModelType.VISION,
|
590
|
+
capabilities=[
|
591
|
+
ModelCapability.TABLE_DETECTION,
|
592
|
+
ModelCapability.TABLE_STRUCTURE_RECOGNITION,
|
593
|
+
ModelCapability.IMAGE_ANALYSIS
|
594
|
+
],
|
595
|
+
metadata={
|
596
|
+
"description": "ISA Table Transformer detection and structure recognition service",
|
597
|
+
"provider": "ISA",
|
598
|
+
"service_name": "isa-vision-table",
|
599
|
+
"service_type": "modal",
|
600
|
+
"deployment_type": "modal_gpu",
|
601
|
+
"endpoint": "https://isa-vision-table.modal.run",
|
602
|
+
"underlying_models": [
|
603
|
+
"microsoft/table-transformer-detection",
|
604
|
+
"microsoft/table-transformer-structure-recognition-v1.1-all"
|
605
|
+
],
|
606
|
+
"gpu_requirement": "T4",
|
607
|
+
"memory_mb": 12288,
|
608
|
+
"max_containers": 15,
|
609
|
+
"cost_per_hour_usd": 0.40,
|
610
|
+
"auto_registered": True,
|
611
|
+
"registered_by": "isa_vision_table_service.py",
|
612
|
+
"is_service": True,
|
613
|
+
"optimized": True,
|
614
|
+
"billing_enabled": True
|
615
|
+
}
|
616
|
+
)
|
617
|
+
|
618
|
+
if success:
|
619
|
+
print(" Table service auto-registered successfully")
|
620
|
+
else:
|
621
|
+
print("� Table service registration failed")
|
622
|
+
|
623
|
+
return {"success": success}
|
624
|
+
|
625
|
+
except Exception as e:
|
626
|
+
print(f"L Auto-registration error: {e}")
|
627
|
+
return {"success": False, "error": str(e)}
|
628
|
+
|
629
|
+
# Deployment script
|
630
|
+
@app.function()
|
631
|
+
def deploy_info():
|
632
|
+
"""Deployment information"""
|
633
|
+
return {
|
634
|
+
"service": "ISA Vision Table Processing",
|
635
|
+
"models": [
|
636
|
+
"microsoft/table-transformer-detection",
|
637
|
+
"microsoft/table-transformer-structure-recognition-v1.1-all"
|
638
|
+
],
|
639
|
+
"gpu_requirement": "T4",
|
640
|
+
"memory_requirement": "12GB",
|
641
|
+
"deploy_command": "modal deploy isa_vision_table_service.py"
|
642
|
+
}
|
643
|
+
|
644
|
+
# Quick deployment function
|
645
|
+
@app.function()
|
646
|
+
def deploy_service():
|
647
|
+
"""Deploy this service instantly"""
|
648
|
+
import subprocess
|
649
|
+
import os
|
650
|
+
|
651
|
+
print("=� Deploying ISA Vision Table Service...")
|
652
|
+
try:
|
653
|
+
# Get the current file path
|
654
|
+
current_file = __file__
|
655
|
+
|
656
|
+
# Run modal deploy command
|
657
|
+
result = subprocess.run(
|
658
|
+
["modal", "deploy", current_file],
|
659
|
+
capture_output=True,
|
660
|
+
text=True,
|
661
|
+
check=True
|
662
|
+
)
|
663
|
+
|
664
|
+
print(" Deployment completed successfully!")
|
665
|
+
print(f"=� Output: {result.stdout}")
|
666
|
+
return {"success": True, "output": result.stdout}
|
667
|
+
|
668
|
+
except subprocess.CalledProcessError as e:
|
669
|
+
print(f"L Deployment failed: {e}")
|
670
|
+
print(f"=� Error: {e.stderr}")
|
671
|
+
return {"success": False, "error": str(e), "stderr": e.stderr}
|
672
|
+
|
673
|
+
if __name__ == "__main__":
|
674
|
+
print("=� ISA Vision Table Service - Modal Deployment")
|
675
|
+
print("Deploy with: modal deploy isa_vision_table_service.py")
|
676
|
+
print("Or call: modal run isa_vision_table_service.py::deploy_service")
|
677
|
+
print("Note: Uses Microsoft Table Transformer for detection and structure recognition")
|
678
|
+
print("\n=� Service will auto-register in model registry upon deployment")
|