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,14 @@
1
+ from kiapi.capabilities.web import SearchRequest, handle_search
2
+ from kiapi.core.app import AppContext
3
+ from kiapi.core.model import ModelSpec
4
+
5
+ from .._operations.build_check_result import build_check_result
6
+ from .._schemas.check_result import CheckResult
7
+
8
+
9
+ def check(ctx: AppContext, spec: ModelSpec) -> CheckResult:
10
+ result, artifacts = handle_search(
11
+ ctx,
12
+ SearchRequest(query="kiapi", max_results=1),
13
+ )
14
+ return build_check_result(spec, result, artifacts)
@@ -0,0 +1,20 @@
1
+ from typing import Any
2
+
3
+ from kiapi.core.file import FileID
4
+ from kiapi.core.model import ModelSpec
5
+
6
+ from .._schemas.check_result import CheckResult
7
+
8
+
9
+ def build_check_result(
10
+ spec: ModelSpec,
11
+ result: dict[str, Any],
12
+ artifacts: list[FileID],
13
+ ) -> CheckResult:
14
+ artifact_label = f", artifacts={len(artifacts)}" if artifacts else ""
15
+ return CheckResult(
16
+ ok=True,
17
+ message=f"{spec.domain}/{spec.family}/{spec.name} ok{artifact_label}",
18
+ artifacts=artifacts,
19
+ result=result,
20
+ )
@@ -0,0 +1,10 @@
1
+ from typing import Protocol
2
+
3
+ from kiapi.core.app import AppContext
4
+ from kiapi.core.model import ModelSpec
5
+
6
+ from .._schemas.check_result import CheckResult
7
+
8
+
9
+ class CheckOperation(Protocol):
10
+ def __call__(self, ctx: AppContext, spec: ModelSpec) -> CheckResult: ...
@@ -0,0 +1,46 @@
1
+ from io import BytesIO
2
+
3
+ from PIL import Image, ImageDraw
4
+
5
+ from kiapi.core.app import AppContext
6
+
7
+
8
+ def create_sample_image(ctx: AppContext, *, size: int = 256) -> str:
9
+ image = Image.new("RGB", (size, size), (245, 245, 238))
10
+ draw = ImageDraw.Draw(image)
11
+ margin = max(size // 8, 8)
12
+ stroke = max(size // 32, 2)
13
+ draw.rectangle(
14
+ (margin, margin, size - margin, size - margin),
15
+ outline=(40, 80, 160),
16
+ width=stroke,
17
+ )
18
+ draw.ellipse(
19
+ (
20
+ int(size * 0.3),
21
+ int(size * 0.28),
22
+ int(size * 0.7),
23
+ int(size * 0.66),
24
+ ),
25
+ fill=(240, 196, 76),
26
+ )
27
+ draw.line(
28
+ (
29
+ int(size * 0.2),
30
+ int(size * 0.75),
31
+ int(size * 0.8),
32
+ int(size * 0.75),
33
+ ),
34
+ fill=(36, 120, 88),
35
+ width=stroke,
36
+ )
37
+
38
+ out = BytesIO()
39
+ image.save(out, format="PNG")
40
+ rec = ctx.file_store.put_bytes(
41
+ out.getvalue(),
42
+ filename="kiapi_check_input.png",
43
+ content_type="image/png",
44
+ meta={"kind": "check_input"},
45
+ )
46
+ return rec.file_id
@@ -0,0 +1,12 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any
3
+
4
+ from kiapi.core.file import FileID
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class CheckResult:
9
+ ok: bool
10
+ message: str
11
+ artifacts: list[FileID] = field(default_factory=list)
12
+ result: dict[str, Any] = field(default_factory=dict)
kiapi/cli/check/cli.py ADDED
@@ -0,0 +1,89 @@
1
+ import importlib
2
+ import re
3
+ import traceback
4
+
5
+ import click
6
+
7
+ from kiapi.cli import register_all_capabilities, select_specs
8
+ from kiapi.core.app import AppContext
9
+ from kiapi.core.model import ModelSpec
10
+
11
+ from ._operations.check_context import CheckOperation
12
+ from ._schemas.check_result import CheckResult
13
+
14
+ _NON_IDENTIFIER = re.compile(r"[^0-9a-zA-Z]+")
15
+
16
+
17
+ @click.command()
18
+ @click.option("--all", "check_all", is_flag=True, help="Check all models")
19
+ @click.option("--domain", "domains", multiple=True, help="Check domain")
20
+ @click.option("--family", "families", multiple=True, help="Check family")
21
+ @click.option("--repo", "repos", multiple=True, help="Check repo/image")
22
+ def check(
23
+ check_all: bool,
24
+ domains: tuple[str, ...],
25
+ families: tuple[str, ...],
26
+ repos: tuple[str, ...],
27
+ ) -> None:
28
+ """Run lightweight smoke checks for activated models."""
29
+ register_all_capabilities()
30
+ specs = select_specs(
31
+ all_selected=check_all,
32
+ domains=domains,
33
+ families=families,
34
+ repos=repos,
35
+ interactive=True,
36
+ action="check",
37
+ )
38
+
39
+ ctx = AppContext.create()
40
+ failures = 0
41
+ try:
42
+ for spec in specs:
43
+ click.echo(f"checking {spec.domain}/{spec.family}/{spec.name} ...")
44
+ result = _run_check(ctx, spec)
45
+ mark = "ok" if result.ok else "failed"
46
+ click.echo(f" [{mark}] {result.message}")
47
+ failures += 0 if result.ok else 1
48
+ finally:
49
+ ctx.memory_manager.shutdown()
50
+
51
+ if failures:
52
+ raise click.ClickException(f"{failures} check(s) failed.")
53
+
54
+
55
+ def _run_check(ctx: AppContext, spec: ModelSpec) -> CheckResult:
56
+ try:
57
+ check_operation = _resolve_check_operation(spec)
58
+ except ModuleNotFoundError:
59
+ return CheckResult(
60
+ ok=False,
61
+ message=f"{spec.domain}/{spec.family}/{spec.name}: check is not implemented",
62
+ )
63
+
64
+ try:
65
+ return check_operation(ctx, spec)
66
+ except Exception as exc:
67
+ traceback.print_exc()
68
+ return CheckResult(
69
+ ok=False,
70
+ message=f"{spec.domain}/{spec.family}/{spec.name}: {exc}",
71
+ )
72
+
73
+
74
+ def _resolve_check_operation(spec: ModelSpec) -> CheckOperation:
75
+ module_name = _module_name(spec)
76
+ module = importlib.import_module(
77
+ f"kiapi.cli.check._helpers.{module_name}",
78
+ )
79
+ check_operation = module.check
80
+ return check_operation # type: ignore[no-any-return]
81
+
82
+
83
+ def _module_name(spec: ModelSpec) -> str:
84
+ parts = ("check", spec.domain, spec.family, spec.name)
85
+ return "_".join(_slug(part) for part in parts)
86
+
87
+
88
+ def _slug(value: str) -> str:
89
+ return _NON_IDENTIFIER.sub("_", value.strip().lower()).strip("_")
kiapi/cli/cli.py ADDED
@@ -0,0 +1,29 @@
1
+ import click
2
+
3
+ from kiapi.core.config import UserConfigError, load_user_settings
4
+
5
+ from .activate.cli import activate
6
+ from .check.cli import check
7
+ from .config.cli import config_cli
8
+ from .deactivate.cli import deactivate
9
+ from .run.cli import run
10
+ from .service.cli import service
11
+ from .status.cli import status
12
+
13
+
14
+ @click.group()
15
+ def main() -> None:
16
+ """kiapi command line interface."""
17
+ try:
18
+ load_user_settings()
19
+ except UserConfigError as exc:
20
+ raise click.ClickException(str(exc)) from exc
21
+
22
+
23
+ main.add_command(run)
24
+ main.add_command(status)
25
+ main.add_command(activate)
26
+ main.add_command(deactivate)
27
+ main.add_command(check)
28
+ main.add_command(config_cli)
29
+ main.add_command(service)
@@ -0,0 +1,17 @@
1
+ import click
2
+
3
+ from .edit.cli import edit
4
+ from .init.cli import init
5
+ from .show.cli import show
6
+ from .template.cli import template
7
+
8
+
9
+ @click.group(name="config")
10
+ def config_cli() -> None:
11
+ """Manage kiapi user settings."""
12
+
13
+
14
+ config_cli.add_command(init)
15
+ config_cli.add_command(show)
16
+ config_cli.add_command(edit)
17
+ config_cli.add_command(template)
@@ -0,0 +1,32 @@
1
+ import os
2
+ import shlex
3
+ import subprocess
4
+
5
+ import click
6
+
7
+ from kiapi.core.config import get_user_settings_path
8
+
9
+
10
+ @click.command(name="edit")
11
+ def edit() -> None:
12
+ """Open the user settings file in an editor."""
13
+ path = get_user_settings_path()
14
+ if not path.exists():
15
+ raise click.ClickException(
16
+ f"Settings file does not exist: {path}\n"
17
+ "Run `kiapi config init` to create it."
18
+ )
19
+
20
+ command = _resolve_editor_command(str(path))
21
+ subprocess.run(command, check=True)
22
+
23
+
24
+ def _resolve_editor_command(path: str) -> list[str]:
25
+ editor = os.getenv("VISUAL") or os.getenv("EDITOR")
26
+ if editor:
27
+ return [*shlex.split(editor), path]
28
+
29
+ if os.name == "posix":
30
+ return ["open", "-t", path]
31
+
32
+ return ["notepad", path]
@@ -0,0 +1,33 @@
1
+ from pathlib import Path
2
+
3
+ import click
4
+
5
+ from kiapi.core.config import get_user_settings_path
6
+
7
+ _DEFAULT_USER_SETTINGS = """# kiapi user settings
8
+ kiapi.api:
9
+ host: 127.0.0.1
10
+ port: 8000
11
+ auth_token: null
12
+
13
+ kiapi.core.memory:
14
+ memory_limit_gb: null
15
+ default_ttl_s: 1800.0
16
+ """
17
+
18
+
19
+ @click.command(name="init")
20
+ def init() -> None:
21
+ """Create the user settings file if it does not exist."""
22
+ path = _init_user_settings()
23
+ click.echo(str(path))
24
+
25
+
26
+ def _init_user_settings() -> Path:
27
+ path = get_user_settings_path()
28
+ if path.exists():
29
+ return path
30
+
31
+ path.parent.mkdir(parents=True, exist_ok=True)
32
+ path.write_text(_DEFAULT_USER_SETTINGS, encoding="utf-8")
33
+ return path
@@ -0,0 +1,13 @@
1
+ import click
2
+
3
+ from kiapi.core.config import get_user_settings_path
4
+
5
+
6
+ @click.command(name="show")
7
+ def show() -> None:
8
+ """Show the user settings file."""
9
+ path = get_user_settings_path()
10
+ if not path.exists():
11
+ raise click.ClickException(f"Settings file does not exist: {path}")
12
+
13
+ click.echo(path.read_text(encoding="utf-8"), nl=False)
@@ -0,0 +1,36 @@
1
+ import click
2
+ from pydantic_settings_manager import generate_user_configs_yaml
3
+
4
+ _SETTINGS_IMPORT_PATHS = [
5
+ "kiapi.api",
6
+ "kiapi.core.logging",
7
+ "kiapi.core.app",
8
+ "kiapi.core.workdir",
9
+ "kiapi.core.file",
10
+ "kiapi.core.memory",
11
+ "kiapi.core.worker",
12
+ "kiapi.core.net",
13
+ "kiapi.capabilities.chat",
14
+ "kiapi.capabilities.embedding",
15
+ "kiapi.capabilities.depthpro",
16
+ "kiapi.capabilities.ernie",
17
+ "kiapi.capabilities.flux2",
18
+ "kiapi.capabilities.ideogram4",
19
+ "kiapi.capabilities.qwen",
20
+ "kiapi.capabilities.seedvr2",
21
+ "kiapi.capabilities.zimage",
22
+ "kiapi.capabilities.acestep",
23
+ "kiapi.capabilities.audiogen",
24
+ "kiapi.capabilities.ltx2",
25
+ "kiapi.capabilities.web",
26
+ ]
27
+
28
+
29
+ @click.command(name="template")
30
+ def template() -> None:
31
+ """Show the full user settings template."""
32
+ click.echo(_generate_user_settings_template())
33
+
34
+
35
+ def _generate_user_settings_template() -> str:
36
+ return generate_user_configs_yaml(_SETTINGS_IMPORT_PATHS)
@@ -0,0 +1,49 @@
1
+ import click
2
+ import questionary
3
+
4
+ from kiapi.cli import (
5
+ dedupe_resources,
6
+ register_all_capabilities,
7
+ run_resources,
8
+ select_specs,
9
+ )
10
+ from kiapi.core.setup import SetupManager, SetupResource
11
+
12
+
13
+ @click.command()
14
+ @click.option("--all", "deactivate_all", is_flag=True, help="Deactivate all models")
15
+ @click.option("--domain", "domains", multiple=True, help="Deactivate domain")
16
+ @click.option("--family", "families", multiple=True, help="Deactivate family")
17
+ @click.option("--repo", "repos", multiple=True, help="Deactivate repo/image")
18
+ def deactivate(
19
+ deactivate_all: bool,
20
+ domains: tuple[str, ...],
21
+ families: tuple[str, ...],
22
+ repos: tuple[str, ...],
23
+ ) -> None:
24
+ """Select and remove Hugging Face snapshots, Docker images, and URL files."""
25
+ register_all_capabilities()
26
+ specs = select_specs(
27
+ all_selected=deactivate_all,
28
+ domains=domains,
29
+ families=families,
30
+ repos=repos,
31
+ interactive=True,
32
+ action="deactivate",
33
+ )
34
+ resources = dedupe_resources(specs)
35
+ if not _confirm_deactivate(resources):
36
+ click.echo("Canceled.")
37
+ return
38
+ run_resources("deactivate", resources, SetupManager())
39
+
40
+
41
+ def _confirm_deactivate(resources: list[SetupResource]) -> bool:
42
+ if not resources:
43
+ return True
44
+ labels = ", ".join(resource.label for resource in resources)
45
+ answer = questionary.confirm(
46
+ f"Deactivate {len(resources)} setup resource(s)? {labels}",
47
+ default=False,
48
+ ).ask()
49
+ return bool(answer)
kiapi/cli/run/asgi.py ADDED
@@ -0,0 +1,16 @@
1
+ from fastapi import FastAPI
2
+
3
+ from kiapi.cli import register_all_capabilities
4
+
5
+
6
+ def create_app() -> FastAPI:
7
+ """ASGI factory for uvicorn (used by hot reload).
8
+
9
+ The reload subprocess re-imports the app fresh, so capability
10
+ registration must run here rather than only in the `kiapi run` CLI.
11
+ """
12
+ register_all_capabilities()
13
+
14
+ from kiapi.api.app import app
15
+
16
+ return app
kiapi/cli/run/cli.py ADDED
@@ -0,0 +1,59 @@
1
+ import os
2
+
3
+ import click
4
+ import uvicorn
5
+
6
+ from kiapi.api import settings_manager as api_settings_manager
7
+ from kiapi.cli import register_all_capabilities
8
+ from kiapi.core.logging import get_log_level
9
+ from kiapi.core.logging import settings_manager as logging_settings_manager
10
+
11
+
12
+ @click.command()
13
+ @click.option("--host", type=str, help="Bind socket to this host")
14
+ @click.option("--port", type=int, help="Bind socket to this port")
15
+ @click.option("--debug", is_flag=True, help="Enable debug logging and hot reload")
16
+ def run(host: str | None, port: int | None, debug: bool) -> None:
17
+ """Run the kiapi API server."""
18
+ api_cli_args: dict[str, str | int] = {}
19
+
20
+ if host is not None:
21
+ api_cli_args["host"] = host
22
+ if port is not None:
23
+ api_cli_args["port"] = port
24
+
25
+ if api_cli_args:
26
+ api_settings_manager.cli_args = api_cli_args
27
+
28
+ settings = api_settings_manager.get_settings()
29
+
30
+ if debug:
31
+ logging_settings_manager.cli_args = {"log_level": "DEBUG"}
32
+ # The reload subprocess re-imports the app fresh and does not inherit
33
+ # in-process cli_args, so propagate the log level via the environment.
34
+ os.environ["KIAPI_LOG_LEVEL"] = "DEBUG"
35
+
36
+ # Hot reload requires an import string (the worker subprocess
37
+ # re-imports the app), so use the ASGI factory that registers
38
+ # capabilities on import.
39
+ uvicorn.run(
40
+ "kiapi.cli.run.asgi:create_app",
41
+ factory=True,
42
+ reload=True,
43
+ reload_dirs=["kiapi"],
44
+ host=settings.host,
45
+ port=settings.port,
46
+ log_level=get_log_level(),
47
+ )
48
+ return
49
+
50
+ register_all_capabilities()
51
+
52
+ from kiapi.api.app import app
53
+
54
+ uvicorn.run(
55
+ app,
56
+ host=settings.host,
57
+ port=settings.port,
58
+ log_level=get_log_level(),
59
+ )
@@ -0,0 +1,5 @@
1
+ from ._services import service_manager
2
+
3
+ __all__ = [
4
+ "service_manager",
5
+ ]
@@ -0,0 +1,107 @@
1
+ import os
2
+ import plistlib
3
+ import subprocess
4
+ import sys
5
+ import time
6
+ from pathlib import Path
7
+
8
+ SERVICE_LABEL = os.getenv("KIAPI_SERVICE_LABEL", "io.github.kiarina.kiapi")
9
+
10
+
11
+ def get_launchd_domain() -> str:
12
+ return f"gui/{os.getuid()}"
13
+
14
+
15
+ def get_plist_path() -> Path:
16
+ return Path.home() / "Library" / "LaunchAgents" / f"{SERVICE_LABEL}.plist"
17
+
18
+
19
+ def get_log_dir() -> Path:
20
+ return Path("/tmp/kiapi/service")
21
+
22
+
23
+ def get_stdout_path() -> Path:
24
+ return get_log_dir() / "out.log"
25
+
26
+
27
+ def get_stderr_path() -> Path:
28
+ return get_log_dir() / "err.log"
29
+
30
+
31
+ def is_installed() -> bool:
32
+ return get_plist_path().exists()
33
+
34
+
35
+ def is_loaded() -> bool:
36
+ result = run_launchctl(["print", f"{get_launchd_domain()}/{SERVICE_LABEL}"])
37
+ return result.returncode == 0
38
+
39
+
40
+ def install() -> None:
41
+ get_log_dir().mkdir(parents=True, exist_ok=True)
42
+ plist_path = get_plist_path()
43
+ plist_path.parent.mkdir(parents=True, exist_ok=True)
44
+
45
+ plist = {
46
+ "Label": SERVICE_LABEL,
47
+ "ProgramArguments": [
48
+ sys.executable,
49
+ "-m",
50
+ "kiapi",
51
+ "run",
52
+ ],
53
+ "EnvironmentVariables": {
54
+ "PYTHONUNBUFFERED": "1",
55
+ },
56
+ "RunAtLoad": True,
57
+ "KeepAlive": True,
58
+ "StandardOutPath": str(get_stdout_path()),
59
+ "StandardErrorPath": str(get_stderr_path()),
60
+ }
61
+ plist_path.write_bytes(plistlib.dumps(plist, sort_keys=False))
62
+
63
+
64
+ def start() -> None:
65
+ domain = get_launchd_domain()
66
+ result = run_launchctl(["bootstrap", domain, str(get_plist_path())])
67
+ if result.returncode != 0:
68
+ raise RuntimeError(_format_launchctl_error(result.stderr))
69
+
70
+ result = run_launchctl(["kickstart", "-k", f"{domain}/{SERVICE_LABEL}"])
71
+ if result.returncode != 0:
72
+ raise RuntimeError(_format_launchctl_error(result.stderr))
73
+
74
+
75
+ def stop() -> None:
76
+ result = run_launchctl(["bootout", f"{get_launchd_domain()}/{SERVICE_LABEL}"])
77
+ if result.returncode != 0:
78
+ raise RuntimeError(_format_launchctl_error(result.stderr))
79
+
80
+ _wait_until_stopped()
81
+
82
+
83
+ def uninstall() -> None:
84
+ get_plist_path().unlink()
85
+
86
+
87
+ def run_launchctl(args: list[str]) -> subprocess.CompletedProcess[str]:
88
+ return subprocess.run(
89
+ ["launchctl", *args],
90
+ check=False,
91
+ capture_output=True,
92
+ text=True,
93
+ )
94
+
95
+
96
+ def _wait_until_stopped() -> None:
97
+ for _ in range(20):
98
+ if not is_loaded():
99
+ return
100
+ time.sleep(0.1)
101
+
102
+
103
+ def _format_launchctl_error(stderr: str) -> str:
104
+ detail = stderr.strip()
105
+ if not detail:
106
+ return "launchctl failed"
107
+ return detail
@@ -0,0 +1,19 @@
1
+ import click
2
+
3
+ from .install.cli import install
4
+ from .start.cli import start
5
+ from .status.cli import status
6
+ from .stop.cli import stop
7
+ from .uninstall.cli import uninstall
8
+
9
+
10
+ @click.group(name="service")
11
+ def service() -> None:
12
+ """Manage the kiapi launchd user service."""
13
+
14
+
15
+ service.add_command(install)
16
+ service.add_command(start)
17
+ service.add_command(stop)
18
+ service.add_command(status)
19
+ service.add_command(uninstall)
@@ -0,0 +1,17 @@
1
+ import click
2
+
3
+ from kiapi.cli.service import service_manager
4
+
5
+
6
+ @click.command(name="install")
7
+ def install() -> None:
8
+ """Install the kiapi launchd user service."""
9
+ plist_path = service_manager.get_plist_path()
10
+ if service_manager.is_installed():
11
+ raise click.ClickException(f"Service is already installed: {plist_path}")
12
+
13
+ service_manager.install()
14
+ click.echo(f"Installed {service_manager.SERVICE_LABEL}")
15
+ click.echo(f"Plist: {plist_path}")
16
+ click.echo(f"stdout: {service_manager.get_stdout_path()}")
17
+ click.echo(f"stderr: {service_manager.get_stderr_path()}")
@@ -0,0 +1,22 @@
1
+ import click
2
+
3
+ from kiapi.cli.service import service_manager
4
+
5
+
6
+ @click.command(name="start")
7
+ def start() -> None:
8
+ """Start the kiapi launchd user service."""
9
+ plist_path = service_manager.get_plist_path()
10
+ if not service_manager.is_installed():
11
+ raise click.ClickException(f"Service is not installed: {plist_path}")
12
+ if service_manager.is_loaded():
13
+ raise click.ClickException(
14
+ f"Service is already started: {service_manager.SERVICE_LABEL}"
15
+ )
16
+
17
+ try:
18
+ service_manager.start()
19
+ except RuntimeError as exc:
20
+ raise click.ClickException(str(exc)) from exc
21
+
22
+ click.echo(f"Started {service_manager.SERVICE_LABEL}")