model-compose 0.3.9__tar.gz → 0.3.11__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 (234) hide show
  1. {model_compose-0.3.9 → model_compose-0.3.11}/PKG-INFO +7 -7
  2. {model_compose-0.3.9 → model_compose-0.3.11}/README.md +6 -6
  3. {model_compose-0.3.9 → model_compose-0.3.11}/pyproject.toml +1 -1
  4. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/base.py +13 -12
  5. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/component.py +9 -8
  6. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/context.py +9 -3
  7. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/http_server.py +1 -1
  8. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/base.py +35 -12
  9. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/tasks/__init__.py +1 -0
  10. model_compose-0.3.11/src/mindor/core/component/services/model/tasks/image_to_text.py +155 -0
  11. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/tasks/summarization.py +12 -10
  12. model_compose-0.3.11/src/mindor/core/component/services/model/tasks/text_classification.py +121 -0
  13. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/tasks/text_embedding.py +55 -22
  14. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/tasks/text_generation.py +12 -10
  15. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/tasks/translation.py +12 -10
  16. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/base.py +5 -5
  17. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/controller.py +2 -2
  18. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runner/http_client.py +2 -1
  19. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runner/mcp_client.py +1 -15
  20. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runtime/specs.py +9 -11
  21. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/services/http_server.py +24 -29
  22. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/services/mcp_server.py +6 -4
  23. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/webui/gradio.py +5 -5
  24. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/webui/webui.py +8 -6
  25. model_compose-0.3.11/src/mindor/core/gateway/services/http_tunnel.py +82 -0
  26. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/listener/services/http_callback.py +5 -3
  27. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/http_client.py +3 -3
  28. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/image.py +1 -1
  29. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/renderers.py +43 -9
  30. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/streaming.py +9 -0
  31. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/context.py +6 -3
  32. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/impl/__init__.py +2 -1
  33. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/impl/delay.py +4 -4
  34. model_compose-0.3.11/src/mindor/core/workflow/job/impl/filter.py +13 -0
  35. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/impl/if_.py +3 -3
  36. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/impl/random_router.py +3 -3
  37. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/impl/switch.py +3 -3
  38. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/schema.py +24 -24
  39. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/workflow.py +11 -10
  40. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/action.py +1 -1
  41. model_compose-0.3.11/src/mindor/dsl/schema/action/impl/common.py +7 -0
  42. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/http_client.py +1 -1
  43. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/http_server.py +1 -1
  44. {model_compose-0.3.9/src/mindor/dsl/schema/component → model_compose-0.3.11/src/mindor/dsl/schema/action}/impl/model/impl/__init__.py +1 -0
  45. model_compose-0.3.11/src/mindor/dsl/schema/action/impl/model/impl/image_to_text.py +12 -0
  46. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/model.py +1 -0
  47. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/common.py +2 -1
  48. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/http_client.py +7 -7
  49. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/http_server.py +3 -3
  50. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/mcp_client.py +3 -3
  51. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/mcp_server.py +3 -3
  52. {model_compose-0.3.9/src/mindor/dsl/schema/action → model_compose-0.3.11/src/mindor/dsl/schema/component}/impl/model/impl/__init__.py +1 -0
  53. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/model/impl/common.py +1 -9
  54. model_compose-0.3.11/src/mindor/dsl/schema/component/impl/model/impl/image_to_text.py +27 -0
  55. model_compose-0.3.11/src/mindor/dsl/schema/component/impl/model/impl/summarization.py +17 -0
  56. model_compose-0.3.11/src/mindor/dsl/schema/component/impl/model/impl/text_classification.py +17 -0
  57. model_compose-0.3.11/src/mindor/dsl/schema/component/impl/model/impl/text_embedding.py +17 -0
  58. model_compose-0.3.11/src/mindor/dsl/schema/component/impl/model/impl/text_generation.py +17 -0
  59. model_compose-0.3.11/src/mindor/dsl/schema/component/impl/model/impl/translation.py +17 -0
  60. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/model/impl/types.py +1 -0
  61. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/model/model.py +1 -0
  62. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/shell.py +4 -4
  63. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/text_splitter.py +3 -3
  64. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/workflow.py +3 -3
  65. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/compose.py +5 -5
  66. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/webui/webui.py +0 -1
  67. model_compose-0.3.11/src/mindor/dsl/schema/gateway/impl/http_tunnel/__init__.py +1 -0
  68. model_compose-0.3.11/src/mindor/dsl/schema/gateway/impl/http_tunnel/http_tunnel.py +11 -0
  69. model_compose-0.3.11/src/mindor/dsl/schema/gateway/impl/http_tunnel/impl/__init__.py +3 -0
  70. model_compose-0.3.11/src/mindor/dsl/schema/gateway/impl/http_tunnel/impl/cloudflare.py +7 -0
  71. model_compose-0.3.9/src/mindor/dsl/schema/gateway/impl/http_tunnel.py → model_compose-0.3.11/src/mindor/dsl/schema/gateway/impl/http_tunnel/impl/common.py +5 -4
  72. model_compose-0.3.11/src/mindor/dsl/schema/gateway/impl/http_tunnel/impl/ngrok.py +7 -0
  73. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/gateway/impl/ssh_tunnel.py +2 -0
  74. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/__init__.py +1 -0
  75. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/common.py +2 -1
  76. model_compose-0.3.11/src/mindor/dsl/schema/job/impl/filter.py +8 -0
  77. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/if_.py +1 -1
  78. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/switch.py +1 -1
  79. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/types.py +1 -0
  80. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/job.py +2 -1
  81. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/listener/impl/http_callback.py +6 -6
  82. model_compose-0.3.11/src/mindor/dsl/schema/transport/ssh.py +33 -0
  83. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/workflow.py +13 -12
  84. model_compose-0.3.11/src/mindor/dsl/utils/__init__.py +0 -0
  85. {model_compose-0.3.9 → model_compose-0.3.11}/src/model_compose.egg-info/PKG-INFO +7 -7
  86. {model_compose-0.3.9 → model_compose-0.3.11}/src/model_compose.egg-info/SOURCES.txt +13 -1
  87. model_compose-0.3.9/src/mindor/core/component/services/model/tasks/text_classification.py +0 -90
  88. model_compose-0.3.9/src/mindor/core/gateway/services/http_tunnel.py +0 -32
  89. model_compose-0.3.9/src/mindor/dsl/schema/action/impl/common.py +0 -6
  90. model_compose-0.3.9/src/mindor/dsl/schema/component/impl/model/impl/summarization.py +0 -9
  91. model_compose-0.3.9/src/mindor/dsl/schema/component/impl/model/impl/text_classification.py +0 -9
  92. model_compose-0.3.9/src/mindor/dsl/schema/component/impl/model/impl/text_embedding.py +0 -9
  93. model_compose-0.3.9/src/mindor/dsl/schema/component/impl/model/impl/text_generation.py +0 -9
  94. model_compose-0.3.9/src/mindor/dsl/schema/component/impl/model/impl/translation.py +0 -9
  95. {model_compose-0.3.9 → model_compose-0.3.11}/LICENSE +0 -0
  96. {model_compose-0.3.9 → model_compose-0.3.11}/setup.cfg +0 -0
  97. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/__init__.py +0 -0
  98. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/cli/__init__.py +0 -0
  99. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/cli/compose.py +0 -0
  100. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/__init__.py +0 -0
  101. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/__init__.py +0 -0
  102. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/__init__.py +0 -0
  103. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/http_client.py +0 -0
  104. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/mcp_client.py +0 -0
  105. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/mcp_server.py +0 -0
  106. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/__init__.py +0 -0
  107. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/model/model.py +0 -0
  108. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/shell.py +0 -0
  109. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/text_splitter.py +0 -0
  110. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/component/services/workflow.py +0 -0
  111. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/compose/__init__.py +0 -0
  112. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/compose/compose.py +0 -0
  113. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/compose/manager.py +0 -0
  114. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/__init__.py +0 -0
  115. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runner/__init__.py +0 -0
  116. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runner/client.py +0 -0
  117. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runner/runner.py +0 -0
  118. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runtime/__init__.py +0 -0
  119. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runtime/docker/__init__.py +0 -0
  120. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runtime/docker/context/Dockerfile +0 -0
  121. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runtime/docker/docker.py +0 -0
  122. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runtime/native/__init__.py +0 -0
  123. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/runtime/native/native.py +0 -0
  124. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/services/__init__.py +0 -0
  125. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/controller/webui/__init__.py +0 -0
  126. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/gateway/__init__.py +0 -0
  127. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/gateway/base.py +0 -0
  128. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/gateway/gateway.py +0 -0
  129. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/gateway/services/__init__.py +0 -0
  130. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/gateway/services/ssh_tunnel.py +0 -0
  131. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/listener/__init__.py +0 -0
  132. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/listener/base.py +0 -0
  133. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/listener/listener.py +0 -0
  134. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/listener/services/__init__.py +0 -0
  135. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/logger/__init__.py +0 -0
  136. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/logger/base.py +0 -0
  137. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/logger/logger.py +0 -0
  138. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/logger/logging.py +0 -0
  139. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/logger/services/__init__.py +0 -0
  140. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/logger/services/console.py +0 -0
  141. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/logger/services/file.py +0 -0
  142. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/runtime/__init__.py +0 -0
  143. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/runtime/docker/__init__.py +0 -0
  144. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/runtime/docker/docker.py +0 -0
  145. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/runtime/env.py +0 -0
  146. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/services/__init__.py +0 -0
  147. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/services/async_service.py +0 -0
  148. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/__init__.py +0 -0
  149. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/caching.py +0 -0
  150. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/http_request.py +0 -0
  151. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/http_status.py +0 -0
  152. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/mcp_client.py +0 -0
  153. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/resolvers.py +0 -0
  154. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/shell.py +0 -0
  155. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/ssh_client.py +0 -0
  156. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/streamer.py +0 -0
  157. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/time.py +0 -0
  158. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/utils/workqueue.py +0 -0
  159. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/__init__.py +0 -0
  160. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/__init__.py +0 -0
  161. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/base.py +0 -0
  162. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/impl/action.py +0 -0
  163. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/core/workflow/job/job.py +0 -0
  164. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/__init__.py +0 -0
  165. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/loader.py +0 -0
  166. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/__init__.py +0 -0
  167. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/__init__.py +0 -0
  168. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/__init__.py +0 -0
  169. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/mcp_client.py +0 -0
  170. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/mcp_server.py +0 -0
  171. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/__init__.py +0 -0
  172. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/impl/common.py +0 -0
  173. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/impl/summarization.py +0 -0
  174. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/impl/text_classification.py +0 -0
  175. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/impl/text_embedding.py +0 -0
  176. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/impl/text_generation.py +0 -0
  177. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/model/impl/translation.py +0 -0
  178. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/shell.py +0 -0
  179. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/text_splitter.py +0 -0
  180. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/action/impl/workflow.py +0 -0
  181. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/__init__.py +0 -0
  182. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/component.py +0 -0
  183. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/__init__.py +0 -0
  184. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/model/__init__.py +0 -0
  185. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/component/impl/types.py +0 -0
  186. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/__init__.py +0 -0
  187. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/controller.py +0 -0
  188. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/impl/__init__.py +0 -0
  189. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/impl/common.py +0 -0
  190. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/impl/http_server.py +0 -0
  191. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/impl/mcp_server.py +0 -0
  192. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/impl/types.py +0 -0
  193. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/webui/__init__.py +0 -0
  194. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/webui/impl/__init__.py +0 -0
  195. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/webui/impl/common.py +0 -0
  196. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/webui/impl/dynamic.py +0 -0
  197. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/webui/impl/gradio.py +0 -0
  198. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/controller/webui/impl/static.py +0 -0
  199. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/gateway/__init__.py +0 -0
  200. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/gateway/gateway.py +0 -0
  201. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/gateway/impl/__init__.py +0 -0
  202. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/gateway/impl/common.py +0 -0
  203. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/gateway/impl/types.py +0 -0
  204. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/__init__.py +0 -0
  205. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/action.py +0 -0
  206. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/delay.py +0 -0
  207. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/job/impl/random_router.py +0 -0
  208. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/listener/__init__.py +0 -0
  209. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/listener/impl/__init__.py +0 -0
  210. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/listener/impl/common.py +0 -0
  211. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/listener/impl/types.py +0 -0
  212. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/listener/listener.py +0 -0
  213. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/logger/__init__.py +0 -0
  214. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/logger/impl/__init__.py +0 -0
  215. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/logger/impl/common.py +0 -0
  216. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/logger/impl/console.py +0 -0
  217. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/logger/impl/file.py +0 -0
  218. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/logger/impl/types.py +0 -0
  219. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/logger/logger.py +0 -0
  220. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/runtime/__init__.py +0 -0
  221. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/runtime/impl/__init__.py +0 -0
  222. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/runtime/impl/common.py +0 -0
  223. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/runtime/impl/docker.py +0 -0
  224. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/runtime/impl/native.py +0 -0
  225. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/runtime/impl/types.py +0 -0
  226. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/schema/runtime/runtime.py +0 -0
  227. {model_compose-0.3.9/src/mindor/dsl/utils → model_compose-0.3.11/src/mindor/dsl/schema/transport}/__init__.py +0 -0
  228. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/utils/annotation.py +0 -0
  229. {model_compose-0.3.9 → model_compose-0.3.11}/src/mindor/dsl/utils/enum.py +0 -0
  230. {model_compose-0.3.9 → model_compose-0.3.11}/src/model_compose.egg-info/dependency_links.txt +0 -0
  231. {model_compose-0.3.9 → model_compose-0.3.11}/src/model_compose.egg-info/entry_points.txt +0 -0
  232. {model_compose-0.3.9 → model_compose-0.3.11}/src/model_compose.egg-info/requires.txt +0 -0
  233. {model_compose-0.3.9 → model_compose-0.3.11}/src/model_compose.egg-info/top_level.txt +0 -0
  234. {model_compose-0.3.9 → model_compose-0.3.11}/tests/test_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: model-compose
