kiapi 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. kiapi/__init__.py +3 -0
  2. kiapi/__main__.py +4 -0
  3. kiapi/api/__init__.py +26 -0
  4. kiapi/api/_constants/require_auth.py +14 -0
  5. kiapi/api/_helpers/build_job_responses.py +73 -0
  6. kiapi/api/_helpers/build_openapi.py +55 -0
  7. kiapi/api/_helpers/build_train_responses.py +21 -0
  8. kiapi/api/_helpers/get_accept.py +20 -0
  9. kiapi/api/_helpers/get_ctx.py +7 -0
  10. kiapi/api/_helpers/get_worker.py +7 -0
  11. kiapi/api/_helpers/register_capability_endpoints.py +70 -0
  12. kiapi/api/_helpers/submit_and_maybe_wait.py +113 -0
  13. kiapi/api/_settings.py +50 -0
  14. kiapi/api/_views/async_job_response.py +21 -0
  15. kiapi/api/_views/capability_model_spec.py +49 -0
  16. kiapi/api/app.py +150 -0
  17. kiapi/api/audio/acestep/_views/extract_response.py +57 -0
  18. kiapi/api/audio/acestep/_views/track_response.py +57 -0
  19. kiapi/api/audio/acestep/router.py +190 -0
  20. kiapi/api/audio/audiogen/_views/audio_response.py +46 -0
  21. kiapi/api/audio/audiogen/router.py +77 -0
  22. kiapi/api/chat/_views/chat_completion_response.py +71 -0
  23. kiapi/api/chat/router.py +253 -0
  24. kiapi/api/embedding/_views/embedding_response.py +35 -0
  25. kiapi/api/embedding/router.py +82 -0
  26. kiapi/api/files/_operations/get_file.py +14 -0
  27. kiapi/api/files/_operations/get_file_id.py +18 -0
  28. kiapi/api/files/_views/file_delete_response.py +14 -0
  29. kiapi/api/files/_views/file_list_response.py +15 -0
  30. kiapi/api/files/router.py +105 -0
  31. kiapi/api/health/_views/health_response.py +26 -0
  32. kiapi/api/health/router.py +28 -0
  33. kiapi/api/image/depthpro/_views/estimate_response.py +70 -0
  34. kiapi/api/image/depthpro/router.py +81 -0
  35. kiapi/api/image/ernie/_views/image_response.py +50 -0
  36. kiapi/api/image/ernie/router.py +181 -0
  37. kiapi/api/image/flux2/_views/image_response.py +53 -0
  38. kiapi/api/image/flux2/router.py +197 -0
  39. kiapi/api/image/ideogram4/_views/image_response.py +55 -0
  40. kiapi/api/image/ideogram4/router.py +87 -0
  41. kiapi/api/image/qwen/_views/image_response.py +47 -0
  42. kiapi/api/image/qwen/router.py +141 -0
  43. kiapi/api/image/seedvr2/_views/image_response.py +50 -0
  44. kiapi/api/image/seedvr2/router.py +83 -0
  45. kiapi/api/image/zimage/_views/image_response.py +49 -0
  46. kiapi/api/image/zimage/router.py +131 -0
  47. kiapi/api/jobs/_operations/get_job_id.py +18 -0
  48. kiapi/api/jobs/_views/job_delete_response.py +19 -0
  49. kiapi/api/jobs/_views/job_list_response.py +15 -0
  50. kiapi/api/jobs/router.py +62 -0
  51. kiapi/api/models/_schemas/openai_model_spec.py +26 -0
  52. kiapi/api/models/_views/model_list_response.py +15 -0
  53. kiapi/api/models/router.py +29 -0
  54. kiapi/api/video/ltx2/_views/__init__.py +1 -0
  55. kiapi/api/video/ltx2/_views/video_response.py +59 -0
  56. kiapi/api/video/ltx2/router.py +89 -0
  57. kiapi/api/web/_views/__init__.py +7 -0
  58. kiapi/api/web/_views/fetch_api_request.py +26 -0
  59. kiapi/api/web/_views/fetch_error_response.py +25 -0
  60. kiapi/api/web/router.py +302 -0
  61. kiapi/capabilities/__init__.py +24 -0
  62. kiapi/capabilities/_exceptions/CapabilityError.py +2 -0
  63. kiapi/capabilities/_exceptions/ValidationError.py +2 -0
  64. kiapi/capabilities/_helpers/attach_mflux_progress.py +50 -0
  65. kiapi/capabilities/_helpers/get_file_path.py +20 -0
  66. kiapi/capabilities/_helpers/resolve_file_ref.py +16 -0
  67. kiapi/capabilities/acestep/README.ja.md +174 -0
  68. kiapi/capabilities/acestep/README.md +167 -0
  69. kiapi/capabilities/acestep/__init__.py +37 -0
  70. kiapi/capabilities/acestep/_constants/description.py +122 -0
  71. kiapi/capabilities/acestep/_exceptions/ace_step_engine_error.py +2 -0
  72. kiapi/capabilities/acestep/_helpers/register.py +96 -0
  73. kiapi/capabilities/acestep/_models/acestep.py +105 -0
  74. kiapi/capabilities/acestep/_operations/handle_cover.py +23 -0
  75. kiapi/capabilities/acestep/_operations/handle_extract.py +38 -0
  76. kiapi/capabilities/acestep/_operations/handle_generate.py +18 -0
  77. kiapi/capabilities/acestep/_operations/handle_repaint.py +25 -0
  78. kiapi/capabilities/acestep/_operations/resolve_ace_step_paths.py +30 -0
  79. kiapi/capabilities/acestep/_operations/resolve_cover_params.py +21 -0
  80. kiapi/capabilities/acestep/_operations/resolve_engine.py +10 -0
  81. kiapi/capabilities/acestep/_operations/resolve_extract_params.py +24 -0
  82. kiapi/capabilities/acestep/_operations/resolve_generate_params.py +18 -0
  83. kiapi/capabilities/acestep/_operations/resolve_repaint_params.py +22 -0
  84. kiapi/capabilities/acestep/_schemas/ace_step_paths.py +29 -0
  85. kiapi/capabilities/acestep/_services/ace_step_engine.py +143 -0
  86. kiapi/capabilities/acestep/_settings.py +82 -0
  87. kiapi/capabilities/acestep/_views/ace_step_base.py +61 -0
  88. kiapi/capabilities/acestep/_views/cover_params.py +26 -0
  89. kiapi/capabilities/acestep/_views/cover_request.py +49 -0
  90. kiapi/capabilities/acestep/_views/extract_params.py +24 -0
  91. kiapi/capabilities/acestep/_views/extract_request.py +33 -0
  92. kiapi/capabilities/acestep/_views/generate_params.py +25 -0
  93. kiapi/capabilities/acestep/_views/generate_request.py +54 -0
  94. kiapi/capabilities/acestep/_views/repaint_params.py +27 -0
  95. kiapi/capabilities/acestep/_views/repaint_request.py +51 -0
  96. kiapi/capabilities/acestep/_views/track_params.py +7 -0
  97. kiapi/capabilities/acestep/worker_subprocess.py +247 -0
  98. kiapi/capabilities/audiogen/README.ja.md +49 -0
  99. kiapi/capabilities/audiogen/README.md +48 -0
  100. kiapi/capabilities/audiogen/__init__.py +25 -0
  101. kiapi/capabilities/audiogen/_constants/description.py +60 -0
  102. kiapi/capabilities/audiogen/_helpers/attach_audiogen_progress.py +27 -0
  103. kiapi/capabilities/audiogen/_helpers/register.py +42 -0
  104. kiapi/capabilities/audiogen/_helpers/validate_generate.py +14 -0
  105. kiapi/capabilities/audiogen/_models/audiogen.py +98 -0
  106. kiapi/capabilities/audiogen/_operations/handle_generate.py +27 -0
  107. kiapi/capabilities/audiogen/_operations/resolve_generate_params.py +25 -0
  108. kiapi/capabilities/audiogen/_settings.py +34 -0
  109. kiapi/capabilities/audiogen/_views/generate_params.py +14 -0
  110. kiapi/capabilities/audiogen/_views/generate_request.py +96 -0
  111. kiapi/capabilities/chat/README.ja.md +822 -0
  112. kiapi/capabilities/chat/README.md +806 -0
  113. kiapi/capabilities/chat/__init__.py +25 -0
  114. kiapi/capabilities/chat/_constants/description.py +163 -0
  115. kiapi/capabilities/chat/_helpers/register.py +67 -0
  116. kiapi/capabilities/chat/_models/qwen3_5.py +183 -0
  117. kiapi/capabilities/chat/_models/qwen3_omni.py +242 -0
  118. kiapi/capabilities/chat/_operations/apply_template.py +74 -0
  119. kiapi/capabilities/chat/_operations/completed_hermes_tool_call_text.py +9 -0
  120. kiapi/capabilities/chat/_operations/emit_streaming_response.py +297 -0
  121. kiapi/capabilities/chat/_operations/ensure_streaming_detokenizer_compat.py +49 -0
  122. kiapi/capabilities/chat/_operations/format_response.py +72 -0
  123. kiapi/capabilities/chat/_operations/handle_chat.py +25 -0
  124. kiapi/capabilities/chat/_operations/parse_hermes_tool_calls.py +63 -0
  125. kiapi/capabilities/chat/_operations/parse_json_tool_calls.py +66 -0
  126. kiapi/capabilities/chat/_operations/parse_messages.py +326 -0
  127. kiapi/capabilities/chat/_operations/resolve_chat_params.py +50 -0
  128. kiapi/capabilities/chat/_operations/stream_text_from_tokens.py +32 -0
  129. kiapi/capabilities/chat/_operations/strip_tool_calls.py +15 -0
  130. kiapi/capabilities/chat/_settings.py +74 -0
  131. kiapi/capabilities/chat/_utils/apply_parallel_tool_call_policy.py +17 -0
  132. kiapi/capabilities/chat/_utils/apply_seed.py +8 -0
  133. kiapi/capabilities/chat/_utils/load_audio_mono.py +31 -0
  134. kiapi/capabilities/chat/_utils/load_mlx_vlm.py +12 -0
  135. kiapi/capabilities/chat/_utils/warmup_params.py +26 -0
  136. kiapi/capabilities/chat/_views/chat_params.py +34 -0
  137. kiapi/capabilities/chat/_views/chat_request.py +153 -0
  138. kiapi/capabilities/depthpro/README.ja.md +131 -0
  139. kiapi/capabilities/depthpro/README.md +124 -0
  140. kiapi/capabilities/depthpro/__init__.py +23 -0
  141. kiapi/capabilities/depthpro/_constants/description.py +39 -0
  142. kiapi/capabilities/depthpro/_helpers/register.py +46 -0
  143. kiapi/capabilities/depthpro/_helpers/validate_estimate.py +32 -0
  144. kiapi/capabilities/depthpro/_models/depthpro.py +144 -0
  145. kiapi/capabilities/depthpro/_operations/handle_estimate.py +50 -0
  146. kiapi/capabilities/depthpro/_operations/is_quantize_override.py +12 -0
  147. kiapi/capabilities/depthpro/_operations/resolve_estimate_params.py +24 -0
  148. kiapi/capabilities/depthpro/_settings.py +46 -0
  149. kiapi/capabilities/depthpro/_views/estimate_params.py +21 -0
  150. kiapi/capabilities/depthpro/_views/estimate_request.py +63 -0
  151. kiapi/capabilities/embedding/README.ja.md +137 -0
  152. kiapi/capabilities/embedding/README.md +128 -0
  153. kiapi/capabilities/embedding/__init__.py +24 -0
  154. kiapi/capabilities/embedding/_constants/description.py +47 -0
  155. kiapi/capabilities/embedding/_helpers/register.py +66 -0
  156. kiapi/capabilities/embedding/_models/qwen3_text.py +53 -0
  157. kiapi/capabilities/embedding/_models/qwen3_vl.py +97 -0
  158. kiapi/capabilities/embedding/_operations/format_response.py +24 -0
  159. kiapi/capabilities/embedding/_operations/handle_embed.py +24 -0
  160. kiapi/capabilities/embedding/_operations/parse_inputs.py +108 -0
  161. kiapi/capabilities/embedding/_operations/resolve_embed_params.py +18 -0
  162. kiapi/capabilities/embedding/_settings.py +27 -0
  163. kiapi/capabilities/embedding/_utils/to_vector.py +20 -0
  164. kiapi/capabilities/embedding/_views/embed_params.py +17 -0
  165. kiapi/capabilities/embedding/_views/embed_request.py +39 -0
  166. kiapi/capabilities/ernie/README.ja.md +242 -0
  167. kiapi/capabilities/ernie/README.md +223 -0
  168. kiapi/capabilities/ernie/__init__.py +34 -0
  169. kiapi/capabilities/ernie/_constants/description.py +71 -0
  170. kiapi/capabilities/ernie/_helpers/register.py +60 -0
  171. kiapi/capabilities/ernie/_helpers/validate_edit.py +19 -0
  172. kiapi/capabilities/ernie/_helpers/validate_generate.py +8 -0
  173. kiapi/capabilities/ernie/_models/ernie.py +356 -0
  174. kiapi/capabilities/ernie/_operations/handle_edit.py +39 -0
  175. kiapi/capabilities/ernie/_operations/handle_generate.py +38 -0
  176. kiapi/capabilities/ernie/_operations/handle_train.py +77 -0
  177. kiapi/capabilities/ernie/_operations/is_quantize_override.py +16 -0
  178. kiapi/capabilities/ernie/_operations/resolve_edit_params.py +44 -0
  179. kiapi/capabilities/ernie/_operations/resolve_generate_params.py +40 -0
  180. kiapi/capabilities/ernie/_operations/resolve_lora_params.py +23 -0
  181. kiapi/capabilities/ernie/_operations/resolve_train_params.py +43 -0
  182. kiapi/capabilities/ernie/_operations/validate_common.py +33 -0
  183. kiapi/capabilities/ernie/_schemas/lora_ref.py +27 -0
  184. kiapi/capabilities/ernie/_settings.py +151 -0
  185. kiapi/capabilities/ernie/_views/edit_params.py +36 -0
  186. kiapi/capabilities/ernie/_views/edit_request.py +142 -0
  187. kiapi/capabilities/ernie/_views/generate_params.py +32 -0
  188. kiapi/capabilities/ernie/_views/generate_request.py +127 -0
  189. kiapi/capabilities/ernie/_views/train_params.py +28 -0
  190. kiapi/capabilities/ernie/_views/train_request.py +96 -0
  191. kiapi/capabilities/flux2/README.ja.md +260 -0
  192. kiapi/capabilities/flux2/README.md +241 -0
  193. kiapi/capabilities/flux2/__init__.py +36 -0
  194. kiapi/capabilities/flux2/_constants/description.py +81 -0
  195. kiapi/capabilities/flux2/_helpers/register.py +98 -0
  196. kiapi/capabilities/flux2/_helpers/validate_edit.py +12 -0
  197. kiapi/capabilities/flux2/_helpers/validate_generate.py +8 -0
  198. kiapi/capabilities/flux2/_models/flux2.py +396 -0
  199. kiapi/capabilities/flux2/_operations/handle_edit.py +44 -0
  200. kiapi/capabilities/flux2/_operations/handle_generate.py +46 -0
  201. kiapi/capabilities/flux2/_operations/handle_train.py +105 -0
  202. kiapi/capabilities/flux2/_operations/is_quantize_override.py +16 -0
  203. kiapi/capabilities/flux2/_operations/resolve_edit_params.py +43 -0
  204. kiapi/capabilities/flux2/_operations/resolve_generate_params.py +44 -0
  205. kiapi/capabilities/flux2/_operations/resolve_lora_params.py +23 -0
  206. kiapi/capabilities/flux2/_operations/resolve_train_params.py +42 -0
  207. kiapi/capabilities/flux2/_operations/role_spec.py +13 -0
  208. kiapi/capabilities/flux2/_operations/split_repo.py +11 -0
  209. kiapi/capabilities/flux2/_operations/validate_common.py +35 -0
  210. kiapi/capabilities/flux2/_schemas/lora_ref.py +27 -0
  211. kiapi/capabilities/flux2/_settings.py +181 -0
  212. kiapi/capabilities/flux2/_views/edit_params.py +36 -0
  213. kiapi/capabilities/flux2/_views/edit_request.py +145 -0
  214. kiapi/capabilities/flux2/_views/generate_params.py +36 -0
  215. kiapi/capabilities/flux2/_views/generate_request.py +150 -0
  216. kiapi/capabilities/flux2/_views/train_params.py +32 -0
  217. kiapi/capabilities/flux2/_views/train_request.py +102 -0
  218. kiapi/capabilities/ideogram4/README.ja.md +230 -0
  219. kiapi/capabilities/ideogram4/README.md +219 -0
  220. kiapi/capabilities/ideogram4/__init__.py +24 -0
  221. kiapi/capabilities/ideogram4/_constants/description.py +65 -0
  222. kiapi/capabilities/ideogram4/_helpers/register.py +44 -0
  223. kiapi/capabilities/ideogram4/_helpers/validate_generate.py +31 -0
  224. kiapi/capabilities/ideogram4/_models/ideogram4.py +120 -0
  225. kiapi/capabilities/ideogram4/_operations/handle_generate.py +30 -0
  226. kiapi/capabilities/ideogram4/_operations/is_quantize_override.py +12 -0
  227. kiapi/capabilities/ideogram4/_operations/resolve_generate_params.py +30 -0
  228. kiapi/capabilities/ideogram4/_settings.py +89 -0
  229. kiapi/capabilities/ideogram4/_views/generate_params.py +27 -0
  230. kiapi/capabilities/ideogram4/_views/generate_request.py +118 -0
  231. kiapi/capabilities/ltx2/README.ja.md +287 -0
  232. kiapi/capabilities/ltx2/README.md +274 -0
  233. kiapi/capabilities/ltx2/__init__.py +26 -0
  234. kiapi/capabilities/ltx2/_constants/description.py +81 -0
  235. kiapi/capabilities/ltx2/_helpers/register.py +58 -0
  236. kiapi/capabilities/ltx2/_helpers/validate_generate.py +42 -0
  237. kiapi/capabilities/ltx2/_models/ltx2.py +106 -0
  238. kiapi/capabilities/ltx2/_operations/detect_mode.py +19 -0
  239. kiapi/capabilities/ltx2/_operations/handle_generate.py +52 -0
  240. kiapi/capabilities/ltx2/_operations/resolve_generate_params.py +31 -0
  241. kiapi/capabilities/ltx2/_settings.py +93 -0
  242. kiapi/capabilities/ltx2/_views/generate_params.py +34 -0
  243. kiapi/capabilities/ltx2/_views/generate_request.py +151 -0
  244. kiapi/capabilities/qwen/README.ja.md +251 -0
  245. kiapi/capabilities/qwen/README.md +235 -0
  246. kiapi/capabilities/qwen/__init__.py +30 -0
  247. kiapi/capabilities/qwen/_constants/description.py +53 -0
  248. kiapi/capabilities/qwen/_helpers/register.py +60 -0
  249. kiapi/capabilities/qwen/_helpers/validate_edit.py +12 -0
  250. kiapi/capabilities/qwen/_helpers/validate_generate.py +12 -0
  251. kiapi/capabilities/qwen/_models/qwen.py +224 -0
  252. kiapi/capabilities/qwen/_operations/handle_edit.py +44 -0
  253. kiapi/capabilities/qwen/_operations/handle_generate.py +46 -0
  254. kiapi/capabilities/qwen/_operations/is_quantize_override.py +15 -0
  255. kiapi/capabilities/qwen/_operations/resolve_edit_params.py +35 -0
  256. kiapi/capabilities/qwen/_operations/resolve_generate_params.py +39 -0
  257. kiapi/capabilities/qwen/_operations/resolve_lora_params.py +23 -0
  258. kiapi/capabilities/qwen/_operations/validate_common.py +32 -0
  259. kiapi/capabilities/qwen/_schemas/lora_ref.py +27 -0
  260. kiapi/capabilities/qwen/_settings.py +107 -0
  261. kiapi/capabilities/qwen/_views/edit_params.py +36 -0
  262. kiapi/capabilities/qwen/_views/edit_request.py +138 -0
  263. kiapi/capabilities/qwen/_views/generate_params.py +37 -0
  264. kiapi/capabilities/qwen/_views/generate_request.py +149 -0
  265. kiapi/capabilities/seedvr2/README.ja.md +234 -0
  266. kiapi/capabilities/seedvr2/README.md +219 -0
  267. kiapi/capabilities/seedvr2/__init__.py +24 -0
  268. kiapi/capabilities/seedvr2/_constants/description.py +46 -0
  269. kiapi/capabilities/seedvr2/_helpers/register.py +60 -0
  270. kiapi/capabilities/seedvr2/_helpers/validate_upscale.py +52 -0
  271. kiapi/capabilities/seedvr2/_models/seedvr2.py +140 -0
  272. kiapi/capabilities/seedvr2/_operations/handle_upscale.py +42 -0
  273. kiapi/capabilities/seedvr2/_operations/is_quantize_override.py +12 -0
  274. kiapi/capabilities/seedvr2/_operations/resolve_upscale_params.py +30 -0
  275. kiapi/capabilities/seedvr2/_settings.py +74 -0
  276. kiapi/capabilities/seedvr2/_views/upscale_params.py +27 -0
  277. kiapi/capabilities/seedvr2/_views/upscale_request.py +94 -0
  278. kiapi/capabilities/web/README.ja.md +187 -0
  279. kiapi/capabilities/web/README.md +171 -0
  280. kiapi/capabilities/web/__init__.py +30 -0
  281. kiapi/capabilities/web/_constants/description.py +38 -0
  282. kiapi/capabilities/web/_exceptions/FetchError.py +24 -0
  283. kiapi/capabilities/web/_exceptions/SearchBackendError.py +11 -0
  284. kiapi/capabilities/web/_helpers/register.py +59 -0
  285. kiapi/capabilities/web/_models/crawl4ai.py +32 -0
  286. kiapi/capabilities/web/_models/searxng.py +44 -0
  287. kiapi/capabilities/web/_operations/handle_fetch.py +145 -0
  288. kiapi/capabilities/web/_operations/handle_search.py +56 -0
  289. kiapi/capabilities/web/_operations/resolve_fetch_params.py +19 -0
  290. kiapi/capabilities/web/_operations/resolve_search_params.py +34 -0
  291. kiapi/capabilities/web/_operations/resolve_searxng_config_dir.py +21 -0
  292. kiapi/capabilities/web/_services/__init__.py +1 -0
  293. kiapi/capabilities/web/_services/web_backend_process.py +144 -0
  294. kiapi/capabilities/web/_settings.py +138 -0
  295. kiapi/capabilities/web/_views/fetch_params.py +27 -0
  296. kiapi/capabilities/web/_views/fetch_request.py +29 -0
  297. kiapi/capabilities/web/_views/fetch_result.py +20 -0
  298. kiapi/capabilities/web/_views/search_params.py +43 -0
  299. kiapi/capabilities/web/_views/search_request.py +93 -0
  300. kiapi/capabilities/web/_views/search_response.py +49 -0
  301. kiapi/capabilities/web/resources/__init__.py +0 -0
  302. kiapi/capabilities/web/resources/searxng/__init__.py +0 -0
  303. kiapi/capabilities/web/resources/searxng/settings.yml +11 -0
  304. kiapi/capabilities/zimage/README.ja.md +249 -0
  305. kiapi/capabilities/zimage/README.md +231 -0
  306. kiapi/capabilities/zimage/__init__.py +34 -0
  307. kiapi/capabilities/zimage/_constants/description.py +73 -0
  308. kiapi/capabilities/zimage/_helpers/register.py +62 -0
  309. kiapi/capabilities/zimage/_helpers/validate_generate.py +37 -0
  310. kiapi/capabilities/zimage/_models/zimage.py +278 -0
  311. kiapi/capabilities/zimage/_operations/handle_generate.py +38 -0
  312. kiapi/capabilities/zimage/_operations/handle_train.py +78 -0
  313. kiapi/capabilities/zimage/_operations/is_quantize_override.py +11 -0
  314. kiapi/capabilities/zimage/_operations/resolve_generate_params.py +39 -0
  315. kiapi/capabilities/zimage/_operations/resolve_lora_params.py +23 -0
  316. kiapi/capabilities/zimage/_operations/resolve_train_params.py +38 -0
  317. kiapi/capabilities/zimage/_schemas/lora_ref.py +27 -0
  318. kiapi/capabilities/zimage/_settings.py +166 -0
  319. kiapi/capabilities/zimage/_views/generate_params.py +23 -0
  320. kiapi/capabilities/zimage/_views/generate_request.py +127 -0
  321. kiapi/capabilities/zimage/_views/train_params.py +22 -0
  322. kiapi/capabilities/zimage/_views/train_request.py +101 -0
  323. kiapi/cli/__init__.py +11 -0
  324. kiapi/cli/_helpers/dedupe_resources.py +12 -0
  325. kiapi/cli/_helpers/register_all_capabilities.py +36 -0
  326. kiapi/cli/_helpers/run_resources.py +24 -0
  327. kiapi/cli/_helpers/select_specs.py +67 -0
  328. kiapi/cli/activate/_operations/preflight_hf_access.py +129 -0
  329. kiapi/cli/activate/cli.py +37 -0
  330. kiapi/cli/check/_helpers/check_audio_acestep_turbo.py +22 -0
  331. kiapi/cli/check/_helpers/check_audio_acestep_xl_base.py +22 -0
  332. kiapi/cli/check/_helpers/check_audio_audiogen_medium.py +24 -0
  333. kiapi/cli/check/_helpers/check_chat_chat_qwen3_6_27b.py +19 -0
  334. kiapi/cli/check/_helpers/check_chat_chat_qwen3_omni.py +19 -0
  335. kiapi/cli/check/_helpers/check_embedding_embedding_qwen3_embedding_8b.py +14 -0
  336. kiapi/cli/check/_helpers/check_embedding_embedding_qwen3_vl_embedding_2b.py +19 -0
  337. kiapi/cli/check/_helpers/check_image_depthpro_base.py +21 -0
  338. kiapi/cli/check/_helpers/check_image_ernie_base.py +23 -0
  339. kiapi/cli/check/_helpers/check_image_ernie_turbo.py +23 -0
  340. kiapi/cli/check/_helpers/check_image_flux2_klein_9b.py +23 -0
  341. kiapi/cli/check/_helpers/check_image_flux2_klein_base_4b.py +23 -0
  342. kiapi/cli/check/_helpers/check_image_flux2_klein_base_9b.py +23 -0
  343. kiapi/cli/check/_helpers/check_image_ideogram4_fp8.py +23 -0
  344. kiapi/cli/check/_helpers/check_image_qwen_edit_2509.py +27 -0
  345. kiapi/cli/check/_helpers/check_image_qwen_image.py +23 -0
  346. kiapi/cli/check/_helpers/check_image_seedvr2_3b.py +23 -0
  347. kiapi/cli/check/_helpers/check_image_seedvr2_7b.py +23 -0
  348. kiapi/cli/check/_helpers/check_image_zimage_base.py +23 -0
  349. kiapi/cli/check/_helpers/check_image_zimage_turbo.py +23 -0
  350. kiapi/cli/check/_helpers/check_video_ltx2_distilled.py +26 -0
  351. kiapi/cli/check/_helpers/check_web_web_fetch.py +14 -0
  352. kiapi/cli/check/_helpers/check_web_web_search.py +14 -0
  353. kiapi/cli/check/_operations/build_check_result.py +20 -0
  354. kiapi/cli/check/_operations/check_context.py +10 -0
  355. kiapi/cli/check/_operations/create_sample_image.py +46 -0
  356. kiapi/cli/check/_schemas/check_result.py +12 -0
  357. kiapi/cli/check/cli.py +89 -0
  358. kiapi/cli/cli.py +29 -0
  359. kiapi/cli/config/cli.py +17 -0
  360. kiapi/cli/config/edit/cli.py +32 -0
  361. kiapi/cli/config/init/cli.py +33 -0
  362. kiapi/cli/config/show/cli.py +13 -0
  363. kiapi/cli/config/template/cli.py +36 -0
  364. kiapi/cli/deactivate/cli.py +49 -0
  365. kiapi/cli/run/asgi.py +16 -0
  366. kiapi/cli/run/cli.py +59 -0
  367. kiapi/cli/service/__init__.py +5 -0
  368. kiapi/cli/service/_services/service_manager.py +107 -0
  369. kiapi/cli/service/cli.py +19 -0
  370. kiapi/cli/service/install/cli.py +17 -0
  371. kiapi/cli/service/start/cli.py +22 -0
  372. kiapi/cli/service/status/cli.py +81 -0
  373. kiapi/cli/service/stop/cli.py +19 -0
  374. kiapi/cli/service/uninstall/cli.py +16 -0
  375. kiapi/cli/status/cli.py +226 -0
  376. kiapi/core/app/__init__.py +16 -0
  377. kiapi/core/app/_schemas/app_context.py +28 -0
  378. kiapi/core/app/_services/user_directory.py +59 -0
  379. kiapi/core/app/_settings.py +46 -0
  380. kiapi/core/capability/__init__.py +11 -0
  381. kiapi/core/capability/_schemas/capability_spec.py +17 -0
  382. kiapi/core/capability/_services/capability_spec_registry.py +21 -0
  383. kiapi/core/config/__init__.py +11 -0
  384. kiapi/core/config/_exceptions/user_config_error.py +2 -0
  385. kiapi/core/config/_helpers/get_user_settings_path.py +7 -0
  386. kiapi/core/config/_helpers/load_user_settings.py +54 -0
  387. kiapi/core/file/__init__.py +37 -0
  388. kiapi/core/file/_helpers/create_file_store.py +7 -0
  389. kiapi/core/file/_helpers/resolve_file_ref.py +90 -0
  390. kiapi/core/file/_schemas/file_data_url_ref.py +19 -0
  391. kiapi/core/file/_schemas/file_id_ref.py +16 -0
  392. kiapi/core/file/_schemas/file_record.py +46 -0
  393. kiapi/core/file/_schemas/file_url_ref.py +16 -0
  394. kiapi/core/file/_services/file_store.py +138 -0
  395. kiapi/core/file/_settings.py +22 -0
  396. kiapi/core/file/_types/file_id.py +2 -0
  397. kiapi/core/file/_types/file_ref.py +12 -0
  398. kiapi/core/file/_views/resolved_file_ref.py +16 -0
  399. kiapi/core/job/__init__.py +24 -0
  400. kiapi/core/job/_enums/job_status.py +9 -0
  401. kiapi/core/job/_helpers/creep_progress.py +123 -0
  402. kiapi/core/job/_models/job.py +121 -0
  403. kiapi/core/job/_services/job_store.py +33 -0
  404. kiapi/core/job/_services/progress_reporter.py +79 -0
  405. kiapi/core/job/_types/job_id.py +3 -0
  406. kiapi/core/job/_types/job_result.py +5 -0
  407. kiapi/core/job/_types/job_type.py +4 -0
  408. kiapi/core/logging/__init__.py +14 -0
  409. kiapi/core/logging/_helpers/get_log_level.py +8 -0
  410. kiapi/core/logging/_helpers/setup_logger.py +14 -0
  411. kiapi/core/logging/_settings.py +34 -0
  412. kiapi/core/logging/_types/log_level.py +3 -0
  413. kiapi/core/memory/__init__.py +21 -0
  414. kiapi/core/memory/_exceptions/memory_budget_error.py +2 -0
  415. kiapi/core/memory/_helpers/create_memory_manager.py +17 -0
  416. kiapi/core/memory/_operations/log_memory_limit.py +29 -0
  417. kiapi/core/memory/_operations/resolve_effective_memory_limit_gb.py +13 -0
  418. kiapi/core/memory/_operations/resolve_framework_strategy.py +42 -0
  419. kiapi/core/memory/_schemas/framework_strategy.py +14 -0
  420. kiapi/core/memory/_schemas/memory_stats.py +24 -0
  421. kiapi/core/memory/_schemas/resident_model.py +14 -0
  422. kiapi/core/memory/_schemas/resident_model_stats.py +49 -0
  423. kiapi/core/memory/_services/memory_manager.py +257 -0
  424. kiapi/core/memory/_settings.py +36 -0
  425. kiapi/core/memory/_types/framework_name.py +4 -0
  426. kiapi/core/memory/_types/resident_key.py +4 -0
  427. kiapi/core/model/__init__.py +36 -0
  428. kiapi/core/model/_exceptions/unknown_model_error.py +2 -0
  429. kiapi/core/model/_schemas/model_spec.py +145 -0
  430. kiapi/core/model/_services/model_registry.py +85 -0
  431. kiapi/core/model/_types/model_alias.py +2 -0
  432. kiapi/core/model/_types/model_domain.py +6 -0
  433. kiapi/core/model/_types/model_family.py +5 -0
  434. kiapi/core/model/_types/model_key.py +8 -0
  435. kiapi/core/model/_types/model_name.py +4 -0
  436. kiapi/core/model/_types/model_repo.py +3 -0
  437. kiapi/core/net/__init__.py +16 -0
  438. kiapi/core/net/_exceptions/unsafe_url_error.py +7 -0
  439. kiapi/core/net/_helpers/verify_public_url.py +68 -0
  440. kiapi/core/net/_settings.py +28 -0
  441. kiapi/core/setup/__init__.py +25 -0
  442. kiapi/core/setup/_exceptions/setup_required_error.py +2 -0
  443. kiapi/core/setup/_schemas/docker_image_resource.py +37 -0
  444. kiapi/core/setup/_schemas/hf_snapshot_resource.py +50 -0
  445. kiapi/core/setup/_schemas/local_path_resource.py +43 -0
  446. kiapi/core/setup/_schemas/python_package_resource.py +58 -0
  447. kiapi/core/setup/_schemas/python_venv_resource.py +63 -0
  448. kiapi/core/setup/_schemas/setup_status.py +7 -0
  449. kiapi/core/setup/_schemas/url_file_resource.py +43 -0
  450. kiapi/core/setup/_services/setup_manager.py +331 -0
  451. kiapi/core/setup/_types/setup_resource.py +21 -0
  452. kiapi/core/setup/_types/setup_target.py +11 -0
  453. kiapi/core/workdir/__init__.py +8 -0
  454. kiapi/core/workdir/_helpers/create_work_dir.py +11 -0
  455. kiapi/core/workdir/_settings.py +21 -0
  456. kiapi/core/worker/__init__.py +23 -0
  457. kiapi/core/worker/_helpers/create_worker.py +9 -0
  458. kiapi/core/worker/_services/worker.py +165 -0
  459. kiapi/core/worker/_settings.py +36 -0
  460. kiapi/core/worker/_types/job_thunk.py +6 -0
  461. kiapi-0.1.0.dist-info/METADATA +337 -0
  462. kiapi-0.1.0.dist-info/RECORD +465 -0
  463. kiapi-0.1.0.dist-info/WHEEL +4 -0
  464. kiapi-0.1.0.dist-info/entry_points.txt +2 -0
  465. kiapi-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,47 @@
