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
@@ -1,532 +0,0 @@
1
- """
2
- Qwen2.5-VL-32B Table Data Extraction Service
3
-
4
- Specialized service for table data extraction using Qwen2.5-VL-32B-Instruct-AWQ
5
- """
6
-
7
- import modal
8
- import torch
9
- import base64
10
- import io
11
- import numpy as np
12
- from PIL import Image
13
- from typing import Dict, List, Optional, Any
14
- import time
15
- import json
16
- import os
17
- import logging
18
-
19
- # Define Modal application
20
- app = modal.App("qwen-vision-table")
21
-
22
- # Download Qwen2.5-VL model
23
- def download_qwen_model():
24
- """Download Qwen2.5-VL-32B-Instruct-AWQ model"""
25
- from huggingface_hub import snapshot_download
26
-
27
- print("📦 Downloading Qwen2.5-VL-32B-Instruct-AWQ...")
28
- os.makedirs("/models", exist_ok=True)
29
-
30
- try:
31
- snapshot_download(
32
- repo_id="Qwen/Qwen2.5-VL-32B-Instruct-AWQ",
33
- local_dir="/models/qwen2.5-vl-32b-awq",
34
- allow_patterns=["**/*.safetensors", "**/*.json", "**/*.py", "**/*.txt"],
35
- # Use auth token if needed for gated models
36
- # token=os.getenv("HF_TOKEN")
37
- )
38
- print("✅ Qwen2.5-VL-32B-Instruct-AWQ downloaded")
39
- except Exception as e:
40
- print(f"⚠️ Model download failed: {e}")
41
- raise
42
-
43
- print("📦 Model download completed")
44
-
45
- # Define Modal container image with AWQ support
46
- image = (
47
- modal.Image.debian_slim(python_version="3.11")
48
- .pip_install([
49
- # Core AI libraries with AWQ support
50
- "torch>=2.1.0",
51
- "torchvision",
52
- "transformers>=4.37.0",
53
- "accelerate>=0.26.0",
54
- "autoawq>=0.2.0", # AWQ quantization support
55
- "huggingface_hub",
56
-
57
- # Qwen-VL specific dependencies
58
- "qwen-vl-utils", # If available
59
- "tiktoken",
60
- "einops",
61
- "timm",
62
-
63
- # Image processing
64
- "pillow>=10.0.1",
65
- "opencv-python-headless",
66
- "numpy>=1.24.3",
67
-
68
- # HTTP libraries
69
- "httpx>=0.26.0",
70
- "requests",
71
-
72
- # Utilities
73
- "pydantic>=2.0.0",
74
- "python-dotenv",
75
- ])
76
- .run_function(download_qwen_model)
77
- .env({
78
- "TRANSFORMERS_CACHE": "/models",
79
- "HF_HOME": "/models",
80
- "TORCH_HOME": "/models",
81
- })
82
- )
83
-
84
- # Table Extraction Service
85
- @app.cls(
86
- gpu="A100", # A100 recommended for 32B model, H100 if available
87
- image=image,
88
- memory=32768, # 32GB RAM for 32B model
89
- timeout=3600, # 1 hour timeout
90
- scaledown_window=60, # 1 minute idle timeout
91
- min_containers=0, # Scale to zero to save costs
92
- # secrets=[modal.Secret.from_name("huggingface-token")] # If needed
93
- )
94
- class QwenTableExtractionService:
95
- """
96
- Table Data Extraction Service using Qwen2.5-VL-32B-Instruct-AWQ
97
-
98
- Provides high-accuracy table extraction from images
99
- """
100
-
101
- @modal.enter()
102
- def load_model(self):
103
- """Load Qwen2.5-VL model on container startup"""
104
- print("🚀 Loading Qwen2.5-VL-32B-Instruct-AWQ...")
105
- start_time = time.time()
106
-
107
- # Initialize attributes
108
- self.model = None
109
- self.processor = None
110
- self.logger = logging.getLogger(__name__)
111
-
112
- try:
113
- from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
114
-
115
- model_path = "Qwen/Qwen2.5-VL-32B-Instruct-AWQ"
116
-
117
- # Load processor
118
- print("📱 Loading processor...")
119
- self.processor = AutoProcessor.from_pretrained(
120
- model_path,
121
- trust_remote_code=True
122
- )
123
-
124
- # Load model with AWQ quantization
125
- print("🧠 Loading AWQ quantized model...")
126
- self.model = Qwen2VLForConditionalGeneration.from_pretrained(
127
- model_path,
128
- torch_dtype=torch.float16,
129
- device_map="auto",
130
- trust_remote_code=True,
131
- # AWQ specific settings
132
- use_safetensors=True,
133
- )
134
-
135
- # Try to import qwen-vl-utils
136
- try:
137
- from qwen_vl_utils import process_vision_info as qwen_process_vision_info
138
- print("✅ qwen-vl-utils imported successfully")
139
- # Use the official process_vision_info if available
140
- globals()['process_vision_info'] = qwen_process_vision_info
141
- except ImportError:
142
- print("⚠️ qwen-vl-utils not found, using custom implementation")
143
-
144
- # Set to evaluation mode
145
- self.model.eval()
146
-
147
- load_time = time.time() - start_time
148
- print(f"✅ Qwen2.5-VL model loaded in {load_time:.2f}s")
149
-
150
- except Exception as e:
151
- print(f"❌ Model loading failed: {e}")
152
- raise
153
-
154
- @modal.method()
155
- def extract_table_data(
156
- self,
157
- image_b64: str,
158
- extraction_format: str = "markdown",
159
- custom_prompt: Optional[str] = None
160
- ) -> Dict[str, Any]:
161
- """
162
- Extract table data from image
163
-
164
- Args:
165
- image_b64: Base64 encoded image
166
- extraction_format: Output format ("markdown", "json", "csv", "html")
167
- custom_prompt: Custom extraction prompt
168
-
169
- Returns:
170
- Extracted table data and metadata
171
- """
172
- start_time = time.time()
173
-
174
- try:
175
- # Decode image
176
- image = self._decode_image(image_b64)
177
-
178
- # Prepare prompt based on format
179
- if custom_prompt:
180
- prompt = custom_prompt
181
- else:
182
- prompt = self._get_extraction_prompt(extraction_format)
183
-
184
- # Process inputs
185
- messages = [
186
- {
187
- "role": "user",
188
- "content": [
189
- {"type": "image", "image": image},
190
- {"type": "text", "text": prompt}
191
- ]
192
- }
193
- ]
194
-
195
- # Prepare inputs for the model
196
- text = self.processor.apply_chat_template(
197
- messages, tokenize=False, add_generation_prompt=True
198
- )
199
-
200
- image_inputs, video_inputs = process_vision_info(messages)
201
- inputs = self.processor(
202
- text=[text],
203
- images=image_inputs,
204
- videos=video_inputs,
205
- padding=True,
206
- return_tensors="pt"
207
- )
208
- inputs = inputs.to("cuda")
209
-
210
- # Generate response
211
- with torch.no_grad():
212
- generated_ids = self.model.generate(
213
- **inputs,
214
- max_new_tokens=2048,
215
- do_sample=False,
216
- temperature=0.0, # Deterministic for table extraction
217
- pad_token_id=self.processor.tokenizer.eos_token_id
218
- )
219
-
220
- # Decode response
221
- generated_ids_trimmed = [
222
- out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
223
- ]
224
- output_text = self.processor.batch_decode(
225
- generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
226
- )[0]
227
-
228
- processing_time = time.time() - start_time
229
-
230
- # Post-process extracted data
231
- processed_data = self._post_process_extraction(output_text, extraction_format)
232
-
233
- return {
234
- 'success': True,
235
- 'service': 'qwen-vision-table',
236
- 'extracted_data': processed_data,
237
- 'raw_output': output_text,
238
- 'format': extraction_format,
239
- 'processing_time': processing_time,
240
- 'model_info': {
241
- 'model': 'Qwen2.5-VL-32B-Instruct-AWQ',
242
- 'gpu': 'A100',
243
- 'quantization': 'AWQ',
244
- 'container_id': os.environ.get('MODAL_TASK_ID', 'unknown')
245
- }
246
- }
247
-
248
- except Exception as e:
249
- self.logger.error(f"Table extraction failed: {e}")
250
- return {
251
- 'success': False,
252
- 'service': 'qwen-vision-table',
253
- 'error': str(e),
254
- 'processing_time': time.time() - start_time
255
- }
256
-
257
- def _get_extraction_prompt(self, format_type: str) -> str:
258
- """Get extraction prompt based on desired format"""
259
- base_prompt = "Please extract all the data from this table accurately."
260
-
261
- format_prompts = {
262
- "markdown": f"{base_prompt} Format the output as a markdown table with proper alignment.",
263
- "json": f"{base_prompt} Format the output as a JSON array where each row is an object with column headers as keys.",
264
- "csv": f"{base_prompt} Format the output as CSV with comma-separated values. Include headers in the first row.",
265
- "html": f"{base_prompt} Format the output as an HTML table with proper <table>, <tr>, <td>, and <th> tags.",
266
- }
267
-
268
- return format_prompts.get(format_type, base_prompt)
269
-
270
- def _post_process_extraction(self, raw_output: str, format_type: str) -> Dict[str, Any]:
271
- """Post-process extracted table data"""
272
- try:
273
- if format_type == "json":
274
- # Try to parse JSON
275
- import json
276
- try:
277
- # Extract JSON from the output if it's wrapped in text
278
- start_idx = raw_output.find('[')
279
- end_idx = raw_output.rfind(']') + 1
280
- if start_idx != -1 and end_idx != 0:
281
- json_str = raw_output[start_idx:end_idx]
282
- parsed_data = json.loads(json_str)
283
- return {"structured_data": parsed_data, "raw_text": raw_output}
284
- except json.JSONDecodeError:
285
- pass
286
-
287
- elif format_type == "csv":
288
- # Parse CSV-like output
289
- lines = raw_output.strip().split('\n')
290
- csv_data = [line.split(',') for line in lines if line.strip()]
291
- return {"structured_data": csv_data, "raw_text": raw_output}
292
-
293
- # For markdown, html, or unparseable formats, return as text
294
- return {"structured_data": raw_output, "raw_text": raw_output}
295
-
296
- except Exception as e:
297
- self.logger.warning(f"Post-processing failed: {e}")
298
- return {"structured_data": raw_output, "raw_text": raw_output}
299
-
300
- @modal.method()
301
- def batch_extract_tables(self, images_b64: List[str], extraction_format: str = "markdown") -> Dict[str, Any]:
302
- """
303
- Extract tables from multiple images
304
-
305
- Args:
306
- images_b64: List of base64 encoded images
307
- extraction_format: Output format for all extractions
308
-
309
- Returns:
310
- Batch extraction results
311
- """
312
- start_time = time.time()
313
- results = []
314
-
315
- for i, image_b64 in enumerate(images_b64):
316
- try:
317
- result = self.extract_table_data(image_b64, extraction_format)
318
- result['image_index'] = i
319
- results.append(result)
320
- except Exception as e:
321
- results.append({
322
- 'success': False,
323
- 'image_index': i,
324
- 'error': str(e)
325
- })
326
-
327
- return {
328
- 'success': True,
329
- 'service': 'qwen-vision-table',
330
- 'batch_results': results,
331
- 'total_images': len(images_b64),
332
- 'successful_extractions': sum(1 for r in results if r.get('success', False)),
333
- 'total_processing_time': time.time() - start_time
334
- }
335
-
336
- @modal.method()
337
- def health_check(self) -> Dict[str, Any]:
338
- """Health check endpoint"""
339
- return {
340
- 'status': 'healthy',
341
- 'service': 'qwen-vision-table',
342
- 'model': 'Qwen2.5-VL-32B-Instruct-AWQ',
343
- 'model_loaded': self.model is not None,
344
- 'processor_loaded': self.processor is not None,
345
- 'timestamp': time.time(),
346
- 'gpu': 'A100'
347
- }
348
-
349
- def _decode_image(self, image_b64: str) -> Image.Image:
350
- """Decode base64 image"""
351
- try:
352
- if image_b64.startswith('data:image'):
353
- image_b64 = image_b64.split(',')[1]
354
-
355
- image_data = base64.b64decode(image_b64)
356
- return Image.open(io.BytesIO(image_data)).convert('RGB')
357
- except Exception as e:
358
- raise ValueError(f"Failed to decode image: {e}")
359
-
360
- # Helper function for vision processing
361
- def process_vision_info(messages):
362
- """Process vision information from messages"""
363
- image_inputs = []
364
- video_inputs = []
365
-
366
- for message in messages:
367
- if isinstance(message.get("content"), list):
368
- for content in message["content"]:
369
- if content.get("type") == "image":
370
- image_inputs.append(content["image"])
371
- elif content.get("type") == "video":
372
- video_inputs.append(content["video"])
373
-
374
- return image_inputs, video_inputs
375
-
376
- # Deployment script
377
- @app.function()
378
- def deploy_info():
379
- """Deployment information"""
380
- return {
381
- "service": "Qwen2.5-VL-32B Table Extraction",
382
- "model": "Qwen/Qwen2.5-VL-32B-Instruct-AWQ",
383
- "gpu_requirement": "A100 (minimum), H100 (recommended)",
384
- "memory_requirement": "32GB+",
385
- "deploy_command": "modal deploy qwen_table_extraction.py"
386
- }
387
-
388
- # Auto-registration function
389
- @app.function()
390
- async def register_service():
391
- """Auto-register this service in the model registry"""
392
- try:
393
- import sys
394
- from pathlib import Path
395
-
396
- # Add project root to path for imports
397
- project_root = Path(__file__).parent.parent.parent.parent
398
- sys.path.insert(0, str(project_root))
399
-
400
- try:
401
- from isa_model.core.model_manager import ModelManager
402
- from isa_model.core.model_repo import ModelType, ModelCapability
403
- from isa_model.core.service_registry import ServiceRegistry
404
- from isa_model.core.types import ServiceType, DeploymentPlatform, ServiceStatus, ResourceRequirements
405
- from isa_model.core.model_service import ModelService
406
- except ImportError:
407
- # Fallback if import fails in Modal environment
408
- print("⚠️ Could not import required modules - registration skipped")
409
- return {"success": False, "error": "Required modules not available"}
410
-
411
- # Use ModelManager to register this service
412
- model_manager = ModelManager()
413
-
414
- # 1. First register the underlying model (backward compatibility)
415
- model_success = model_manager.registry.register_model(
416
- model_id="qwen2.5-vl-32b-table-service",
417
- model_type=ModelType.VISION,
418
- capabilities=[
419
- ModelCapability.TABLE_DETECTION,
420
- ModelCapability.TABLE_STRUCTURE_RECOGNITION,
421
- ModelCapability.OCR,
422
- ModelCapability.IMAGE_ANALYSIS
423
- ],
424
- metadata={
425
- "description": "Qwen2.5-VL-32B table extraction service",
426
- "service_name": "qwen-vision-table",
427
- "service_type": "modal",
428
- "deployment_type": "modal",
429
- "endpoint": "https://qwen-vision-table.modal.run",
430
- "underlying_model": "Qwen/Qwen2.5-VL-32B-Instruct-AWQ",
431
- "gpu_requirement": "A100",
432
- "memory_mb": 32768,
433
- "auto_registered": True,
434
- "registered_by": "isa_vision_table_service.py",
435
- "is_service": True # Mark this as a service, not a raw model
436
- }
437
- )
438
-
439
- # 2. Register as a deployed service in the ServiceRegistry (MaaS platform)
440
- service_success = False
441
- try:
442
- service_registry = ServiceRegistry(model_manager.registry)
443
-
444
- # Create ModelService instance
445
- service = ModelService(
446
- service_id="qwen-table-modal-001",
447
- service_name="isa_vision_table",
448
- model_id="qwen2.5-vl-32b-table-service",
449
- deployment_platform=DeploymentPlatform.MODAL,
450
- service_type=ServiceType.VISION,
451
- status=ServiceStatus.HEALTHY,
452
- inference_endpoint="https://qwen-vision-table.modal.run/extract_table_data",
453
- health_endpoint="https://qwen-vision-table.modal.run/health_check",
454
- capabilities=["table_detection", "table_structure_recognition", "ocr", "image_analysis"],
455
- resource_requirements=ResourceRequirements(
456
- gpu_type="A100",
457
- memory_mb=32768,
458
- cpu_cores=8,
459
- min_replicas=0,
460
- max_replicas=3
461
- ),
462
- metadata={
463
- "description": "Qwen2.5-VL-32B table extraction service",
464
- "underlying_model": "Qwen/Qwen2.5-VL-32B-Instruct-AWQ",
465
- "auto_scaling": True,
466
- "scale_to_zero": True,
467
- "platform": "modal",
468
- "registered_by": "isa_vision_table_service.py"
469
- }
470
- )
471
-
472
- # Register in ServiceRegistry
473
- service_success = await service_registry.register_service(service)
474
-
475
- if service_success:
476
- print("✅ Service registered in MaaS platform ServiceRegistry")
477
- else:
478
- print("⚠️ ServiceRegistry registration failed")
479
-
480
- except Exception as e:
481
- print(f"⚠️ ServiceRegistry registration error: {e}")
482
-
483
- if model_success:
484
- print("✅ Model registry registration successful")
485
- else:
486
- print("⚠️ Model registry registration failed")
487
-
488
- overall_success = model_success and service_success
489
- return {
490
- "success": overall_success,
491
- "model_registry": model_success,
492
- "service_registry": service_success
493
- }
494
-
495
- except Exception as e:
496
- print(f"❌ Auto-registration error: {e}")
497
- return {"success": False, "error": str(e)}
498
-
499
- # Quick deployment function
500
- @app.function()
501
- def deploy_service():
502
- """Deploy this service instantly"""
503
- import subprocess
504
-
505
- print("🚀 Deploying Qwen2.5-VL Table Extraction Service...")
506
- try:
507
- # Get the current file path
508
- current_file = __file__
509
-
510
- # Run modal deploy command
511
- result = subprocess.run(
512
- ["modal", "deploy", current_file],
513
- capture_output=True,
514
- text=True,
515
- check=True
516
- )
517
-
518
- print("✅ Deployment completed successfully!")
519
- print(f"📝 Output: {result.stdout}")
520
- return {"success": True, "output": result.stdout}
521
-
522
- except subprocess.CalledProcessError as e:
523
- print(f"❌ Deployment failed: {e}")
524
- print(f"📝 Error: {e.stderr}")
525
- return {"success": False, "error": str(e), "stderr": e.stderr}
526
-
527
- if __name__ == "__main__":
528
- print("🚀 Qwen2.5-VL Table Extraction Service - Modal Deployment")
529
- print("Deploy with: modal deploy isa_vision_table_service.py")
530
- print("Or call: modal run isa_vision_table_service.py::deploy_service")
531
- print("Note: Requires A100 GPU and 32GB+ RAM for optimal performance")
532
- print("\n📝 Service will auto-register in model registry upon deployment")