inline-core 1.2.53__tar.gz → 1.2.62__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. {inline_core-1.2.53 → inline_core-1.2.62}/CLAUDE.md +85 -4
  2. {inline_core-1.2.53 → inline_core-1.2.62}/PKG-INFO +30 -17
  3. {inline_core-1.2.53 → inline_core-1.2.62}/README.md +26 -14
  4. {inline_core-1.2.53 → inline_core-1.2.62}/pyproject.toml +16 -4
  5. inline_core-1.2.62/scripts/flux2_train_matrix.py +204 -0
  6. inline_core-1.2.62/scripts/minimax_h3_lora_check.py +145 -0
  7. inline_core-1.2.62/scripts/minimax_h3_train_matrix.py +203 -0
  8. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/memory.py +15 -3
  9. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/registry.py +4 -0
  10. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/catalog.py +21 -0
  11. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/checkpoint.py +5 -0
  12. inline_core-1.2.62/src/inline_core/models/flux2/__init__.py +1 -0
  13. inline_core-1.2.62/src/inline_core/models/flux2/controlnet.py +234 -0
  14. inline_core-1.2.62/src/inline_core/models/flux2/embeds.py +165 -0
  15. inline_core-1.2.62/src/inline_core/models/flux2/provider.py +84 -0
  16. inline_core-1.2.62/src/inline_core/models/flux2/requirements.py +414 -0
  17. inline_core-1.2.62/src/inline_core/models/flux2/runner.py +677 -0
  18. inline_core-1.2.62/src/inline_core/models/flux2/variants.py +334 -0
  19. inline_core-1.2.62/src/inline_core/models/keymap.py +304 -0
  20. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/provider.py +11 -0
  21. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/runner.py +3 -3
  22. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/loaders.py +466 -4
  23. inline_core-1.2.62/src/inline_core/models/minimaxh3/__init__.py +7 -0
  24. inline_core-1.2.62/src/inline_core/models/minimaxh3/adaln.py +146 -0
  25. inline_core-1.2.62/src/inline_core/models/minimaxh3/keys.py +134 -0
  26. inline_core-1.2.62/src/inline_core/models/minimaxh3/load.py +350 -0
  27. inline_core-1.2.62/src/inline_core/models/minimaxh3/pipeline.py +831 -0
  28. inline_core-1.2.62/src/inline_core/models/minimaxh3/provider.py +102 -0
  29. inline_core-1.2.62/src/inline_core/models/minimaxh3/requirements.py +295 -0
  30. inline_core-1.2.62/src/inline_core/models/minimaxh3/runner.py +410 -0
  31. inline_core-1.2.62/src/inline_core/models/minimaxh3/vae_keys.py +125 -0
  32. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/__init__.py +46 -0
  33. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/autoencoder_kl_minimax_h3.py +922 -0
  34. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/autoencoder_kl_minimax_h3_audio.py +679 -0
  35. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/before_denoise.py +425 -0
  36. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/before_encoder.py +408 -0
  37. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/decoders.py +199 -0
  38. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/denoise.py +325 -0
  39. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/encoders.py +639 -0
  40. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/modular_blocks_minimax_h3.py +345 -0
  41. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/modular_pipeline.py +115 -0
  42. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/packing.py +538 -0
  43. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/packing_ref2va.py +841 -0
  44. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/scheduling_minimax_h3.py +288 -0
  45. inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/transformer_minimax_h3.py +644 -0
  46. inline_core-1.2.62/src/inline_core/models/offload.py +285 -0
  47. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/pipeline_runtime.py +89 -1
  48. inline_core-1.2.62/src/inline_core/models/prepared.py +151 -0
  49. inline_core-1.2.62/src/inline_core/models/references.py +125 -0
  50. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/requirements.py +54 -2
  51. inline_core-1.2.62/src/inline_core/models/video_params.py +144 -0
  52. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/provider.py +12 -0
  53. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/runner.py +3 -3
  54. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/file_store.py +36 -6
  55. inline_core-1.2.62/src/inline_core/runtime/store.py +45 -0
  56. inline_core-1.2.62/src/inline_core/runtime/video_encode.py +204 -0
  57. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/app.py +6 -4
  58. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/bootstrap.py +19 -0
  59. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/serialize.py +28 -4
  60. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/fal.py +10 -1
  61. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/frames.py +44 -18
  62. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/generation.py +37 -4
  63. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/graph_build.py +130 -28
  64. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/handlers.py +31 -4
  65. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/models.py +32 -2
  66. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/moodboard.py +15 -3
  67. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/schema.py +8 -2
  68. inline_core-1.2.62/src/inline_core/training/arch.py +372 -0
  69. inline_core-1.2.62/src/inline_core/training/cache.py +46 -0
  70. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/dataset.py +65 -10
  71. inline_core-1.2.62/src/inline_core/training/h3.py +384 -0
  72. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/models.py +137 -2
  73. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/trainer.py +24 -19
  74. inline_core-1.2.62/tests/conftest.py +25 -0
  75. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_install.py +13 -2
  76. inline_core-1.2.62/tests/test_flux2_controlnet.py +159 -0
  77. inline_core-1.2.62/tests/test_flux2_folder.py +179 -0
  78. inline_core-1.2.62/tests/test_flux2_resolve.py +176 -0
  79. inline_core-1.2.62/tests/test_flux2_runner.py +126 -0
  80. inline_core-1.2.62/tests/test_flux2_training.py +199 -0
  81. inline_core-1.2.62/tests/test_flux2_variants.py +129 -0
  82. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_frontend_serving.py +47 -1
  83. inline_core-1.2.62/tests/test_keymap.py +268 -0
  84. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_memory_policy.py +39 -0
  85. inline_core-1.2.62/tests/test_minimaxh3_adaln.py +166 -0
  86. inline_core-1.2.62/tests/test_minimaxh3_keys.py +138 -0
  87. inline_core-1.2.62/tests/test_minimaxh3_load.py +257 -0
  88. inline_core-1.2.62/tests/test_minimaxh3_nodes.py +382 -0
  89. inline_core-1.2.62/tests/test_minimaxh3_training.py +306 -0
  90. inline_core-1.2.62/tests/test_offload_prepared.py +233 -0
  91. inline_core-1.2.62/tests/test_output_kind_contract.py +67 -0
  92. inline_core-1.2.62/tests/test_references.py +84 -0
  93. inline_core-1.2.62/tests/test_staged_residency.py +101 -0
  94. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_fal.py +46 -0
  95. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_generation.py +89 -4
  96. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_graph_build.py +4 -4
  97. inline_core-1.2.62/tests/test_studio_multi_reference.py +163 -0
  98. inline_core-1.2.62/tests/test_studio_node_size.py +58 -0
  99. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_rpc.py +5 -0
  100. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_schema.py +19 -0
  101. inline_core-1.2.62/tests/test_video_encode.py +158 -0
  102. inline_core-1.2.62/tests/test_video_params.py +114 -0
  103. inline_core-1.2.62/tests/test_webui_install.py +154 -0
  104. {inline_core-1.2.53 → inline_core-1.2.62}/uv.lock +31 -3
  105. {inline_core-1.2.53 → inline_core-1.2.62}/webui.bat +107 -15
  106. {inline_core-1.2.53 → inline_core-1.2.62}/webui.sh +92 -17
  107. inline_core-1.2.53/src/inline_core/runtime/store.py +0 -18
  108. inline_core-1.2.53/src/inline_core/training/arch.py +0 -184
  109. {inline_core-1.2.53 → inline_core-1.2.62}/.gitignore +0 -0
  110. {inline_core-1.2.53 → inline_core-1.2.62}/.python-version +0 -0
  111. {inline_core-1.2.53 → inline_core-1.2.62}/main.py +0 -0
  112. {inline_core-1.2.53 → inline_core-1.2.62}/scripts/reference.py +0 -0
  113. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/__init__.py +0 -0
  114. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/components/__init__.py +0 -0
  115. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/components/conditioning.py +0 -0
  116. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/components/interfaces.py +0 -0
  117. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/config.py +0 -0
  118. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/__init__.py +0 -0
  119. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/auto.py +0 -0
  120. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/detect.py +0 -0
  121. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/policy.py +0 -0
  122. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/types.py +0 -0
  123. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/errors.py +0 -0
  124. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/__init__.py +0 -0
  125. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/api.py +0 -0
  126. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/constraints.py +0 -0
  127. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/fetch.py +0 -0
  128. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/handlers.py +0 -0
  129. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/importer.py +0 -0
  130. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/install.py +0 -0
  131. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/loader.py +0 -0
  132. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/manifest.py +0 -0
  133. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/models.py +0 -0
  134. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/paths.py +0 -0
  135. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/resolve.py +0 -0
  136. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/scanner.py +0 -0
  137. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/state.py +0 -0
  138. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/tools.py +0 -0
  139. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/ffmpeg.py +0 -0
  140. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/__init__.py +0 -0
  141. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/cache.py +0 -0
  142. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/descriptor.py +0 -0
  143. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/executor.py +0 -0
  144. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/loader_runners.py +0 -0
  145. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/primitives.py +0 -0
  146. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/runners.py +0 -0
  147. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/schema.py +0 -0
  148. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/topo.py +0 -0
  149. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/validate.py +0 -0
  150. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/media.py +0 -0
  151. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/__init__.py +0 -0
  152. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/controlspace.py +0 -0
  153. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/__init__.py +0 -0
  154. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/convert.py +0 -0
  155. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/depth_control.py +0 -0
  156. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/img2img.py +0 -0
  157. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/requirements.py +0 -0
  158. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/lora.py +0 -0
  159. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/preprocess/__init__.py +0 -0
  160. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/preprocess/requirements.py +0 -0
  161. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/preprocess/runner.py +0 -0
  162. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/sampling.py +0 -0
  163. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/__init__.py +0 -0
  164. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/primitives.py +0 -0
  165. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/requirements.py +0 -0
  166. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/__init__.py +0 -0
  167. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/config.py +0 -0
  168. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/group.py +0 -0
  169. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/launch.py +0 -0
  170. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/protocol.py +0 -0
  171. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/registry.py +0 -0
  172. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/worker.py +0 -0
  173. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/__init__.py +0 -0
  174. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/context.py +0 -0
  175. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/progress.py +0 -0
  176. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/run.py +0 -0
  177. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/sampling/__init__.py +0 -0
  178. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/sampling/batch.py +0 -0
  179. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/__init__.py +0 -0
  180. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/__main__.py +0 -0
  181. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/assets.py +0 -0
  182. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/frontend.py +0 -0
  183. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/manager.py +0 -0
  184. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/rpc.py +0 -0
  185. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/run_store.py +0 -0
  186. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/__init__.py +0 -0
  187. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/assets.py +0 -0
  188. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/config.py +0 -0
  189. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/image_meta.py +0 -0
  190. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/peaks.py +0 -0
  191. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/recipe.py +0 -0
  192. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/store.py +0 -0
  193. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/system_stats.py +0 -0
  194. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/__init__.py +0 -0
  195. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/compose.py +0 -0
  196. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/ffmpeg.py +0 -0
  197. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/render.py +0 -0
  198. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/resolve.py +0 -0
  199. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/training.py +0 -0
  200. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/training_store.py +0 -0
  201. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/takes.py +0 -0
  202. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/__init__.py +0 -0
  203. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/__main__.py +0 -0
  204. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/caption.py +0 -0
  205. {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/protocol.py +0 -0
  206. {inline_core-1.2.53 → inline_core-1.2.62}/tests/helpers.py +0 -0
  207. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_cache.py +0 -0
  208. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_catalog.py +0 -0
  209. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_checkpoint.py +0 -0
  210. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_config.py +0 -0
  211. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_device_detect.py +0 -0
  212. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_executor.py +0 -0
  213. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_api.py +0 -0
  214. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_manifest.py +0 -0
  215. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_resolve.py +0 -0
  216. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_scanner.py +0 -0
  217. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_spine.py +0 -0
  218. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_state.py +0 -0
  219. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_file_store.py +0 -0
  220. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_hidden_nodes.py +0 -0
  221. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_convert.py +0 -0
  222. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_depth_control.py +0 -0
  223. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_requirements.py +0 -0
  224. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_runner.py +0 -0
  225. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_loader_runners.py +0 -0
  226. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_loaders.py +0 -0
  227. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_lora.py +0 -0
  228. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_lora_download.py +0 -0
  229. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_model_requirements.py +0 -0
  230. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_parallel_group.py +0 -0
  231. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_pipeline_cache.py +0 -0
  232. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_primitives.py +0 -0
  233. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_recipe.py +0 -0
  234. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_rpc_bridge.py +0 -0
  235. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_run_store.py +0 -0
  236. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_sampling.py +0 -0
  237. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_schema.py +0 -0
  238. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_server.py +0 -0
  239. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_assets.py +0 -0
  240. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_frames.py +0 -0
  241. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_models.py +0 -0
  242. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_moodboard.py +0 -0
  243. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_peaks.py +0 -0
  244. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_store.py +0 -0
  245. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_timeline.py +0 -0
  246. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_training.py +0 -0
  247. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_take_bytes.py +0 -0
  248. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_topo.py +0 -0
  249. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_arch.py +0 -0
  250. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_dataset.py +0 -0
  251. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_models.py +0 -0
  252. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_resolve.py +0 -0
  253. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_validate.py +0 -0
  254. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_xfuser_sampler.py +0 -0
  255. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_zimage_primitives.py +0 -0
  256. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_zimage_resolve.py +0 -0
  257. {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_zimage_runner.py +0 -0
@@ -95,7 +95,16 @@ HTTP/WS → server/app.py → RunManager → Executor → Registry (desc
95
95
  the ComfyUI-equivalent decomposed graph and the intended long-term surface. **Descriptor-only
96
96
  today - their runners land in C2.** A graph built from them validates and type-checks but raises
97
97
  `No runner registered` at execution.
98
- - **Model runners** (`models/<name>/`) - high-level single generation nodes. **`alibaba/z-image-turbo`
98
+ - **Model runners** (`models/<name>/`) - high-level single generation nodes. **`black-forest-labs/flux-2`
99
+ (`models/flux2/`) is the reference for a _family_:** one node covers klein 4B/9B, their base builds,
100
+ the KV variant and dev, because the picked checkpoint is identified from its own tensor shapes
101
+ (`flux2/variants.py`) and everything else follows. Adding a checkpoint is a row in that table.
102
+ Two rules it establishes: **identify a checkpoint by content, never by filename** (`diffusion_models/`
103
+ is shared across architectures, and Qwen3-4B and Qwen3-VL-4B have byte-identical embedding shapes),
104
+ and **derive geometry from the checkpoint** rather than bundling a config per variant, so a future
105
+ build loads with no code change. A **diffusers folder** is a valid checkpoint too, which is the only
106
+ way a 32B model reaches a 24 GB card: its NF4 shards stream through `from_pretrained`, where
107
+ `from_single_file` cannot quantize at all. **`alibaba/z-image-turbo`
99
108
  (`models/zimage/`) is the one runnable generation path today** (prompt + optional image → one take,
100
109
  backed by diffusers' `ZImagePipeline`/`ZImageImg2ImgPipeline`). This is the "Z-Image pipeline that
101
110
  already works" - the primitives will reach parity in C2. It loads from a **single diffusion
@@ -112,6 +121,11 @@ between nodes and are never takes.
112
121
 
113
122
  ### Storage & configuration (all env, see `config.py`)
114
123
 
124
+ - **Never put weights on an instance's ephemeral/scratch disk.** On cloud GPU boxes (`/opt/dlami/nvme`,
125
+ `/mnt/resource`, and anything else labelled ephemeral or instance-store) the volume is **wiped on
126
+ every stop/start**, taking the models and leaving dangling symlinks in `models/`. This has cost two
127
+ full re-downloads of MiniMax H3 at ~130 GB each. Weights go on the persistent root volume, or on an
128
+ attached volume that survives a restart. Scratch is fine for logs and temporary output only.
115
129
  - **Models root** - `INLINE_MODELS_DIR`, else `./models`. **Bring your own weights; nothing is
116
130
  downloaded.** ComfyUI-style category subfolders (`diffusion_models/`, `vae/`, `text_encoders/`,
117
131
  `loras/`, `controlnet/`, `checkpoints/`, `clip_vision/`, `upscale_models/`, `embeddings/`). The
@@ -143,6 +157,18 @@ between nodes and are never takes.
143
157
  (Turing/Volta - compute capability < 8.0, e.g. a T4): same footprint, but it uses the fp16 tensor
144
158
  cores instead of bf16's slow path. The **VAE stays upcast** (bf16, or fp32 when the denoiser is
145
159
  fp16) because fp16 VAE decode can overflow to black/NaN images (`_compute_dtype` in `device/`).
160
+ - **Quantization rungs** - the fit ladder is full-precision resident → int8 resident → **NF4 resident**
161
+ → sequential offload → wont-fit. NF4 is what makes a 32B model viable on a 24 GB card. Note int8
162
+ forces bf16 (torchao's weight-only int8 silently no-ops under fp16) while NF4 does not, so a Turing
163
+ card keeps its fp16 tensor cores under NF4.
164
+ - **Prequantized checkpoints must not be re-quantized.** A checkpoint that ships already quantized
165
+ (`flux2/variants.is_prequantized`) has an on-disk size that already _is_ its resident size, so the
166
+ ladder's assumption that quantization halves it does not hold, and handing diffusers a second,
167
+ different quantization config is a hard error. Pass `Quantization.NONE` for those.
168
+ - **Staged loading** - when the text encoder and the transformer cannot be co-resident (dev is a
169
+ 15 GB encoder beside an 18 GB transformer), the prompt is encoded first and the encoder freed before
170
+ the transformer loads. The decision has to be made _before_ the load: by the time an OOM fires there
171
+ is nothing left to free.
146
172
  - **Multi-GPU** - `INLINE_PARALLEL` (e.g. `pipefusion=2`, `pipefusion=2,ulysses=2`); degrees multiply
147
173
  to the world size, which must equal the GPU count.
148
174
 
@@ -202,6 +228,11 @@ real codec that moves tensors lives with the model runner.
202
228
  Don't scatter it.
203
229
  - **Bring-your-own models.** Nothing is downloaded by the engine. The catalog scans; the user places
204
230
  files. A model picker is a `SELECT` param with `options_from="<category>"`.
231
+ - **Verify image models by rendering.** The FLUX.2 work shipped five bugs past a green test suite,
232
+ and every one produced a _wrong image rather than an error_: a mis-keyed checkpoint, a
233
+ vision-language encoder loaded in place of a text one, an unnormalized latent, and a control context
234
+ cast to a quantized weight's `uint8` storage dtype. A unit test cannot see a plausible-but-wrong
235
+ image. Render something and look at it.
205
236
  - **Tests (pytest).** Cover the logic that matters: graph validate/topo/executor/cache, the catalog
206
237
  scan, the run store + server contract, the device/memory policy, the parallel group + xfuser seam,
207
238
  and each model runner (import-guarded, no GPU needed). See `tests/`.
@@ -211,14 +242,17 @@ real codec that moves tensors lives with the model runner.
211
242
 
212
243
  ```
213
244
  uv venv # create ./.venv
214
- uv pip install -e ".[server,dev]" # engine + server + test tooling
215
- uv pip install -e ".[runtime]" # + torch, diffusers, transformers (real generation)
216
- uv pip install -e ".[runtime,parallel]" # + xfuser, for multi-GPU denoise (2+ GPUs)
245
+ # --python pins the target: without it uv installs into an activated venv/conda env, not ./.venv
246
+ uv pip install --python .venv/bin/python -e ".[server,dev]" # engine + server + test tooling
247
+ uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
248
+ uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, multi-GPU denoise
217
249
 
218
250
  ./webui.sh # run (loopback:8848); friendly flags → INLINE_* env
219
251
  ./webui.sh --listen --port 9000 # bind all interfaces
220
252
  ./webui.sh --lowvram # tight-VRAM profile
221
253
  ./webui.sh --install --extra runtime # set up ./.venv with the model runtime, then exit
254
+ # (reuses an existing ./.venv; --recreate rebuilds it, and
255
+ # an activated foreign env is reported, never modified)
222
256
  python -m inline_core.server # run the server directly (INLINE_HOST / INLINE_PORT)
223
257
 
224
258
  ruff check . # lint (zero warnings)
@@ -227,6 +261,53 @@ uv run pytest -q # tests (no GPU; model code is import-
227
261
 
228
262
  ## Where to add things
229
263
 
264
+ - **New video model** → do **not** rediscover the plumbing; it exists as shared seams, and
265
+ `models/minimaxh3/` is the reference caller:
266
+ - `runtime/video_encode.py` + `TakeStore.save_video` / `save_audio` - frames plus a waveform to one
267
+ playable MP4. A model that generates video and its soundtrack jointly returns **both** takes;
268
+ only the one matching the descriptor's `output_kind` claims the node's canvas slot (see
269
+ `studio/generation._save_take`, and `tests/test_output_kind_contract.py` which keeps the
270
+ declarations honest).
271
+ - `models/video_params.py` - `VideoGrid` + `video_param_fields(...)`, the way
272
+ `sampling_param_fields(...)` already works. A duration snaps **up** onto the model's frame grid
273
+ and is then clamped into the model's window, which is what both reference implementations do:
274
+ asking H3 for 10 seconds gives 10.125, not 9.417. **fps is a model constant, never a param**,
275
+ or it desyncs from the grid.
276
+ - `models/references.py` - wired image/video/audio ports as one ordered, numbered list. Wiring
277
+ order is what the prompt addresses, so it is meaning, not decoration.
278
+ - `models/keymap.py` - load a checkpoint written for another implementation. Declare a key plan
279
+ (rename / split / swap halves / drop / assert-equal) and apply it while weights stream in. The
280
+ transforms it performs are the ones that fail **silently**, so a plan declares its expected row
281
+ layout and the detector measures the real one. It needs the **whole tensor**: one head's worth of
282
+ rows cannot tell the layouts apart, and it raises rather than guessing.
283
+ - `models/prepared.py` - cache a quantised model once. Everything that changes the bytes goes in
284
+ the hash, including model-specific flags, or switching a flag serves a stale artifact.
285
+ - `models/offload.py` - the device policy's plan to a concrete torchao + group-offload recipe,
286
+ plus **split residency**: group offload holds the whole model in host RAM, so a model bigger
287
+ than the RAM available has nowhere to sit and the kernel swaps it. `blocks_to_place` sizes the
288
+ overflow and those leading blocks go on the accelerator instead, placed as they land rather
289
+ than after the load. It moves the minimum, because every block left resident is VRAM the
290
+ render wanted for activations.
291
+ - **A group-offloaded model's host footprint is reclaimable at load and unreclaimable one step
292
+ later, so never size a split from free memory during the load.** Streaming from a safetensors
293
+ mmap leaves the CPU-side weights as clean file-backed pages the kernel can drop and re-read for
294
+ free. The first denoising step ends that: group offload returns each block with
295
+ `module.to("cpu")`, which allocates fresh anonymous memory and drops the file-backed storage.
296
+ A planner reading `available` mid-load is reading a number that is about to stop being true,
297
+ and the failure mode is not an exception. It is the machine resetting with the page cache
298
+ converted out from under it, no OOM message and no shutdown sequence. Budget the full
299
+ post-conversion footprint, and count what other components will claim from the same RAM
300
+ afterwards (a leaf-offloaded VAE lands there too).
301
+ - **Ordering, when a load both transforms and quantises:** structural transform first,
302
+ quantisation last, and a prequantized source takes no structural transform at all. The three
303
+ clauses and why they are not negotiable are in `models/offload.py`'s docstring.
304
+ - **Vendoring unreleased upstream code** → `models/<name>/vendor/`, **verbatim, import rewrites
305
+ only**. Put a provenance header in its `__init__.py` naming the repo, PR, branch, commit sha and
306
+ date. `models/*/vendor/` is already excluded from ruff and pyright by a glob, because editing it to
307
+ satisfy our linters destroys the one property that makes a re-sync reviewable. Never patch
308
+ installed diffusers: construct components directly and pass them in, so nothing resolves a class by
309
+ name through a registry we do not own. Pin, don't floor, any dependency whose experimental surface
310
+ the vendored code imports from.
230
311
  - **New model runner** → a subpackage `models/<name>/` with `runner.py` (a `NodeDescriptor` + a
231
312
  `NodeRunner` + `register_<name>(registry, store, policy)`) and an `__init__.py` re-exporting it;
232
313
  add a `try/except ImportError` block in `server/bootstrap.py`; add an optional-deps extra in
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inline-core
3
- Version: 1.2.53
3
+ Version: 1.2.62
4
4
  Summary: The generation engine behind Inline Studio.
5
5
  License-Expression: GPL-3.0-or-later
6
6
  Requires-Python: >=3.11
@@ -10,7 +10,7 @@ Provides-Extra: all
10
10
  Requires-Dist: accelerate>=0.30; extra == 'all'
11
11
  Requires-Dist: bitsandbytes>=0.43; (platform_system != 'Darwin') and extra == 'all'
12
12
  Requires-Dist: controlnet-aux>=0.0.7; extra == 'all'
13
- Requires-Dist: diffusers>=0.39; extra == 'all'
13
+ Requires-Dist: diffusers==0.39.0; extra == 'all'
14
14
  Requires-Dist: einops>=0.7; extra == 'all'
15
15
  Requires-Dist: fastapi>=0.110; extra == 'all'
16
16
  Requires-Dist: huggingface-hub>=0.23; extra == 'all'
@@ -37,8 +37,9 @@ Requires-Dist: nvidia-ml-py>=12; extra == 'parallel'
37
37
  Requires-Dist: xfuser>=0.4; extra == 'parallel'
38
38
  Provides-Extra: runtime
39
39
  Requires-Dist: accelerate>=0.30; extra == 'runtime'
40
+ Requires-Dist: av>=12; extra == 'runtime'
40
41
  Requires-Dist: controlnet-aux>=0.0.7; extra == 'runtime'
41
- Requires-Dist: diffusers>=0.39; extra == 'runtime'
42
+ Requires-Dist: diffusers==0.39.0; extra == 'runtime'
42
43
  Requires-Dist: huggingface-hub>=0.23; extra == 'runtime'
43
44
  Requires-Dist: onnxruntime>=1.17; extra == 'runtime'
44
45
  Requires-Dist: safetensors>=0.4; extra == 'runtime'
@@ -67,17 +68,24 @@ The generation engine behind Inline. It takes a typed node graph (JSON) and retu
67
68
  low-VRAM laptops up to multi-GPU machines that split a single image's sampling across GPUs (via
68
69
  xDiT). It is Inline Studio's built-in render backend.
69
70
 
70
- Models today: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow diffusion transformer and the model
71
- xDiT already supports, so the multi-GPU split works on it from the start; and **Krea 2** (Krea AI),
72
- a 12.9B single-stream MMDiT released as an undistilled RAW base plus an 8-step distilled Turbo.
73
-
74
- > Status: early, and running end to end against a stub engine. In place and tested: the graph engine,
75
- > the typed `/v1` HTTP + websocket API (durable runs, streamed progress, coalescing), the model-dir
76
- > scan, the device + memory policy (profiles, dtype, offload, int8), the low-level primitive node
77
- > vocabulary. The Z-Image loader is written and validates on a GPU.
78
- > Cross-request batching, single-image multi-GPU (an xDiT worker group behind the sampler seam, with
79
- > the policy and IPC round-trip tested), and out-of-process custom nodes are built as seams but not
80
- > yet running on real hardware.
71
+ Models today, all running locally on your own GPU: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow
72
+ diffusion transformer and the model xDiT already supports, so the multi-GPU split works on it from the
73
+ start; **Krea 2** (Krea AI), a 12.9B single-stream MMDiT released as an undistilled RAW base plus an
74
+ 8-step distilled Turbo; **FLUX.2** (Black Forest Labs); and **MiniMax H3**, which generates video and
75
+ its soundtrack in a single pass.
76
+
77
+ Core also runs the **LoRA trainer** behind Inline Studio's Trainer canvas, so the same engine that
78
+ generates can fine-tune Z-Image, Krea 2, FLUX.2 and MiniMax H3 on your own images without a cloud
79
+ step. Training is cheaper than generating: Krea 2 fits a 16GB card at 512px with a 4-bit base. Its
80
+ dependencies sit behind the `training` extra. See the
81
+ [LoRA training guide](https://inlinestudio.art/lora-training) for the measured VRAM table.
82
+
83
+ > Status: the graph engine, the typed `/v1` HTTP + websocket API (durable runs, streamed progress,
84
+ > coalescing), the model-dir scan, the device + memory policy (profiles, dtype, offload, int8), the
85
+ > low-level primitive node vocabulary, the model runners above, and the LoRA trainer all run on real
86
+ > hardware. Cross-request batching, single-image multi-GPU (an xDiT worker group behind the sampler
87
+ > seam, with the policy and IPC round-trip tested), and out-of-process custom nodes are built as
88
+ > seams but are not yet exercised on real hardware.
81
89
 
82
90
  ## Engine design
83
91
 
@@ -101,13 +109,18 @@ a 6 GB laptop, pure CPU, or split across several GPUs, without touching the grap
101
109
 
102
110
  Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
103
111
 
112
+ `--python` pins each install to `./.venv`; without it uv targets whatever venv or conda env is
113
+ activated in your shell, and installs land there instead.
114
+
104
115
  ```
105
116
  uv venv
106
- uv pip install -e ".[server]" # engine + HTTP/websocket API
107
- uv pip install -e ".[runtime]" # + torch, diffusers, transformers (for real generation)
108
- uv pip install -e ".[runtime,parallel]" # + xfuser, to split one image across GPUs (2+ GPUs)
117
+ uv pip install --python .venv/bin/python -e ".[server]" # engine + HTTP/websocket API
118
+ uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
119
+ uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, 2+ GPUs
109
120
  ```
110
121
 
122
+ Or let the launcher do it: `./webui.sh --install --extra runtime` (Windows: `.\webui.bat`).
123
+
111
124
  ## Models
112
125
 
113
126
  Drop files into the models dir (default `./models`, override with `INLINE_MODELS_DIR`), ComfyUI-style,
@@ -5,17 +5,24 @@ The generation engine behind Inline. It takes a typed node graph (JSON) and retu
5
5
  low-VRAM laptops up to multi-GPU machines that split a single image's sampling across GPUs (via
6
6
  xDiT). It is Inline Studio's built-in render backend.
7
7
 
8
- Models today: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow diffusion transformer and the model
9
- xDiT already supports, so the multi-GPU split works on it from the start; and **Krea 2** (Krea AI),
10
- a 12.9B single-stream MMDiT released as an undistilled RAW base plus an 8-step distilled Turbo.
11
-
12
- > Status: early, and running end to end against a stub engine. In place and tested: the graph engine,
13
- > the typed `/v1` HTTP + websocket API (durable runs, streamed progress, coalescing), the model-dir
14
- > scan, the device + memory policy (profiles, dtype, offload, int8), the low-level primitive node
15
- > vocabulary. The Z-Image loader is written and validates on a GPU.
16
- > Cross-request batching, single-image multi-GPU (an xDiT worker group behind the sampler seam, with
17
- > the policy and IPC round-trip tested), and out-of-process custom nodes are built as seams but not
18
- > yet running on real hardware.
8
+ Models today, all running locally on your own GPU: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow
9
+ diffusion transformer and the model xDiT already supports, so the multi-GPU split works on it from the
10
+ start; **Krea 2** (Krea AI), a 12.9B single-stream MMDiT released as an undistilled RAW base plus an
11
+ 8-step distilled Turbo; **FLUX.2** (Black Forest Labs); and **MiniMax H3**, which generates video and
12
+ its soundtrack in a single pass.
13
+
14
+ Core also runs the **LoRA trainer** behind Inline Studio's Trainer canvas, so the same engine that
15
+ generates can fine-tune Z-Image, Krea 2, FLUX.2 and MiniMax H3 on your own images without a cloud
16
+ step. Training is cheaper than generating: Krea 2 fits a 16GB card at 512px with a 4-bit base. Its
17
+ dependencies sit behind the `training` extra. See the
18
+ [LoRA training guide](https://inlinestudio.art/lora-training) for the measured VRAM table.
19
+
20
+ > Status: the graph engine, the typed `/v1` HTTP + websocket API (durable runs, streamed progress,
21
+ > coalescing), the model-dir scan, the device + memory policy (profiles, dtype, offload, int8), the
22
+ > low-level primitive node vocabulary, the model runners above, and the LoRA trainer all run on real
23
+ > hardware. Cross-request batching, single-image multi-GPU (an xDiT worker group behind the sampler
24
+ > seam, with the policy and IPC round-trip tested), and out-of-process custom nodes are built as
25
+ > seams but are not yet exercised on real hardware.
19
26
 
20
27
  ## Engine design
21
28
 
@@ -39,13 +46,18 @@ a 6 GB laptop, pure CPU, or split across several GPUs, without touching the grap
39
46
 
40
47
  Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
41
48
 
49
+ `--python` pins each install to `./.venv`; without it uv targets whatever venv or conda env is
50
+ activated in your shell, and installs land there instead.
51
+
42
52
  ```
43
53
  uv venv
44
- uv pip install -e ".[server]" # engine + HTTP/websocket API
45
- uv pip install -e ".[runtime]" # + torch, diffusers, transformers (for real generation)
46
- uv pip install -e ".[runtime,parallel]" # + xfuser, to split one image across GPUs (2+ GPUs)
54
+ uv pip install --python .venv/bin/python -e ".[server]" # engine + HTTP/websocket API
55
+ uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
56
+ uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, 2+ GPUs
47
57
  ```
48
58
 
59
+ Or let the launcher do it: `./webui.sh --install --extra runtime` (Windows: `.\webui.bat`).
60
+
49
61
  ## Models
50
62
 
51
63
  Drop files into the models dir (default `./models`, override with `INLINE_MODELS_DIR`), ComfyUI-style,
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  # PyPI name; the import package is `inline_core` (src/inline_core).
3
3
  name = "inline-core"
4
- version = "1.2.53"
4
+ version = "1.2.62"
5
5
  description = "The generation engine behind Inline Studio."
6
6
  readme = "README.md"
7
7
  license = "GPL-3.0-or-later"
@@ -18,7 +18,9 @@ runtime = [
18
18
  # A bare `torch` is CPU-only on Windows; see [tool.uv] below and requirements.txt.
19
19
  "torch>=2.2",
20
20
  # Krea 2 needs diffusers >= 0.39 (Krea2Pipeline); Z-Image needs >= 0.36 (ZImagePipeline).
21
- "diffusers>=0.39",
21
+ # Pinned, not floored: MiniMax H3 is vendored from an unmerged PR and imports six symbols
22
+ # from the experimental Modular Diffusers surface, which a minor release may rename.
23
+ "diffusers==0.39.0",
22
24
  "transformers>=4.44",
23
25
  "accelerate>=0.30",
24
26
  "safetensors>=0.4",
@@ -32,6 +34,10 @@ runtime = [
32
34
  # HED, lineart, MLSD, scribble, normal. DWPose runs its detector on ONNX Runtime.
33
35
  "controlnet-aux>=0.0.7",
34
36
  "onnxruntime>=1.17",
37
+ # MiniMax H3's reference node decodes a wired video or audio clip when it builds the reference.
38
+ # The blocks raise a plain ImportError without it, so the node would advertise two ports it
39
+ # cannot read. Video output goes out through ffmpeg, not this.
40
+ "av>=12",
35
41
  ]
36
42
  server = [
37
43
  "fastapi>=0.110",
@@ -71,7 +77,7 @@ dev = [
71
77
  all = [
72
78
  # runtime
73
79
  "torch>=2.2",
74
- "diffusers>=0.39",
80
+ "diffusers==0.39.0",
75
81
  "transformers>=4.44",
76
82
  "accelerate>=0.30",
77
83
  "safetensors>=0.4",
@@ -116,15 +122,21 @@ packages = ["src/inline_core"]
116
122
  [tool.ruff]
117
123
  line-length = 100
118
124
  target-version = "py311"
125
+ # Vendored upstream code (see models/minimaxh3/vendor/__init__.py). Editing it to satisfy our
126
+ # linters would destroy the one property that makes a re-sync reviewable: it is verbatim.
127
+ extend-exclude = ["src/inline_core/models/*/vendor"]
119
128
 
120
129
  [tool.ruff.lint]
121
130
  select = ["E", "F", "I", "UP", "B"]
122
131
 
123
132
  [tool.pyright]
124
133
  include = ["src", "tests"]
134
+ exclude = ["**/models/*/vendor"]
125
135
  pythonVersion = "3.11"
126
136
  typeCheckingMode = "strict"
127
137
 
128
138
  [tool.pytest.ini_options]
129
139
  testpaths = ["tests"]
130
- pythonpath = ["src"]
140
+ # "." so `tests` imports as a package: several suites share fixtures via `from tests.x import y`,
141
+ # and without it those modules fail to collect and silently stop running.
142
+ pythonpath = ["src", "."]
@@ -0,0 +1,204 @@
1
+ """VRAM + step-time sweep for FLUX.2 LoRA training: the cells behind the README benchmark table.
2
+
3
+ cd core && PYTHONPATH=src .venv/bin/python scripts/flux2_train_matrix.py --dataset <dir>
4
+
5
+ One cell = one real run of `python -m inline_core.training`, the same entry point the Trainer tab
6
+ spawns, so a number here is a number a user would see. Anything else (importing `train` in-process,
7
+ or a hand-rolled loop) would measure a different program.
8
+
9
+ Held fixed at the settings the existing Z-Image and Krea 2 rows used: 12 steps, rank 16, batch 1,
10
+ gradient checkpointing on. What varies is resolution and base precision. Peak VRAM is the trainer's
11
+ own `torch.cuda.max_memory_allocated` reading off the last progress line; an OOM is recorded as a
12
+ cell rather than aborting the sweep, because "does not fit" is a result the table needs.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import json
19
+ import os
20
+ import subprocess
21
+ import sys
22
+ import time
23
+ from pathlib import Path
24
+
25
+ _REPO = Path(__file__).resolve().parent.parent.parent
26
+ _CORE = _REPO / "core"
27
+ _DEFAULT_OUT = _REPO / "outputs" / "flux2-train-matrix"
28
+
29
+ # (resolution, baseQuant). `none` is the bf16 base; `nf4` is the 4-bit (QLoRA) base.
30
+ CELLS: tuple[tuple[int, str], ...] = (
31
+ (512, "none"),
32
+ (512, "nf4"),
33
+ (1024, "none"),
34
+ (1024, "nf4"),
35
+ )
36
+
37
+ _STEPS = 12
38
+ _RANK = 16
39
+
40
+
41
+ def _manifest(work: Path, dataset: Path, models: Path, resolution: int, quant: str) -> Path:
42
+ """The same manifest shape `studio/training.py::_prepare` writes."""
43
+ checkpoints = work / "checkpoints"
44
+ checkpoints.mkdir(parents=True, exist_ok=True)
45
+ manifest = {
46
+ "runId": work.name,
47
+ "workingDir": str(work),
48
+ "datasetDir": str(dataset),
49
+ "checkpointDir": str(checkpoints),
50
+ "outputPath": str(work / "lora.safetensors"),
51
+ "resumeFrom": None,
52
+ "modelsDir": str(models),
53
+ "arch": "flux2",
54
+ # FLUX.2 offers one base mode: the undistilled klein base. `raw` is that mode's key.
55
+ "baseMode": "raw",
56
+ "triggerWord": "",
57
+ "hyperparams": {
58
+ "arch": "flux2",
59
+ "baseMode": "raw",
60
+ "baseQuant": quant,
61
+ # Explicit, not `auto`: the sweep is measuring what each precision costs, and auto would
62
+ # silently swap a bf16 cell for NF4 the moment it predicted a bad fit.
63
+ "offload": "off",
64
+ "loraScope": "full",
65
+ "captionDropout": 0.0,
66
+ "flipAugment": False,
67
+ "rank": _RANK,
68
+ "alpha": _RANK,
69
+ "learningRate": 1e-4,
70
+ "batchSize": 1,
71
+ "steps": _STEPS,
72
+ "saveEvery": _STEPS,
73
+ "resolution": resolution,
74
+ },
75
+ "gpuIds": [],
76
+ }
77
+ path = work / "manifest.json"
78
+ path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
79
+ return path
80
+
81
+
82
+ def _run_cell(python: str, manifest: Path, log: Path) -> dict[str, object]:
83
+ """Drain the JSON-line protocol, keeping the last VRAM reading and the wall time from the first
84
+ training step onward - loading and latent precache are not what the table reports."""
85
+ env = {**os.environ, "PYTHONPATH": str(_CORE / "src")}
86
+ proc = subprocess.Popen(
87
+ [python, "-m", "inline_core.training", str(manifest)],
88
+ cwd=str(_CORE),
89
+ env=env,
90
+ stdout=subprocess.PIPE,
91
+ stderr=subprocess.STDOUT,
92
+ text=True,
93
+ bufsize=1,
94
+ )
95
+ vram: float | None = None
96
+ error: str | None = None
97
+ first_step_at: float | None = None
98
+ last_step_at: float | None = None
99
+ steps_seen = 0
100
+ started = time.perf_counter()
101
+ lines: list[str] = []
102
+ assert proc.stdout is not None
103
+ for line in proc.stdout:
104
+ lines.append(line)
105
+ line = line.strip()
106
+ if not line.startswith("{"):
107
+ continue
108
+ try:
109
+ message = json.loads(line)
110
+ except json.JSONDecodeError:
111
+ continue
112
+ kind = message.get("type")
113
+ if kind == "progress":
114
+ if message.get("vram") is not None:
115
+ vram = float(message["vram"])
116
+ if message.get("step"):
117
+ steps_seen = int(message["step"])
118
+ now = time.perf_counter()
119
+ if first_step_at is None:
120
+ first_step_at = now
121
+ last_step_at = now
122
+ elif kind == "error":
123
+ error = str(message.get("message") or "")
124
+ proc.wait()
125
+ log.write_text("".join(lines), encoding="utf-8")
126
+
127
+ oom = bool(error) and ("out of gpu memory" in error.lower() or "out of memory" in error.lower())
128
+ # Step 1 pays for the first graph build, so time the interval after it and scale by the gap.
129
+ per_step: float | None = None
130
+ if first_step_at is not None and last_step_at is not None and steps_seen > 1:
131
+ per_step = (last_step_at - first_step_at) / (steps_seen - 1)
132
+ return {
133
+ "peak_vram_gb": vram,
134
+ "seconds_per_step": round(per_step, 2) if per_step else None,
135
+ "seconds_12_steps": round(per_step * _STEPS, 1) if per_step else None,
136
+ "total_seconds": round(time.perf_counter() - started, 1),
137
+ "steps_completed": steps_seen,
138
+ "status": "oom" if oom else ("ok" if proc.returncode == 0 else "failed"),
139
+ "error": error,
140
+ "log": log.name,
141
+ }
142
+
143
+
144
+ def main() -> int:
145
+ parser = argparse.ArgumentParser()
146
+ parser.add_argument("--dataset", type=Path, required=True, help="dir of NNNN.jpg + NNNN.txt")
147
+ parser.add_argument("--out", type=Path, default=_DEFAULT_OUT)
148
+ parser.add_argument("--models", type=Path, default=_CORE / "models")
149
+ parser.add_argument("--python", default=str(_CORE / ".venv" / "bin" / "python"))
150
+ parser.add_argument("--gpu", default="", help="label for the results file, e.g. 'L40S (46GB)'")
151
+ parser.add_argument("--only", default="", help="substring of a cell id, to redo one row")
152
+ args = parser.parse_args()
153
+
154
+ if not args.dataset.is_dir():
155
+ raise SystemExit(f"dataset not found: {args.dataset}")
156
+
157
+ args.out.mkdir(parents=True, exist_ok=True)
158
+ results_path = args.out / "results.json"
159
+ results: dict[str, dict[str, object]] = {}
160
+ if results_path.exists():
161
+ results = json.loads(results_path.read_text()).get("cells", {})
162
+
163
+ label = args.gpu
164
+ if not label:
165
+ try:
166
+ name = subprocess.run(
167
+ ["nvidia-smi", "--query-gpu=name,memory.total", "--format=csv,noheader"],
168
+ capture_output=True,
169
+ text=True,
170
+ check=True,
171
+ ).stdout.strip()
172
+ label = name.splitlines()[0]
173
+ except Exception: # noqa: BLE001 - the label is cosmetic
174
+ label = "unknown GPU"
175
+
176
+ def write() -> None:
177
+ results_path.write_text(
178
+ json.dumps(
179
+ {"gpu": label, "steps": _STEPS, "rank": _RANK, "cells": results},
180
+ indent=2,
181
+ )
182
+ )
183
+
184
+ for resolution, quant in CELLS:
185
+ cell_id = f"{resolution}-{quant}"
186
+ if args.only and args.only not in cell_id:
187
+ continue
188
+ work = args.out / cell_id
189
+ work.mkdir(parents=True, exist_ok=True)
190
+ manifest = _manifest(work, args.dataset, args.models, resolution, quant)
191
+ print(f"--- {cell_id}: {resolution}px, base {quant} ---", flush=True)
192
+ result = _run_cell(args.python, manifest, args.out / f"{cell_id}.log")
193
+ result.update({"resolution": resolution, "base_quant": quant})
194
+ results[cell_id] = result
195
+ print(json.dumps(result, indent=2), flush=True)
196
+ write()
197
+
198
+ write()
199
+ print(f"\n{results_path}")
200
+ return 0
201
+
202
+
203
+ if __name__ == "__main__":
204
+ raise SystemExit(main())