nexaai 1.0.19rc7__cp310-cp310-macosx_14_0_universal2.whl → 1.0.19rc8__cp310-cp310-macosx_14_0_universal2.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.

Potentially problematic release.


This version of nexaai might be problematic. Click here for more details.

Files changed (196) hide show
  1. nexaai/_stub.cpython-310-darwin.so +0 -0
  2. nexaai/_version.py +1 -1
  3. nexaai/binds/libnexa_bridge.dylib +0 -0
  4. {nexaai-1.0.19rc7.dist-info → nexaai-1.0.19rc8.dist-info}/METADATA +1 -1
  5. {nexaai-1.0.19rc7.dist-info → nexaai-1.0.19rc8.dist-info}/RECORD +7 -196
  6. nexaai/binds/nexa_mlx/py-lib/asr/__init__.py +0 -12
  7. nexaai/binds/nexa_mlx/py-lib/asr/interface.py +0 -122
  8. nexaai/binds/nexa_mlx/py-lib/common/__init__.py +0 -0
  9. nexaai/binds/nexa_mlx/py-lib/common/utils.py +0 -25
  10. nexaai/binds/nexa_mlx/py-lib/cv/__init__.py +0 -0
  11. nexaai/binds/nexa_mlx/py-lib/cv/generate.py +0 -195
  12. nexaai/binds/nexa_mlx/py-lib/cv/interface.py +0 -151
  13. nexaai/binds/nexa_mlx/py-lib/cv/main.py +0 -81
  14. nexaai/binds/nexa_mlx/py-lib/cv/modeling/pp_ocr_v4.py +0 -1736
  15. nexaai/binds/nexa_mlx/py-lib/embedding/__init__.py +0 -0
  16. nexaai/binds/nexa_mlx/py-lib/embedding/generate.py +0 -333
  17. nexaai/binds/nexa_mlx/py-lib/embedding/interface.py +0 -617
  18. nexaai/binds/nexa_mlx/py-lib/embedding/main.py +0 -173
  19. nexaai/binds/nexa_mlx/py-lib/embedding/modeling/__init__.py +0 -0
  20. nexaai/binds/nexa_mlx/py-lib/embedding/modeling/nexa_jina_v2.py +0 -399
  21. nexaai/binds/nexa_mlx/py-lib/image_gen/__init__.py +0 -1
  22. nexaai/binds/nexa_mlx/py-lib/image_gen/generate_sd.py +0 -244
  23. nexaai/binds/nexa_mlx/py-lib/image_gen/interface.py +0 -82
  24. nexaai/binds/nexa_mlx/py-lib/image_gen/main.py +0 -281
  25. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/__init__.py +0 -306
  26. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/clip.py +0 -116
  27. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/config.py +0 -65
  28. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/model_io.py +0 -386
  29. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/sampler.py +0 -105
  30. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/tokenizer.py +0 -100
  31. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/unet.py +0 -460
  32. nexaai/binds/nexa_mlx/py-lib/image_gen/stable_diffusion/vae.py +0 -274
  33. nexaai/binds/nexa_mlx/py-lib/llm/__init__.py +0 -0
  34. nexaai/binds/nexa_mlx/py-lib/llm/generate.py +0 -149
  35. nexaai/binds/nexa_mlx/py-lib/llm/interface.py +0 -764
  36. nexaai/binds/nexa_mlx/py-lib/llm/main.py +0 -68
  37. nexaai/binds/nexa_mlx/py-lib/rerank/__init__.py +0 -0
  38. nexaai/binds/nexa_mlx/py-lib/rerank/generate.py +0 -174
  39. nexaai/binds/nexa_mlx/py-lib/rerank/interface.py +0 -287
  40. nexaai/binds/nexa_mlx/py-lib/rerank/main.py +0 -127
  41. nexaai/binds/nexa_mlx/py-lib/rerank/modeling/__init__.py +0 -0
  42. nexaai/binds/nexa_mlx/py-lib/rerank/modeling/nexa_jina_rerank.py +0 -330
  43. nexaai/binds/nexa_mlx/py-lib/sd/__init__.py +0 -1
  44. nexaai/binds/nexa_mlx/py-lib/sd/interface.py +0 -362
  45. nexaai/binds/nexa_mlx/py-lib/sd/main.py +0 -286
  46. nexaai/binds/nexa_mlx/py-lib/sd/modeling/__init__.py +0 -306
  47. nexaai/binds/nexa_mlx/py-lib/sd/modeling/clip.py +0 -116
  48. nexaai/binds/nexa_mlx/py-lib/sd/modeling/config.py +0 -65
  49. nexaai/binds/nexa_mlx/py-lib/sd/modeling/model_io.py +0 -385
  50. nexaai/binds/nexa_mlx/py-lib/sd/modeling/sampler.py +0 -105
  51. nexaai/binds/nexa_mlx/py-lib/sd/modeling/tokenizer.py +0 -100
  52. nexaai/binds/nexa_mlx/py-lib/sd/modeling/unet.py +0 -460
  53. nexaai/binds/nexa_mlx/py-lib/sd/modeling/vae.py +0 -274
  54. nexaai/binds/nexa_mlx/py-lib/tts/__init__.py +0 -12
  55. nexaai/binds/nexa_mlx/py-lib/tts/interface.py +0 -276
  56. nexaai/binds/nexa_mlx/py-lib/vlm/__init__.py +0 -3
  57. nexaai/binds/nexa_mlx/py-lib/vlm/generate.py +0 -572
  58. nexaai/binds/nexa_mlx/py-lib/vlm/generate_qwen3_vl.py +0 -294
  59. nexaai/binds/nexa_mlx/py-lib/vlm/generate_qwen3_vl_moe.py +0 -276
  60. nexaai/binds/nexa_mlx/py-lib/vlm/interface.py +0 -504
  61. nexaai/binds/nexa_mlx/py-lib/vlm/main.py +0 -320
  62. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/__init__.py +0 -0
  63. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/convert.py +0 -68
  64. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/__init__.py +0 -0
  65. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/aya_vision/__init__.py +0 -8
  66. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/aya_vision/aya_vision.py +0 -193
  67. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/aya_vision/interpolate.py +0 -186
  68. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/aya_vision/language.py +0 -233
  69. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/aya_vision/vision.py +0 -503
  70. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/base.py +0 -202
  71. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/cache.py +0 -230
  72. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/deepseek_vl_v2/__init__.py +0 -10
  73. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/deepseek_vl_v2/conversation.py +0 -264
  74. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/deepseek_vl_v2/deepseek_vl_v2.py +0 -472
  75. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/deepseek_vl_v2/language.py +0 -591
  76. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/deepseek_vl_v2/processing_deepsek_vl_v2.py +0 -526
  77. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/deepseek_vl_v2/vision.py +0 -356
  78. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/florence2/__init__.py +0 -8
  79. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/florence2/florence2.py +0 -366
  80. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/florence2/language.py +0 -488
  81. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/florence2/vision.py +0 -591
  82. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3/__init__.py +0 -8
  83. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3/gemma3.py +0 -213
  84. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3/language.py +0 -315
  85. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3/vision.py +0 -238
  86. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3n/__init__.py +0 -2
  87. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3n/audio.py +0 -1038
  88. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3n/config.py +0 -139
  89. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3n/gemma3n.py +0 -322
  90. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3n/language.py +0 -629
  91. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/gemma3n/vision.py +0 -1022
  92. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics2/__init__.py +0 -9
  93. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics2/idefics2.py +0 -294
  94. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics2/language.py +0 -191
  95. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics2/vision.py +0 -267
  96. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics3/__init__.py +0 -8
  97. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics3/idefics3.py +0 -175
  98. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics3/language.py +0 -192
  99. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/idefics3/vision.py +0 -233
  100. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/internvl_chat/__init__.py +0 -9
  101. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/internvl_chat/internvl_chat.py +0 -140
  102. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/internvl_chat/language.py +0 -220
  103. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/internvl_chat/processor.py +0 -393
  104. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/internvl_chat/vision.py +0 -293
  105. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/kernels.py +0 -307
  106. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/kimi_vl/__init__.py +0 -8
  107. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/kimi_vl/kimi_vl.py +0 -143
  108. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/kimi_vl/language.py +0 -509
  109. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/kimi_vl/vision.py +0 -522
  110. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llama4/__init__.py +0 -8
  111. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llama4/language.py +0 -386
  112. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llama4/llama4.py +0 -138
  113. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llama4/vision.py +0 -560
  114. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava/__init__.py +0 -8
  115. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava/language.py +0 -240
  116. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava/llava.py +0 -153
  117. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava/vision.py +0 -259
  118. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_bunny/__init__.py +0 -9
  119. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_bunny/language.py +0 -236
  120. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_bunny/llava_bunny.py +0 -256
  121. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_bunny/vision.py +0 -303
  122. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_next/__init__.py +0 -8
  123. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_next/language.py +0 -230
  124. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_next/llava_next.py +0 -160
  125. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/llava_next/vision.py +0 -243
  126. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/mistral3/__init__.py +0 -8
  127. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/mistral3/mistral3.py +0 -283
  128. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/mllama/__init__.py +0 -8
  129. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/mllama/language.py +0 -416
  130. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/mllama/mllama.py +0 -172
  131. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/mllama/vision.py +0 -499
  132. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/molmo/__init__.py +0 -8
  133. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/molmo/language.py +0 -243
  134. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/molmo/molmo.py +0 -133
  135. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/molmo/vision.py +0 -465
  136. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/multi_modality/__init__.py +0 -10
  137. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/multi_modality/language.py +0 -230
  138. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/multi_modality/multi_modality.py +0 -385
  139. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/multi_modality/sam.py +0 -557
  140. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/multi_modality/vision.py +0 -526
  141. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/paligemma/__init__.py +0 -8
  142. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/paligemma/language.py +0 -282
  143. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/paligemma/paligemma.py +0 -160
  144. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/paligemma/vision.py +0 -242
  145. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/phi3_v/__init__.py +0 -8
  146. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/phi3_v/language.py +0 -21
  147. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/phi3_v/phi3_v.py +0 -243
  148. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/phi3_v/su_rope.py +0 -71
  149. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/phi3_v/vision.py +0 -324
  150. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/pixtral/__init__.py +0 -8
  151. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/pixtral/language.py +0 -229
  152. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/pixtral/pixtral.py +0 -161
  153. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/pixtral/vision.py +0 -320
  154. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_5_vl/__init__.py +0 -2
  155. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_5_vl/config.py +0 -108
  156. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_5_vl/language.py +0 -490
  157. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_5_vl/qwen2_5_vl.py +0 -168
  158. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_5_vl/vision.py +0 -414
  159. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_vl/__init__.py +0 -2
  160. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_vl/config.py +0 -104
  161. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_vl/language.py +0 -490
  162. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_vl/qwen2_vl.py +0 -167
  163. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen2_vl/vision.py +0 -312
  164. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/llm_common/__init__.py +0 -0
  165. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/llm_common/base.py +0 -117
  166. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/llm_common/cache.py +0 -531
  167. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/llm_common/generate.py +0 -701
  168. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/llm_common/rope_utils.py +0 -255
  169. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/llm_common/sample_utils.py +0 -303
  170. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/llm_common/tokenizer_utils.py +0 -407
  171. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/processor.py +0 -476
  172. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3_vl/qwen3vl.py +0 -1223
  173. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/llm_common/__init__.py +0 -0
  174. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/llm_common/base.py +0 -117
  175. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/llm_common/cache.py +0 -531
  176. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/llm_common/generate.py +0 -701
  177. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/llm_common/rope_utils.py +0 -255
  178. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/llm_common/sample_utils.py +0 -303
  179. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/llm_common/tokenizer_utils.py +0 -407
  180. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/processor.py +0 -476
  181. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/qwen3vl_moe.py +0 -1309
  182. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/qwen3vl_moe/switch_layers.py +0 -210
  183. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/smolvlm/__init__.py +0 -8
  184. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/models/smolvlm/smolvlm.py +0 -62
  185. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/processing_qwen2_5_vl.py +0 -209
  186. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/processing_qwen2_vl.py +0 -215
  187. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/prompt_utils.py +0 -474
  188. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/sample_utils.py +0 -39
  189. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/tokenizer_utils.py +0 -344
  190. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/trainer/__init__.py +0 -9
  191. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/trainer/lora.py +0 -70
  192. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/trainer/trainer.py +0 -296
  193. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/trainer/utils.py +0 -160
  194. nexaai/binds/nexa_mlx/py-lib/vlm/modeling/utils.py +0 -928
  195. {nexaai-1.0.19rc7.dist-info → nexaai-1.0.19rc8.dist-info}/WHEEL +0 -0
  196. {nexaai-1.0.19rc7.dist-info → nexaai-1.0.19rc8.dist-info}/top_level.txt +0 -0
