isa-model 0.3.6__tar.gz → 0.3.7__tar.gz

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 (158) hide show
  1. {isa_model-0.3.6 → isa_model-0.3.7}/PKG-INFO +1 -1
  2. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/client.py +170 -3
  3. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/services/auto_deploy_vision_service.py +4 -3
  4. isa_model-0.3.7/isa_model/deployment/services/simple_auto_deploy_vision_service.py +275 -0
  5. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/ai_factory.py +83 -3
  6. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/routes/unified.py +72 -0
  7. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model.egg-info/PKG-INFO +1 -1
  8. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model.egg-info/SOURCES.txt +1 -0
  9. {isa_model-0.3.6 → isa_model-0.3.7}/pyproject.toml +1 -1
  10. {isa_model-0.3.6 → isa_model-0.3.7}/tests/test_isa_model_client_http.py +149 -1
  11. {isa_model-0.3.6 → isa_model-0.3.7}/MANIFEST.in +0 -0
  12. {isa_model-0.3.6 → isa_model-0.3.7}/README.md +0 -0
  13. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/__init__.py +0 -0
  14. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/config/__init__.py +0 -0
  15. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/config/config_manager.py +0 -0
  16. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/config.py +0 -0
  17. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/models/model_billing_tracker.py +0 -0
  18. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/models/model_manager.py +0 -0
  19. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/models/model_repo.py +0 -0
  20. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/models/model_storage.py +0 -0
  21. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/pricing_manager.py +0 -0
  22. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/services/__init__.py +0 -0
  23. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/services/intelligent_model_selector.py +0 -0
  24. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/storage/hf_storage.py +0 -0
  25. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/storage/local_storage.py +0 -0
  26. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/storage/minio_storage.py +0 -0
  27. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/core/types.py +0 -0
  28. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/__init__.py +0 -0
  29. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/cloud/__init__.py +0 -0
  30. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/cloud/modal/__init__.py +0 -0
  31. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/cloud/modal/isa_vision_doc_service.py +0 -0
  32. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/cloud/modal/isa_vision_table_service.py +0 -0
  33. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/cloud/modal/isa_vision_ui_service.py +0 -0
  34. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/cloud/modal/register_models.py +0 -0
  35. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/core/__init__.py +0 -0
  36. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/core/deployment_config.py +0 -0
  37. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/core/deployment_manager.py +0 -0
  38. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/core/isa_deployment_service.py +0 -0
  39. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/gpu_int8_ds8/app/server.py +0 -0
  40. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/gpu_int8_ds8/scripts/test_client.py +0 -0
  41. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/gpu_int8_ds8/scripts/test_client_os.py +0 -0
  42. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/runtime/deployed_service.py +0 -0
  43. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/services/__init__.py +0 -0
  44. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/services/model_service.py +0 -0
  45. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/services/service_monitor.py +0 -0
  46. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/deployment/services/service_registry.py +0 -0
  47. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/__init__.py +0 -0
  48. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/benchmarks.py +0 -0
  49. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/config/__init__.py +0 -0
  50. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/config/evaluation_config.py +0 -0
  51. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/evaluators/__init__.py +0 -0
  52. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/evaluators/base_evaluator.py +0 -0
  53. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/evaluators/llm_evaluator.py +0 -0
  54. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/factory.py +0 -0
  55. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/infrastructure/__init__.py +0 -0
  56. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/infrastructure/experiment_tracker.py +0 -0
  57. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/eval/metrics.py +0 -0
  58. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/__init__.py +0 -0
  59. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/adapter/unified_api.py +0 -0
  60. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/base.py +0 -0
  61. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/__init__.py +0 -0
  62. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/base_provider.py +0 -0
  63. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/ml_provider.py +0 -0
  64. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/modal_provider.py +0 -0
  65. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/model_cache_manager.py +0 -0
  66. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/ollama_provider.py +0 -0
  67. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/openai_provider.py +0 -0
  68. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/replicate_provider.py +0 -0
  69. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/triton_provider.py +0 -0
  70. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/providers/yyds_provider.py +0 -0
  71. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/__init__.py +0 -0
  72. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/audio/base_stt_service.py +0 -0
  73. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/audio/base_tts_service.py +0 -0
  74. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/audio/openai_realtime_service.py +0 -0
  75. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/audio/openai_stt_service.py +0 -0
  76. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/audio/openai_tts_service.py +0 -0
  77. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/audio/replicate_tts_service.py +0 -0
  78. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/base_service.py +0 -0
  79. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/embedding/base_embed_service.py +0 -0
  80. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/embedding/helpers/text_splitter.py +0 -0
  81. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/embedding/ollama_embed_service.py +0 -0
  82. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/embedding/openai_embed_service.py +0 -0
  83. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/helpers/stacked_config.py +0 -0
  84. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/img/__init__.py +0 -0
  85. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/img/base_image_gen_service.py +0 -0
  86. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/img/flux_professional_service.py +0 -0
  87. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/img/helpers/base_stacked_service.py +0 -0
  88. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/img/replicate_image_gen_service.py +0 -0
  89. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/__init__.py +0 -0
  90. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/base_llm_service.py +0 -0
  91. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/helpers/llm_adapter.py +0 -0
  92. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/helpers/llm_prompts.py +0 -0
  93. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/helpers/llm_utils.py +0 -0
  94. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/ollama_llm_service.py +0 -0
  95. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/openai_llm_service.py +0 -0
  96. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/llm/yyds_llm_service.py +0 -0
  97. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/ml/base_ml_service.py +0 -0
  98. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/ml/sklearn_ml_service.py +0 -0
  99. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/others/table_transformer_service.py +0 -0
  100. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/__init__.py +0 -0
  101. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/base_vision_service.py +0 -0
  102. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/disabled/isA_vision_service.py +0 -0
  103. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/doc_analysis_service.py +0 -0
  104. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/helpers/base_stacked_service.py +0 -0
  105. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/helpers/image_utils.py +0 -0
  106. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/helpers/vision_prompts.py +0 -0
  107. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/openai_vision_service.py +0 -0
  108. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/replicate_vision_service.py +0 -0
  109. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/services/vision/ui_analysis_service.py +0 -0
  110. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/utils/conversion/bge_rerank_convert.py +0 -0
  111. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/utils/conversion/onnx_converter.py +0 -0
  112. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/inference/utils/conversion/torch_converter.py +0 -0
  113. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/scripts/inference_tracker.py +0 -0
  114. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/scripts/mlflow_manager.py +0 -0
  115. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/scripts/model_registry.py +0 -0
  116. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/scripts/register_models.py +0 -0
  117. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/scripts/register_models_with_embeddings.py +0 -0
  118. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/scripts/start_mlflow.py +0 -0
  119. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/scripts/training_tracker.py +0 -0
  120. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/__init__.py +0 -0
  121. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/__init__.py +0 -0
  122. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/fastapi_server.py +0 -0
  123. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/middleware/__init__.py +0 -0
  124. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/middleware/request_logger.py +0 -0
  125. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/routes/__init__.py +0 -0
  126. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/routes/health.py +0 -0
  127. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/routes/llm.py +0 -0
  128. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/routes/ui_analysis.py +0 -0
  129. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/routes/vision.py +0 -0
  130. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/schemas/__init__.py +0 -0
  131. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/schemas/common.py +0 -0
  132. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/serving/api/schemas/ui_analysis.py +0 -0
  133. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/__init__.py +0 -0
  134. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/annotation_schema.py +0 -0
  135. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/processors/annotation_processor.py +0 -0
  136. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/storage/dataset_manager.py +0 -0
  137. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/storage/dataset_schema.py +0 -0
  138. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/tests/test_annotation_flow.py +0 -0
  139. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/tests/test_minio copy.py +0 -0
  140. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/tests/test_minio_upload.py +0 -0
  141. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/annotation/views/annotation_controller.py +0 -0
  142. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/cloud/__init__.py +0 -0
  143. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/cloud/job_orchestrator.py +0 -0
  144. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/cloud/runpod_trainer.py +0 -0
  145. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/cloud/storage_manager.py +0 -0
  146. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/core/__init__.py +0 -0
  147. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/core/config.py +0 -0
  148. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/core/dataset.py +0 -0
  149. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/core/trainer.py +0 -0
  150. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/core/utils.py +0 -0
  151. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model/training/factory.py +0 -0
  152. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model.egg-info/dependency_links.txt +0 -0
  153. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model.egg-info/requires.txt +0 -0
  154. {isa_model-0.3.6 → isa_model-0.3.7}/isa_model.egg-info/top_level.txt +0 -0
  155. {isa_model-0.3.6 → isa_model-0.3.7}/setup.cfg +0 -0
  156. {isa_model-0.3.6 → isa_model-0.3.7}/setup.py +0 -0
  157. {isa_model-0.3.6 → isa_model-0.3.7}/tests/test_cleaned_ai_factory.py +0 -0
  158. {isa_model-0.3.6 → isa_model-0.3.7}/tests/test_isa_model_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isa_model
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: Unified AI model serving framework
5
5
  Author: isA_Model Contributors
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -89,6 +89,47 @@ class ISAModelClient:
89
89
 
