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,519 @@
1
+ """
2
+ ISA Vision OCR Service
3
+
4
+ Specialized service for multilingual OCR using SuryaOCR
5
+ Supports 90+ languages with high accuracy text detection and recognition
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-ocr")
22
+
23
+ # Download SuryaOCR models
24
+ def download_surya_models():
25
+ """Download SuryaOCR models and dependencies"""
26
+ print("= Downloading SuryaOCR models...")
27
+ os.makedirs("/models", exist_ok=True)
28
+
29
+ try:
30
+ # SuryaOCR will auto-download models on first use
31
+ # Just verify the installation works
32
+ print(" SuryaOCR models will be downloaded on first use")
33
+
34
+ except Exception as e:
35
+ print(f" SuryaOCR setup warning: {e}")
36
+
37
+ print(" SuryaOCR setup completed")
38
+
39
+ # Define Modal container image
40
+ image = (
41
+ modal.Image.debian_slim(python_version="3.11")
42
+ .apt_install([
43
+ # Graphics libraries for image processing
44
+ "libgl1-mesa-glx",
45
+ "libglib2.0-0",
46
+ "libsm6",
47
+ "libxext6",
48
+ "libxrender-dev",
49
+ "libgomp1",
50
+ # Font support for multilingual text
51
+ "fontconfig",
52
+ "fonts-dejavu-core",
53
+ "fonts-liberation",
54
+ ])
55
+ .pip_install([
56
+ # Core AI libraries
57
+ "torch>=2.0.0",
58
+ "torchvision",
59
+ "transformers>=4.35.0",
60
+ "huggingface_hub",
61
+ "accelerate",
62
+
63
+ # SuryaOCR specific dependencies
64
+ "surya-ocr>=0.5.0", # Latest stable version
65
+
66
+ # Image processing
67
+ "pillow>=10.0.1",
68
+ "opencv-python-headless",
69
+ "numpy>=1.24.3",
70
+
71
+ # HTTP libraries
72
+ "httpx>=0.26.0",
73
+ "requests",
74
+
75
+ # Utilities
76
+ "pydantic>=2.0.0",
77
+ "python-dotenv",
78
+ ])
79
+ .run_function(download_surya_models)
80
+ .env({
81
+ "TRANSFORMERS_CACHE": "/models",
82
+ "TORCH_HOME": "/models/torch",
83
+ "SURYA_CACHE": "/models/surya",
84
+ "HF_HOME": "/models",
85
+ })
86
+ )
87
+
88
+ # SuryaOCR Service - Optimized for T4 GPU
89
+ @app.cls(
90
+ gpu="T4", # T4 4GB GPU - cost effective for OCR
91
+ image=image,
92
+ memory=8192, # 8GB RAM
93
+ timeout=1800, # 30 minutes
94
+ scaledown_window=60, # 1 minute idle timeout
95
+ min_containers=0, # Scale to zero to save costs
96
+ max_containers=20, # Support up to 20 concurrent containers
97
+ )
98
+ class SuryaOCRService:
99
+ """
100
+ SuryaOCR Multilingual Text Detection and Recognition Service
101
+
102
+ Provides high-accuracy OCR for 90+ languages
103
+ Optimized for document processing with cost-effective deployment
104
+ """
105
+
106
+ @modal.enter()
107
+ def load_models(self):
108
+ """Load SuryaOCR models on container startup"""
109
+ print("= Loading SuryaOCR models...")
110
+ start_time = time.time()
111
+
112
+ # Initialize instance variables
113
+ self.models_loaded = False
114
+ self.logger = logging.getLogger(__name__)
115
+ self.request_count = 0
116
+ self.total_processing_time = 0.0
117
+
118
+ try:
119
+ # Import SuryaOCR components - correct API
120
+ from surya.recognition import RecognitionPredictor
121
+ from surya.detection import DetectionPredictor
122
+
123
+ print("= Loading SuryaOCR predictors...")
124
+ self.recognition_predictor = RecognitionPredictor()
125
+ self.detection_predictor = DetectionPredictor()
126
+
127
+ print("= SuryaOCR predictors loaded successfully")
128
+ self.models_loaded = True
129
+
130
+ load_time = time.time() - start_time
131
+ print(f" SuryaOCR models loaded successfully in {load_time:.2f}s")
132
+
133
+ except Exception as e:
134
+ print(f"L SuryaOCR model loading failed: {e}")
135
+ import traceback
136
+ traceback.print_exc()
137
+ # Don't raise - allow service to start with degraded functionality
138
+ print(" Service will run with reduced functionality")
139
+
140
+ @modal.method()
141
+ def extract_text(
142
+ self,
143
+ image_b64: str,
144
+ languages: List[str] = ["en"],
145
+ detection_threshold: float = 0.6
146
+ ) -> Dict[str, Any]:
147
+ """
148
+ Extract text from image using SuryaOCR
149
+
150
+ Args:
151
+ image_b64: Base64 encoded image
152
+ languages: List of languages to detect (e.g., ["en", "zh", "ja"])
153
+ detection_threshold: Text detection confidence threshold
154
+
155
+ Returns:
156
+ OCR results with text, bounding boxes, and metadata
157
+ """
158
+ start_time = time.time()
159
+ self.request_count += 1
160
+
161
+ try:
162
+ # Validate models are loaded
163
+ if not hasattr(self, 'models_loaded') or not self.models_loaded:
164
+ raise RuntimeError("SuryaOCR models not loaded")
165
+
166
+ # Decode and process image
167
+ image = self._decode_image(image_b64)
168
+
169
+ # Run SuryaOCR detection and recognition
170
+ text_results = self._run_surya_ocr(image, languages, detection_threshold)
171
+
172
+ processing_time = time.time() - start_time
173
+ self.total_processing_time += processing_time
174
+
175
+ # Calculate cost (T4 GPU: ~$0.40/hour)
176
+ gpu_cost = (processing_time / 3600) * 0.40
177
+
178
+ result = {
179
+ 'success': True,
180
+ 'service': 'isa-vision-ocr',
181
+ 'provider': 'ISA',
182
+ 'text_results': text_results,
183
+ 'text_count': len(text_results),
184
+ 'languages': languages,
185
+ 'processing_time': processing_time,
186
+ 'ocr_method': 'surya-ocr',
187
+ 'billing': {
188
+ 'request_id': f"req_{self.request_count}_{int(time.time())}",
189
+ 'gpu_seconds': processing_time,
190
+ 'estimated_cost_usd': round(gpu_cost, 6),
191
+ 'gpu_type': 'T4'
192
+ },
193
+ 'model_info': {
194
+ 'model': 'SuryaOCR Detection + Recognition',
195
+ 'provider': 'ISA',
196
+ 'gpu': 'T4',
197
+ 'languages_supported': 90,
198
+ 'container_id': os.environ.get('MODAL_TASK_ID', 'unknown')
199
+ }
200
+ }
201
+
202
+ # Output JSON for client parsing
203
+ print("=== JSON_RESULT_START ===")
204
+ print(json.dumps(result, default=str))
205
+ print("=== JSON_RESULT_END ===")
206
+
207
+ return result
208
+
209
+ except Exception as e:
210
+ processing_time = time.time() - start_time
211
+ self.logger.error(f"SuryaOCR extraction failed: {e}")
212
+ error_result = {
213
+ 'success': False,
214
+ 'service': 'isa-vision-ocr',
215
+ 'provider': 'ISA',
216
+ 'error': str(e),
217
+ 'processing_time': processing_time,
218
+ 'billing': {
219
+ 'request_id': f"req_{self.request_count}_{int(time.time())}",
220
+ 'gpu_seconds': processing_time,
221
+ 'estimated_cost_usd': round((processing_time / 3600) * 0.40, 6),
222
+ 'gpu_type': 'T4'
223
+ }
224
+ }
225
+
226
+ print("=== JSON_RESULT_START ===")
227
+ print(json.dumps(error_result, default=str))
228
+ print("=== JSON_RESULT_END ===")
229
+
230
+ return error_result
231
+
232
+ def _run_surya_ocr(self, image: Image.Image, languages: List[str], threshold: float) -> List[Dict[str, Any]]:
233
+ """Run SuryaOCR detection and recognition"""
234
+ print(f" Running SuryaOCR for languages: {languages}")
235
+
236
+ try:
237
+ # Run OCR with SuryaOCR using correct API
238
+ predictions = self.recognition_predictor(
239
+ [image],
240
+ det_predictor=self.detection_predictor
241
+ )
242
+
243
+ text_results = []
244
+
245
+ # Process OCR results
246
+ if predictions and len(predictions) > 0:
247
+ prediction = predictions[0] # First (and only) image
248
+
249
+ for idx, text_line in enumerate(prediction.text_lines):
250
+ # Extract bounding box coordinates
251
+ bbox = text_line.bbox
252
+ x1, y1, x2, y2 = bbox
253
+
254
+ # Extract text and confidence
255
+ text_content = text_line.text
256
+ confidence = text_line.confidence if hasattr(text_line, 'confidence') else 0.9
257
+
258
+ # Skip low-confidence detections
259
+ if confidence < threshold:
260
+ continue
261
+
262
+ text_results.append({
263
+ 'id': f'surya_{idx}',
264
+ 'text': text_content,
265
+ 'confidence': float(confidence),
266
+ 'bbox': [int(x1), int(y1), int(x2), int(y2)],
267
+ 'center': [
268
+ int((x1 + x2) // 2),
269
+ int((y1 + y2) // 2)
270
+ ],
271
+ 'language': languages[0] if languages else 'auto' # Primary language
272
+ })
273
+
274
+ print(f" SuryaOCR extracted {len(text_results)} text regions")
275
+ return text_results
276
+
277
+ except Exception as e:
278
+ print(f"L SuryaOCR processing failed: {e}")
279
+ import traceback
280
+ traceback.print_exc()
281
+ return []
282
+
283
+ @modal.method()
284
+ def detect_text_regions(self, image_b64: str, threshold: float = 0.6) -> Dict[str, Any]:
285
+ """
286
+ Detect text regions only (without recognition)
287
+
288
+ Args:
289
+ image_b64: Base64 encoded image
290
+ threshold: Detection confidence threshold
291
+
292
+ Returns:
293
+ Text detection results with bounding boxes
294
+ """
295
+ start_time = time.time()
296
+
297
+ try:
298
+ if not self.det_model or not self.det_processor:
299
+ raise RuntimeError("SuryaOCR detection model not loaded")
300
+
301
+ image = self._decode_image(image_b64)
302
+
303
+ from surya.detection import batch_text_detection
304
+
305
+ # Run text detection only
306
+ line_predictions = batch_text_detection([image], self.det_model, self.det_processor)
307
+
308
+ text_regions = []
309
+ if line_predictions and len(line_predictions) > 0:
310
+ prediction = line_predictions[0]
311
+
312
+ for idx, text_line in enumerate(prediction.bboxes):
313
+ bbox = text_line.bbox
314
+ confidence = text_line.confidence if hasattr(text_line, 'confidence') else 0.9
315
+
316
+ if confidence >= threshold:
317
+ x1, y1, x2, y2 = bbox
318
+ text_regions.append({
319
+ 'id': f'region_{idx}',
320
+ 'bbox': [int(x1), int(y1), int(x2), int(y2)],
321
+ 'confidence': float(confidence),
322
+ 'center': [int((x1 + x2) // 2), int((y1 + y2) // 2)]
323
+ })
324
+
325
+ processing_time = time.time() - start_time
326
+
327
+ return {
328
+ 'success': True,
329
+ 'service': 'isa-vision-ocr',
330
+ 'function': 'text_detection',
331
+ 'text_regions': text_regions,
332
+ 'region_count': len(text_regions),
333
+ 'processing_time': processing_time
334
+ }
335
+
336
+ except Exception as e:
337
+ return {
338
+ 'success': False,
339
+ 'service': 'isa-vision-ocr',
340
+ 'function': 'text_detection',
341
+ 'error': str(e),
342
+ 'processing_time': time.time() - start_time
343
+ }
344
+
345
+ @modal.method()
346
+ def health_check(self) -> Dict[str, Any]:
347
+ """Health check endpoint"""
348
+ return {
349
+ 'status': 'healthy',
350
+ 'service': 'isa-vision-ocr',
351
+ 'provider': 'ISA',
352
+ 'models_loaded': {
353
+ 'detection': self.det_model is not None,
354
+ 'recognition': self.rec_model is not None
355
+ },
356
+ 'model_name': 'SuryaOCR Detection + Recognition',
357
+ 'languages_supported': 90,
358
+ 'timestamp': time.time(),
359
+ 'gpu': 'T4',
360
+ 'memory_usage': '8GB',
361
+ 'request_count': self.request_count
362
+ }
363
+
364
+ @modal.method()
365
+ def get_usage_stats(self) -> Dict[str, Any]:
366
+ """Get service usage statistics for billing"""
367
+ avg_processing_time = (
368
+ self.total_processing_time / self.request_count
369
+ if self.request_count > 0 else 0
370
+ )
371
+ total_cost = (self.total_processing_time / 3600) * 0.40
372
+
373
+ return {
374
+ 'service': 'isa-vision-ocr',
375
+ 'provider': 'ISA',
376
+ 'stats': {
377
+ 'total_requests': self.request_count,
378
+ 'total_gpu_seconds': round(self.total_processing_time, 3),
379
+ 'avg_processing_time': round(avg_processing_time, 3),
380
+ 'total_cost_usd': round(total_cost, 6),
381
+ 'container_id': os.environ.get('MODAL_TASK_ID', 'unknown')
382
+ }
383
+ }
384
+
385
+ def _decode_image(self, image_b64: str) -> Image.Image:
386
+ """Decode base64 image"""
387
+ try:
388
+ # Handle data URL format
389
+ if image_b64.startswith('data:image'):
390
+ image_b64 = image_b64.split(',')[1]
391
+
392
+ # Clean up base64 string
393
+ image_b64 = image_b64.strip().replace('\n', '').replace('\r', '').replace(' ', '')
394
+
395
+ # Decode base64
396
+ image_data = base64.b64decode(image_b64)
397
+ print(f" Decoded image size: {len(image_data)} bytes")
398
+
399
+ # Open with PIL
400
+ image = Image.open(io.BytesIO(image_data))
401
+ print(f" Image format: {image.format}, size: {image.size}, mode: {image.mode}")
402
+
403
+ return image.convert('RGB')
404
+
405
+ except Exception as e:
406
+ print(f"L Image decode error: {e}")
407
+ raise e
408
+
409
+ # Auto-registration function
410
+ @app.function()
411
+ async def register_service():
412
+ """Auto-register this service in the model registry"""
413
+ try:
414
+ import sys
415
+ from pathlib import Path
416
+
417
+ # Add project root to path for imports
418
+ project_root = Path(__file__).parent.parent.parent.parent
419
+ sys.path.insert(0, str(project_root))
420
+
421
+ try:
422
+ from isa_model.core.models.model_manager import ModelManager
423
+ from isa_model.core.models.model_repo import ModelType, ModelCapability
424
+ except ImportError:
425
+ print(" Could not import model manager - registration skipped")
426
+ return {"success": False, "error": "Model manager not available"}
427
+
428
+ # Use ModelManager to register this service
429
+ model_manager = ModelManager()
430
+
431
+ # Register the ISA service in the registry
432
+ success = model_manager.registry.register_model(
433
+ model_id="isa-surya-ocr-service",
434
+ model_type=ModelType.VISION,
435
+ capabilities=[
436
+ ModelCapability.OCR,
437
+ ModelCapability.TEXT_DETECTION,
438
+ ModelCapability.IMAGE_ANALYSIS
439
+ ],
440
+ metadata={
441
+ "description": "ISA SuryaOCR multilingual text extraction service",
442
+ "provider": "ISA",
443
+ "service_name": "isa-vision-ocr",
444
+ "service_type": "modal",
445
+ "deployment_type": "modal_gpu",
446
+ "endpoint": "https://isa-vision-ocr.modal.run",
447
+ "underlying_model": "SuryaOCR Detection + Recognition",
448
+ "gpu_requirement": "T4",
449
+ "memory_mb": 8192,
450
+ "max_containers": 20,
451
+ "cost_per_hour_usd": 0.40,
452
+ "auto_registered": True,
453
+ "registered_by": "isa_vision_ocr_service.py",
454
+ "is_service": True,
455
+ "optimized": True,
456
+ "billing_enabled": True,
457
+ "languages_supported": 90,
458
+ "multilingual": True
459
+ }
460
+ )
461
+
462
+ if success:
463
+ print(" OCR service auto-registered successfully")
464
+ else:
465
+ print(" OCR service registration failed")
466
+
467
+ return {"success": success}
468
+
469
+ except Exception as e:
470
+ print(f"L Auto-registration error: {e}")
471
+ return {"success": False, "error": str(e)}
472
+
473
+ # Deployment script
474
+ @app.function()
475
+ def deploy_info():
476
+ """Deployment information"""
477
+ return {
478
+ "service": "ISA Vision OCR Detection",
479
+ "model": "SuryaOCR Detection + Recognition (90+ languages)",
480
+ "gpu_requirement": "T4",
481
+ "memory_requirement": "8GB",
482
+ "deploy_command": "modal deploy isa_vision_ocr_service.py"
483
+ }
484
+
485
+ # Quick deployment function
486
+ @app.function()
487
+ def deploy_service():
488
+ """Deploy this service instantly"""
489
+ import subprocess
490
+ import os
491
+
492
+ print("= Deploying ISA Vision OCR Service...")
493
+ try:
494
+ # Get the current file path
495
+ current_file = __file__
496
+
497
+ # Run modal deploy command
498
+ result = subprocess.run(
499
+ ["modal", "deploy", current_file],
500
+ capture_output=True,
501
+ text=True,
502
+ check=True
503
+ )
504
+
505
+ print(" Deployment completed successfully!")
506
+ print(f"= Output: {result.stdout}")
507
+ return {"success": True, "output": result.stdout}
508
+
509
+ except subprocess.CalledProcessError as e:
510
+ print(f"L Deployment failed: {e}")
511
+ print(f"= Error: {e.stderr}")
512
+ return {"success": False, "error": str(e), "stderr": e.stderr}
513
+
514
+ if __name__ == "__main__":
515
+ print("= ISA Vision OCR Service - Modal Deployment")
516
+ print("Deploy with: modal deploy isa_vision_ocr_service.py")
517
+ print("Or call: modal run isa_vision_ocr_service.py::deploy_service")
518
+ print("Note: Uses SuryaOCR for 90+ language support")
519
+ print("\n= Service will auto-register in model registry upon deployment")