@@ -1,617 +0,0 @@
1
- # Copyright © Nexa AI
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- from __future__ import annotations
16
-
17
- import os
18
- import json
19
- import mlx.core as mx
20
- import numpy as np
21
- from pathlib import Path
22
- from typing import Any, List, Optional, Sequence
23
- from abc import ABC, abstractmethod
24
-
25
- # Import necessary modules
26
- from tokenizers import Tokenizer
27
-
28
- # Import from ml.py for API alignment
29
- import sys
30
- from pathlib import Path as PathLib
31
- sys.path.insert(0, str(PathLib(__file__).parent.parent))
32
-
33
- from ml import (
34
- Embedder as BaseEmbedder,
35
- EmbeddingConfig,
36
- Path as PathType,
37
- )
38
-
39
- # Import profiling module
40
- from profiling import ProfilingMixin, StopReason
41
-
42
- # Import the model implementation for Jina
43
- try:
44
- from .modeling.nexa_jina_v2 import Model, ModelArgs
45
- except ImportError:
46
- # Fallback for when module is run directly
47
- from modeling.nexa_jina_v2 import Model, ModelArgs
48
-
49
- # Import mlx_embeddings for general embedding support
50
- try:
51
- import mlx_embeddings
52
- MLX_EMBEDDINGS_AVAILABLE = True
53
- except ImportError:
54
- MLX_EMBEDDINGS_AVAILABLE = False
55
-
56
-
57
- class BaseMLXEmbedder(BaseEmbedder, ProfilingMixin, ABC):
58
- """
59
- Abstract base embedder interface for MLX embedding models.
60
- API aligned with ml.py Embedder abstract base class.
61
- """
62
-
63
- def __init__(
64
- self,
65
- model_path: PathType,
66
- tokenizer_path: PathType,
67
- device: Optional[str] = None,
68
- ) -> None:
69
- """Initialize the Embedder model."""
70
- # Initialize profiling mixin
71
- ProfilingMixin.__init__(self)
72
-
73
- # Store paths
74
- if (os.path.isfile(model_path)):
75
- model_path = os.path.dirname(model_path)
76
-
77
- # Call parent constructor
78
- # MLX manages device automatically, so we pass None for device
79
- super().__init__(model_path, tokenizer_path, device)
80
-
81
- self.model_path = model_path
82
- self.tokenizer_path = tokenizer_path
83
- self.device = device if device is not None else "cpu"
84
-
85
- # Initialize model and tokenizer as None
86
- self.model = None
87
- self.tokenizer = None
88
- self.config = None
89
-
90
- def destroy(self) -> None:
91
- """Destroy the model and free resources."""
92
- self.model = None
93
- self.tokenizer = None
94
- self.config = None
95
- self.reset_profiling()
96
-
97
- @abstractmethod
98
- def load_model(self, model_path: PathType) -> bool:
99
- """Load model from path."""
100
- pass
101
-
102
- def close(self) -> None:
103
- """Close the model."""
104
- self.destroy()
105
-
106
- @abstractmethod
107
- def embed(
108
- self,
109
- texts: Sequence[str],
110
- config: Optional[EmbeddingConfig] = None,
111
- clear_cache: bool = True,
112
- ) -> List[List[float]]:
113
- """Generate embeddings for texts."""
114
- pass
115
-
116
- @abstractmethod
117
- def embedding_dim(self) -> int:
118
- """Get embedding dimension."""
119
- pass
120
-
121
- def set_lora(self, lora_id: int) -> None:
122
- """Set active LoRA adapter. (Disabled for embedding models)"""
123
- raise NotImplementedError("LoRA is not supported for embedding models")
124
-
125
- def add_lora(self, lora_path: PathType) -> int:
126
- """Add LoRA adapter and return its ID. (Disabled for embedding models)"""
127
- raise NotImplementedError("LoRA is not supported for embedding models")
128
-
129
- def remove_lora(self, lora_id: int) -> None:
130
- """Remove LoRA adapter. (Disabled for embedding models)"""
131
- raise NotImplementedError("LoRA is not supported for embedding models")
132
-
133
- def list_loras(self) -> List[int]:
134
- """List available LoRA adapters. (Disabled for embedding models)"""
135
- raise NotImplementedError("LoRA is not supported for embedding models")
136
-
137
- def _normalize_embedding(self, embedding: List[float], method: str) -> List[float]:
138
- """Normalize embedding using specified method."""
139
- if method == "none":
140
- return embedding
141
-
142
- embedding_array = np.array(embedding)
143
-
144
- if method == "l2":
145
- norm = np.linalg.norm(embedding_array)
146
- if norm > 0:
147
- embedding_array = embedding_array / norm
148
- elif method == "mean":
149
- mean_val = np.mean(embedding_array)
150
- embedding_array = embedding_array - mean_val
151
-
152
- return embedding_array.tolist()
153
-
154
-
155
- class JinaV2Embedder(BaseMLXEmbedder):
156
- """
157
- Embedder implementation specifically for Jina V2 models.
158
- """
159
-
160
- def load_model(self, model_path: PathType) -> bool:
161
- """Load model from path."""
162
- try:
163
- # Use the provided model_path or fall back to instance path
164
- if model_path:
165
- # Apply same file-to-directory conversion as in __init__
166
- if os.path.isfile(model_path):
167
- model_path = os.path.dirname(model_path)
168
- self.model_path = model_path
169
-
170
- # Load the model using internal implementation
171
- self.model = self._load_jina_model(self.model_path)
172
- self.tokenizer = self._load_tokenizer()
173
-
174
- return True
175
- except Exception as e:
176
- print(f"Failed to load model: {e}")
177
- return False
178
-
179
- def embed(
180
- self,
181
- texts: Sequence[str],
182
- config: Optional[EmbeddingConfig] = None,
183
- clear_cache: bool = True,
184
- ) -> List[List[float]]:
185
- """Generate embeddings for texts."""
186
- if self.model is None or self.tokenizer is None:
187
- raise RuntimeError("Model not loaded. Call load_model() first.")
188
-
189
- if config is None:
190
- config = EmbeddingConfig()
191
-
192
- # Start profiling
193
- self._start_profiling()
194
-
195
- # Calculate total tokens for all texts
196
- total_tokens = sum(len(self.tokenizer.encode(text).ids) for text in texts)
197
- self._update_prompt_tokens(total_tokens)
198
-
199
- # End prompt processing, start decode
200
- self._prompt_end()
201
- self._decode_start()
202
-
203
- try:
204
- embeddings = []
205
-
206
- # Process texts in batches
207
- batch_size = config.batch_size
208
- for i in range(0, len(texts), batch_size):
209
- batch_texts = texts[i:i + batch_size]
210
- batch_embeddings = self._encode_batch(batch_texts, config)
211
- embeddings.extend(batch_embeddings)
212
-
213
- if clear_cache:
214
- mx.clear_cache()
215
-
216
- # End timing and finalize profiling data
217
- self._update_generated_tokens(0) # No generation in embedding
218
- self._set_stop_reason(StopReason.ML_STOP_REASON_COMPLETED)
219
- self._decode_end()
220
- self._end_profiling()
221
-
222
- return embeddings
223
-
224
- except Exception as e:
225
- self._set_stop_reason(StopReason.ML_STOP_REASON_UNKNOWN)
226
- self._decode_end()
227
- self._end_profiling()
228
- raise RuntimeError(f"Error generating embeddings: {str(e)}")
229
-
230
- def embedding_dim(self) -> int:
231
- """Get embedding dimension."""
232
- if self.config is None:
233
- return 768 # Default dimension for Jina v2
234
- return self.config.hidden_size
235
-
236
- def _load_jina_model(self, model_dir: str) -> Model:
237
- """Initialize and load the Jina V2 model with FP16 weights."""
238
-
239
- # Validate that model path exists
240
- if not os.path.exists(model_dir):
241
- raise ValueError(f"Model path does not exist: {model_dir}")
242
-
243
- print(f"Using local model path: {model_dir}")
244
- config_path = os.path.join(model_dir, "config.json")
245
-
246
- if not os.path.exists(config_path):
247
- raise FileNotFoundError(f"Config file not found: {config_path}")
248
-
249
- with open(config_path, "r") as f:
250
- config_dict = json.load(f)
251
-
252
- # Create ModelArgs from loaded config
253
- config = ModelArgs(
254
- model_type=config_dict["model_type"],
255
- vocab_size=config_dict["vocab_size"],
256
- hidden_size=config_dict["hidden_size"],
257
- num_hidden_layers=config_dict["num_hidden_layers"],
258
- num_attention_heads=config_dict["num_attention_heads"],
259
- intermediate_size=config_dict["intermediate_size"],
260
- hidden_act=config_dict["hidden_act"],
261
- hidden_dropout_prob=config_dict["hidden_dropout_prob"],
262
- attention_probs_dropout_prob=config_dict["attention_probs_dropout_prob"],
263
- max_position_embeddings=config_dict["max_position_embeddings"],
264
- type_vocab_size=config_dict["type_vocab_size"],
265
- initializer_range=config_dict["initializer_range"],
266
- layer_norm_eps=config_dict["layer_norm_eps"],
267
- pad_token_id=config_dict["pad_token_id"],
268
- position_embedding_type=config_dict["position_embedding_type"],
269
- use_cache=config_dict["use_cache"],
270
- classifier_dropout=config_dict["classifier_dropout"],
271
- feed_forward_type=config_dict["feed_forward_type"],
272
- emb_pooler=config_dict["emb_pooler"],
273
- attn_implementation=config_dict["attn_implementation"],
274
- )
275
-
276
- # Store config for embedding_dim()
277
- self.config = config
278
-
279
- # Initialize model
280
- model = Model(config)
281
-
282
- # Load FP16 weights from model path
283
- weights_path = os.path.join(model_dir, "model.safetensors")
284
- self._model_dir = model_dir
285
-
286
- # Validate that weights file exists
287
- if not os.path.exists(weights_path):
288
- raise FileNotFoundError(f"Model weights file not found: {weights_path}")
289
-
290
- model.load_weights(weights_path, strict=True)
291
- model.eval()
292
-
293
- return model
294
-
295
- def _load_tokenizer(self) -> Tokenizer:
296
- """Load and configure the tokenizer."""
297
- tokenizer_path = os.path.join(self._model_dir, "tokenizer.json")
298
- tokenizer = Tokenizer.from_file(tokenizer_path)
299
- tokenizer.enable_padding(pad_id=0, pad_token="[PAD]")
300
- tokenizer.enable_truncation(max_length=512)
301
- return tokenizer
302
-
303
- def _encode_batch(self, texts: List[str], config: EmbeddingConfig) -> List[List[float]]:
304
- """Encode a batch of texts and return their embeddings."""
305
- embeddings = []
306
-
307
- for text in texts:
308
- embedding = self._encode_single_text(text, config)
309
- embeddings.append(embedding)
310
-
311
- return embeddings
312
-
313
- def _encode_single_text(self, text: str, config: EmbeddingConfig) -> List[float]:
314
- """Encode a single text and return its embedding."""
315
- # Tokenize the text
316
- encoding = self.tokenizer.encode(text)
317
-
318
- # Prepare inputs
319
- input_ids = np.array([encoding.ids], dtype=np.int32)
320
- attention_mask = np.array([encoding.attention_mask], dtype=np.float32)
321
- token_type_ids = np.array([encoding.type_ids if encoding.type_ids else [0] * len(encoding.ids)], dtype=np.int32)
322
-
323
- # Convert to MLX arrays
324
- input_ids = mx.array(input_ids)
325
- attention_mask = mx.array(attention_mask)
326
- token_type_ids = mx.array(token_type_ids)
327
-
328
- # Get embeddings
329
- embeddings = self.model.encode(
330
- input_ids=input_ids,
331
- attention_mask=attention_mask,
332
- token_type_ids=token_type_ids,
333
- )
334
-
335
- # Convert to list and apply normalization if requested
336
- embedding_list = embeddings.flatten().tolist()
337
-
338
- if config.normalize:
339
- embedding_list = self._normalize_embedding(embedding_list, config.normalize_method)
340
-
341
- return embedding_list
342
-
343
-
344
- class MlxEmbeddingEmbedder(BaseMLXEmbedder):
345
- """
346
- Embedder implementation using mlx_embeddings package for general embedding models.
347
- """
348
-
349
- def load_model(self, model_path: PathType) -> bool:
350
- """Load model from path using mlx_embeddings."""
351
- if not MLX_EMBEDDINGS_AVAILABLE:
352
- print("Warning: mlx_embeddings not available. Please install it to use general embedding models.")
353
- raise ImportError("mlx_embeddings package is not available. Please install it first.")
354
-
355
- try:
356
- # Use the provided model_path or fall back to instance path
357
- if model_path:
358
- if os.path.isfile(model_path):
359
- model_path = os.path.dirname(model_path)
360
- self.model_path = model_path
361
-
362
- # Load model and tokenizer using mlx_embeddings
363
- self.model, self.tokenizer = mlx_embeddings.load(self.model_path)
364
-
365
- # Load config to get dimensions
366
- config_path = os.path.join(self.model_path, "config.json")
367
- if os.path.exists(config_path):
368
- with open(config_path, "r") as f:
369
- self.config = json.load(f)
370
-
371
- return True
372
- except Exception as e:
373
- print(f"Failed to load model: {e}")
374
- return False
375
-
376
- def embed(
377
- self,
378
- texts: Sequence[str],
379
- config: Optional[EmbeddingConfig] = None,
380
- clear_cache: bool = True,
381
- ) -> List[List[float]]:
382
- """Generate embeddings for texts using mlx_embeddings."""
383
- if self.model is None or self.tokenizer is None:
384
- raise RuntimeError("Model not loaded. Call load_model() first.")
385
-
386
- if config is None:
387
- config = EmbeddingConfig()
388
-
389
- # Start profiling
390
- self._start_profiling()
391
-
392
- try:
393
- # Calculate total tokens for profiling
394
- if hasattr(self.tokenizer, 'encode'):
395
- total_tokens = sum(len(self.tokenizer.encode(text)) for text in texts)
396
- else:
397
- # For tokenizers that don't have simple encode method
398
- total_tokens = len(texts) * 50 # Rough estimate
399
-
400
- self._update_prompt_tokens(total_tokens)
401
-
402
- # End prompt processing, start decode
403
- self._prompt_end()
404
- self._decode_start()
405
-
406
- # Check if this is a Gemma3TextModel
407
- # WORKAROUND: Gemma3TextModel has a bug where it expects 'inputs' as positional arg
408
- # but mlx_embeddings.generate passes 'input_ids' as keyword arg
409
- # See: https://github.com/ml-explore/mlx-examples/issues/... (bug report pending)
410
- is_gemma = False
411
- if self.config and "architectures" in self.config:
412
- architectures = self.config.get("architectures", [])
413
- is_gemma = "Gemma3TextModel" in architectures
414
-
415
- if is_gemma:
416
- # HARDCODED WORKAROUND for Gemma3TextModel bug
417
- # Use direct tokenization and model call instead of mlx_embeddings.generate
418
- max_length = config.max_length if hasattr(config, 'max_length') else 512
419
-
420
- # Tokenize using batch_encode_plus
421
- encoded_input = self.tokenizer.batch_encode_plus(
422
- list(texts),
423
- padding=True,
424
- truncation=True,
425
- return_tensors='mlx',
426
- max_length=max_length
427
- )
428
-
429
- # Get input tensors
430
- input_ids = encoded_input['input_ids']
431
- attention_mask = encoded_input.get('attention_mask', None)
432
-
433
- # Call model with positional input_ids and keyword attention_mask
434
- # This matches Gemma3TextModel's expected signature
435
- output = self.model(input_ids, attention_mask=attention_mask)
436
-
437
- # Extract embeddings
438
- embeddings_tensor = output.text_embeds
439
- else:
440
- # Normal path for non-Gemma models
441
- # Generate embeddings using mlx_embeddings standard approach
442
- output = mlx_embeddings.generate(
443
- self.model,
444
- self.tokenizer,
445
- texts=list(texts),
446
- max_length=config.max_length if hasattr(config, 'max_length') else 512,
447
- padding=True,
448
- truncation=True
449
- )
450
-
451
- # Extract embeddings
452
- embeddings_tensor = output.text_embeds
453
-
454
- # Convert to list format
455
- embeddings = []
456
- for i in range(embeddings_tensor.shape[0]):
457
- embedding = embeddings_tensor[i].tolist()
458
-
459
- # Apply normalization if requested
460
- if config.normalize:
461
- embedding = self._normalize_embedding(embedding, config.normalize_method)
462
-
463
- embeddings.append(embedding)
464
-
465
- if clear_cache:
466
- mx.clear_cache()
467
-
468
- # End timing and finalize profiling data
469
- self._update_generated_tokens(0) # No generation in embedding
470
- self._set_stop_reason(StopReason.ML_STOP_REASON_COMPLETED)
471
- self._decode_end()
472
- self._end_profiling()
473
-
474
- return embeddings
475
-
476
- except Exception as e:
477
- self._set_stop_reason(StopReason.ML_STOP_REASON_UNKNOWN)
478
- self._decode_end()
479
- self._end_profiling()
480
- raise RuntimeError(f"Error generating embeddings: {str(e)}")
481
-
482
- def embedding_dim(self) -> int:
483
- """Get embedding dimension."""
484
- if self.config is None:
485
- return 768 # Default dimension
486
-
487
- # Try different config keys that might contain the dimension
488
- if "hidden_size" in self.config:
489
- return self.config["hidden_size"]
490
- elif "d_model" in self.config:
491
- return self.config["d_model"]
492
- elif "dim" in self.config:
493
- return self.config["dim"]
494
- else:
495
- return 768 # Fallback default
496
-
497
-
498
- class MLXEmbedder(BaseMLXEmbedder):
499
- """
500
- Concrete embedder class that routes to the appropriate implementation.
501
- This class can be instantiated directly (for C++ compatibility) and will
502
- automatically delegate to JinaV2Embedder or MlxEmbeddingEmbedder based on model type.
503
- """
504
-
505
- def __init__(
506
- self,
507
- model_path: PathType,
508
- tokenizer_path: PathType,
509
- device: Optional[str] = None,
510
- ) -> None:
511
- """Initialize the Embedder model."""
512
- super().__init__(model_path, tokenizer_path, device)
513
- self._impl = None # Will hold the actual implementation
514
-
515
- def _get_implementation(self) -> BaseMLXEmbedder:
516
- """Get or create the appropriate implementation based on model type."""
517
- if self._impl is None:
518
- # Detect model type and create appropriate implementation
519
- model_type = _detect_model_type(self.model_path)
520
-
521
- if model_type == "jina_v2":
522
- self._impl = JinaV2Embedder(self.model_path, self.tokenizer_path, self.device)
523
- else:
524
- self._impl = MlxEmbeddingEmbedder(self.model_path, self.tokenizer_path, self.device)
525
-
526
- # Copy over any existing state
527
- if self.model is not None:
528
- self._impl.model = self.model
529
- if self.tokenizer is not None:
530
- self._impl.tokenizer = self.tokenizer
531
- if self.config is not None:
532
- self._impl.config = self.config
533
-
534
- return self._impl
535
-
536
- def load_model(self, model_path: PathType) -> bool:
537
- """Load model from path."""
538
- # Get the appropriate implementation and delegate
539
- impl = self._get_implementation()
540
- result = impl.load_model(model_path)
541
-
542
- # Sync state back
543
- self.model = impl.model
544
- self.tokenizer = impl.tokenizer
545
- self.config = impl.config
546
-
547
- return result
548
-
549
- def embed(
550
- self,
551
- texts: Sequence[str],
552
- config: Optional[EmbeddingConfig] = None,
553
- clear_cache: bool = True,
554
- ) -> List[List[float]]:
555
- """Generate embeddings for texts."""
556
- # Get the appropriate implementation and delegate
557
- impl = self._get_implementation()
558
- return impl.embed(texts, config, clear_cache)
559
-
560
- def embedding_dim(self) -> int:
561
- """Get embedding dimension."""
562
- # Get the appropriate implementation and delegate
563
- impl = self._get_implementation()
564
- return impl.embedding_dim()
565
-
566
- def destroy(self) -> None:
567
- """Destroy the model and free resources."""
568
- super().destroy()
569
- if self._impl is not None:
570
- self._impl.destroy()
571
- self._impl = None
572
-
573
-
574
- # Backward compatibility alias
575
- Embedder = MLXEmbedder
576
-
577
-
578
- def _detect_model_type(model_path: PathType) -> str:
579
- """Detect the model type from config.json."""
580
- if os.path.isfile(model_path):
581
- model_path = os.path.dirname(model_path)
582
-
583
- config_path = os.path.join(model_path, "config.json")
584
-
585
- if not os.path.exists(config_path):
586
- # If no config.json, assume it's a generic model
587
- return "generic"
588
-
589
- try:
590
- with open(config_path, "r") as f:
591
- config = json.load(f)
592
-
593
- # Check architectures field for JinaBertModel
594
- architectures = config.get("architectures", [])
595
- if "JinaBertModel" in architectures:
596
- return "jina_v2"
597
-
598
- # Default to generic mlx_embeddings for other models
599
- return "generic"
600
-
601
- except Exception as e:
602
- print(f"Warning: Could not parse config.json: {e}")
603
- return "generic"
604
-
605
-
606
- # Factory function for creating embedder instances
607
- def create_embedder(
608
- model_path: PathType,
609
- tokenizer_path: Optional[PathType] = None,
610
- device: Optional[str] = None,
611
- ) -> MLXEmbedder:
612
- """Create and return an MLXEmbedder instance that automatically routes to the appropriate implementation."""
613
- if tokenizer_path is None:
614
- tokenizer_path = model_path
615
-
616
- # Return the concrete MLXEmbedder which will handle routing internally
617
- return MLXEmbedder(model_path, tokenizer_path, device)