90
90
  logger.info("ISA Model Client initialized")
91
91
 
92
+ async def stream(
93
+ self,
94
+ input_data: Union[str, bytes, Path, Dict[str, Any]],
95
+ task: str,
96
+ service_type: str,
97
+ model_hint: Optional[str] = None,
98
+ provider_hint: Optional[str] = None,
99
+ **kwargs
100
+ ):
101
+ """
102
+ Streaming invoke method that yields tokens in real-time
103
+
104
+ Args:
105
+ input_data: Input data (text for LLM streaming)
106
+ task: Task to perform
107
+ service_type: Type of service (only "text" supports streaming)
108
+ model_hint: Optional model preference
109
+ provider_hint: Optional provider preference
110
+ **kwargs: Additional parameters
111
+
112
+ Yields:
113
+ Individual tokens as they arrive from the model
114
+
115
+ Example:
116
+ async for token in client.stream("Hello world", "chat", "text"):
117
+ print(token, end="", flush=True)
118
+ """
119
+ if service_type != "text":
120
+ raise ValueError("Streaming is only supported for text/LLM services")
121
+
122
+ try:
123
+ if self.mode == "api":
124
+ async for token in self._stream_api(input_data, task, service_type, model_hint, provider_hint, **kwargs):
125
+ yield token
126
+ else:
127
+ async for token in self._stream_local(input_data, task, service_type, model_hint, provider_hint, **kwargs):
128
+ yield token
129
+ except Exception as e:
130
+ logger.error(f"Failed to stream {task} on {service_type}: {e}")
131
+ raise
132
+
92
133
  async def invoke(
93
134
  self,
94
135
  input_data: Union[str, bytes, Path, Dict[str, Any]],
@@ -96,8 +137,9 @@ class ISAModelClient:
96
137
  service_type: str,
97
138
  model_hint: Optional[str] = None,
98
139
  provider_hint: Optional[str] = None,
140
+ stream: bool = False,
99
141
  **kwargs
100
- ) -> Dict[str, Any]:
142
+ ) -> Union[Dict[str, Any], object]:
101
143
  """
102
144
  Unified invoke method with intelligent model selection
103
145
 
@@ -107,10 +149,12 @@ class ISAModelClient:
107
149
  service_type: Type of service (vision, audio, text, image, embedding)
108
150
  model_hint: Optional model preference
109
151
  provider_hint: Optional provider preference
152
+ stream: Enable streaming for text services (returns AsyncGenerator)
110
153
  **kwargs: Additional task-specific parameters
111
154
 
112
155
  Returns:
113
- Unified response dictionary with result and metadata
156
+ If stream=False: Unified response dictionary with result and metadata
157
+ If stream=True: AsyncGenerator yielding tokens (only for text services)
114
158
 
115
159
  Examples:
116
160
  # Vision tasks
@@ -126,6 +170,10 @@ class ISAModelClient:
126
170
  await client.invoke("Translate this text", "translate", "text")
127
171
  await client.invoke("What is AI?", "chat", "text")
128
172
 
173
+ # Streaming text
174
+ async for token in await client.invoke("Hello", "chat", "text", stream=True):
175
+ print(token, end="", flush=True)
176
+
129
177
  # Image generation
130
178
  await client.invoke("A beautiful sunset", "generate_image", "image")
131
179
 
@@ -133,7 +181,31 @@ class ISAModelClient:
133
181
  await client.invoke("Text to embed", "create_embedding", "embedding")
134
182
  """