3
- Version: 0.3.9
3
+ Version: 0.3.11
4
4
  Summary: model-compose: Declarative AI Model and Workflow Orchestrator
5
5
  Author-email: Hanyeol Cho <hanyeol.cho@gmail.com>
6
6
  License-Expression: MIT
@@ -165,7 +165,7 @@ controller:
165
165
  port: 8081
166
166
 
167
167
  components:
168
- chatgpt:
168
+ - id: chatgpt
169
169
  type: http-client
170
170
  base_url: https://api.openai.com/v1
171
171
  path: /chat/completions
@@ -182,10 +182,10 @@ components:
182
182
  quote: ${response.choices[0].message.content}
183
183
 
184
184
  workflows:
185
- generate-quote:
185
+ - id: generate-quote
186
186
  default: true
187
187
  jobs:
188
- get-quote:
188
+ - id: get-quote
189
189
  component: chatgpt
190
190
  ```
191
191
 
@@ -302,7 +302,7 @@ controller:
302
302
  base_path: /mcp
303
303
 
304
304
  components:
305
- chatgpt:
305
+ - id: chatgpt
306
306
  type: http-client
307
307
  base_url: https://api.openai.com/v1
308
308
  path: /chat/completions
@@ -319,10 +319,10 @@ components:
319
319
  quote: ${response.choices[0].message.content}
320
320
 
321
321
  workflows:
322
- generate-quote:
322
+ - id: generate-quote
323
323
  default: true
324
324
  jobs:
325
- get-quote:
325
+ - id: get-quote
326
326
  component: chatgpt
327
327
  ```
