diffusers-workflow 0.4.0a10__tar.gz → 0.4.0b1__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 (293) hide show
  1. {diffusers_workflow-0.4.0a10/diffusers_workflow.egg-info → diffusers_workflow-0.4.0b1}/PKG-INFO +20 -5
  2. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/README.md +19 -4
  3. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1/diffusers_workflow.egg-info}/PKG-INFO +20 -5
  4. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/diffusers_workflow.egg-info/SOURCES.txt +42 -22
  5. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/__init__.py +14 -2
  6. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/events.py +22 -1
  7. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/pipeline_processors/chain.py +14 -7
  8. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/pipeline_processors/pipeline.py +50 -4
  9. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/previous_results.py +5 -3
  10. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/repl.py +18 -0
  11. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/repl_commands.py +4 -1
  12. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/result.py +40 -1
  13. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/run.py +14 -0
  14. diffusers_workflow-0.4.0b1/dw/schema.py +43 -0
  15. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/security.py +181 -0
  16. diffusers_workflow-0.4.0b1/dw/serve.py +170 -0
  17. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/app.py +579 -50
  18. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/jobs.py +100 -11
  19. diffusers_workflow-0.4.0b1/dw/server/mcp_mount.py +91 -0
  20. diffusers_workflow-0.4.0b1/dw/server/netinfo.py +124 -0
  21. diffusers_workflow-0.4.0a10/dw/server/ui/assets/cssMode-DBf-T_da.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/cssMode-DIA5LESv.js +1 -1
  22. diffusers_workflow-0.4.0a10/dw/server/ui/assets/editor.api-B0D5Ygq7.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/editor.api-CuOF-U_A.js +1 -1
  23. diffusers_workflow-0.4.0a10/dw/server/ui/assets/freemarker2-Br8g4G1T.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/freemarker2-xMcLxHzc.js +1 -1
  24. diffusers_workflow-0.4.0a10/dw/server/ui/assets/handlebars-BKo1TaOF.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/handlebars-Dbt47IUh.js +1 -1
  25. diffusers_workflow-0.4.0a10/dw/server/ui/assets/html-Bis1seyM.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/html-C4QoqgED.js +1 -1
  26. diffusers_workflow-0.4.0a10/dw/server/ui/assets/htmlMode-D2SOD2MF.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/htmlMode-BQ_x-rQl.js +1 -1
  27. diffusers_workflow-0.4.0b1/dw/server/ui/assets/index-BCNGRglb.css +1 -0
  28. diffusers_workflow-0.4.0b1/dw/server/ui/assets/index-C14JKFhY.js +28 -0
  29. diffusers_workflow-0.4.0a10/dw/server/ui/assets/javascript-CkEbVb78.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/javascript-yDlADdyl.js +1 -1
  30. diffusers_workflow-0.4.0a10/dw/server/ui/assets/jsonMode-dVJbYwxg.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/jsonMode-X4znCY4b.js +1 -1
  31. diffusers_workflow-0.4.0a10/dw/server/ui/assets/liquid-Btak-6uF.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/liquid-CAaCQzwu.js +1 -1
  32. diffusers_workflow-0.4.0a10/dw/server/ui/assets/lspLanguageFeatures-BfeZZQbb.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/lspLanguageFeatures-CTJIGm94.js +1 -1
  33. diffusers_workflow-0.4.0a10/dw/server/ui/assets/mdx-D9KXK7-s.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/mdx-ByHLng1y.js +1 -1
  34. diffusers_workflow-0.4.0a10/dw/server/ui/assets/monaco-ZMCk_MWf.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/monaco-LJZc6TiS.js +4 -4
  35. diffusers_workflow-0.4.0a10/dw/server/ui/assets/python-0FnO4xGM.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/python-BCT_lvfW.js +1 -1
  36. diffusers_workflow-0.4.0a10/dw/server/ui/assets/razor-B6PMzeY4.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/razor-Bw9oTolL.js +1 -1
  37. diffusers_workflow-0.4.0a10/dw/server/ui/assets/tsMode-nxyvZH1t.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/tsMode-BGvHTpYz.js +1 -1
  38. diffusers_workflow-0.4.0a10/dw/server/ui/assets/typescript-BhBe8aGf.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/typescript-mwKKpQXP.js +1 -1
  39. diffusers_workflow-0.4.0a10/dw/server/ui/assets/workers-ChAf-t8A.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/workers-BOhWN9wu.js +1 -1
  40. diffusers_workflow-0.4.0a10/dw/server/ui/assets/xml-z2r9dHSO.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/xml-DuQ6E6P7.js +1 -1
  41. diffusers_workflow-0.4.0a10/dw/server/ui/assets/yaml-DrcHrz7f.js → diffusers_workflow-0.4.0b1/dw/server/ui/assets/yaml-D7o22x0f.js +1 -1
  42. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/index.html +2 -2
  43. diffusers_workflow-0.4.0b1/dw/server/updater.py +192 -0
  44. diffusers_workflow-0.4.0b1/dw/step_cache.py +260 -0
  45. diffusers_workflow-0.4.0b1/dw/tasks/audio_utils.py +579 -0
  46. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/concat_videos.py +44 -12
  47. diffusers_workflow-0.4.0b1/dw/tasks/dissolve_videos.py +138 -0
  48. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/gather.py +27 -9
  49. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/image_utils.py +65 -0
  50. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/interpolate_frames.py +13 -3
  51. diffusers_workflow-0.4.0b1/dw/tasks/stabilize.py +121 -0
  52. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/task.py +99 -10
  53. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/video_utils.py +137 -0
  54. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/type_helpers.py +12 -0
  55. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/validate.py +13 -1
  56. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/variables.py +92 -38
  57. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/worker.py +8 -2
  58. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/workflow.py +222 -61
  59. diffusers_workflow-0.4.0b1/dw/workflows/h3_context_ir.json +57 -0
  60. diffusers_workflow-0.4.0b1/dw_mcp/__main__.py +122 -0
  61. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/catalog.py +9 -1
  62. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/client.py +71 -2
  63. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/diagnose.py +50 -0
  64. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/media.py +53 -0
  65. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/server.py +48 -1
  66. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/pyproject.toml +4 -1
  67. diffusers_workflow-0.4.0b1/tests/test_audio_utils.py +469 -0
  68. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_chain.py +28 -0
  69. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_cli.py +18 -1
  70. diffusers_workflow-0.4.0b1/tests/test_concat_videos.py +309 -0
  71. diffusers_workflow-0.4.0b1/tests/test_dissolve_videos.py +97 -0
  72. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_gather.py +96 -8
  73. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_interpolate_frames.py +19 -4
  74. diffusers_workflow-0.4.0b1/tests/test_jobs_reused.py +53 -0
  75. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_catalog.py +1 -0
  76. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_client.py +39 -0
  77. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_diagnose.py +82 -0
  78. diffusers_workflow-0.4.0b1/tests/test_mcp_main.py +138 -0
  79. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_media.py +182 -0
  80. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_server.py +30 -0
  81. diffusers_workflow-0.4.0b1/tests/test_mix_audio.py +53 -0
  82. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_modular_pipeline.py +88 -0
  83. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_phase_events.py +77 -1
  84. diffusers_workflow-0.4.0b1/tests/test_recenter_crop.py +72 -0
  85. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_result.py +23 -0
  86. diffusers_workflow-0.4.0b1/tests/test_result_output_naming.py +34 -0
  87. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_security.py +40 -0
  88. diffusers_workflow-0.4.0b1/tests/test_serve_main.py +84 -0
  89. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_server.py +793 -13
  90. diffusers_workflow-0.4.0b1/tests/test_server_downloads.py +123 -0
  91. diffusers_workflow-0.4.0b1/tests/test_server_info.py +177 -0
  92. diffusers_workflow-0.4.0b1/tests/test_server_mcp.py +174 -0
  93. diffusers_workflow-0.4.0b1/tests/test_stabilize.py +110 -0
  94. diffusers_workflow-0.4.0b1/tests/test_step_cache.py +349 -0
  95. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_task.py +56 -0
  96. diffusers_workflow-0.4.0b1/tests/test_updater.py +126 -0
  97. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_variables.py +61 -15
  98. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_video_utils.py +96 -0
  99. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_worker_execute.py +25 -1
  100. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_workflow.py +118 -0
  101. diffusers_workflow-0.4.0b1/tests/test_workflow_step_cache.py +610 -0
  102. diffusers_workflow-0.4.0b1/tests/test_workflow_trust.py +237 -0
  103. diffusers_workflow-0.4.0a10/dw/schema.py +0 -24
  104. diffusers_workflow-0.4.0a10/dw/serve.py +0 -90
  105. diffusers_workflow-0.4.0a10/dw/server/ui/assets/index-D7eWnTCB.css +0 -1
  106. diffusers_workflow-0.4.0a10/dw/server/ui/assets/index-JyFxgIR9.js +0 -20
  107. diffusers_workflow-0.4.0a10/dw/server/updater.py +0 -119
  108. diffusers_workflow-0.4.0a10/dw/tasks/audio_utils.py +0 -266
  109. diffusers_workflow-0.4.0a10/dw/workflows/h3_context_ir.json +0 -57
  110. diffusers_workflow-0.4.0a10/dw_mcp/__main__.py +0 -39
  111. diffusers_workflow-0.4.0a10/tests/test_audio_utils.py +0 -194
  112. diffusers_workflow-0.4.0a10/tests/test_concat_videos.py +0 -133
  113. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/LICENSE +0 -0
  114. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/MANIFEST.in +0 -0
  115. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/diffusers_workflow.egg-info/dependency_links.txt +0 -0
  116. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/diffusers_workflow.egg-info/entry_points.txt +0 -0
  117. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/diffusers_workflow.egg-info/requires.txt +0 -0
  118. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/diffusers_workflow.egg-info/top_level.txt +0 -0
  119. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/arguments.py +0 -0
  120. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/cache_blocks.json +0 -0
  121. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/cache_blocks.py +0 -0
  122. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/community_pipelines/pipeline_flux_rf_inversion.py +0 -0
  123. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/hub_cache.py +0 -0
  124. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/introspection.py +0 -0
  125. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/log_setup.py +0 -0
  126. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/pipeline_processors/config_objects.py +0 -0
  127. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/pipeline_processors/remote.py +0 -0
  128. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/prompt_schema.json +0 -0
  129. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/prompt_weighting.py +0 -0
  130. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/prompts.py +0 -0
  131. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/repl_worker.py +0 -0
  132. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/__init__.py +0 -0
  133. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/enhancers.py +0 -0
  134. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/abap-08VXUWAP.js +0 -0
  135. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/apex-BWPQTe0t.js +0 -0
  136. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/azcli-Bc_sGQ0U.js +0 -0
  137. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/bat-i0X4ZdIN.js +0 -0
  138. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/bicep-B5-_aFwp.js +0 -0
  139. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/cameligo-DMUM7wLl.js +0 -0
  140. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/clojure-Cm7r79vr.js +0 -0
  141. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/codicon-Brq4_Ui5.ttf +0 -0
  142. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/coffee-Ba7i2nA0.js +0 -0
  143. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/cpp-C7h46wYY.js +0 -0
  144. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/csharp-BKxtCVv1.js +0 -0
  145. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/csp-bTuwJoIa.js +0 -0
  146. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/css-DIMkf-bt.js +0 -0
  147. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/css.worker-B3ciXF_0.js +0 -0
  148. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/cypher-CVaqCwHa.js +0 -0
  149. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/dart-onAF5SnQ.js +0 -0
  150. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/dockerfile-DZFCIeNp.js +0 -0
  151. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/ecl-D05T4iGw.js +0 -0
  152. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/editor-jjEx9u7D.css +0 -0
  153. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/editor.worker-q-txB4vs.js +0 -0
  154. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/elixir-6RTg0lbw.js +0 -0
  155. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/flow9-C5_-GSwl.js +0 -0
  156. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/fsharp-C8Ef5oNN.js +0 -0
  157. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/go-C-y9NEjX.js +0 -0
  158. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/graphql-fmXr3nnJ.js +0 -0
  159. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/hcl-CpzslTdj.js +0 -0
  160. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/html.worker-C93Ht9o9.js +0 -0
  161. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/ini-sBoK_t0W.js +0 -0
  162. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/java-BEtHBSE6.js +0 -0
  163. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/json.worker-B2V3pomh.js +0 -0
  164. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/julia-Bri6UV-V.js +0 -0
  165. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/kotlin-BOotOW0E.js +0 -0
  166. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/less-B9JPFI3C.js +0 -0
  167. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/lexon-CfSJPG6W.js +0 -0
  168. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/lua-CsQS60Ue.js +0 -0
  169. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/m3-D-oSqn_W.js +0 -0
  170. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/markdown-Cimd5fb3.js +0 -0
  171. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/mips-CIPQ_RoX.js +0 -0
  172. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/monaco--ixms01u.css +0 -0
  173. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/msdax-DauUninz.js +0 -0
  174. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/mysql-SOo6toE5.js +0 -0
  175. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/objective-c-FvmIjYaQ.js +0 -0
  176. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/pascal-DrH0SRf2.js +0 -0
  177. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/pascaligo-D-ptJ9y-.js +0 -0
  178. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/perl-oz_6vUea.js +0 -0
  179. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/pgsql-DTj74zXo.js +0 -0
  180. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/php-nr791fC2.js +0 -0
  181. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/pla-CopQ2nXW.js +0 -0
  182. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/postiats-43DmfD33.js +0 -0
  183. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/powerquery-D3hlyOfw.js +0 -0
  184. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/powershell-DmHpPYUd.js +0 -0
  185. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/protobuf-C531GsRP.js +0 -0
  186. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/pug-Z5eAx3Zn.js +0 -0
  187. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/qsharp-DkqhCAOL.js +0 -0
  188. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/r-BwWrilGY.js +0 -0
  189. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/redis-ClamHrr6.js +0 -0
  190. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/redshift-DT7zqm-g.js +0 -0
  191. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/restructuredtext-BYgofb2h.js +0 -0
  192. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/ruby-DezsRK8O.js +0 -0
  193. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/rust-DdL9SqIa.js +0 -0
  194. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/sb-CcwsVR0C.js +0 -0
  195. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/scala-DHpiXF5c.js +0 -0
  196. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/scheme-BeGwcela.js +0 -0
  197. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/scss-gp-XZpBa.js +0 -0
  198. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/shell-CC2rA5mh.js +0 -0
  199. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/solidity-BEEn4gHE.js +0 -0
  200. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/sophia-CRfGWb83.js +0 -0
  201. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/sparql-D_Lu-MrJ.js +0 -0
  202. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/sql-NEE52Syq.js +0 -0
  203. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/st-DbInun42.js +0 -0
  204. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/swift-Bxkupp3x.js +0 -0
  205. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/systemverilog-Bz4Y3fRF.js +0 -0
  206. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/tcl-DISqw1ZD.js +0 -0
  207. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/ts.worker-D7T1-Ig5.js +0 -0
  208. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/twig-De2hgUGE.js +0 -0
  209. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/typespec-B8J7ngcE.js +0 -0
  210. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/vb-DV3o63ZY.js +0 -0
  211. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/server/ui/assets/wgsl-DpFanUEy.js +0 -0
  212. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/settings.py +0 -0
  213. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/step.py +0 -0
  214. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/background_remover.py +0 -0
  215. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/borders.py +0 -0
  216. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/depth_estimator.py +0 -0
  217. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/diffusion_upscale.py +0 -0
  218. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/format_messages.py +0 -0
  219. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/image_to_text.py +0 -0
  220. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/model_cache.py +0 -0
  221. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/pair_audio.py +0 -0
  222. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/qr_code.py +0 -0
  223. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/restore_faces.py +0 -0
  224. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/rife_model.py +0 -0
  225. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/segment.py +0 -0
  226. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/tensor_image.py +0 -0
  227. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/text_generation.py +0 -0
  228. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/text_sections.py +0 -0
  229. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/upscale.py +0 -0
  230. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/tasks/zoe_depth.py +0 -0
  231. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/teacache.py +0 -0
  232. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/teacache_models.json +0 -0
  233. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/test.py +0 -0
  234. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/workflow_schema.json +0 -0
  235. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/workflows/augment_prompt.json +0 -0
  236. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/workflows/describe_image.json +0 -0
  237. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw/workflows/test.json +0 -0
  238. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/__init__.py +0 -0
  239. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/authoring.py +0 -0
  240. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/models.py +0 -0
  241. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/dw_mcp/prompts.py +0 -0
  242. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/setup.cfg +0 -0
  243. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_argument_updates.py +0 -0
  244. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_arguments.py +0 -0
  245. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_borders.py +0 -0
  246. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_cache_blocks.py +0 -0
  247. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_component_pruning.py +0 -0
  248. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_config_objects.py +0 -0
  249. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_configuration_schema.py +0 -0
  250. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_depth_estimator.py +0 -0
  251. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_device.py +0 -0
  252. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_device_helpers.py +0 -0
  253. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_device_portability.py +0 -0
  254. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_diffusion_upscale.py +0 -0
  255. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_docs_links.py +0 -0
  256. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_events.py +0 -0
  257. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_examples.py +0 -0
  258. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_hub_cache.py +0 -0
  259. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_image_to_text.py +0 -0
  260. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_image_utils.py +0 -0
  261. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_integration.py +0 -0
  262. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_introspection.py +0 -0
  263. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_list_images.py +0 -0
  264. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_authoring.py +0 -0
  265. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_models.py +0 -0
  266. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_mcp_prompts.py +0 -0
  267. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_model_cache.py +0 -0
  268. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_offload_placement.py +0 -0
  269. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_pair_audio.py +0 -0
  270. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_pipeline_caching.py +0 -0
  271. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_pipeline_components.py +0 -0
  272. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_previous_results.py +0 -0
  273. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_prompt_parser.py +0 -0
  274. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_prompt_weighting.py +0 -0
  275. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_prompts.py +0 -0
  276. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_repl_commands.py +0 -0
  277. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_repl_ergonomics.py +0 -0
  278. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_repl_hierarchical.py +0 -0
  279. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_repl_reorganization.py +0 -0
  280. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_repl_worker.py +0 -0
  281. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_resize_bucket.py +0 -0
  282. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_scheduler_config.py +0 -0
  283. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_schema.py +0 -0
  284. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_segment.py +0 -0
  285. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_step.py +0 -0
  286. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_strip_exif_and_watermark.py +0 -0
  287. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_task_discovery.py +0 -0
  288. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_teacache.py +0 -0
  289. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_tensor_image.py +0 -0
  290. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_text_generation.py +0 -0
  291. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_text_sections.py +0 -0
  292. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_type_helpers.py +0 -0
  293. {diffusers_workflow-0.4.0a10 → diffusers_workflow-0.4.0b1}/tests/test_worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffusers-workflow