135
183
  try:
136
- # Route to appropriate mode
184
+ # Handle streaming case
185
+ if stream:
186
+ if service_type != "text":
187
+ raise ValueError("Streaming is only supported for text services")
188
+
189
+ if self.mode == "api":
190
+ return self._stream_api(
191
+ input_data=input_data,
192
+ task=task,
193
+ service_type=service_type,
194
+ model_hint=model_hint,
195
+ provider_hint=provider_hint,
196
+ **kwargs
197
+ )
198
+ else:
199
+ return self._stream_local(
200
+ input_data=input_data,
201
+ task=task,
202
+ service_type=service_type,
203
+ model_hint=model_hint,
204
+ provider_hint=provider_hint,
205
+ **kwargs
206
+ )
207
+
208
+ # Route to appropriate mode for non-streaming
137
209
  if self.mode == "api":
138
210
  return await self._invoke_api(
139
211
  input_data=input_data,
@@ -744,6 +816,101 @@ class ISAModelClient:
744
816
  logger.error(f"API binary upload failed: {e}")
745
817
  raise
746
818
 
819
+ async def _stream_local(
820
+ self,
821
+ input_data: Union[str, bytes, Path, Dict[str, Any]],
822
+ task: str,
823
+ service_type: str,
824
+ model_hint: Optional[str] = None,
825
+ provider_hint: Optional[str] = None,
826
+ **kwargs
827
+ ):
828
+ """Local streaming using AI Factory"""
829
+ # Step 1: Select best model for this task
830
+ selected_model = await self._select_model(
831
+ input_data=input_data,
832
+ task=task,
833
+ service_type=service_type,
834
+ model_hint=model_hint,
835
+ provider_hint=provider_hint
836
+ )
837
+
838
+ # Step 2: Get appropriate service
839
+ service = await self._get_service(
840
+ service_type=service_type,
841
+ model_name=selected_model["model_id"],
842
+ provider=selected_model["provider"],
843
+ task=task
844
+ )
845
+
846
+ # Step 3: Yield tokens from the stream
847
+ async for token in service.astream(input_data):
848
+ yield token
849
+
850
+ async def _stream_api(
851
+ self,
852
+ input_data: Union[str, bytes, Path, Dict[str, Any]],
853
+ task: str,
854
+ service_type: str,
855
+ model_hint: Optional[str] = None,
856
+ provider_hint: Optional[str] = None,
857
+ **kwargs
858
+ ):
859
+ """API streaming using Server-Sent Events (SSE)"""
860
+
861
+ # Only support text streaming for now
862
+ if not isinstance(input_data, (str, dict)):
863
+ raise ValueError("API streaming only supports text input")
864
+
865
+ payload = {
866
+ "input_data": input_data,
867
+ "task": task,
868
+ "service_type": service_type,
869
+ "model_hint": model_hint,
870
+ "provider_hint": provider_hint,
871
+ "stream": True,
872
+ "parameters": kwargs
873
+ }
874
+
875
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=300)) as session:
876
+ try:
877
+ async with session.post(
878
+ f"{self.api_url}/api/v1/stream",
879
+ json=payload,
880
+ headers=self.headers
881
+ ) as response:
882
+
883
+ if response.status == 200:
884
+ # Parse SSE stream
885
+ async for line in response.content:
886
+ if line:
887
+ line_str = line.decode().strip()
888
+ if line_str.startswith("data: "):
889
+ try:
890
+ # Parse SSE data
891
+ import json
892
+ json_str = line_str[6:] # Remove "data: " prefix
893
+ data = json.loads(json_str)
894
+
895
+ if data.get("type") == "token" and "token" in data:
896
+ yield data["token"]
897
+ elif data.get("type") == "completion":
898
+ # End of stream
899
+ break
900
+ elif data.get("type") == "error":
901
+ raise Exception(f"Server error: {data.get('error')}")
902
+
903
+ except json.JSONDecodeError:
904
+ # Skip malformed lines
905
+ continue
906
+ else:
907
+ error_data = await response.text()
908
+ raise Exception(f"API streaming error {response.status}: {error_data}")
909
+
910
+ except Exception as e:
911
+ logger.error(f"API streaming failed: {e}")
912
+ raise
913
+
747
914
 
