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,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")