1
+ DESCRIPTION = """Text and multimodal embeddings for retrieval and similarity search.
2
+
3
+ POST one item to `/v1/embedding` with one field per modality (`text` and/or
4
+ `image`). Returns a single L2-normalized, last-token-pooled vector. This is **not**
5
+ OpenAI's array `input` shape — one item per request. Sync only (no async mode).
6
+
7
+ ## Upstream docs
8
+ - [mlx-embeddings](https://github.com/Blaizzy/mlx-embeddings) — the MLX embedding engine kiapi runs
9
+ - [mlx-community/Qwen3-Embedding-8B-mxfp8](https://huggingface.co/mlx-community/Qwen3-Embedding-8B-mxfp8) — `qwen3-embedding-8b` weights
10
+ - [mlx-community/Qwen3-VL-Embedding-2B-mxfp8](https://huggingface.co/mlx-community/Qwen3-VL-Embedding-2B-mxfp8) — `qwen3-vl-embedding-2b` weights
11
+
12
+ ## Choosing A Model
13
+ `model` selects a registered embedding model (full catalog and aliases:
14
+ `GET /v1/embedding/models`). The served models differ by input modality, so
15
+ choose by what you send:
16
+ - **qwen3-embedding-8b** (default) — text only. Larger, stronger text retrieval.
17
+ - **qwen3-vl-embedding-2b** — text + image. Use it for image embeddings or a
18
+ shared text/image space; sending `image` to the text-only model returns 400.
19
+
20
+ Vectors from different models live in different spaces and may differ in
21
+ dimensionality — embed both your queries and your corpus with the **same** model.
22
+
23
+ ## Notes
24
+ - One input item per request. To embed N items, make N requests.
25
+ - Provide at least one modality input; an empty request returns 400.
26
+ - Vectors are already L2-normalized, so cosine similarity reduces to a dot
27
+ product.
28
+
29
+ ## Examples
30
+
31
+ ### Text (default model)
32
+ ```sh
33
+ curl -sS http://HOST:PORT/v1/embedding \\
34
+ -H 'Content-Type: application/json' \\
35
+ -d '{"text": "今日の天気は晴れです"}'
36
+ ```
37
+
38
+ ### Image (multimodal model)
39
+ ```sh
40
+ curl -sS http://HOST:PORT/v1/embedding \\
41
+ -H 'Content-Type: application/json' \\
42
+ -d '{
43
+ "model": "qwen3-vl-embedding-2b",
44
+ "image": "data:image/png;base64,iVBORw0..."
45
+ }'
46
+ ```
47
+ """
@@ -0,0 +1,66 @@
1
+ """Register embedding's models + OpenAPI description in the global registries."""
2
+
3
+ from kiapi.core.capability import CapabilitySpec, capability_spec_registry
4
+ from kiapi.core.model import ModelSpec, model_registry
5
+ from kiapi.core.setup import HfSnapshotResource
6
+
7
+ from .._constants.description import DESCRIPTION
8
+ from .._models import qwen3_text, qwen3_vl
9
+
10
+
11
+ def register() -> None:
12
+ capability_spec_registry.register(
13
+ CapabilitySpec(
14
+ name="embedding",
15
+ domain="embedding",
16
+ title="kiapi Embedding API",
17
+ summary="Create text and multimodal embeddings for retrieval and similarity search.",
18
+ description=DESCRIPTION,
19
+ openapi_path="/v1/embedding/openapi.json",
20
+ docs_path="/v1/embedding/docs",
21
+ redoc_path="/v1/embedding/redoc",
22
+ path_prefixes=("/v1/embedding",),
23
+ )
24
+ )
25
+
26
+ model_registry.register(
27
+ ModelSpec(
28
+ name="qwen3-embedding-8b",
29
+ family="embedding",
30
+ domain="embedding",
31
+ repo="mlx-community/Qwen3-Embedding-8B-mxfp8",
32
+ module=qwen3_text,
33
+ weight_gb=7.3, # measured on device (estimate was 8.0)
34
+ peak_headroom_gb=2.0,
35
+ framework="mlx",
36
+ priority=10,
37
+ aliases=("text", "qwen3-embedding", "qwen3_embedding"),
38
+ default=True,
39
+ setup_resources=(
40
+ HfSnapshotResource(
41
+ repo="mlx-community/Qwen3-Embedding-8B-mxfp8",
42
+ disk_gb=7.82,
43
+ ),
44
+ ),
45
+ )
46
+ )
47
+ model_registry.register(
48
+ ModelSpec(
49
+ name="qwen3-vl-embedding-2b",
50
+ family="embedding",
51
+ domain="embedding",
52
+ repo="mlx-community/Qwen3-VL-Embedding-2B-mxfp8",
53
+ module=qwen3_vl,
54
+ weight_gb=2.4, # measured on device (estimate was 2.0)
55
+ peak_headroom_gb=2.0, # image inputs add some headroom
56
+ framework="mlx",
57
+ priority=20, # tiny + frequently used → keep resident
58
+ aliases=("vl", "qwen3-vl-embedding", "qwen3_vl_embedding"),
59
+ setup_resources=(
60
+ HfSnapshotResource(
61
+ repo="mlx-community/Qwen3-VL-Embedding-2B-mxfp8",
62
+ disk_gb=2.59,
63
+ ),
64
+ ),
65
+ )
66
+ )
@@ -0,0 +1,53 @@
1
+ """Handler for Qwen3-Embedding-8B (text embeddings; ``model_type: qwen3``).
2
+
3
+ A text-only embedding model. Owns its own load + embed flow; shares the
4
+ input-parsing and response-shaping operations with the VL handler.
5
+ """
6
+
7
+ import tempfile
8
+ import time
9
+ from pathlib import Path
10
+ from types import SimpleNamespace
11
+ from typing import Any
12
+
13
+ from kiapi.core.model import ModelSpec
14
+
15
+ from .._operations.format_response import format_response
16
+ from .._operations.parse_inputs import parse_inputs
17
+ from .._utils.to_vector import to_vector
18
+ from .._views.embed_params import EmbedParams
19
+
20
+ FEATURES = {"text"}
21
+
22
+
23
+ def load(spec: ModelSpec) -> SimpleNamespace:
24
+ from mlx_embeddings import load as _load # type: ignore
25
+
26
+ model, processor = _load(spec.repo)
27
+ return SimpleNamespace(model=model, processor=processor)
28
+
29
+
30
+ def warmup(payload: SimpleNamespace) -> None:
31
+ run(
32
+ payload,
33
+ EmbedParams(model="qwen3-embedding-8b", inputs={"text": "hi"}, max_length=512),
34
+ )
35
+
36
+
37
+ def run(payload: SimpleNamespace, params: EmbedParams) -> dict[str, Any]:
38
+ from mlx_embeddings import generate
39
+
40
+ model, processor = payload.model, payload.processor
41
+ # text-only: parse_inputs validates capabilities; no media files are written,
42
+ # so the tmp_dir is never actually touched.
43
+ parsed = parse_inputs(params.inputs, Path(tempfile.gettempdir()), allow=FEATURES)
44
+
45
+ t0 = time.time()
46
+ output = generate(model, processor, parsed["text"], max_length=params.max_length)
47
+ elapsed = time.time() - t0
48
+
49
+ return format_response(
50
+ model_name=params.model,
51
+ embedding=to_vector(output),
52
+ elapsed=elapsed,
53
+ )
@@ -0,0 +1,97 @@
1
+ """Handler for Qwen3-VL-Embedding-2B (text + image embeddings; ``model_type: qwen3_vl``).
2
+
3
+ Owns the full embed flow for the multimodal embedding model. The MLX-converted
4
+ processor may be missing the ``chat_template`` and token-id attributes that
5
+ Transformers normally sets up, so :func:`load` patches them in after loading (a
6
+ known Qwen3-VL quirk, carried over from the original single-purpose server).
7
+
8
+ Embedding is done via the model's high-level ``process([item], processor=...)``
9
+ API, where ``item`` is ``{"text": ..., "image": <path>}`` (either key optional).
10
+ """
11
+
12
+ import shutil
13
+ import time
14
+ from types import SimpleNamespace
15
+ from typing import Any
16
+
17
+ from kiapi.core.model import ModelSpec
18
+ from kiapi.core.workdir import create_work_dir
19
+
20
+ from .._operations.format_response import format_response
21
+ from .._operations.parse_inputs import parse_inputs
22
+ from .._utils.to_vector import to_vector
23
+ from .._views.embed_params import EmbedParams
24
+
25
+ FEATURES = {"text", "image"}
26
+
27
+ # Source repo for the chat template, when the converted processor lacks one.
28
+ TEMPLATE_SOURCE_MODEL_ID = "Qwen/Qwen3-VL-Embedding-2B"
29
+
30
+
31
+ def load(spec: ModelSpec) -> SimpleNamespace:
32
+ from mlx_embeddings import load as _load # type: ignore
33
+
34
+ model, processor = _load(spec.repo)
35
+ payload = SimpleNamespace(model=model, processor=processor)
36
+ _patch_processor(payload.processor)
37
+ return payload
38
+
39
+
40
+ def warmup(payload: SimpleNamespace) -> None:
41
+ run(
42
+ payload,
43
+ EmbedParams(
44
+ model="qwen3-vl-embedding-2b", inputs={"text": "hi"}, max_length=512
45
+ ),
46
+ )
47
+
48
+
49
+ def _patch_processor(processor: Any) -> None:
50
+ """Patch in the chat template / token-id attributes the converted processor
51
+ may be missing (Qwen3-VL quirk). Best-effort and idempotent."""
52
+ inner = getattr(processor, "processor", None)
53
+ tokenizer = getattr(processor, "tokenizer", None)
54
+
55
+ if getattr(processor, "chat_template", None) is None:
56
+ try:
57
+ chat_template = processor._load_chat_template(TEMPLATE_SOURCE_MODEL_ID)
58
+ if inner is not None:
59
+ inner.chat_template = chat_template
60
+ if tokenizer is not None:
61
+ tokenizer.chat_template = chat_template
62
+ except Exception:
63
+ pass
64
+
65
+ if inner is not None:
66
+ image_token_id = getattr(processor, "image_token_id", None)
67
+ video_token_id = getattr(processor, "video_token_id", None)
68
+ if image_token_id is not None:
69
+ inner.image_ids = [image_token_id]
70
+ if video_token_id is not None:
71
+ inner.video_ids = [video_token_id]
72
+ inner.audio_ids = []
73
+
74
+
75
+ def run(payload: SimpleNamespace, params: EmbedParams) -> dict[str, Any]:
76
+ model, processor = payload.model, payload.processor
77
+ tmp_dir = create_work_dir("embedding/qwen3_vl")
78
+ try:
79
+ parsed = parse_inputs(params.inputs, tmp_dir, allow=FEATURES)
80
+
81
+ item: dict[str, Any] = {}
82
+ if "text" in parsed:
83
+ item["text"] = parsed["text"]
84
+ if "image" in parsed:
85
+ item["image"] = parsed["image"] # local file path
86
+
87
+ t0 = time.time()
88
+ embeddings = model.process([item], processor=processor)
89
+ elapsed = time.time() - t0
90
+
91
+ return format_response(
92
+ model_name=params.model,
93
+ embedding=to_vector(embeddings),
94
+ elapsed=elapsed,
95
+ )
96
+ finally:
97
+ shutil.rmtree(tmp_dir, ignore_errors=True)
@@ -0,0 +1,24 @@
1
+ """Shape an embedding vector into the server's ``/v1/embedding`` response dict.
2
+
3
+ Identical across handlers, so it lives here and the per-model ``run()`` calls it
4
+ after computing the vector.
5
+ """
6
+
7
+ from typing import Any
8
+
9
+
10
+ def format_response(
11
+ *,
12
+ model_name: str,
13
+ embedding: list[float],
14
+ elapsed: float,
15
+ prompt_tokens: int = 0,
16
+ ) -> dict[str, Any]:
17
+ """Build the ``/v1/embedding`` response dict for a single embedding."""
18
+ return {
19
+ "model": model_name,
20
+ "embedding": embedding,
21
+ "dimension": len(embedding),
22
+ "usage": {"prompt_tokens": prompt_tokens, "total_tokens": prompt_tokens},
23
+ "timings": {"total_s": round(elapsed, 3)},
24
+ }
@@ -0,0 +1,24 @@
1
+ """Embedding service entry: resolve → acquire (memory budget) → run.
2
+
3
+ Body of the embedding job's worker-thread thunk. Mirrors mlx-embedding-server's
4
+ Engine.run, but loads through the *global* memory manager so embedding models
5
+ share the budget with every other capability.
6
+ """
7
+
8
+ from kiapi.core.app import AppContext
9
+ from kiapi.core.model import model_registry
10
+
11
+ from .._settings import settings_manager
12
+ from .._views.embed_request import EmbedRequest
13
+ from .resolve_embed_params import resolve_embed_params
14
+
15
+
16
+ def handle_embed(ctx: AppContext, req: EmbedRequest) -> tuple[dict, list[str]]:
17
+ """Run one embedding. Returns (embedding_result, artifact_file_ids)."""
18
+ settings = settings_manager.get_settings()
19
+ spec = model_registry.resolve("embedding", req.model)
20
+ ctx.ensure_model_ready(spec)
21
+ params = resolve_embed_params(settings, req, variant=spec.name)
22
+ payload = ctx.memory_manager.acquire(spec)
23
+ result = spec.module.run(payload, params)
24
+ return result, [] # embeddings produce no file artifacts
@@ -0,0 +1,108 @@
1
+ """Turn an embedding request's modality inputs into usable values.
2
+
3
+ The request carries one field per modality (``text``, ``image``, ...). Model
4
+ handlers call :func:`parse_inputs` with the set of modalities they support
5
+ (``allow=``); anything outside that set — or an empty request — is rejected with
6
+ :class:`~kiapi.capabilities.CapabilityError` (mapped to HTTP 400 by the API layer).
7
+
8
+ - ``text`` is passed through as-is.
9
+ - ``image`` accepts a data URL, an http(s) URL, or bare base64, and is
10
+ materialized to a file under ``tmp_dir`` (the loader reads paths).
11
+
12
+ Returns a dict keyed by modality, e.g. ``{"text": "...", "image": "/tmp/..png"}``.
13
+ """
14
+
15
+ import base64
16
+ import binascii
17
+ import re
18
+ import urllib.request
19
+ import uuid
20
+ from pathlib import Path
21
+ from typing import Any
22
+
23
+ from kiapi.capabilities import CapabilityError
24
+ from kiapi.core.net import UnsafeURLError, verify_public_url
25
+
26
+ _DATA_URL = re.compile(r"^data:(?P<mime>[\w./+-]+)?;base64,(?P<data>.*)$", re.DOTALL)
27
+
28
+ _EXT_BY_MIME = {
29
+ "image/png": ".png",
30
+ "image/jpeg": ".jpg",
31
+ "image/jpg": ".jpg",
32
+ "image/webp": ".webp",
33
+ "image/gif": ".gif",
34
+ }
35
+ _DEFAULT_EXT = {"image": ".png"}
36
+
37
+
38
+ def _write_bytes(data: bytes, tmp_dir: Path, kind: str, ext: str) -> str:
39
+ path = tmp_dir / f"{kind}_{uuid.uuid4().hex}{ext}"
40
+ path.write_bytes(data)
41
+ return str(path)
42
+
43
+
44
+ def _materialize(source: str, kind: str, tmp_dir: Path) -> str:
45
+ """Turn a data URL / http(s) URL / bare base64 into a file path."""
46
+ if not isinstance(source, str) or not source:
47
+ raise CapabilityError(f"{kind}: empty or non-string source")
48
+
49
+ m = _DATA_URL.match(source)
50
+ if m:
51
+ mime = m.group("mime") or ""
52
+ ext = _EXT_BY_MIME.get(mime, _DEFAULT_EXT[kind])
53
+ try:
54
+ return _write_bytes(base64.b64decode(m.group("data")), tmp_dir, kind, ext)
55
+ except (binascii.Error, ValueError) as exc:
56
+ raise CapabilityError(f"{kind}: invalid base64 data URL ({exc})") # noqa: B904
57
+
58
+ if source.startswith(("http://", "https://")):
59
+ try:
60
+ verify_public_url(source, kind=kind)
61
+ except UnsafeURLError as exc:
62
+ raise CapabilityError(f"{kind}: {exc}") # noqa: B904
63
+ try:
64
+ with urllib.request.urlopen(source, timeout=30) as resp:
65
+ data = resp.read()
66
+ except Exception as exc:
67
+ raise CapabilityError(f"{kind}: failed to fetch {source!r} ({exc})") # noqa: B904
68
+ ext = Path(source.split("?")[0]).suffix or _DEFAULT_EXT[kind]
69
+ return _write_bytes(data, tmp_dir, kind, ext)
70
+
71
+ # Bare base64 (no data: prefix) — the common case for {"image": "<b64>"}.
72
+ try:
73
+ data = base64.b64decode(source, validate=True)
74
+ except (binascii.Error, ValueError):
75
+ raise CapabilityError(f"{kind}: source is not a data URL, URL, or base64") # noqa: B904
76
+ return _write_bytes(data, tmp_dir, kind, _DEFAULT_EXT[kind])
77
+
78
+
79
+ def parse_inputs(
80
+ inputs: dict[str, Any],
81
+ tmp_dir: Path,
82
+ *,
83
+ allow: set[str] | None = None,
84
+ ) -> dict[str, Any]:
85
+ """Validate + materialize request inputs into a per-modality dict.
86
+
87
+ ``allow`` is the set of modalities the selected model supports (e.g.
88
+ ``{"text", "image"}``). An input outside it raises :class:`CapabilityError`.
89
+ ``None`` allows everything (used by tests).
90
+ """
91
+ if not inputs:
92
+ raise CapabilityError(
93
+ "request has no input (provide at least one of: text, image)"
94
+ )
95
+
96
+ out: dict[str, Any] = {}
97
+ for kind, source in inputs.items():
98
+ if allow is not None and kind not in allow:
99
+ raise CapabilityError(
100
+ f"{kind} input is not supported by the selected model"
101
+ )
102
+ if kind == "text":
103
+ out["text"] = source or ""
104
+ elif kind == "image":
105
+ out["image"] = _materialize(source, "image", tmp_dir)
106
+ else: # pragma: no cover — schema only exposes known modalities
107
+ raise CapabilityError(f"unsupported input modality: {kind!r}")
108
+ return out
@@ -0,0 +1,18 @@
1
+ """Merge an embedding request with settings defaults into the complete EmbedParams."""
2
+
3
+ from .._settings import EmbeddingSettings
4
+ from .._views.embed_params import EmbedParams
5
+ from .._views.embed_request import EmbedRequest
6
+
7
+
8
+ def resolve_embed_params(
9
+ settings: EmbeddingSettings,
10
+ req: EmbedRequest,
11
+ *,
12
+ variant: str,
13
+ ) -> EmbedParams:
14
+ return EmbedParams(
15
+ model=variant,
16
+ inputs=req.inputs(),
17
+ max_length=settings.max_length,
18
+ )
@@ -0,0 +1,27 @@
1
+ """Embedding-capability defaults, read from the environment (``KIAPI_EMBEDDING_``)."""
2
+
3
+ from pydantic import Field
4
+ from pydantic_settings import BaseSettings, SettingsConfigDict
5
+ from pydantic_settings_manager import SettingsManager
6
+
7
+
8
+ class EmbeddingSettings(BaseSettings):
9
+ """Settings for Embedding input length limits."""
10
+
11
+ model_config = SettingsConfigDict(
12
+ env_prefix="KIAPI_EMBEDDING_",
13
+ extra="ignore",
14
+ protected_namespaces=(),
15
+ )
16
+
17
+ max_length: int = Field(
18
+ default=512,
19
+ title="Maximum input token length",
20
+ description=(
21
+ "Maximum token length passed to the embedding model tokenizer.\n"
22
+ "Inputs longer than this are truncated before model processing."
23
+ ),
24
+ )
25
+
26
+
27
+ settings_manager = SettingsManager(EmbeddingSettings)
@@ -0,0 +1,20 @@
1
+ """Extract a single embedding vector from an mlx-embeddings model output."""
2
+
3
+ from typing import Any
4
+
5
+
6
+ def to_vector(output: Any) -> list[float]:
7
+ """Extract a single embedding vector from an mlx-embeddings model output.
8
+
9
+ mlx-embeddings returns a model-output object with ``text_embeds`` (normalized,
10
+ pooled, shape ``(batch, dim)``). We embed one item per request, so take row 0.
11
+ Falls back to treating the output itself as the array if there's no attribute.
12
+ """
13
+ import mlx.core as mx
14
+
15
+ embeds = getattr(output, "text_embeds", None)
16
+ if embeds is None:
17
+ embeds = getattr(output, "pooler_output", output)
18
+ mx.eval(embeds)
19
+ rows = embeds.tolist()
20
+ return rows[0] if rows and isinstance(rows[0], list) else rows
@@ -0,0 +1,17 @@
1
+ """The complete contract for one embedding run.
2
+
3
+ Built from settings + request by ``resolve_embed_params``; a model's ``run`` needs
4
+ nothing else (no ``req`` / ``settings``) to produce the embedding and its response.
5
+ ``model`` is the canonical model name to echo back; ``inputs`` are the request's
6
+ raw modality sources (materialized per-model via ``parse_inputs``).
7
+ """
8
+
9
+ from typing import Any
10
+
11
+ from pydantic import BaseModel
12
+
13
+
14
+ class EmbedParams(BaseModel):
15
+ model: str
16
+ inputs: dict[str, Any]
17
+ max_length: int
@@ -0,0 +1,39 @@
1
+ """Embedding request model — one item, one field per modality."""
2
+
3
+ from typing import Any
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+
8
+ class EmbedRequest(BaseModel):
9
+ model_config = ConfigDict(extra="allow")
10
+
11
+ model: str | None = Field(
12
+ default=None,
13
+ description=(
14
+ "Registry name, alias, or repo of the embedding model (see "
15
+ "`GET /v1/embedding/models`). Omit to use the default model."
16
+ ),
17
+ )
18
+
19
+ text: str | None = Field(
20
+ default=None,
21
+ description="Text to embed. Supported by every embedding model.",
22
+ )
23
+ image: str | None = Field(
24
+ default=None,
25
+ description=(
26
+ "Image to embed, as a base64 string, data URL, http(s) URL, or local "
27
+ "path. Only multimodal models accept it; sending it to a text-only "
28
+ "model returns HTTP 400."
29
+ ),
30
+ )
31
+
32
+ def inputs(self) -> dict[str, Any]:
33
+ """Present modality inputs, keyed by modality name (skips unset ones)."""
34
+ out: dict[str, Any] = {}
35
+ if self.text is not None:
36
+ out["text"] = self.text
37
+ if self.image is not None:
38
+ out["image"] = self.image
39
+ return out