328
328
  This configuration launches the controller as an **MCP server**, which listens on port 8080 and exposes your workflows over a **JSON-RPC API**.
@@ -136,7 +136,7 @@ controller:
136
136
  port: 8081
137
137
 
138
138
  components:
139
- chatgpt:
139
+ - id: chatgpt
140
140
  type: http-client
141
141
  base_url: https://api.openai.com/v1
142
142
  path: /chat/completions
@@ -153,10 +153,10 @@ components:
153
153
  quote: ${response.choices[0].message.content}
154
154
 
155
155
  workflows:
156
- generate-quote:
156
+ - id: generate-quote
157
157
  default: true
158
158
  jobs:
159
- get-quote:
159
+ - id: get-quote
160
160
  component: chatgpt
161
161
  ```
162
162
 
@@ -273,7 +273,7 @@ controller:
273
273
  base_path: /mcp
274
274
 
275
275
  components:
276
- chatgpt:
276
+ - id: chatgpt
277
277
  type: http-client
278
278
  base_url: https://api.openai.com/v1
279
279
  path: /chat/completions
@@ -290,10 +290,10 @@ components:
290
290
  quote: ${response.choices[0].message.content}
291
291
 
292
292
  workflows:
293
- generate-quote:
293
+ - id: generate-quote
294
294
  default: true
295
295
  jobs:
296
- get-quote:
296
+ - id: get-quote
297
297
  component: chatgpt
298
298
  ```