748
915
  # Convenience function for quick access
749
916
  def create_client(
@@ -19,10 +19,11 @@ class AutoDeployVisionService(BaseVisionService):
19
19
  of Modal services for ISA vision tasks.
20
20
  """
21
21
 
22
- def __init__(self, provider_name: str = "modal", model_name: str = "qwen_table", **kwargs):
23
- # Use centralized architecture
24
- super().__init__(provider_name, model_name, **kwargs)
22
+ def __init__(self, model_name: str = "isa_vision_table", config: dict = None, **kwargs):
23
+ # Initialize BaseVisionService with modal provider
24
+ super().__init__("modal", model_name, **kwargs)
25
25
  self.model_name = model_name
26
+ self.config = config or {}
26
27
  self.underlying_service = None
27
28
  self._factory = None
28
29
 
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple Auto-Deploy Vision Service Wrapper
4
+
5
+ A simplified version that avoids complex import dependencies.
6
+ """
7
+
8
+ import asyncio
9
+ import subprocess
10
+ import logging
11
+ import time
12
+ from typing import Dict, Any, Optional, Union, List, BinaryIO
13
+ from pathlib import Path
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class SimpleAutoDeployVisionService:
18
+ """
19
+ Simplified vision service wrapper that handles automatic deployment
20
+ of Modal services for ISA vision tasks without complex inheritance.
21
+ """
22
+
23
+ def __init__(self, model_name: str = "isa_vision_ui", config: dict = None):
24
+ self.model_name = model_name
25
+ self.config = config or {}
26
+ self.underlying_service = None
27
+ self._factory = None
28
+ self._modal_deployed = False
29
+
30
+ logger.info(f"Initialized SimpleAutoDeployVisionService for {model_name}")
31
+
32
+ def _get_factory(self):
33
+ """Get AIFactory instance for service management"""
34
+ if not self._factory:
35
+ from isa_model.inference.ai_factory import AIFactory
36
+ self._factory = AIFactory()
37
+ return self._factory
38
+
39
+ async def _ensure_service_deployed(self) -> bool:
40
+ """Ensure the Modal service is deployed before use"""
41
+ if self._modal_deployed:
42
+ logger.info(f"Service {self.model_name} already deployed")
43
+ return True
44
+
45
+ try:
46
+ factory = self._get_factory()
47
+
48
+ # Check if service is available
49
+ app_name = factory._get_modal_app_name(self.model_name)
50
+ if not factory._check_modal_service_availability(app_name):
51
+ logger.info(f"Deploying {self.model_name} service...")
52
+ success = factory._auto_deploy_modal_service(self.model_name)
53
+ if not success:
54
+ logger.error(f"Failed to deploy {self.model_name}")
55
+ return False
56
+
57
+ # Wait for service to be ready
58
+ logger.info(f"Waiting for {self.model_name} service to be ready...")
59
+ await self._wait_for_service_ready(app_name)
60
+
61
+ # Mark as deployed
62
+ self._modal_deployed = True
63
+
64
+ # Initialize underlying service using proper factory method
65
+ if not self.underlying_service:
66
+ # Create a simple mock service for testing
67
+ self.underlying_service = MockModalVisionService(self.model_name)
68
+
69
+ return True
70
+
71
+ except Exception as e:
72
+ logger.error(f"Failed to ensure service deployment: {e}")
73
+ return False
74
+
75
+ async def _wait_for_service_ready(self, app_name: str, max_wait_time: int = 300):
76
+ """Wait for Modal service to be ready"""
77
+ logger.info(f"Waiting up to {max_wait_time} seconds for {app_name} to be ready...")
78
+ start_time = time.time()
79
+
80
+ while time.time() - start_time < max_wait_time:
81
+ try:
82
+ # Simple wait simulation
83
+ await asyncio.sleep(5)
84
+ logger.info(f"Still waiting for {app_name}... ({int(time.time() - start_time)}s elapsed)")
85
+
86
+ # For testing, assume service is ready after 10 seconds
87
+ if time.time() - start_time > 10:
88
+ logger.info(f"Service {app_name} assumed ready for testing!")
89
+ return
90
+
91
+ except Exception as e:
92
+ logger.debug(f"Service not ready yet: {e}")
93
+
94
+ logger.warning(f"Service {app_name} may not be fully ready after {max_wait_time}s")
95
+
96
+ async def detect_ui_elements(self, image: Union[str, BinaryIO]) -> Dict[str, Any]:
97
+ """Detect UI elements with auto-deploy"""
98
+
99
+ # Ensure service is deployed
100
+ if not await self._ensure_service_deployed():
101
+ return {
102
+ 'success': False,
103
+ 'error': f'Failed to deploy {self.model_name} service',
104
+ 'service': self.model_name
105
+ }
106
+
107
+ try:
108
+ # Call the underlying service (mock for testing)
109
+ logger.info(f"Calling UI detection service for {self.model_name}")
110
+ result = await self.underlying_service.detect_ui_elements(image)
111
+
112
+ return result
113
+
114
+ except Exception as e:
115
+ logger.error(f"UI detection failed: {e}")
116
+ return {
117
+ 'success': False,
118
+ 'error': str(e),
119
+ 'service': self.model_name
120
+ }
121
+
122
+ async def analyze_image(
123
+ self,
124
+ image: Union[str, BinaryIO],
125
+ prompt: Optional[str] = None,
126
+ max_tokens: int = 1000
127
+ ) -> Dict[str, Any]:
128
+ """Analyze image with auto-deploy"""
129
+ if not await self._ensure_service_deployed():
130
+ return {
131
+ 'success': False,
132
+ 'error': f'Failed to deploy {self.model_name} service',
133
+ 'service': self.model_name
134
+ }
135
+
136
+ try:
137
+ result = await self.underlying_service.analyze_image(image, prompt, max_tokens)
138
+ return result
139
+ except Exception as e:
140
+ logger.error(f"Image analysis failed: {e}")
141
+ return {
142
+ 'success': False,
143
+ 'error': str(e),
144
+ 'service': self.model_name
145
+ }
146
+
147
+ async def invoke(
148
+ self,
149
+ image: Union[str, BinaryIO],
150
+ prompt: Optional[str] = None,
151
+ task: Optional[str] = None,
152
+ **kwargs
153
+ ) -> Dict[str, Any]:
154
+ """Unified invoke method for all vision operations"""
155
+ if not await self._ensure_service_deployed():
156
+ return {
157
+ 'success': False,
158
+ 'error': f'Failed to deploy {self.model_name} service',
159
+ 'service': self.model_name
160
+ }
161
+
162
+ try:
163
+ # Route to appropriate method based on task
164
+ if task == "detect_ui_elements" or task == "ui_detection":
165
+ return await self.detect_ui_elements(image)
166
+ elif task == "analyze" or task is None:
167
+ return await self.analyze_image(image, prompt, kwargs.get("max_tokens", 1000))
168
+ else:
169
+ return await self.underlying_service.invoke(image, prompt, task, **kwargs)
170
+ except Exception as e:
171
+ logger.error(f"Vision invoke failed: {e}")
172
+ return {
173
+ 'success': False,
174
+ 'error': str(e),
175
+ 'service': self.model_name
176
+ }
177
+
178
+ def get_supported_formats(self) -> List[str]:
179
+ """Get list of supported image formats"""
180
+ return ['jpg', 'jpeg', 'png', 'gif', 'webp']
181
+
182
+ def get_max_image_size(self) -> Dict[str, int]:
183
+ """Get maximum supported image dimensions"""
184
+ return {"width": 2048, "height": 2048, "file_size_mb": 10}
185
+
186
+ async def close(self):
187
+ """Cleanup resources"""
188
+ if self.underlying_service:
189
+ await self.underlying_service.close()
190
+ logger.info(f"Closed {self.model_name} service")
191
+
192
+
193
+ class MockModalVisionService:
194
+ """Mock Modal vision service for testing"""
195
+
196
+ def __init__(self, model_name: str):
197
+ self.model_name = model_name
198
+ logger.info(f"Initialized mock service for {model_name}")
199
+
200
+ async def detect_ui_elements(self, image: Union[str, BinaryIO]) -> Dict[str, Any]:
201
+ """Mock UI element detection"""
202
+ await asyncio.sleep(0.1) # Simulate processing time
203
+
204
+ # Return mock UI elements based on model type
205
+ if "ui" in self.model_name:
206
+ ui_elements = [
207
+ {
208
+ 'id': 'ui_0',
209
+ 'type': 'button',
210
+ 'content': 'Search Button',
211
+ 'center': [400, 200],
212
+ 'bbox': [350, 180, 450, 220],
213
+ 'confidence': 0.95,
214
+ 'interactable': True
215
+ },
216
+ {
217
+ 'id': 'ui_1',
218
+ 'type': 'input',
219
+ 'content': 'Search Input',
220
+ 'center': [300, 150],
221
+ 'bbox': [200, 130, 400, 170],
222
+ 'confidence': 0.88,
223
+ 'interactable': True
224
+ }
225
+ ]
226
+ else:
227
+ ui_elements = []
228
+
229
+ return {
230
+ 'success': True,
231
+ 'service': self.model_name,
232
+ 'ui_elements': ui_elements,
233
+ 'element_count': len(ui_elements),
234
+ 'processing_time': 0.1,
235
+ 'detection_method': 'mock_omniparser',
236
+ 'model_info': {
237
+ 'primary': 'Mock OmniParser v2.0',
238
+ 'gpu': 'T4',
239
+ 'container_id': 'mock-container'
240
+ }
241
+ }
242
+
243
+ async def analyze_image(
244
+ self,
245
+ image: Union[str, BinaryIO],
246
+ prompt: Optional[str] = None,
247
+ max_tokens: int = 1000
248
+ ) -> Dict[str, Any]:
249
+ """Mock image analysis"""
250
+ await asyncio.sleep(0.1)
251
+
252
+ return {
253
+ 'success': True,
254
+ 'service': self.model_name,
255
+ 'text': f'Mock analysis of image with prompt: {prompt}',
256
+ 'confidence': 0.9,
257
+ 'processing_time': 0.1
258
+ }
259
+
260
+ async def invoke(
261
+ self,
262
+ image: Union[str, BinaryIO],
263
+ prompt: Optional[str] = None,
264
+ task: Optional[str] = None,
265
+ **kwargs
266
+ ) -> Dict[str, Any]:
267
+ """Mock invoke method"""
268
+ if task == "detect_ui_elements":
269
+ return await self.detect_ui_elements(image)
270
+ else:
271
+ return await self.analyze_image(image, prompt, kwargs.get("max_tokens", 1000))
272
+
273
+ async def close(self):
274
+ """Mock cleanup"""
275
+ pass
@@ -123,9 +123,9 @@ class AIFactory:
123
123
  # Handle special ISA vision services
124
124
  if model_name in ["isa_vision_table", "isa_vision_ui", "isa_vision_doc"]:
125
125
  try:
126
- from isa_model.inference.services.vision.auto_deploy_vision_service import AutoDeployVisionService
126
+ from isa_model.deployment.services.simple_auto_deploy_vision_service import SimpleAutoDeployVisionService
127
127
  logger.info(f"Creating auto-deploy service wrapper for {model_name}")
128
- return AutoDeployVisionService(model_name, config)
128
+ return SimpleAutoDeployVisionService(model_name, config)
129
129
  except Exception as e:
130
130
  logger.error(f"Failed to create ISA vision service: {e}")
131
131
  raise
@@ -347,4 +347,84 @@ class AIFactory:
347
347
  """Get the singleton instance"""
348
348
  if cls._instance is None:
349
349
  cls._instance = cls()
350
- return cls._instance
350
+ return cls._instance
351
+
352
+ # Modal service deployment methods for AutoDeployVisionService
353
+ def _get_modal_app_name(self, model_name: str) -> str:
354
+ """Get Modal app name for a given model"""
355
+ app_mapping = {
356
+ "isa_vision_table": "qwen-vision-table",
357
+ "isa_vision_ui": "isa-vision-ui",
358
+ "isa_vision_doc": "isa-vision-doc"
359
+ }
360
+ return app_mapping.get(model_name, f"unknown-{model_name}")
361
+
362
+ def _check_modal_service_availability(self, app_name: str) -> bool:
363
+ """Check if Modal service is available and running"""
364
+ try:
365
+ import modal
366
+ # Try to lookup the app
367
+ app = modal.App.lookup(app_name)
368
+ return True
369
+ except Exception as e:
370
+ logger.debug(f"Modal service {app_name} not available: {e}")
371
+ return False
372
+
373
+ def _auto_deploy_modal_service(self, model_name: str) -> bool:
374
+ """Auto-deploy Modal service for given model"""
375
+ try:
376
+ import subprocess
377
+ import os
378
+ from pathlib import Path
379
+
380
+ # Get the Modal service file path
381
+ service_files = {
382
+ "isa_vision_table": "isa_vision_table_service.py",
383
+ "isa_vision_ui": "isa_vision_ui_service.py",
384
+ "isa_vision_doc": "isa_vision_doc_service.py"
385
+ }
386
+
387
+ if model_name not in service_files:
388
+ logger.error(f"No Modal service file found for {model_name}")
389
+ return False
390
+
391
+ # Get the service file path
392
+ service_file = service_files[model_name]
393
+ modal_dir = Path(__file__).parent.parent / "deployment" / "cloud" / "modal"
394
+ service_path = modal_dir / service_file
395
+
396
+ if not service_path.exists():
397
+ logger.error(f"Modal service file not found: {service_path}")
398
+ return False
399
+
400
+ logger.info(f"Deploying Modal service: {service_file}")
401
+
402
+ # Run modal deploy command
403
+ result = subprocess.run(
404
+ ["modal", "deploy", str(service_path)],
405
+ capture_output=True,
406
+ text=True,
407
+ timeout=600, # 10 minute timeout
408
+ cwd=str(modal_dir)
409
+ )
410
+
411
+ if result.returncode == 0:
412
+ logger.info(f"Successfully deployed {model_name} Modal service")
413
+ return True
414
+ else:
415
+ logger.error(f"Failed to deploy {model_name}: {result.stderr}")
416
+ return False
417
+
418
+ except subprocess.TimeoutExpired:
419
+ logger.error(f"Deployment timeout for {model_name}")
420
+ return False
421
+ except Exception as e:
422
+ logger.error(f"Exception during {model_name} deployment: {e}")
423
+ return False
424
+
425
+ def _shutdown_modal_service(self, model_name: str):
426
+ """Shutdown Modal service (optional - Modal handles auto-scaling)"""
427
+ # Modal services auto-scale to zero, so explicit shutdown isn't required
428
+ # This method is here for compatibility with AutoDeployVisionService
429
+ logger.info(f"Modal service {model_name} will auto-scale to zero when idle")
430
+ pass