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,90 @@
1
+ import base64
2
+ import binascii
3
+ import mimetypes
4
+ import urllib.error
5
+ import urllib.parse
6
+ import urllib.request
7
+ from pathlib import Path
8
+
9
+ from kiapi.core.net import UnsafeURLError, verify_public_url
10
+
11
+ from .._schemas.file_data_url_ref import FileDataURLRef
12
+ from .._schemas.file_id_ref import FileIDRef
13
+ from .._schemas.file_record import FileRecord
14
+ from .._schemas.file_url_ref import FileURLRef
15
+ from .._services.file_store import FileStore
16
+ from .._types.file_ref import FileRef
17
+ from .._views.resolved_file_ref import ResolvedFileRef
18
+
19
+
20
+ def resolve_file_ref(
21
+ file_store: FileStore,
22
+ ref: FileRef,
23
+ *,
24
+ kind: str,
25
+ ) -> ResolvedFileRef:
26
+ if isinstance(ref, FileIDRef):
27
+ rec = file_store.get(ref.file_id)
28
+ if rec is None:
29
+ raise FileNotFoundError(f"unknown {kind} file_id {ref.file_id!r}")
30
+ return ResolvedFileRef(rec)
31
+
32
+ if isinstance(ref, FileURLRef):
33
+ return ResolvedFileRef(_store_url(file_store, ref, kind=kind))
34
+
35
+ if isinstance(ref, FileDataURLRef):
36
+ return ResolvedFileRef(_store_data_url(file_store, ref, kind=kind))
37
+
38
+
39
+ def _store_url(file_store: FileStore, ref: FileURLRef, *, kind: str) -> FileRecord:
40
+ parsed = urllib.parse.urlparse(ref.url)
41
+ if parsed.scheme not in ("http", "https"):
42
+ raise ValueError(f"{kind} url must be an absolute http:// or https:// URL")
43
+
44
+ try:
45
+ verify_public_url(ref.url, kind=kind)
46
+ except UnsafeURLError as exc:
47
+ raise ValueError(str(exc)) from exc
48
+
49
+ try:
50
+ with urllib.request.urlopen(ref.url, timeout=30) as response:
51
+ data = response.read()
52
+ content_type = response.headers.get_content_type()
53
+ except urllib.error.URLError as exc:
54
+ raise ValueError(f"failed to fetch {kind} url {ref.url!r}: {exc}") from exc
55
+
56
+ filename = (
57
+ Path(parsed.path).name or f"{kind}{_suffix_for_content_type(content_type)}"
58
+ )
59
+ return file_store.put_bytes(
60
+ data,
61
+ filename=filename,
62
+ content_type=content_type,
63
+ meta={"source": "url", "url": ref.url, "kind": kind},
64
+ )
65
+
66
+
67
+ def _store_data_url(
68
+ file_store: FileStore, ref: FileDataURLRef, *, kind: str
69
+ ) -> FileRecord:
70
+ header, sep, raw = ref.data_url.partition(",")
71
+ if sep != "," or not header.startswith("data:"):
72
+ raise ValueError(f"{kind} data_url must be a data URL")
73
+
74
+ media_type = header[5:].split(";", 1)[0] or "application/octet-stream"
75
+ is_base64 = ";base64" in header
76
+ try:
77
+ data = base64.b64decode(raw, validate=True) if is_base64 else raw.encode()
78
+ except (binascii.Error, ValueError) as exc:
79
+ raise ValueError(f"invalid {kind} data_url payload: {exc}") from exc
80
+
81
+ return file_store.put_bytes(
82
+ data,
83
+ filename=f"{kind}{_suffix_for_content_type(media_type)}",
84
+ content_type=media_type,
85
+ meta={"source": "data_url", "kind": kind},
86
+ )
87
+
88
+
89
+ def _suffix_for_content_type(content_type: str | None) -> str:
90
+ return mimetypes.guess_extension(content_type or "") or ".bin"
@@ -0,0 +1,19 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class FileDataURLRef(BaseModel):
7
+ model_config = {
8
+ "json_schema_extra": {
9
+ "examples": [
10
+ {
11
+ "type": "data_url",
12
+ "data_url": "data:image/png;base64,iVBORw0KGgo...",
13
+ },
14
+ ],
15
+ },
16
+ }
17
+
18
+ type: Literal["data_url"] = "data_url"
19
+ data_url: str = Field(..., min_length=1)
@@ -0,0 +1,16 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class FileIDRef(BaseModel):
7
+ model_config = {
8
+ "json_schema_extra": {
9
+ "examples": [
10
+ {"type": "file_id", "file_id": "file_0123456789abcdef"},
11
+ ],
12
+ },
13
+ }
14
+
15
+ type: Literal["file_id"] = "file_id"
16
+ file_id: str = Field(..., min_length=1)
@@ -0,0 +1,46 @@
1
+ from typing import Any
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from .._types.file_id import FileID
6
+
7
+
8
+ class FileRecord(BaseModel):
9
+ """A stored file's metadata. Doubles as the Files API response schema.
10
+
11
+ ``path`` is the on-disk location and is internal to the file store; it is
12
+ excluded from serialization so ``model_dump()`` yields the API/sidecar shape.
13
+ """
14
+
15
+ file_id: FileID = Field(
16
+ ...,
17
+ description="Persistent file id. Use this in FileRef inputs or download it with GET /v1/files/{file_id}/download.",
18
+ examples=["file_0123456789abcdef"],
19
+ )
20
+ filename: str = Field(
21
+ ...,
22
+ description="Original or generated filename associated with the stored bytes.",
23
+ examples=["image_1766200000.png"],
24
+ )
25
+ content_type: str = Field(
26
+ ...,
27
+ description="Media type of the stored file.",
28
+ examples=["image/png"],
29
+ )
30
+ size: int = Field(
31
+ ...,
32
+ ge=0,
33
+ description="File size in bytes.",
34
+ examples=[123456],
35
+ )
36
+ created_at: float = Field(
37
+ ...,
38
+ description="Unix timestamp when the file was stored.",
39
+ examples=[1766200000.0],
40
+ )
41
+ meta: dict[str, Any] = Field(
42
+ default_factory=dict,
43
+ description="Capability-specific metadata such as seed, request params, timings, dimensions, or artifact kind.",
44
+ examples=[{"model": "turbo", "width": 1024, "height": 1024}],
45
+ )
46
+ path: str = Field(..., exclude=True)
@@ -0,0 +1,16 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class FileURLRef(BaseModel):
7
+ model_config = {
8
+ "json_schema_extra": {
9
+ "examples": [
10
+ {"type": "url", "url": "https://example.com/input.png"},
11
+ ],
12
+ },
13
+ }
14
+
15
+ type: Literal["url"] = "url"
16
+ url: str = Field(..., min_length=1)
@@ -0,0 +1,138 @@
1
+ """Unified file store. Artifacts (and uploads) are addressed by ``file_id``.
2
+
3
+ Files outlive jobs while their files remain on disk: jobs are in-memory and reset
4
+ on process restart, while stored files stay self-describing via a sidecar
5
+ ``<file_id>.json`` holding the original filename, content type, size, and an
6
+ optional ``meta`` blob. This
7
+ mirrors the per-server Files APIs (ace-step / audiocraft / video) unified into
8
+ one store under ``files_root``.
9
+ """
10
+
11
+ import json
12
+ import mimetypes
13
+ import shutil
14
+ import time
15
+ import uuid
16
+ from pathlib import Path
17
+ from typing import Any
18
+
19
+ from .._schemas.file_record import FileRecord
20
+ from .._settings import FileSettings
21
+ from .._types.file_id import FileID
22
+
23
+
24
+ class FileStore:
25
+ def __init__(self, settings: FileSettings) -> None:
26
+ self.root = Path(settings.files_root).expanduser()
27
+ self.root.mkdir(parents=True, exist_ok=True)
28
+
29
+ def _blob_path(self, file_id: FileID, suffix: str) -> Path:
30
+ return self.root / f"{file_id}{suffix}"
31
+
32
+ def _sidecar(self, file_id: FileID) -> Path:
33
+ return self.root / f"{file_id}.json"
34
+
35
+ # -- write ----------------------------------------------------------------
36
+
37
+ def put_bytes(
38
+ self,
39
+ data: bytes,
40
+ *,
41
+ filename: str,
42
+ content_type: str | None = None,
43
+ meta: dict[str, Any] | None = None,
44
+ ) -> FileRecord:
45
+ file_id = _generate_file_id()
46
+ suffix = Path(filename).suffix
47
+ path = self._blob_path(file_id, suffix)
48
+ path.write_bytes(data)
49
+ rec = FileRecord(
50
+ file_id=file_id,
51
+ filename=filename,
52
+ content_type=_resolve_content_type(filename, content_type),
53
+ size=len(data),
54
+ created_at=time.time(),
55
+ meta=meta or {},
56
+ path=str(path),
57
+ )
58
+ self._write_sidecar(rec, suffix)
59
+ return rec
60
+
61
+ def put_path(
62
+ self,
63
+ src: str | Path,
64
+ *,
65
+ filename: str | None = None,
66
+ content_type: str | None = None,
67
+ meta: dict[str, Any] | None = None,
68
+ move: bool = False,
69
+ ) -> FileRecord:
70
+ src = Path(src)
71
+ file_id = _generate_file_id()
72
+ suffix = src.suffix
73
+ filename = filename or src.name
74
+ path = self._blob_path(file_id, suffix)
75
+ if move:
76
+ shutil.move(str(src), str(path))
77
+ else:
78
+ shutil.copyfile(src, path)
79
+ rec = FileRecord(
80
+ file_id=file_id,
81
+ filename=filename,
82
+ content_type=_resolve_content_type(filename, content_type),
83
+ size=path.stat().st_size,
84
+ created_at=time.time(),
85
+ meta=meta or {},
86
+ path=str(path),
87
+ )
88
+ self._write_sidecar(rec, suffix)
89
+ return rec
90
+
91
+ def _write_sidecar(self, rec: FileRecord, suffix: str) -> None:
92
+ payload = rec.model_dump()
93
+ payload["_suffix"] = suffix
94
+ self._sidecar(rec.file_id).write_text(json.dumps(payload, ensure_ascii=False))
95
+
96
+ # -- read -----------------------------------------------------------------
97
+
98
+ def get(self, file_id: FileID) -> FileRecord | None:
99
+ sidecar = self._sidecar(file_id)
100
+ if not sidecar.exists():
101
+ return None
102
+ d = json.loads(sidecar.read_text())
103
+ suffix = d.get("_suffix", "")
104
+ return FileRecord(
105
+ file_id=d["file_id"],
106
+ filename=d["filename"],
107
+ content_type=d["content_type"],
108
+ size=d["size"],
109
+ created_at=d["created_at"],
110
+ meta=d.get("meta", {}),
111
+ path=str(self._blob_path(file_id, suffix)),
112
+ )
113
+
114
+ def list(self) -> list[FileRecord]:
115
+ recs = []
116
+ for sidecar in self.root.glob("*.json"):
117
+ rec = self.get(sidecar.stem)
118
+ if rec is not None:
119
+ recs.append(rec)
120
+ return sorted(recs, key=lambda r: r.created_at, reverse=True)
121
+
122
+ def delete(self, file_id: FileID) -> bool:
123
+ rec = self.get(file_id)
124
+ if rec is None:
125
+ return False
126
+ Path(rec.path).unlink(missing_ok=True)
127
+ self._sidecar(file_id).unlink(missing_ok=True)
128
+ return True
129
+
130
+
131
+ def _generate_file_id() -> FileID:
132
+ return f"file_{uuid.uuid4().hex}"
133
+
134
+
135
+ def _resolve_content_type(filename: str, content_type: str | None) -> str:
136
+ return (
137
+ content_type or mimetypes.guess_type(filename)[0] or "application/octet-stream"
138
+ )
@@ -0,0 +1,22 @@
1
+ from pydantic import Field
2
+ from pydantic_settings import BaseSettings, SettingsConfigDict
3
+ from pydantic_settings_manager import SettingsManager
4
+
5
+
6
+ class FileSettings(BaseSettings):
7
+ """Settings for the file store that keeps uploads and generated artifacts."""
8
+
9
+ model_config = SettingsConfigDict(env_prefix="KIAPI_")
10
+
11
+ files_root: str = Field(
12
+ default="/tmp/kiapi/files",
13
+ title="File storage directory",
14
+ description=(
15
+ "Directory where uploaded files and generated artifacts are stored.\n"
16
+ "The default is under /tmp so files may disappear after reboot or tmp cleanup.\n"
17
+ "~ is expanded as the home directory of the running user."
18
+ ),
19
+ )
20
+
21
+
22
+ settings_manager = SettingsManager(FileSettings)
@@ -0,0 +1,2 @@
1
+ type FileID = str
2
+ """The address of a stored file while it remains available in the Files API."""
@@ -0,0 +1,12 @@
1
+ from typing import Annotated
2
+
3
+ from pydantic import Field
4
+
5
+ from .._schemas.file_data_url_ref import FileDataURLRef
6
+ from .._schemas.file_id_ref import FileIDRef
7
+ from .._schemas.file_url_ref import FileURLRef
8
+
9
+ type FileRef = Annotated[
10
+ FileIDRef | FileURLRef | FileDataURLRef,
11
+ Field(discriminator="type"),
12
+ ]
@@ -0,0 +1,16 @@
1
+ from dataclasses import dataclass
2
+
3
+ from .._schemas.file_record import FileRecord
4
+
5
+
6
+ @dataclass(frozen=True)
7
+ class ResolvedFileRef:
8
+ record: FileRecord
9
+
10
+ @property
11
+ def file_id(self) -> str:
12
+ return self.record.file_id
13
+
14
+ @property
15
+ def path(self) -> str:
16
+ return self.record.path
@@ -0,0 +1,24 @@
1
+ """Unified job model + in-memory job store. Every generation (sync or async) is
2
+ a Job; sync waits for it, async returns its id. Jobs reset on restart.
3
+
4
+ Public surface (was ``core/jobs.py``): :class:`Job`, :class:`JobStore`,
5
+ :class:`JobStatus`, :class:`ProgressReporter`, :func:`creep_progress`.
6
+ """
7
+
8
+ from ._enums.job_status import JobStatus
9
+ from ._helpers.creep_progress import creep_progress
10
+ from ._models.job import Job
11
+ from ._services.job_store import JobStore
12
+ from ._services.progress_reporter import ProgressReporter
13
+ from ._types.job_id import JobID
14
+ from ._types.job_result import JobResult
15
+
16
+ __all__ = [
17
+ "Job",
18
+ "JobID",
19
+ "JobResult",
20
+ "JobStatus",
21
+ "JobStore",
22
+ "ProgressReporter",
23
+ "creep_progress",
24
+ ]
@@ -0,0 +1,9 @@
1
+ from enum import StrEnum
2
+
3
+
4
+ class JobStatus(StrEnum):
5
+ QUEUED = "queued"
6
+ RUNNING = "running"
7
+ SUCCEEDED = "succeeded"
8
+ FAILED = "failed"
9
+ CANCELED = "canceled"
@@ -0,0 +1,123 @@
1
+ """Synthetic 'liveness' progress for jobs whose backend exposes no per-step hook.
2
+
3
+ Some generation backends (notably ltx2's ``mlx_video.generate_video``, which only
4
+ drives its own internal rich progress bar) give us no way to observe denoising
5
+ steps — unlike mflux, which offers a callback registry (see capabilities'
6
+ ``attach_mflux_progress``). A polling client, typically an LLM agent, reads a job
7
+ whose ``progress`` never moves as possibly hung and may stop waiting.
8
+
9
+ For those backends we creep the reported fraction forward on a piecewise-linear
10
+ schedule (see :func:`_scheduled_fraction`) — constant, easy-to-read rates rather
11
+ than a smooth curve. This is a deliberate fiction: it signals 'alive and working',
12
+ not real completion; the genuine terminal 1.0 still comes only from
13
+ :meth:`Job.mark_succeeded`.
14
+
15
+ The job's worker thread is blocked inside the backend call while this runs, so a
16
+ daemon thread does the ticking. ContextVars don't cross threads, so it captures
17
+ the worker thread's bound :class:`ProgressReporter` up front and pushes updates
18
+ through it — the same throttling and job wiring apply.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import threading
24
+ import time
25
+ from collections.abc import Iterator
26
+ from contextlib import contextmanager
27
+
28
+ from .._services.progress_reporter import ProgressReporter
29
+
30
+
31
+ def _scheduled_fraction(
32
+ elapsed: float,
33
+ *,
34
+ eta_s: float,
35
+ cap: float,
36
+ ramp_frac: float,
37
+ ramp_rate: float,
38
+ mid_frac: float,
39
+ mid_fallback_rate: float,
40
+ tail_rate: float,
41
+ ) -> float:
42
+ """The reported fraction at ``elapsed`` seconds — three constant-rate phases:
43
+
44
+ 1. **ramp** — linear from 0 to ``ramp_frac`` at a *fixed* ``ramp_rate`` per
45
+ second (e.g. 0 → 0.20 at 0.5%/s, reaching 0.20 after 40s). The rate is
46
+ always honoured, even for a short ``eta_s``, so the start is always a gentle
47
+ crawl — easier to wait on than an immediate jump.
48
+ 2. **mid** — linear from ``ramp_frac`` to ``mid_frac``. Normally paced to hit
49
+ ``mid_frac`` exactly at ``eta_s``; but if the ramp has already consumed
50
+ ``eta_s`` (``eta_s <= ramp duration``), there is no room left to pace to, so
51
+ it falls back to the fixed ``mid_fallback_rate`` per second (e.g. 1%/s).
52
+ 3. **tail** — linear from ``mid_frac`` upward at the slow ``tail_rate`` per
53
+ second, clamped at ``cap`` — the overrun crawl.
54
+ """
55
+ knee_t = ramp_frac / ramp_rate # fixed: guarantees the slow start
56
+ if elapsed <= knee_t:
57
+ return min(cap, ramp_rate * elapsed)
58
+
59
+ if eta_s > knee_t:
60
+ mid_end_t = eta_s # room to pace: land on mid_frac exactly at eta
61
+ else:
62
+ mid_end_t = knee_t + (mid_frac - ramp_frac) / mid_fallback_rate
63
+
64
+ if elapsed <= mid_end_t:
65
+ fraction = ramp_frac + (mid_frac - ramp_frac) * (elapsed - knee_t) / (
66
+ mid_end_t - knee_t
67
+ )
68
+ else:
69
+ fraction = mid_frac + tail_rate * (elapsed - mid_end_t)
70
+ return min(cap, max(0.0, fraction))
71
+
72
+
73
+ @contextmanager
74
+ def creep_progress(
75
+ *,
76
+ eta_s: float,
77
+ cap: float = 0.999,
78
+ label: str = "generating",
79
+ interval_s: float = 1.0,
80
+ ramp_frac: float = 0.20,
81
+ ramp_rate: float = 0.005,
82
+ mid_frac: float = 0.80,
83
+ mid_fallback_rate: float = 0.01,
84
+ tail_rate: float = 0.0005,
85
+ ) -> Iterator[None]:
86
+ """Tick synthetic progress on a piecewise-linear schedule while the block runs.
87
+
88
+ The fraction follows :func:`_scheduled_fraction`: a fixed-rate ramp to
89
+ ``ramp_frac`` (always a gentle start), an even climb to ``mid_frac`` timed to
90
+ land at ``eta_s`` (or a fixed ``mid_fallback_rate`` if ``eta_s`` is already
91
+ spent), then a slow ``tail_rate`` crawl up to ``cap``. ``eta_s`` only sets the
92
+ pace, never the ceiling, so a job that overruns keeps inching forward in the
93
+ tail phase rather than stalling. ``eta_s <= 0`` disables creeping entirely.
94
+ """
95
+ reporter = ProgressReporter.current()
96
+ if eta_s <= 0:
97
+ yield
98
+ return
99
+
100
+ stop = threading.Event()
101
+ t0 = time.monotonic()
102
+
103
+ def _tick() -> None:
104
+ while not stop.wait(interval_s):
105
+ fraction = _scheduled_fraction(
106
+ time.monotonic() - t0,
107
+ eta_s=eta_s,
108
+ cap=cap,
109
+ ramp_frac=ramp_frac,
110
+ ramp_rate=ramp_rate,
111
+ mid_frac=mid_frac,
112
+ mid_fallback_rate=mid_fallback_rate,
113
+ tail_rate=tail_rate,
114
+ )
115
+ reporter.update(fraction, label)
116
+
117
+ thread = threading.Thread(target=_tick, name="kiapi-progress-creep", daemon=True)
118
+ thread.start()
119
+ try:
120
+ yield
121
+ finally:
122
+ stop.set()
123
+ thread.join(timeout=2.0)
@@ -0,0 +1,121 @@
1
+ """Unified job model.
2
+
3
+ Every generation in kiapi — sync or async, chat or video — is a Job. Sync
4
+ requests create a job, wait for it, and return its result; async requests create
5
+ a job and return its id immediately. This gives one consistent place to inspect
6
+ work in flight and one consistent result shape.
7
+
8
+ ``result`` is a free-form dict whose shape depends on ``type`` (the caller
9
+ dispatches on ``type``); ``artifacts`` lists file_ids produced (see core/file).
10
+ Jobs are in-memory only and reset on restart; artifacts are Files API entries
11
+ that can outlive jobs while their files remain on disk.
12
+ """
13
+
14
+ import time
15
+ import uuid
16
+ from typing import Any
17
+
18
+ from pydantic import BaseModel, Field
19
+
20
+ from kiapi.core.file import FileID
21
+
22
+ from .._enums.job_status import JobStatus
23
+ from .._types.job_id import JobID
24
+ from .._types.job_result import JobResult
25
+ from .._types.job_type import JobType
26
+
27
+
28
+ class Job(BaseModel):
29
+ type: JobType = Field(
30
+ ...,
31
+ description="Job type. Use this to interpret the capability-specific result payload.",
32
+ examples=["zimage"],
33
+ )
34
+ params: dict[str, Any] = Field(
35
+ default_factory=dict,
36
+ description="Request parameters captured for inspection and reproducibility. Secret or large media payloads may be omitted or redacted by endpoints.",
37
+ )
38
+ id: JobID = Field(
39
+ default_factory=lambda: f"job_{uuid.uuid4().hex}",
40
+ description="In-memory job id. Jobs are cleared when the kiapi process restarts.",
41
+ examples=["job_0123456789abcdef"],
42
+ )
43
+ status: JobStatus = Field(
44
+ default=JobStatus.QUEUED,
45
+ description="Job lifecycle state: queued, running, succeeded, failed, or canceled.",
46
+ examples=["succeeded"],
47
+ )
48
+ result: JobResult | None = Field(
49
+ default=None,
50
+ description="Capability-specific result metadata. Completed generation jobs usually also expose produced file ids in artifacts.",
51
+ examples=[{"file_id": "file_0123456789abcdef", "image_bytes": 123456}],
52
+ )
53
+ artifacts: list[FileID] = Field(
54
+ default_factory=list,
55
+ description="File ids produced by the job. Use GET /v1/files/{file_id} for metadata or /download for bytes.",
56
+ examples=[["file_0123456789abcdef"]],
57
+ )
58
+ error: str | None = Field(
59
+ default=None,
60
+ description="Error message when status is failed; otherwise null.",
61
+ examples=["model 'turbo' is not activated"],
62
+ )
63
+ created_at: float = Field(
64
+ default_factory=lambda: time.time(),
65
+ description="Unix timestamp when the job was created.",
66
+ examples=[1766200000.0],
67
+ )
68
+ started_at: float | None = Field(
69
+ default=None,
70
+ description="Unix timestamp when the worker started the job, or null while queued.",
71
+ examples=[1766200001.0],
72
+ )
73
+ finished_at: float | None = Field(
74
+ default=None,
75
+ description="Unix timestamp when the job reached a terminal state, or null while queued/running.",
76
+ examples=[1766200030.0],
77
+ )
78
+ progress: float | None = Field(
79
+ default=None,
80
+ ge=0.0,
81
+ le=1.0,
82
+ description="Best-effort completion fraction in [0.0, 1.0]. Null means the job has not reported progress.",
83
+ examples=[0.42],
84
+ )
85
+ progress_label: str = Field(
86
+ default="queued",
87
+ description="Short human-readable phase label such as queued, running, denoising, saving, or done.",
88
+ examples=["denoising"],
89
+ )
90
+
91
+ def to_dict(self) -> dict[str, Any]:
92
+ return self.model_dump()
93
+
94
+ def mark_running(self) -> None:
95
+ self.status = JobStatus.RUNNING
96
+ self.started_at = time.time()
97
+ self.progress = 0.0
98
+ self.progress_label = "running"
99
+
100
+ def update_progress(self, fraction: float, label: str | None = None) -> None:
101
+ self.progress = min(1.0, max(0.0, fraction))
102
+
103
+ if label is not None:
104
+ self.progress_label = label
105
+
106
+ def mark_succeeded(self, result: JobResult, artifacts: list[FileID]) -> None:
107
+ self.status = JobStatus.SUCCEEDED
108
+ self.result = result
109
+ self.artifacts = artifacts
110
+ self.progress = 1.0
111
+ self.progress_label = "done"
112
+ self.finished_at = time.time()
113
+
114
+ def mark_failed(self, error: str) -> None:
115
+ self.status = JobStatus.FAILED
116
+ self.error = error
117
+ self.finished_at = time.time()
118
+
119
+ def mark_canceled(self) -> None:
120
+ self.status = JobStatus.CANCELED
121
+ self.finished_at = time.time()