3
- Version: 0.4.0a10
3
+ Version: 0.4.0b1
4
4
  Summary: Declarative workflow engine and web UI for Hugging Face Diffusers
5
5
  Author: dkackman
6
6
  License: Apache-2.0
@@ -79,6 +79,8 @@ Dynamic: license-file
79
79
 
80
80
  A declarative workflow engine and web UI for the [Hugging Face Diffusers library](https://github.com/huggingface/diffusers). Define image/video generation pipelines in JSON — with full access to the configuration diffusers exposes — and run them from the command line, an interactive REPL, or a browser.
81
81
 
82
+ A workflow JSON file is portable and easy to hand off — but that same flexibility means loading one can execute arbitrary Python (dynamic imports are how it reaches any diffusers pipeline or quantization backend without a bespoke adapter for each). Treat a workflow file from someone else the way you'd treat a `.py` script: see [Trust model](docs/SECURITY.md#trust-model) before running one you didn't write.
83
+
82
84
  **Python 3.10-3.14 | CUDA (NVIDIA) | MPS (Apple Silicon) | CPU**
83
85
 
84
86
  <picture>
@@ -89,10 +91,11 @@ A declarative workflow engine and web UI for the [Hugging Face Diffusers library
89
91
  ## Features
90
92
 
91
93
  - **Web UI** — browse and run workflows, edit them in introspection-driven forms, watch jobs stream live progress, manage generated output and the models on disk. `python -m dw.serve` and open a browser. See [Server & Web UI](docs/SERVER.md).
92
- - **MCP server** — a stdio server that lets an MCP client (Claude Code first) author, validate, save, run and diagnose workflows against a running `dw.serve`. `dw-mcp`. See [MCP Server](docs/MCP.md).
94
+ - **MCP server** — a tool surface that lets an MCP client (Claude Code first) author, validate, save, run and diagnose workflows against a running `dw.serve`: `dw-mcp` over stdio, or mounted at `/mcp` by `dw.serve --mcp` for a client on another machine. See [MCP Server](docs/MCP.md) and [Remote GPU server](docs/REMOTE.md).
95
+ - **Step-output caching** — a step whose resolved arguments and seed are unchanged since the last run in the same process reuses its cached result instead of re-executing. This applies to any `Workflow.run` — REPL iteration and a re-run of a server-submitted job alike, so re-running a fixed-seed workflow from the UI finishes instantly and writes no new output files. The cache holds the most recent 50 steps and is dropped by `memory clear`
93
96
  - **Declarative JSON workflows** with variable substitution and cross-step data flow
94
97
  - **Multi-step pipelines** — chain text-to-image, image-to-video, inpainting, ControlNet
95
- - **Reproducible by construction** — outputs embed their full workflow definition and seed; any image in the gallery reopens as the exact workflow that made it
98
+ - **Reproducible by construction** — outputs embed their full workflow definition and seed; any image in the gallery reopens as the exact workflow that made it (see [Trust model](docs/SECURITY.md#trust-model) before reopening one someone else sent you). A rerun never overwrites a prior output — a name collision gets an incrementing suffix instead
96
99
  - **Long-video chaining** — run a video pipeline once per segment and stitch the segments into one clip, with audio-driven length and frame-to-frame continuity
97
100
  - **Quantization** — BitsAndBytes, TorchAO, GGUF, SDNQ, optimum-quanto
98
101
  - **Inference acceleration** — TeaCache, FirstBlockCache, FasterCache, MagCache, TaylorSeerCache
@@ -153,15 +156,26 @@ Jobs queue, stream progress live (per denoising step), cancel cooperatively, and
153
156
 
154
157
  ### Run a Workflow
155
158
 
159
+ `workflows/sd15.json` is the smallest, fastest starting point — a small, ungated model and a literal prompt, so the first run needs no Hugging Face login and downloads only a few GB:
160
+
156
161
  ```bash
162
+ python -m dw.run workflows/sd15.json
163
+ python -m dw.run workflows/sd15.json prompt="a cat" num_images_per_prompt=4
164
+ ```
165
+
166
+ Most of the workflows under `workflows/` (Flux, LTX-2, MiniMax...) use **gated** Hugging Face models — the repo owner has to approve your account before you can download them. Before running one of those, request access on the model's Hugging Face page (e.g. [black-forest-labs/FLUX.1-dev](https://huggingface.co/black-forest-labs/FLUX.1-dev)) and log in locally:
167
+
168
+ ```bash
169
+ huggingface-cli login
157
170
  python -m dw.run workflows/flux/FluxDev.json
158
- python -m dw.run workflows/flux/FluxDev.json prompt="a cat" num_images_per_prompt=4
159
171
  ```
160
172
 
173
+ Without this, the run fails partway through with an HTTP 401/403 from the Hub.
174
+
161
175
  ### Validate a Workflow
162
176
 
163
177
  ```bash
164
- python -m dw.validate workflows/flux/FluxDev.json
178
+ python -m dw.validate workflows/sd15.json
165
179
  ```
166
180
 
167
181
  ### Interactive REPL
@@ -329,6 +343,7 @@ See [workflows/](workflows/) for more workflow files.
329
343
 
330
344
  - [Server & Web UI](docs/SERVER.md) — The web UI, jobs API, and introspection service
331
345
  - [MCP Server](docs/MCP.md) — Tool surface for MCP clients (Claude Code, Claude Desktop)
346
+ - [Remote GPU server](docs/REMOTE.md) — Using the server, UI and MCP from another machine
332
347
  - [Workflow Guide](docs/WORKFLOW_GUIDE.md) — JSON structure, variables, steps, data flow
333
348
  - [Quantization](docs/QUANTIZATION.md) — BitsAndBytes, TorchAO, GGUF, SDNQ
334
349
  - [Inference Acceleration](docs/ACCELERATION.md) — torch.compile, FirstBlockCache, MagCache, TaylorSeer, TeaCache
@@ -4,6 +4,8 @@
4
4
 
5
5
  A declarative workflow engine and web UI for the [Hugging Face Diffusers library](https://github.com/huggingface/diffusers). Define image/video generation pipelines in JSON — with full access to the configuration diffusers exposes — and run them from the command line, an interactive REPL, or a browser.
6
6
 
7
+ A workflow JSON file is portable and easy to hand off — but that same flexibility means loading one can execute arbitrary Python (dynamic imports are how it reaches any diffusers pipeline or quantization backend without a bespoke adapter for each). Treat a workflow file from someone else the way you'd treat a `.py` script: see [Trust model](docs/SECURITY.md#trust-model) before running one you didn't write.
8
+
7
9
  **Python 3.10-3.14 | CUDA (NVIDIA) | MPS (Apple Silicon) | CPU**
8
10
 
9
11
  <picture>
@@ -14,10 +16,11 @@ A declarative workflow engine and web UI for the [Hugging Face Diffusers library
14
16
  ## Features
15
17
 
16
18
  - **Web UI** — browse and run workflows, edit them in introspection-driven forms, watch jobs stream live progress, manage generated output and the models on disk. `python -m dw.serve` and open a browser. See [Server & Web UI](docs/SERVER.md).
17
- - **MCP server** — a stdio server that lets an MCP client (Claude Code first) author, validate, save, run and diagnose workflows against a running `dw.serve`. `dw-mcp`. See [MCP Server](docs/MCP.md).
19
+ - **MCP server** — a tool surface that lets an MCP client (Claude Code first) author, validate, save, run and diagnose workflows against a running `dw.serve`: `dw-mcp` over stdio, or mounted at `/mcp` by `dw.serve --mcp` for a client on another machine. See [MCP Server](docs/MCP.md) and [Remote GPU server](docs/REMOTE.md).
20
+ - **Step-output caching** — a step whose resolved arguments and seed are unchanged since the last run in the same process reuses its cached result instead of re-executing. This applies to any `Workflow.run` — REPL iteration and a re-run of a server-submitted job alike, so re-running a fixed-seed workflow from the UI finishes instantly and writes no new output files. The cache holds the most recent 50 steps and is dropped by `memory clear`
18
21
  - **Declarative JSON workflows** with variable substitution and cross-step data flow
19
22
  - **Multi-step pipelines** — chain text-to-image, image-to-video, inpainting, ControlNet
20
- - **Reproducible by construction** — outputs embed their full workflow definition and seed; any image in the gallery reopens as the exact workflow that made it
23
+ - **Reproducible by construction** — outputs embed their full workflow definition and seed; any image in the gallery reopens as the exact workflow that made it (see [Trust model](docs/SECURITY.md#trust-model) before reopening one someone else sent you). A rerun never overwrites a prior output — a name collision gets an incrementing suffix instead
21
24
  - **Long-video chaining** — run a video pipeline once per segment and stitch the segments into one clip, with audio-driven length and frame-to-frame continuity
22
25
  - **Quantization** — BitsAndBytes, TorchAO, GGUF, SDNQ, optimum-quanto
23
26
  - **Inference acceleration** — TeaCache, FirstBlockCache, FasterCache, MagCache, TaylorSeerCache
@@ -78,15 +81,26 @@ Jobs queue, stream progress live (per denoising step), cancel cooperatively, and
78
81
 
79
82
  ### Run a Workflow
80
83
 
84
+ `workflows/sd15.json` is the smallest, fastest starting point — a small, ungated model and a literal prompt, so the first run needs no Hugging Face login and downloads only a few GB:
85
+
81
86
  ```bash
87
+ python -m dw.run workflows/sd15.json
88
+ python -m dw.run workflows/sd15.json prompt="a cat" num_images_per_prompt=4
89
+ ```
90
+
91
+ Most of the workflows under `workflows/` (Flux, LTX-2, MiniMax...) use **gated** Hugging Face models — the repo owner has to approve your account before you can download them. Before running one of those, request access on the model's Hugging Face page (e.g. [black-forest-labs/FLUX.1-dev](https://huggingface.co/black-forest-labs/FLUX.1-dev)) and log in locally:
92
+
93
+ ```bash
94
+ huggingface-cli login
82
95
  python -m dw.run workflows/flux/FluxDev.json
83
- python -m dw.run workflows/flux/FluxDev.json prompt="a cat" num_images_per_prompt=4
84
96
  ```
85
97
 
98
+ Without this, the run fails partway through with an HTTP 401/403 from the Hub.
99
+
86
100
  ### Validate a Workflow
87
101
 
88
102
  ```bash
89
- python -m dw.validate workflows/flux/FluxDev.json
103
+ python -m dw.validate workflows/sd15.json
90
104
  ```
91
105
 
92
106
  ### Interactive REPL
@@ -254,6 +268,7 @@ See [workflows/](workflows/) for more workflow files.
254
268
 
255
269
  - [Server & Web UI](docs/SERVER.md) — The web UI, jobs API, and introspection service
256
270
  - [MCP Server](docs/MCP.md) — Tool surface for MCP clients (Claude Code, Claude Desktop)
271
+ - [Remote GPU server](docs/REMOTE.md) — Using the server, UI and MCP from another machine
257
272
  - [Workflow Guide](docs/WORKFLOW_GUIDE.md) — JSON structure, variables, steps, data flow
258
273
  - [Quantization](docs/QUANTIZATION.md) — BitsAndBytes, TorchAO, GGUF, SDNQ
259
274
  - [Inference Acceleration](docs/ACCELERATION.md) — torch.compile, FirstBlockCache, MagCache, TaylorSeer, TeaCache
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffusers-workflow
3
- Version: 0.4.0a10
3
+ Version: 0.4.0b1
4
4
  Summary: Declarative workflow engine and web UI for Hugging Face Diffusers
5
5
  Author: dkackman
6
6
  License: Apache-2.0
@@ -79,6 +79,8 @@ Dynamic: license-file
79
79
 
80
80
  A declarative workflow engine and web UI for the [Hugging Face Diffusers library](https://github.com/huggingface/diffusers). Define image/video generation pipelines in JSON — with full access to the configuration diffusers exposes — and run them from the command line, an interactive REPL, or a browser.
81
81
 
82
+ A workflow JSON file is portable and easy to hand off — but that same flexibility means loading one can execute arbitrary Python (dynamic imports are how it reaches any diffusers pipeline or quantization backend without a bespoke adapter for each). Treat a workflow file from someone else the way you'd treat a `.py` script: see [Trust model](docs/SECURITY.md#trust-model) before running one you didn't write.
83
+
82
84
  **Python 3.10-3.14 | CUDA (NVIDIA) | MPS (Apple Silicon) | CPU**
83
85
 
84
86
  <picture>
@@ -89,10 +91,11 @@ A declarative workflow engine and web UI for the [Hugging Face Diffusers library
89
91
  ## Features
90
92
 
91
93
  - **Web UI** — browse and run workflows, edit them in introspection-driven forms, watch jobs stream live progress, manage generated output and the models on disk. `python -m dw.serve` and open a browser. See [Server & Web UI](docs/SERVER.md).
92
- - **MCP server** — a stdio server that lets an MCP client (Claude Code first) author, validate, save, run and diagnose workflows against a running `dw.serve`. `dw-mcp`. See [MCP Server](docs/MCP.md).
94
+ - **MCP server** — a tool surface that lets an MCP client (Claude Code first) author, validate, save, run and diagnose workflows against a running `dw.serve`: `dw-mcp` over stdio, or mounted at `/mcp` by `dw.serve --mcp` for a client on another machine. See [MCP Server](docs/MCP.md) and [Remote GPU server](docs/REMOTE.md).
95
+ - **Step-output caching** — a step whose resolved arguments and seed are unchanged since the last run in the same process reuses its cached result instead of re-executing. This applies to any `Workflow.run` — REPL iteration and a re-run of a server-submitted job alike, so re-running a fixed-seed workflow from the UI finishes instantly and writes no new output files. The cache holds the most recent 50 steps and is dropped by `memory clear`
93
96
  - **Declarative JSON workflows** with variable substitution and cross-step data flow
94
97
  - **Multi-step pipelines** — chain text-to-image, image-to-video, inpainting, ControlNet
95
- - **Reproducible by construction** — outputs embed their full workflow definition and seed; any image in the gallery reopens as the exact workflow that made it
98
+ - **Reproducible by construction** — outputs embed their full workflow definition and seed; any image in the gallery reopens as the exact workflow that made it (see [Trust model](docs/SECURITY.md#trust-model) before reopening one someone else sent you). A rerun never overwrites a prior output — a name collision gets an incrementing suffix instead
96
99
  - **Long-video chaining** — run a video pipeline once per segment and stitch the segments into one clip, with audio-driven length and frame-to-frame continuity
97
100
  - **Quantization** — BitsAndBytes, TorchAO, GGUF, SDNQ, optimum-quanto
98
101
  - **Inference acceleration** — TeaCache, FirstBlockCache, FasterCache, MagCache, TaylorSeerCache
@@ -153,15 +156,26 @@ Jobs queue, stream progress live (per denoising step), cancel cooperatively, and
153
156
 
154
157
  ### Run a Workflow
155
158
 
159
+ `workflows/sd15.json` is the smallest, fastest starting point — a small, ungated model and a literal prompt, so the first run needs no Hugging Face login and downloads only a few GB:
160
+
156
161
  ```bash
162
+ python -m dw.run workflows/sd15.json
163
+ python -m dw.run workflows/sd15.json prompt="a cat" num_images_per_prompt=4
164
+ ```
165
+
166
+ Most of the workflows under `workflows/` (Flux, LTX-2, MiniMax...) use **gated** Hugging Face models — the repo owner has to approve your account before you can download them. Before running one of those, request access on the model's Hugging Face page (e.g. [black-forest-labs/FLUX.1-dev](https://huggingface.co/black-forest-labs/FLUX.1-dev)) and log in locally:
167
+
168
+ ```bash
169
+ huggingface-cli login
157
170
  python -m dw.run workflows/flux/FluxDev.json
158
- python -m dw.run workflows/flux/FluxDev.json prompt="a cat" num_images_per_prompt=4
159
171
  ```
160
172
 
173
+ Without this, the run fails partway through with an HTTP 401/403 from the Hub.
174
+
161
175
  ### Validate a Workflow
162
176
 
163
177
  ```bash
164
- python -m dw.validate workflows/flux/FluxDev.json
178
+ python -m dw.validate workflows/sd15.json
165
179
  ```
166
180
 
167
181
  ### Interactive REPL
@@ -329,6 +343,7 @@ See [workflows/](workflows/) for more workflow files.
329
343
 
330
344
  - [Server & Web UI](docs/SERVER.md) — The web UI, jobs API, and introspection service
331
345
  - [MCP Server](docs/MCP.md) — Tool surface for MCP clients (Claude Code, Claude Desktop)
346
+ - [Remote GPU server](docs/REMOTE.md) — Using the server, UI and MCP from another machine
332
347
  - [Workflow Guide](docs/WORKFLOW_GUIDE.md) — JSON structure, variables, steps, data flow
333
348
  - [Quantization](docs/QUANTIZATION.md) — BitsAndBytes, TorchAO, GGUF, SDNQ
334
349
  - [Inference Acceleration](docs/ACCELERATION.md) — torch.compile, FirstBlockCache, MagCache, TaylorSeer, TeaCache
@@ -30,6 +30,7 @@ dw/security.py
30
30
  dw/serve.py
31
31
  dw/settings.py
32
32
  dw/step.py
33
+ dw/step_cache.py
33
34
  dw/teacache.py
34
35
  dw/teacache_models.json
35
36
  dw/test.py
@@ -48,6 +49,8 @@ dw/server/__init__.py
48
49
  dw/server/app.py
49
50
  dw/server/enhancers.py
50
51
  dw/server/jobs.py
52
+ dw/server/mcp_mount.py
53
+ dw/server/netinfo.py
51
54
  dw/server/updater.py
52
55
  dw/server/ui/index.html
53
56
  dw/server/ui/assets/abap-08VXUWAP.js
@@ -64,45 +67,45 @@ dw/server/ui/assets/csharp-BKxtCVv1.js
64
67
  dw/server/ui/assets/csp-bTuwJoIa.js
65
68
  dw/server/ui/assets/css-DIMkf-bt.js
66
69
  dw/server/ui/assets/css.worker-B3ciXF_0.js
67
- dw/server/ui/assets/cssMode-DBf-T_da.js
70
+ dw/server/ui/assets/cssMode-DIA5LESv.js
68
71
  dw/server/ui/assets/cypher-CVaqCwHa.js
69
72
  dw/server/ui/assets/dart-onAF5SnQ.js
70
73
  dw/server/ui/assets/dockerfile-DZFCIeNp.js
71
74
  dw/server/ui/assets/ecl-D05T4iGw.js
72
75
  dw/server/ui/assets/editor-jjEx9u7D.css
73
- dw/server/ui/assets/editor.api-B0D5Ygq7.js
76
+ dw/server/ui/assets/editor.api-CuOF-U_A.js
74
77
  dw/server/ui/assets/editor.worker-q-txB4vs.js
75
78
  dw/server/ui/assets/elixir-6RTg0lbw.js
76
79
  dw/server/ui/assets/flow9-C5_-GSwl.js
77
- dw/server/ui/assets/freemarker2-Br8g4G1T.js
80
+ dw/server/ui/assets/freemarker2-xMcLxHzc.js
78
81
  dw/server/ui/assets/fsharp-C8Ef5oNN.js
79
82
  dw/server/ui/assets/go-C-y9NEjX.js
80
83
  dw/server/ui/assets/graphql-fmXr3nnJ.js
81
- dw/server/ui/assets/handlebars-BKo1TaOF.js
84
+ dw/server/ui/assets/handlebars-Dbt47IUh.js
82
85
  dw/server/ui/assets/hcl-CpzslTdj.js
83
- dw/server/ui/assets/html-Bis1seyM.js
86
+ dw/server/ui/assets/html-C4QoqgED.js
84
87
  dw/server/ui/assets/html.worker-C93Ht9o9.js
85
- dw/server/ui/assets/htmlMode-D2SOD2MF.js
86
- dw/server/ui/assets/index-D7eWnTCB.css
87
- dw/server/ui/assets/index-JyFxgIR9.js
88
+ dw/server/ui/assets/htmlMode-BQ_x-rQl.js
89
+ dw/server/ui/assets/index-BCNGRglb.css
90
+ dw/server/ui/assets/index-C14JKFhY.js
88
91
  dw/server/ui/assets/ini-sBoK_t0W.js
89
92
  dw/server/ui/assets/java-BEtHBSE6.js
90
- dw/server/ui/assets/javascript-CkEbVb78.js
93
+ dw/server/ui/assets/javascript-yDlADdyl.js
91
94
  dw/server/ui/assets/json.worker-B2V3pomh.js
92
- dw/server/ui/assets/jsonMode-dVJbYwxg.js
95
+ dw/server/ui/assets/jsonMode-X4znCY4b.js
93
96
  dw/server/ui/assets/julia-Bri6UV-V.js
94
97
  dw/server/ui/assets/kotlin-BOotOW0E.js
95
98
  dw/server/ui/assets/less-B9JPFI3C.js
96
99
  dw/server/ui/assets/lexon-CfSJPG6W.js
97
- dw/server/ui/assets/liquid-Btak-6uF.js
98
- dw/server/ui/assets/lspLanguageFeatures-BfeZZQbb.js
100
+ dw/server/ui/assets/liquid-CAaCQzwu.js
101
+ dw/server/ui/assets/lspLanguageFeatures-CTJIGm94.js
99
102
  dw/server/ui/assets/lua-CsQS60Ue.js
100
103
  dw/server/ui/assets/m3-D-oSqn_W.js
101
104
  dw/server/ui/assets/markdown-Cimd5fb3.js
102
- dw/server/ui/assets/mdx-D9KXK7-s.js
105
+ dw/server/ui/assets/mdx-ByHLng1y.js
103
106
  dw/server/ui/assets/mips-CIPQ_RoX.js
104
107
  dw/server/ui/assets/monaco--ixms01u.css
105
- dw/server/ui/assets/monaco-ZMCk_MWf.js
108
+ dw/server/ui/assets/monaco-LJZc6TiS.js
106
109
  dw/server/ui/assets/msdax-DauUninz.js
107
110
  dw/server/ui/assets/mysql-SOo6toE5.js
108
111
  dw/server/ui/assets/objective-c-FvmIjYaQ.js
@@ -117,10 +120,10 @@ dw/server/ui/assets/powerquery-D3hlyOfw.js
117
120
  dw/server/ui/assets/powershell-DmHpPYUd.js
118
121
  dw/server/ui/assets/protobuf-C531GsRP.js
119
122
  dw/server/ui/assets/pug-Z5eAx3Zn.js
120
- dw/server/ui/assets/python-0FnO4xGM.js
123
+ dw/server/ui/assets/python-BCT_lvfW.js
121
124
  dw/server/ui/assets/qsharp-DkqhCAOL.js
122
125
  dw/server/ui/assets/r-BwWrilGY.js
123
- dw/server/ui/assets/razor-B6PMzeY4.js
126
+ dw/server/ui/assets/razor-Bw9oTolL.js
124
127
  dw/server/ui/assets/redis-ClamHrr6.js
125
128
  dw/server/ui/assets/redshift-DT7zqm-g.js
126
129
  dw/server/ui/assets/restructuredtext-BYgofb2h.js
@@ -140,21 +143,22 @@ dw/server/ui/assets/swift-Bxkupp3x.js
140
143
  dw/server/ui/assets/systemverilog-Bz4Y3fRF.js
141
144
  dw/server/ui/assets/tcl-DISqw1ZD.js
142
145
  dw/server/ui/assets/ts.worker-D7T1-Ig5.js
143
- dw/server/ui/assets/tsMode-nxyvZH1t.js
146
+ dw/server/ui/assets/tsMode-BGvHTpYz.js
144
147
  dw/server/ui/assets/twig-De2hgUGE.js
145
- dw/server/ui/assets/typescript-BhBe8aGf.js
148
+ dw/server/ui/assets/typescript-mwKKpQXP.js
146
149
  dw/server/ui/assets/typespec-B8J7ngcE.js
147
150
  dw/server/ui/assets/vb-DV3o63ZY.js
148
151
  dw/server/ui/assets/wgsl-DpFanUEy.js
149
- dw/server/ui/assets/workers-ChAf-t8A.js
150
- dw/server/ui/assets/xml-z2r9dHSO.js
151
- dw/server/ui/assets/yaml-DrcHrz7f.js
152
+ dw/server/ui/assets/workers-BOhWN9wu.js
153
+ dw/server/ui/assets/xml-DuQ6E6P7.js
154
+ dw/server/ui/assets/yaml-D7o22x0f.js
152
155
  dw/tasks/audio_utils.py
153
156
  dw/tasks/background_remover.py
154
157
  dw/tasks/borders.py
155
158
  dw/tasks/concat_videos.py
156
159
  dw/tasks/depth_estimator.py
157
160
  dw/tasks/diffusion_upscale.py
161
+ dw/tasks/dissolve_videos.py
158
162
  dw/tasks/format_messages.py
159
163
  dw/tasks/gather.py
160
164
  dw/tasks/image_to_text.py
@@ -166,6 +170,7 @@ dw/tasks/qr_code.py
166
170
  dw/tasks/restore_faces.py
167
171
  dw/tasks/rife_model.py
168
172
  dw/tasks/segment.py
173
+ dw/tasks/stabilize.py
169
174
  dw/tasks/task.py
170
175
  dw/tasks/tensor_image.py
171
176
  dw/tasks/text_generation.py
@@ -203,6 +208,7 @@ tests/test_device.py
203
208
  tests/test_device_helpers.py
204
209
  tests/test_device_portability.py
205
210
  tests/test_diffusion_upscale.py
211
+ tests/test_dissolve_videos.py
206
212
  tests/test_docs_links.py
207
213
  tests/test_events.py
208
214
  tests/test_examples.py
@@ -213,15 +219,18 @@ tests/test_image_utils.py
213
219
  tests/test_integration.py
214
220
  tests/test_interpolate_frames.py
215
221
  tests/test_introspection.py
222
+ tests/test_jobs_reused.py
216
223
  tests/test_list_images.py
217
224
  tests/test_mcp_authoring.py
218
225
  tests/test_mcp_catalog.py
219
226
  tests/test_mcp_client.py
220
227
  tests/test_mcp_diagnose.py
228
+ tests/test_mcp_main.py
221
229
  tests/test_mcp_media.py
222
230
  tests/test_mcp_models.py
223
231
  tests/test_mcp_prompts.py
224
232
  tests/test_mcp_server.py
233
+ tests/test_mix_audio.py
225
234
  tests/test_model_cache.py
226
235
  tests/test_modular_pipeline.py
227
236
  tests/test_offload_placement.py
@@ -233,6 +242,7 @@ tests/test_previous_results.py
233
242
  tests/test_prompt_parser.py
234
243
  tests/test_prompt_weighting.py
235
244
  tests/test_prompts.py
245
+ tests/test_recenter_crop.py
236
246
  tests/test_repl_commands.py
237
247
  tests/test_repl_ergonomics.py
238
248
  tests/test_repl_hierarchical.py
@@ -240,12 +250,19 @@ tests/test_repl_reorganization.py
240
250
  tests/test_repl_worker.py
241
251
  tests/test_resize_bucket.py
242
252
  tests/test_result.py
253
+ tests/test_result_output_naming.py
243
254
  tests/test_scheduler_config.py
244
255
  tests/test_schema.py
245
256
  tests/test_security.py
246
257
  tests/test_segment.py
258
+ tests/test_serve_main.py
247
259
  tests/test_server.py
260
+ tests/test_server_downloads.py
261
+ tests/test_server_info.py
262
+ tests/test_server_mcp.py
263
+ tests/test_stabilize.py
248
264
  tests/test_step.py
265
+ tests/test_step_cache.py
249
266
  tests/test_strip_exif_and_watermark.py
250
267
  tests/test_task.py
251
268
  tests/test_task_discovery.py
@@ -254,8 +271,11 @@ tests/test_tensor_image.py
254
271
  tests/test_text_generation.py
255
272
  tests/test_text_sections.py
256
273
  tests/test_type_helpers.py
274
+ tests/test_updater.py
257
275
  tests/test_variables.py
258
276
  tests/test_video_utils.py
259
277
  tests/test_worker.py
260
278
  tests/test_worker_execute.py
261
- tests/test_workflow.py
279
+ tests/test_workflow.py
280
+ tests/test_workflow_step_cache.py
281
+ tests/test_workflow_trust.py
@@ -29,8 +29,20 @@ warnings.filterwarnings("ignore", category=FutureWarning)
29
29
  warnings.filterwarnings("ignore", category=UserWarning)
30
30
  warnings.filterwarnings("ignore", category=DeprecationWarning)
31
31
 
32
- # Lazy import torch to avoid import errors when torch isn't available
33
- # (e.g., when using system Python instead of venv)
32
+ # Eager (but guarded) import of torch. This module's own top-level code needs
33
+ # torch's exceptions/types unconditionally to detect its absence gracefully
34
+ # (see _TORCH_AVAILABLE below) rather than deferring the try/except to first
35
+ # use everywhere torch is touched. It would be nice for a torch-free path like
36
+ # `python -m dw.validate` (pure JSON schema validation) to skip this multi-
37
+ # second import, but that isn't achievable by changing dw/__init__.py alone:
38
+ # dw/validate.py imports dw/workflow.py, which does its own unconditional
39
+ # `import torch` at module scope (Workflow.run() uses torch.Generator() for
40
+ # seeding) - so torch loads regardless of what this module does. Making the
41
+ # import here lazy without also restructuring dw/workflow.py's random-seed
42
+ # handling would just move the cost around, not remove it, and touching
43
+ # dw/workflow.py's import structure is a larger, riskier change than this
44
+ # fix pass is meant to make. Left eager on purpose; see the audit notes for
45
+ # why a real fix needs to start in dw/workflow.py, not here.
34
46
  try:
35
47
  import torch
36
48
  import diffusers
@@ -27,6 +27,10 @@ class RunContext:
27
27
  def __init__(self, on_event=None):
28
28
  self._on_event = on_event
29
29
  self._cancel = threading.Event()
30
+ # The most recent phase this run reported (see emit_phase/PHASES) -
31
+ # cancel() reads it to tell a client whether the cancel takes effect
32
+ # right away or has to wait out an in-flight, non-interruptible phase
33
+ self._current_phase = None
30
34
  # Pipeline cache keys this run resolved - the worker evicts entries a
31
35
  # run no longer touches, so an edited workflow drops stale models
32
36
  self.touched_pipelines = set()
@@ -40,8 +44,18 @@ class RunContext:
40
44
  # A broken sink must not kill a run that is otherwise fine
41
45
  logger.warning(f"Progress event sink failed on '{event_type}': {e}")
42
46
 
47
+ def note_phase(self, phase):
48
+ """Record the run's latest phase - called by emit_phase, read by
49
+ cancel() to judge whether the current phase can be interrupted."""
50
+ self._current_phase = phase
51
+
43
52
  def cancel(self):
44
53
  self._cancel.set()
54
+ if self._current_phase in NON_INTERRUPTIBLE_PHASES:
55
+ # A model load or a task step has no checkpoint to catch this
56
+ # flag until it finishes - say so, or the client sees the cancel
57
+ # request go silent for however long that takes
58
+ self.emit("cancel_pending", phase=self._current_phase)
45
59
 
46
60
  @property
47
61
  def cancelled(self):
@@ -82,6 +96,11 @@ def deactivate_context(token):
82
96
  # the run is waiting on, not what any one library is doing internally
83
97
  PHASES = ("loading", "cached", "generating", "decoding", "saving", "task")
84
98
 
99
+ # Phases with no checkpoint of their own: nothing inside a from_pretrained()
100
+ # call or a task handler consults the cancel flag, so a cancel requested
101
+ # during one of these can only take effect once the phase finishes on its own
102
+ NON_INTERRUPTIBLE_PHASES = ("loading", "task")
103
+
85
104
 
86
105
  def emit_phase(phase, detail=None):
87
106
  """Report a coarse phase change on the active run.
@@ -92,4 +111,6 @@ def emit_phase(phase, detail=None):
92
111
  enough (a handful per step) to carry a free-text detail alongside, which
93
112
  is what makes 'loading' readable as 'which model'.
94
113
  """
95
- get_context().emit("phase", phase=phase, detail=detail)
114
+ context = get_context()
115
+ context.note_phase(phase)
116
+ context.emit("phase", phase=phase, detail=detail)
@@ -35,8 +35,7 @@ import torch
35
35
  from diffusers.utils import encode_video, is_av_available
36
36
 
37
37
  from .. import empty_device_cache
38
- from ..result import AudioVideo, get_artifact_list
39
- from ..security import validate_output_path
38
+ from ..result import AudioVideo, get_artifact_list, output_file_path
40
39
  from ..tasks.audio_utils import (
41
40
  as_channels_samples,
42
41
  equal_power_crossfade_join,
@@ -165,6 +164,11 @@ class SegmentedFrames:
165
164
  self.paths = list(paths)
166
165
  self.total_frames = total_frames
167
166
  self.keep_files = keep_files
167
+ # True once cleanup() has actually removed the files (not when
168
+ # keep_files skipped that) - a cached Result pointing at a cleaned-up
169
+ # SegmentedFrames must not be served to a later miss, since the files
170
+ # a replay would open are gone. See Result.retainable.
171
+ self.cleaned = False
168
172
 
169
173
  def __len__(self):
170
174
  """Chunk count - one per segment file."""
@@ -191,6 +195,7 @@ class SegmentedFrames:
191
195
  os.remove(path)
192
196
  except FileNotFoundError:
193
197
  pass
198
+ self.cleaned = True
194
199
 
195
200
 
196
201
  class SegmentSpill:
@@ -240,12 +245,14 @@ class SegmentSpill:
240
245
  chain leaves fully playable segments
241
246
  sample_rate: Sample rate of that audio
242
247
  """
243
- path = validate_output_path(
244
- os.path.join(
245
- self.output_dir,
246
- f"{self.base_name}.segment-{len(self.paths):03d}.mp4",
247
- ),
248
+ # A crashed or completed chain leaves segment files behind on disk,
249
+ # ready to salvage - and the per-wrapper iteration counter (base_name)
250
+ # restarts at 0 in a fresh process, so a rerun must dedupe through the
251
+ # same '-N' convention every other output goes through rather than
252
+ # silently overwriting them.
253
+ path = output_file_path(
248
254
  self.output_dir,
255
+ f"{self.base_name}.segment-{len(self.paths):03d}.mp4",
249
256
  )
250
257
 
251
258
  audio_track = None
@@ -16,6 +16,10 @@ from .remote import remote_text_encoder
16
16
  from ..cache_blocks import register_cache_blocks
17
17
  from ..teacache import teacache_context
18
18
  from ..type_helpers import has_method
19
+ from ..security import (
20
+ require_trusted_from_pretrained_arguments,
21
+ require_trusted_pre_load_modules,
22
+ )
19
23
  from .. import empty_device_cache, get_device_type, resolve_device
20
24
  from diffusers import attention_backend
21
25
 
@@ -23,6 +27,7 @@ from diffusers import attention_backend
23
27
  # imported where they are used - at module scope they add seconds to every startup
24
28
 
25
29
  from ..events import WorkflowCancelled, emit_phase, get_context
30
+ from huggingface_hub.errors import HfHubHTTPError
26
31
 
27
32
  logger = logging.getLogger("dw")
28
33
 
@@ -224,8 +229,12 @@ class Pipeline:
224
229
  logger.debug(f"Loading pipeline: {self.name}")
225
230
 
226
231
  # Import modules that need to register with diffusers/transformers before loading
227
- # (e.g., sdnq registers its quantization method on import)
228
- for module_name in self.configuration.get("pre_load_modules", []):
232
+ # (e.g., sdnq registers its quantization method on import). This runs
233
+ # arbitrary python at import time, so an untrusted workflow is refused
234
+ # here unless --trust-workflows was passed - see docs/SECURITY.md
235
+ pre_load_modules = self.configuration.get("pre_load_modules", [])
236
+ require_trusted_pre_load_modules(pre_load_modules)
237
+ for module_name in pre_load_modules:
229
238
  logger.info(f"Pre-loading module: {module_name}")
230
239
  importlib.import_module(module_name)
231
240
 
@@ -1509,6 +1518,10 @@ def load_component(
1509
1518
  component_type = configuration["component_type"]
1510
1519
  component = None
1511
1520
 
1521
+ # Refused before anything reaches the Hub: an untrusted workflow must not
1522
+ # be able to have diffusers fetch and run code on its behalf
1523
+ require_trusted_from_pretrained_arguments(from_pretrained_arguments, component_name)
1524
+
1512
1525
  # A standard pipeline takes a component as a constructor argument. A modular one
1513
1526
  # cannot: it is built from the component specs in its own index and given the
1514
1527
  # objects afterwards, which is also what keeps load_components() from pulling a
@@ -1537,6 +1550,7 @@ def load_component(
1537
1550
  f"Consider changing torch_dtype from float16 to float32 for {component_name} "
1538
1551
  )
1539
1552
 
1553
+ model_name = None
1540
1554
  try:
1541
1555
  with loading_device(configuration):
1542
1556
  # Load from model name
@@ -1600,12 +1614,44 @@ def load_component(
1600
1614
  )
1601
1615
 
1602
1616
  except Exception as e:
1603
- # One log line with the full traceback - every error class was logged
1604
- # and re-raised identically
1617
+ # 401/403 from the Hub means the account behind whatever token (or
1618
+ # lack of one) HfApi is using cannot read this repo - almost always
1619
+ # a gated model the user has not requested access to, or has not
1620
+ # logged in for. A whole-pipeline load raises the HfHubHTTPError
1621
+ # itself; a per-component load gets it wrapped in an EnvironmentError
1622
+ # by diffusers' _get_model_file / transformers' cached_file, so the
1623
+ # cause chain is searched. Every other error (a real outage, a bad
1624
+ # repo id) is logged once with its traceback and re-raised unchanged
1625
+ if _hub_auth_status(e) is not None:
1626
+ repo = model_name or component_name
1627
+ logger.error(
1628
+ f"Hugging Face authentication required loading {component_name} "
1629
+ f"({repo}): {e}",
1630
+ exc_info=True,
1631
+ )
1632
+ raise RuntimeError(
1633
+ f"Model '{repo}' requires Hugging Face authentication - run "
1634
+ f"'huggingface-cli login', or request access at "
1635
+ f"https://huggingface.co/{repo}"
1636
+ ) from e
1605
1637
  logger.error(f"{type(e).__name__} loading {component_name}: {e}", exc_info=True)
1606
1638
  raise
1607
1639
 
1608
1640
 
1641
+ def _hub_auth_status(error):
1642
+ """The 401/403 status an exception (or anything in its cause/context
1643
+ chain) carries from the Hub, else None."""
1644
+ seen = set()
1645
+ while error is not None and id(error) not in seen:
1646
+ seen.add(id(error))
1647
+ if isinstance(error, HfHubHTTPError):
1648
+ status = getattr(getattr(error, "response", None), "status_code", None)
1649
+ if status in (401, 403):
1650
+ return status
1651
+ error = error.__cause__ or error.__context__
1652
+ return None
1653
+
1654
+
1609
1655
  def apply_sdnq_optimizations(pipeline, component_names):
1610
1656
  """Apply SDNQ quantized matmul optimization to pipeline components.
1611
1657
 
@@ -6,6 +6,7 @@ from .arguments import (
6
6
  PREVIOUS_RESULT_PREFIX,
7
7
  build_objects,
8
8
  )
9
+ from .step_cache import reference_resolves_to
9
10
 
10
11
  logger = logging.getLogger("dw")
11
12
 
@@ -126,13 +127,14 @@ def get_previous_results(previous_results, previous_result_name):
126
127
  f"Previous result '{previous_result_name}' not found. Available results: {list(previous_results.keys())}"
127
128
  )
128
129
 
129
- # Find the longest known step name that is a prefix of the reference
130
- # followed by ".", and treat the remainder as the property name.
130
+ # Find the longest known step name the reference resolves to, and treat
131
+ # the remainder as the property name. The exact-match case returned
132
+ # above, so every name reaching here is a strict '<name>.' prefix.
131
133
  result_name = max(
132
134
  (
133
135
  name
134
136
  for name in previous_results
135
- if previous_result_name.startswith(name + ".")
137
+ if reference_resolves_to(previous_result_name, name)
136
138
  ),
137
139
  key=len,
138
140
  default=None,