299
299
  This configuration launches the controller as an **MCP server**, which listens on port 8080 and exposes your workflows over a **JSON-RPC API**.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "model-compose"
3
- version = "0.3.9"
3
+ version = "0.3.11"
4
4
  description = "model-compose: Declarative AI Model and Workflow Orchestrator"
5
5
  authors = [
6
6
  { name = "Hanyeol Cho", email = "hanyeol.cho@gmail.com" }
@@ -10,40 +10,41 @@ from mindor.core.utils.workqueue import WorkQueue
10
10
  from .context import ComponentActionContext
11
11
 
12
12
  class ActionResolver:
13
- def __init__(self, actions: Dict[str, ActionConfig]):
14
- self.actions = actions
13
+ def __init__(self, actions: List[ActionConfig]):
14
+ self.actions: List[ActionConfig] = actions
15
15
 
16
16
  def resolve(self, action_id: Optional[str]) -> Tuple[str, ActionConfig]:
17
17
  action_id = action_id or self._find_default_id(self.actions)
18
+ action = next((action for action in self.actions if action.id == action_id), None)
18
19
 
19
- if not action_id in self.actions:
20
+ if action is None:
20
21
  raise ValueError(f"Action not found: {action_id}")
21
22
 
22
- return action_id, self.actions[action_id]
23
+ return action_id, action
23
24
 
24
- def _find_default_id(self, actions: Dict[str, ActionConfig]) -> str:
25
- default_ids = [ action_id for action_id, action in actions.items() if action.default ]
25
+ def _find_default_id(self, actions: List[ActionConfig]) -> str:
26
+ default_ids = [ action.id for action in actions if action.default or action.id == "__default__" ]
26
27
 
27
28
  if len(default_ids) > 1:
28
29
  raise ValueError("Multiple actions have default: true")
29
30
 
30
- if not default_ids and "__default__" not in actions:
31
+ if not default_ids:
31
32
  raise ValueError("No default action defined.")
32
33
 
33
- return default_ids[0] if default_ids else "__default__"
34
+ return default_ids[0]
34
35
 
35
36
  class ComponentGlobalConfigs:
36
37
  def __init__(
37
38
  self,
38
- components: Dict[str, ComponentConfig],
39
+ components: List[ComponentConfig],
39
40
  listeners: List[ListenerConfig],
40
41
  gateways: List[GatewayConfig],
41
- workflows: Dict[str, WorkflowConfig]
42
+ workflows: List[WorkflowConfig]
42
43
  ):
43
- self.components: Dict[str, ComponentConfig] = components
44
+ self.components: List[ComponentConfig] = components
44
45
  self.listeners: List[ListenerConfig] = listeners
45
46
  self.gateways: List[GatewayConfig] = gateways
46
- self.workflows: Dict[str, WorkflowConfig] = workflows
47
+ self.workflows: List[WorkflowConfig] = workflows
47
48
 
48
49
  class ComponentService(AsyncService):
49
50
  def __init__(self, id: str, config: ComponentConfig, global_configs: ComponentGlobalConfigs, daemon: bool):
@@ -5,27 +5,28 @@ from .base import ComponentService, ComponentGlobalConfigs, ComponentRegistry
5
5
  ComponentInstances: Dict[str, ComponentService] = {}
6
6
 
7
7
  class ComponentResolver:
8
- def __init__(self, components: Dict[str, ComponentConfig]):
9
- self.components: Dict[str, ComponentConfig] = components
8
+ def __init__(self, components: List[ComponentConfig]):
9
+ self.components: List[ComponentConfig] = components
10
10
 
11
11
  def resolve(self, component_id: Optional[str]) -> Tuple[str, ComponentConfig]:
12
12
  component_id = component_id or self._find_default_id(self.components)
13
+ component = next((component for component in self.components if component.id == component_id), None)
13
14
 
14
- if not component_id in self.components:
15
+ if component is None:
15
16
  raise ValueError(f"Component not found: {component_id}")
16
17
 
17
- return component_id, self.components[component_id]
18
+ return component_id, component
18
19
 
19
- def _find_default_id(self, components: Dict[str, ComponentConfig]) -> str:
20
- default_ids = [ component_id for component_id, component in components.items() if component.default ]
20
+ def _find_default_id(self, components: List[ComponentConfig]) -> str:
21
+ default_ids = [ component.id for component in components if component.default or component.id == "__default__" ]
21
22
 
22
23
  if len(default_ids) > 1:
23
24
  raise ValueError("Multiple components have default: true")
24
25
 
25
- if not default_ids and "__default__" not in components:
26
+ if not default_ids:
26
27
  raise ValueError("No default component defined.")
27
28
 
28
- return default_ids[0] if default_ids else "__default__"
29
+ return default_ids[0]
29
30
 
30
31
  def create_component(id: str, config: ComponentConfig, global_configs: ComponentGlobalConfigs, daemon: bool) -> ComponentService:
31
32
  try:
@@ -1,5 +1,5 @@
1
1
  from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
2
- from mindor.core.utils.renderers import VariableRenderer
2
+ from mindor.core.utils.renderers import VariableRenderer, ImageValueRenderer
3
3
  from mindor.core.gateway import find_gateway_by_port
4
4
 
5
5
  class ComponentActionContext:
@@ -13,8 +13,14 @@ class ComponentActionContext:
13
13
  def register_source(self, key: str, source: Any) -> None:
14
14
  self.sources[key] = source
15
15
 
16
- async def render_variable(self, data: Dict[str, Any], ignore_files: bool = False) -> Any:
17
- return await self.renderer.render(data, ignore_files)
16
+ async def render_variable(self, value: Any, ignore_files: bool = False) -> Any:
17
+ return await self.renderer.render(value, ignore_files)
18
+
19
+ async def render_image(self, value: Any) -> Any:
20
+ return await ImageValueRenderer().render(await self.render_variable(value))
21
+
22
+ def contains_variable_reference(self, key: str, value: Any) -> bool:
23
+ return self.renderer.contains_reference(key, value)
18
24
 
19
25
  async def _resolve_source(self, key: str, index: Optional[int]) -> Any:
20
26
  if key in self.sources:
@@ -56,7 +56,7 @@ class HttpServerPollingCompletion(HttpServerCompletion):
56
56
 
57
57
  class HttpServerCallbackCompletion(HttpServerCompletion):
58
58
  async def run(self, context: ComponentActionContext, client: HttpClient) -> Any:
59
- callback_id = await context.render_variable(self.config.wait_for)
59
+ callback_id = await context.render_variable(self.config.wait_for) if self.config.wait_for else "__default__"
60
60
  future: asyncio.Future = asyncio.get_running_loop().create_future()
61
61
  HttpCallbackListener.register_pending_future(callback_id, future)
62
62
 
@@ -4,7 +4,7 @@ from mindor.dsl.schema.component import ModelComponentConfig, ModelTaskType, Dev
4
4
  from mindor.dsl.schema.action import ModelActionConfig
5
5
  from mindor.core.services import AsyncService
6
6
  from ...context import ComponentActionContext
7
- from transformers import PreTrainedModel, PreTrainedTokenizer
7
+ from transformers import PreTrainedModel, PreTrainedTokenizer, ProcessorMixin
8
8
  import torch, asyncio
9
9
 
10
10
  class ModelTaskService(AsyncService):
@@ -41,7 +41,7 @@ class ModelTaskService(AsyncService):
41
41
 
42
42
  def _get_common_model_params(self) -> Dict[str, Any]:
43
43
  params: Dict[str, Any] = {}
44
-
44
+
45
45
  if self.config.device_mode != DeviceMode.SINGLE:
46
46
  params["device_map"] = self.config.device_mode.value
47
47
 
@@ -61,7 +61,10 @@ class ModelTaskService(AsyncService):
61
61
  params["local_files_only"] = True
62
62
 
63
63
  return params
64
-
64
+
65
+ def _get_model_class(self) -> Type[PreTrainedModel]:
66
+ raise NotImplementedError("Model class loader not implemented.")
67
+
65
68
  def _load_pretrained_tokenizer(self, extra_params: Optional[Dict[str, Any]] = None) -> PreTrainedTokenizer:
66
69
  params = self._get_common_tokenizer_params()
67
70
 
@@ -86,17 +89,37 @@ class ModelTaskService(AsyncService):
86
89
  params["local_files_only"] = True
87
90
 
88
91
  return params
89
-
90
- def _get_model_device(self, model: PreTrainedModel) -> torch.device:
91
- return next(model.parameters()).device
92
92
 
93
- @abstractmethod
94
- def _get_model_class(self) -> Type[PreTrainedModel]:
95
- pass
96
-
97
- @abstractmethod
98
93
  def _get_tokenizer_class(self) -> Type[PreTrainedTokenizer]:
99
- pass
94
+ raise NotImplementedError("Tokenizer class loader not implemented.")
95
+
96
+ def _load_pretrained_processor(self, extra_params: Optional[Dict[str, Any]] = None) -> ProcessorMixin:
97
+ params = self._get_common_processor_params()
98
+
99
+ if extra_params:
100
+ params.update(extra_params)
101
+
102
+ return self._get_processor_class().from_pretrained(self.config.model, **params)
103
+
104
+ def _get_common_processor_params(self) -> Dict[str, Any]:
105
+ params: Dict[str, Any] = {}
106
+
107
+ if self.config.revision:
108
+ params["revision"] = self.config.revision
109
+
110
+ if self.config.cache_dir:
111
+ params["cache_dir"] = self.config.cache_dir
112
+
113
+ if self.config.local_files_only:
114
+ params["local_files_only"] = True
115
+
116
+ return params
117
+
118
+ def _get_processor_class(self) -> Type[ProcessorMixin]:
119
+ raise NotImplementedError("Processor class loader not implemented.")
120
+
121
+ def _get_model_device(self, model: PreTrainedModel) -> torch.device:
122
+ return next(model.parameters()).device
100
123
 
101
124
  def register_model_task_service(type: ModelTaskType):
102
125
  def decorator(cls: Type[ModelTaskService]) -> Type[ModelTaskService]:
@@ -3,3 +3,4 @@ from .summarization import *
3
3
  from .translation import *
4
4
  from .text_classification import *
5
5
  from .text_embedding import *
6
+ from .image_to_text import *
@@ -0,0 +1,155 @@
1
+ from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Protocol, Any
2
+ from mindor.dsl.schema.component import ModelComponentConfig, ImageToTextModelArchitecture
3
+ from mindor.dsl.schema.action import ModelActionConfig, ImageToTextModelActionConfig
4
+ from mindor.core.utils.streamer import AsyncStreamer
5
+ from mindor.core.logger import logging
6
+ from ..base import ModelTaskService, ModelTaskType, register_model_task_service
7
+ from ..base import ComponentActionContext
8
+ from transformers import PreTrainedModel, PreTrainedTokenizer, ProcessorMixin, GenerationMixin, TextIteratorStreamer
9
+ from PIL import Image as PILImage
10
+ from threading import Thread
11
+ from torch import Tensor
12
+ import torch, asyncio
13
+
14
+ class WithTokenizer(Protocol):
15
+ tokenizer: PreTrainedTokenizer
16
+
17
+ class ImageToTextTaskAction:
18
+ def __init__(self, config: ImageToTextModelActionConfig, model: PreTrainedModel, processor: ProcessorMixin, device: torch.device):
19
+ self.config: ImageToTextModelActionConfig = config
20
+ self.model: Union[PreTrainedModel, GenerationMixin] = model
21
+ self.processor: Union[ProcessorMixin, WithTokenizer] = processor
22
+ self.device: torch.device = device
23
+
24
+ async def run(self, context: ComponentActionContext, loop: asyncio.AbstractEventLoop) -> Any:
25
+ image: Union[PILImage.Image, List[PILImage.Image]] = await context.render_image(self.config.image)
26
+ prompt: Optional[Union[str, List[str]]] = await context.render_variable(self.config.prompt)
27
+
28
+ batch_size = await context.render_variable(self.config.params.batch_size)
29
+ stream = await context.render_variable(self.config.stream)
30
+
31
+ is_single_input: bool = True if not isinstance(images, list) else False
32
+ images: List[PILImage.Image] = [ image ] if is_single_input else image
33
+ prompts: Optional[List[str]] = [ prompt ] if is_single_input else prompt
34
+ results = []
35
+
36
+ if stream and (batch_size != 1 or len(images) != 1):
37
+ raise ValueError("Streaming mode only supports a single input image with batch size of 1.")
38
+
39
+ streamer = TextIteratorStreamer(self.processor.tokenizer, skip_prompt=True, skip_special_tokens=True) if stream else None
40
+ for index in range(0, len(images), batch_size):
41
+ batch_images = images[index:index + batch_size]
42
+ batch_prompts = prompts[index:index + batch_size] if prompts else None
43
+
44
+ inputs: Tensor = self.processor(images=batch_images, text=batch_prompts, return_tensors="pt")
45
+ inputs = inputs.to(self.device)
46
+
47
+ def _generate():
48
+ with torch.inference_mode():
49
+ outputs = self.model.generate(
50
+ **inputs,
51
+ streamer=streamer
52
+ )
53
+
54
+ outputs = self.processor.tokenizer.batch_decode(outputs, skip_special_tokens=True)
55
+ results.extend(outputs)
56
+
57
+ if stream:
58
+ thread = Thread(target=_generate)
59
+ thread.start()
60
+ else:
61
+ _generate()
62
+
63
+ if stream:
64
+ async def _stream_generator():
65
+ async for chunk in AsyncStreamer(streamer, loop):
66
+ context.register_source("result", chunk)
67
+ yield (await context.render_variable(self.config.output, ignore_files=True)) if self.config.output else chunk
68
+
69
+ return _stream_generator()
70
+ else:
71
+ result = results[0] if is_single_input else results
72
+ context.register_source("result", result)
73
+
74
+ return (await context.render_variable(self.config.output, ignore_files=True)) if self.config.output else result
75
+
76
+ @register_model_task_service(ModelTaskType.IMAGE_TO_TEXT)
77
+ class ImageToTextTaskService(ModelTaskService):
78
+ def __init__(self, id: str, config: ModelComponentConfig, daemon: bool):
79
+ super().__init__(id, config, daemon)
80
+
81
+ self.model: Optional[Union[PreTrainedModel, GenerationMixin]] = None
82
+ self.processor: Optional[ProcessorMixin] = None
83
+ self.device: Optional[torch.device] = None
84
+
85
+ async def _serve(self) -> None:
86
+ try:
87
+ self.model = self._load_pretrained_model()
88
+ self.processor = self._load_pretrained_processor()
89
+ self.device = self._get_model_device(self.model)
90
+ logging.info(f"Model and processor loaded successfully on device '{self.device}': {self.config.model}")
91
+ except Exception as e:
92
+ logging.error(f"Failed to load model '{self.config.model}': {e}")
93
+ raise
94
+
95
+ async def _shutdown(self) -> None:
96
+ self.model = None
97
+ self.processor = None
98
+ self.device = None
99
+
100
+ async def _run(self, action: ModelActionConfig, context: ComponentActionContext, loop: asyncio.AbstractEventLoop) -> Any:
101
+ return await ImageToTextTaskAction(action, self.model, self.processor, self.device).run(context, loop)
102
+
103
+ def _get_model_class(self) -> Type[PreTrainedModel]:
104
+ if self.config.architecture == ImageToTextModelArchitecture.BLIP:
105
+ from transformers import BlipForConditionalGeneration
106
+ return BlipForConditionalGeneration
107
+
108
+ if self.config.architecture == ImageToTextModelArchitecture.BLIP2:
109
+ from transformers import Blip2ForConditionalGeneration
110
+ return Blip2ForConditionalGeneration
111
+
112
+ if self.config.architecture == ImageToTextModelArchitecture.GIT:
113
+ from transformers import GitForCausalLM
114
+ return GitForCausalLM
115
+
116
+ if self.config.architecture == ImageToTextModelArchitecture.PIX2STRUCT:
117
+ from transformers import Pix2StructForConditionalGeneration
118
+ return Pix2StructForConditionalGeneration
119
+
120
+ if self.config.architecture == ImageToTextModelArchitecture.DONUT:
121
+ from transformers import VisionEncoderDecoderModel # Donut uses this
122
+ return VisionEncoderDecoderModel
123
+
124
+ if self.config.architecture == ImageToTextModelArchitecture.KOSMOS2:
125
+ from transformers import Kosmos2ForConditionalGeneration
126
+ return Kosmos2ForConditionalGeneration
127
+
128
+ raise ValueError(f"Unknown architecture: {self.config.architecture}")
129
+
130
+ def _get_processor_class(self) -> Type[ProcessorMixin]:
131
+ if self.config.architecture == ImageToTextModelArchitecture.BLIP:
132
+ from transformers import BlipProcessor
133
+ return BlipProcessor
134
+
135
+ if self.config.architecture == ImageToTextModelArchitecture.BLIP2:
136
+ from transformers import Blip2Processor
137
+ return Blip2Processor
138
+
139
+ if self.config.architecture == ImageToTextModelArchitecture.GIT:
140
+ from transformers import GitProcessor
141
+ return GitProcessor
142
+
143
+ if self.config.architecture == ImageToTextModelArchitecture.PIX2STRUCT:
144
+ from transformers import Pix2StructProcessor
145
+ return Pix2StructProcessor
146
+
147
+ if self.config.architecture == ImageToTextModelArchitecture.DONUT:
148
+ from transformers import DonutProcessor
149
+ return DonutProcessor
150
+
151
+ if self.config.architecture == ImageToTextModelArchitecture.KOSMOS2:
152
+ from transformers import Kosmos2Processor
153
+ return Kosmos2Processor
154
+
155
+ raise ValueError(f"Unknown architecture: {self.config.architecture}")
@@ -11,7 +11,7 @@ from torch import Tensor
11
11
  import torch, asyncio
12
12
 
13
13
  class SummarizationTaskAction:
14
- def __init__(self, config: SummarizationModelActionConfig, model: Union[PreTrainedModel, GenerationMixin], tokenizer: PreTrainedTokenizer, device: torch.device):
14
+ def __init__(self, config: SummarizationModelActionConfig, model: PreTrainedModel, tokenizer: PreTrainedTokenizer, device: torch.device):
15
15
  self.config: SummarizationModelActionConfig = config
16
16
  self.model: Union[PreTrainedModel, GenerationMixin] = model
17
17
  self.tokenizer: PreTrainedTokenizer = tokenizer
@@ -32,7 +32,8 @@ class SummarizationTaskAction:
32
32
  batch_size = await context.render_variable(self.config.params.batch_size)
33
33
  stream = await context.render_variable(self.config.stream)
34
34
 
35
- texts: List[str] = [ text ] if isinstance(text, str) else text
35
+ is_single_input: bool = True if not isinstance(text, list) else False
36
+ texts: List[str] = [ text ] if is_single_input else text
36
37
  results = []
37
38
 
38
39
  if stream and (batch_size != 1 or len(texts) != 1):
@@ -45,7 +46,7 @@ class SummarizationTaskAction:
45
46
  inputs = { k: v.to(self.device) for k, v in inputs.items() }
46
47
 
47
48
  def _generate():
48
- with torch.no_grad():
49
+ with torch.inference_mode():
49
50
  outputs = self.model.generate(
50
51
  **inputs,
51
52
  max_length=max_output_length,
@@ -61,8 +62,9 @@ class SummarizationTaskAction:
61
62
  streamer=streamer
62
63
  )
63
64
 
64
- outputs = self.tokenizer.batch_decode(outputs, skip_special_tokens=True)
65
- results.extend(outputs)
65
+ if not stream:
66
+ outputs = self.tokenizer.batch_decode(outputs, skip_special_tokens=True)
67
+ results.extend(outputs)
66
68
 
67
69
  if stream:
68
70
  thread = Thread(target=_generate)
@@ -70,15 +72,15 @@ class SummarizationTaskAction:
70
72
  else:
71
73
  _generate()
72
74
 
73
- if stream:
75
+ if stream:
74
76
  async def _stream_generator():
75
- async for result in AsyncStreamer(streamer, loop):
76
- context.register_source("result", result)
77
- yield (await context.render_variable(self.config.output, ignore_files=True)) if self.config.output else result
77
+ async for chunk in AsyncStreamer(streamer, loop):
78
+ context.register_source("result", chunk)
79
+ yield (await context.render_variable(self.config.output, ignore_files=True)) if self.config.output else chunk
78
80
 
79
81
  return _stream_generator()
80
82
  else:
81
- result = results if len(results) > 1 else results[0]
83
+ result = results[0] if is_single_input else results
82
84
  context.register_source("result", result)
83
85
 
84
86
  return (await context.render_variable(self.config.output, ignore_files=True)) if self.config.output else result
@@ -0,0 +1,121 @@
1
+ from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, Any
2
+ from mindor.dsl.schema.component import ModelComponentConfig
3
+ from mindor.dsl.schema.action import ModelActionConfig, TextClassificationModelActionConfig
4
+ from mindor.core.logger import logging
5
+ from ..base import ModelTaskService, ModelTaskType, register_model_task_service
6
+ from ..base import ComponentActionContext
7
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer, PreTrainedModel, PreTrainedTokenizer
8
+ from transformers.modeling_outputs import SequenceClassifierOutput
9
+ import torch.nn.functional as F
10
+ from torch import Tensor
11
+ import torch, asyncio
12
+
13
+ class TextClassificationTaskAction:
14
+ def __init__(self, config: TextClassificationModelActionConfig, model: PreTrainedModel, tokenizer: PreTrainedTokenizer, device: torch.device):
15
+ self.config: TextClassificationModelActionConfig = config
16
+ self.model: PreTrainedModel = model
17
+ self.tokenizer: PreTrainedTokenizer = tokenizer
18
+ self.device: torch.device = device
19
+
20
+ async def run(self, context: ComponentActionContext, labels: Optional[List[str]]) -> Any:
21
+ text: Union[str, List[str]] = await context.render_variable(self.config.text)
22
+
23
+ return_probabilities = await context.render_variable(self.config.params.return_probabilities)
24
+ batch_size = await context.render_variable(self.config.params.batch_size)
25
+ stream = await context.render_variable(self.config.stream)
26
+
27
+ is_single_input: bool = True if not isinstance(text, list) else False
28
+ is_output_array_mode: bool = context.contains_variable_reference("result[]", self.config.output)
29
+ texts: List[str] = [ text ] if is_single_input else text
30
+ results = []
31
+
32
+ async def _predict():
33
+ for index in range(0, len(texts), batch_size):
34
+ batch_texts = texts[index:index + batch_size]
35
+ inputs: Dict[str, Tensor] = self.tokenizer(batch_texts, return_tensors="pt", padding=True, truncation=True)
36
+ inputs = { k: v.to(self.device) for k, v in inputs.items() }
37
+
38
+ with torch.inference_mode():
39
+ outputs: SequenceClassifierOutput = self.model(**inputs)
40
+ logits = outputs.logits # shape: (batch_size, num_classes)
41
+ predictions = []
42
+
43
+ if return_probabilities:
44
+ probs = F.softmax(logits, dim=-1).cpu()
45
+ for prob in probs:
46
+ predicted_index = torch.argmax(prob).item()
47
+ predictions.append({
48
+ "label": labels[predicted_index] if labels else predicted_index,
49
+ "probabilities": prob.tolist()
50
+ })
51
+ else:
52
+ predicted_indices = torch.argmax(logits, dim=-1).tolist()
53
+ for predicted_index in predicted_indices:
54
+ predictions.append(labels[predicted_index] if labels else predicted_index)
55
+
56
+ if self.config.output and is_output_array_mode:
57
+ rendered_outputs = []
58
+ for prediction in predictions:
59
+ context.register_source("result[]", prediction)
60
+ output = await context.render_variable(self.config.output, ignore_files=True)
61
+ rendered_outputs.append(output)
62
+ yield rendered_outputs
63
+ else:
64
+ yield predictions
65
+
66
+ if stream:
67
+ async def _stream_generator():
68
+ async for predictions in _predict():
69
+ if not is_output_array_mode:
70
+ for prediction in predictions:
71
+ context.register_source("result", prediction)
72
+ yield (await context.render_variable(self.config.output, ignore_files=True)) if self.config.output else result
73
+ else:
74
+ for prediction in predictions:
75
+ yield prediction
76
+
77
+ return _stream_generator()
78
+ else:
79
+ async for predictions in _predict():
80
+ results.extend(predictions)
81
+
82
+ if not is_output_array_mode:
83
+ result = results[0] if is_single_input else results
84
+ context.register_source("result", result)
85
+
86
+ return (await context.render_variable(self.config.output, ignore_files=True)) if self.config.output else result
87
+ else:
88
+ return results
89
+
90
+ @register_model_task_service(ModelTaskType.TEXT_CLASSIFICATION)
91
+ class TextClassificationTaskService(ModelTaskService):
92
+ def __init__(self, id: str, config: ModelComponentConfig, daemon: bool):
93
+ super().__init__(id, config, daemon)
94
+
95
+ self.model: Optional[PreTrainedModel] = None
96
+ self.tokenizer: Optional[PreTrainedTokenizer] = None
97
+ self.device: Optional[torch.device] = None
98
+
99
+ async def _serve(self) -> None:
100
+ try:
101
+ self.model = self._load_pretrained_model()
102
+ self.tokenizer = self._load_pretrained_tokenizer()
103
+ self.device = self._get_model_device(self.model)
104
+ logging.info(f"Model and tokenizer loaded successfully on device '{self.device}': {self.config.model}")
105
+ except Exception as e:
106
+ logging.error(f"Failed to load model '{self.config.model}': {e}")
107
+ raise
108
+
109
+ async def _shutdown(self) -> None:
110
+ self.model = None
111
+ self.tokenizer = None
112
+ self.device = None
113
+
114
+ async def _run(self, action: ModelActionConfig, context: ComponentActionContext, loop: asyncio.AbstractEventLoop) -> Any:
115
+ return await TextClassificationTaskAction(action, self.model, self.tokenizer, self.device).run(context, self.config.labels)
116
+
117
+ def _get_model_class(self) -> Type[PreTrainedModel]:
118
+ return AutoModelForSequenceClassification
119
+
120
+ def _get_tokenizer_class(self) -> Type[PreTrainedTokenizer]:
121
+ return AutoTokenizer