diffusers-workflow 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. diffusers_workflow-0.4.0.dist-info/METADATA +318 -0
  2. diffusers_workflow-0.4.0.dist-info/RECORD +260 -0
  3. diffusers_workflow-0.4.0.dist-info/WHEEL +5 -0
  4. diffusers_workflow-0.4.0.dist-info/entry_points.txt +7 -0
  5. diffusers_workflow-0.4.0.dist-info/licenses/LICENSE +201 -0
  6. diffusers_workflow-0.4.0.dist-info/top_level.txt +2 -0
  7. dw/__init__.py +440 -0
  8. dw/adapter_compatibility.py +226 -0
  9. dw/arguments.py +1231 -0
  10. dw/assessment_rules.py +159 -0
  11. dw/assets.py +130 -0
  12. dw/cache_blocks.json +16 -0
  13. dw/cache_blocks.py +146 -0
  14. dw/community_pipelines/pipeline_flux_rf_inversion.py +1184 -0
  15. dw/content_types.py +150 -0
  16. dw/dissolve_frame_errors.py +121 -0
  17. dw/docs/ACCELERATION.md +352 -0
  18. dw/docs/AGENT_LOOP.md +95 -0
  19. dw/docs/DEPENDENCIES.md +91 -0
  20. dw/docs/IP_ADAPTER.md +109 -0
  21. dw/docs/LORAS.md +131 -0
  22. dw/docs/MCP.md +517 -0
  23. dw/docs/PROMPT_WEIGHTING.md +78 -0
  24. dw/docs/QUANTIZATION.md +230 -0
  25. dw/docs/RECIPES_24GB.md +201 -0
  26. dw/docs/RELEASING.md +195 -0
  27. dw/docs/REMOTE.md +140 -0
  28. dw/docs/REPL_COMMANDS.md +121 -0
  29. dw/docs/REPL_WORKER_GUIDE.md +51 -0
  30. dw/docs/SECURITY.md +272 -0
  31. dw/docs/SECURITY_QUICKREF.md +112 -0
  32. dw/docs/SERVER.md +679 -0
  33. dw/docs/TASKS.md +1741 -0
  34. dw/docs/TESTING.md +71 -0
  35. dw/docs/WORKFLOW_GUIDE.md +2038 -0
  36. dw/docs/WORKSPACES.md +316 -0
  37. dw/download_watch.py +335 -0
  38. dw/elision.py +306 -0
  39. dw/events.py +275 -0
  40. dw/for_each.py +409 -0
  41. dw/host_memory.py +258 -0
  42. dw/host_memory_projection.py +230 -0
  43. dw/hub_cache.py +432 -0
  44. dw/introspection.py +1228 -0
  45. dw/kernel_availability.py +208 -0
  46. dw/locations.py +599 -0
  47. dw/log_setup.py +45 -0
  48. dw/loudness.py +82 -0
  49. dw/media_audio.py +217 -0
  50. dw/media_frames.py +367 -0
  51. dw/media_info.py +297 -0
  52. dw/pipeline_processors/chain.py +821 -0
  53. dw/pipeline_processors/config_objects.py +237 -0
  54. dw/pipeline_processors/pipeline.py +2297 -0
  55. dw/pipeline_processors/remote.py +46 -0
  56. dw/plan.py +920 -0
  57. dw/previous_results.py +411 -0
  58. dw/probe_paths.py +59 -0
  59. dw/prompt_schema.json +48 -0
  60. dw/prompt_weighting.py +378 -0
  61. dw/prompts.py +159 -0
  62. dw/realize.py +250 -0
  63. dw/reference_limits.py +215 -0
  64. dw/reference_names.py +125 -0
  65. dw/repl.py +338 -0
  66. dw/repl_commands.py +836 -0
  67. dw/repl_worker.py +159 -0
  68. dw/result.py +1720 -0
  69. dw/result_fps.py +82 -0
  70. dw/run.py +162 -0
  71. dw/runs.py +768 -0
  72. dw/scalar_result_validation.py +97 -0
  73. dw/schema.py +283 -0
  74. dw/security.py +1038 -0
  75. dw/select_validation.py +115 -0
  76. dw/serve.py +277 -0
  77. dw/server/__init__.py +2 -0
  78. dw/server/app.py +4586 -0
  79. dw/server/assess.py +132 -0
  80. dw/server/catalog_shape.py +487 -0
  81. dw/server/enhancers.py +129 -0
  82. dw/server/exports.py +480 -0
  83. dw/server/guides.py +257 -0
  84. dw/server/jobs.py +1561 -0
  85. dw/server/mcp_mount.py +95 -0
  86. dw/server/netinfo.py +124 -0
  87. dw/server/observed_cost.py +379 -0
  88. dw/server/sysinfo.py +71 -0
  89. dw/server/ui/assets/abap-08VXUWAP.js +1 -0
  90. dw/server/ui/assets/apex-BWPQTe0t.js +1 -0
  91. dw/server/ui/assets/azcli-Bc_sGQ0U.js +1 -0
  92. dw/server/ui/assets/bat-i0X4ZdIN.js +1 -0
  93. dw/server/ui/assets/bicep-B5-_aFwp.js +2 -0
  94. dw/server/ui/assets/cameligo-DMUM7wLl.js +1 -0
  95. dw/server/ui/assets/clojure-Cm7r79vr.js +1 -0
  96. dw/server/ui/assets/codicon-Brq4_Ui5.ttf +0 -0
  97. dw/server/ui/assets/coffee-Ba7i2nA0.js +1 -0
  98. dw/server/ui/assets/cpp-C7h46wYY.js +1 -0
  99. dw/server/ui/assets/csharp-BKxtCVv1.js +1 -0
  100. dw/server/ui/assets/csp-bTuwJoIa.js +1 -0
  101. dw/server/ui/assets/css-DIMkf-bt.js +3 -0
  102. dw/server/ui/assets/css.worker-B3ciXF_0.js +93 -0
  103. dw/server/ui/assets/cssMode-CPznxfY8.js +1 -0
  104. dw/server/ui/assets/cypher-CVaqCwHa.js +1 -0
  105. dw/server/ui/assets/dart-onAF5SnQ.js +1 -0
  106. dw/server/ui/assets/dockerfile-DZFCIeNp.js +1 -0
  107. dw/server/ui/assets/ecl-D05T4iGw.js +1 -0
  108. dw/server/ui/assets/editor-jjEx9u7D.css +1 -0
  109. dw/server/ui/assets/editor.api-CpWcotrd.js +847 -0
  110. dw/server/ui/assets/editor.worker-q-txB4vs.js +30 -0
  111. dw/server/ui/assets/elixir-6RTg0lbw.js +1 -0
  112. dw/server/ui/assets/flow9-C5_-GSwl.js +1 -0
  113. dw/server/ui/assets/freemarker2-CXtRM8N4.js +3 -0
  114. dw/server/ui/assets/fsharp-C8Ef5oNN.js +1 -0
  115. dw/server/ui/assets/go-C-y9NEjX.js +1 -0
  116. dw/server/ui/assets/graphql-fmXr3nnJ.js +1 -0
  117. dw/server/ui/assets/handlebars-N7x-6NMY.js +1 -0
  118. dw/server/ui/assets/hcl-CpzslTdj.js +1 -0
  119. dw/server/ui/assets/html-PhsdjHSr.js +1 -0
  120. dw/server/ui/assets/html.worker-C93Ht9o9.js +506 -0
  121. dw/server/ui/assets/htmlMode-Dgj0SEok.js +1 -0
  122. dw/server/ui/assets/index-3Vw6WAPW.css +1 -0
  123. dw/server/ui/assets/index-DgrYhQd9.js +43 -0
  124. dw/server/ui/assets/ini-sBoK_t0W.js +1 -0
  125. dw/server/ui/assets/java-BEtHBSE6.js +1 -0
  126. dw/server/ui/assets/javascript-BJqN9Qhv.js +1 -0
  127. dw/server/ui/assets/json.worker-B2V3pomh.js +62 -0
  128. dw/server/ui/assets/jsonMode-DbM4SWSv.js +7 -0
  129. dw/server/ui/assets/julia-Bri6UV-V.js +1 -0
  130. dw/server/ui/assets/kotlin-BOotOW0E.js +1 -0
  131. dw/server/ui/assets/less-B9JPFI3C.js +2 -0
  132. dw/server/ui/assets/lexon-CfSJPG6W.js +1 -0
  133. dw/server/ui/assets/liquid-BWr8lEc4.js +1 -0
  134. dw/server/ui/assets/lspLanguageFeatures-C1iGuDyZ.js +4 -0
  135. dw/server/ui/assets/lua-CsQS60Ue.js +1 -0
  136. dw/server/ui/assets/m3-D-oSqn_W.js +1 -0
  137. dw/server/ui/assets/markdown-Cimd5fb3.js +1 -0
  138. dw/server/ui/assets/mdx-DAdMi_0p.js +1 -0
  139. dw/server/ui/assets/mips-CIPQ_RoX.js +1 -0
  140. dw/server/ui/assets/monaco--ixms01u.css +1 -0
  141. dw/server/ui/assets/monaco-BGCeEqaw.js +56 -0
  142. dw/server/ui/assets/msdax-DauUninz.js +1 -0
  143. dw/server/ui/assets/mysql-SOo6toE5.js +1 -0
  144. dw/server/ui/assets/objective-c-FvmIjYaQ.js +1 -0
  145. dw/server/ui/assets/pascal-DrH0SRf2.js +1 -0
  146. dw/server/ui/assets/pascaligo-D-ptJ9y-.js +1 -0
  147. dw/server/ui/assets/perl-oz_6vUea.js +1 -0
  148. dw/server/ui/assets/pgsql-DTj74zXo.js +1 -0
  149. dw/server/ui/assets/php-nr791fC2.js +1 -0
  150. dw/server/ui/assets/pla-CopQ2nXW.js +1 -0
  151. dw/server/ui/assets/postiats-43DmfD33.js +1 -0
  152. dw/server/ui/assets/powerquery-D3hlyOfw.js +1 -0
  153. dw/server/ui/assets/powershell-DmHpPYUd.js +1 -0
  154. dw/server/ui/assets/protobuf-C531GsRP.js +2 -0
  155. dw/server/ui/assets/pug-Z5eAx3Zn.js +1 -0
  156. dw/server/ui/assets/python-Bcn70HdC.js +1 -0
  157. dw/server/ui/assets/qsharp-DkqhCAOL.js +1 -0
  158. dw/server/ui/assets/r-BwWrilGY.js +1 -0
  159. dw/server/ui/assets/razor-D1HmNnby.js +1 -0
  160. dw/server/ui/assets/redis-ClamHrr6.js +1 -0
  161. dw/server/ui/assets/redshift-DT7zqm-g.js +1 -0
  162. dw/server/ui/assets/restructuredtext-BYgofb2h.js +1 -0
  163. dw/server/ui/assets/ruby-DezsRK8O.js +1 -0
  164. dw/server/ui/assets/rust-DdL9SqIa.js +1 -0
  165. dw/server/ui/assets/sb-CcwsVR0C.js +1 -0
  166. dw/server/ui/assets/scala-DHpiXF5c.js +1 -0
  167. dw/server/ui/assets/scheme-BeGwcela.js +1 -0
  168. dw/server/ui/assets/scss-gp-XZpBa.js +3 -0
  169. dw/server/ui/assets/shell-CC2rA5mh.js +1 -0
  170. dw/server/ui/assets/solidity-BEEn4gHE.js +1 -0
  171. dw/server/ui/assets/sophia-CRfGWb83.js +1 -0
  172. dw/server/ui/assets/sparql-D_Lu-MrJ.js +1 -0
  173. dw/server/ui/assets/sql-NEE52Syq.js +1 -0
  174. dw/server/ui/assets/st-DbInun42.js +1 -0
  175. dw/server/ui/assets/swift-Bxkupp3x.js +1 -0
  176. dw/server/ui/assets/systemverilog-Bz4Y3fRF.js +1 -0
  177. dw/server/ui/assets/tcl-DISqw1ZD.js +1 -0
  178. dw/server/ui/assets/ts.worker-D7T1-Ig5.js +67738 -0
  179. dw/server/ui/assets/tsMode-D6u0XmOW.js +11 -0
  180. dw/server/ui/assets/twig-De2hgUGE.js +1 -0
  181. dw/server/ui/assets/typescript-BU6v-LMV.js +1 -0
  182. dw/server/ui/assets/typespec-B8J7ngcE.js +1 -0
  183. dw/server/ui/assets/vb-DV3o63ZY.js +1 -0
  184. dw/server/ui/assets/wgsl-DpFanUEy.js +298 -0
  185. dw/server/ui/assets/workers-Cn7cTUKr.js +1 -0
  186. dw/server/ui/assets/xml--0LP2Lwk.js +1 -0
  187. dw/server/ui/assets/yaml-mpBg9jnt.js +1 -0
  188. dw/server/ui/index.html +17 -0
  189. dw/server/updater.py +192 -0
  190. dw/settings.py +98 -0
  191. dw/shot_span_preflight.py +116 -0
  192. dw/shots.py +359 -0
  193. dw/slice_preflight.py +148 -0
  194. dw/step.py +187 -0
  195. dw/step_cache.py +442 -0
  196. dw/subfolders.py +107 -0
  197. dw/task_domains.py +307 -0
  198. dw/tasks/assess.py +826 -0
  199. dw/tasks/audio_transcription.py +88 -0
  200. dw/tasks/audio_utils.py +1862 -0
  201. dw/tasks/background_remover.py +43 -0
  202. dw/tasks/borders.py +113 -0
  203. dw/tasks/compose_text.py +74 -0
  204. dw/tasks/concat_videos.py +300 -0
  205. dw/tasks/depth_estimator.py +54 -0
  206. dw/tasks/diffusion_upscale.py +109 -0
  207. dw/tasks/dissolve_videos.py +342 -0
  208. dw/tasks/format_messages.py +24 -0
  209. dw/tasks/gather.py +173 -0
  210. dw/tasks/grade.py +97 -0
  211. dw/tasks/image_to_text.py +43 -0
  212. dw/tasks/image_utils.py +764 -0
  213. dw/tasks/interpolate_frames.py +252 -0
  214. dw/tasks/judge.py +68 -0
  215. dw/tasks/model_cache.py +55 -0
  216. dw/tasks/pair_audio.py +268 -0
  217. dw/tasks/qr_code.py +19 -0
  218. dw/tasks/restore_faces.py +175 -0
  219. dw/tasks/rife_model.py +192 -0
  220. dw/tasks/segment.py +121 -0
  221. dw/tasks/select.py +111 -0
  222. dw/tasks/speech_generation.py +228 -0
  223. dw/tasks/stabilize.py +129 -0
  224. dw/tasks/task.py +920 -0
  225. dw/tasks/tensor_image.py +57 -0
  226. dw/tasks/text_generation.py +169 -0
  227. dw/tasks/text_sections.py +80 -0
  228. dw/tasks/upscale.py +203 -0
  229. dw/tasks/video_utils.py +624 -0
  230. dw/tasks/zoe_depth.py +71 -0
  231. dw/teacache.py +381 -0
  232. dw/teacache_models.json +99 -0
  233. dw/test.py +29 -0
  234. dw/type_helpers.py +231 -0
  235. dw/validate.py +68 -0
  236. dw/variable_constraints.py +444 -0
  237. dw/variables.py +443 -0
  238. dw/video_extensions.py +141 -0
  239. dw/vram_estimate.py +116 -0
  240. dw/worker.py +764 -0
  241. dw/workflow.py +2007 -0
  242. dw/workflow_schema.json +1346 -0
  243. dw/workflow_sources.py +383 -0
  244. dw/workflows/h3_context_ir.json +57 -0
  245. dw/workflows/test.json +31 -0
  246. dw/workspace.py +730 -0
  247. dw_mcp/__init__.py +6 -0
  248. dw_mcp/__main__.py +133 -0
  249. dw_mcp/assets.py +336 -0
  250. dw_mcp/authoring.py +114 -0
  251. dw_mcp/catalog.py +360 -0
  252. dw_mcp/client.py +486 -0
  253. dw_mcp/diagnose.py +371 -0
  254. dw_mcp/exports.py +84 -0
  255. dw_mcp/guides.py +35 -0
  256. dw_mcp/media.py +638 -0
  257. dw_mcp/models.py +97 -0
  258. dw_mcp/prompts.py +104 -0
  259. dw_mcp/server.py +1343 -0
  260. dw_mcp/workspaces.py +212 -0
dw/repl.py ADDED
@@ -0,0 +1,338 @@
1
+ """
2
+ Interactive REPL for Diffusers Workflow.
3
+
4
+ Main entry point for the REPL interface. Delegates command handling
5
+ to specialized command classes and worker management to WorkerManager.
6
+ """
7
+
8
+ import cmd
9
+ import sys
10
+ import argparse
11
+ import difflib
12
+ import logging
13
+ import os
14
+ import multiprocessing
15
+ from . import startup
16
+ from .repl_worker import WorkerManager
17
+ from .workspace import resolve_workspace, set_workspace
18
+ from .repl_commands import (
19
+ ConfigCommands,
20
+ ArgCommands,
21
+ MemoryCommands,
22
+ WorkflowCommands,
23
+ )
24
+
25
+ # CRITICAL: Set multiprocessing start method to 'spawn' for CUDA compatibility
26
+ # Must be done before any multiprocessing operations
27
+ if multiprocessing.get_start_method(allow_none=True) != "spawn":
28
+ try:
29
+ multiprocessing.set_start_method("spawn", force=True)
30
+ except RuntimeError:
31
+ # Already set, ignore
32
+ pass
33
+
34
+ logger = logging.getLogger("dw")
35
+
36
+
37
+ class DiffusersWorkflowREPL(cmd.Cmd):
38
+ """Interactive command line interface for Diffusers Workflow"""
39
+
40
+ intro = (
41
+ "Welcome to the Diffusers Workflow REPL.\n"
42
+ " 'workflow list' shows available workflows, 'help' gets you oriented.\n"
43
+ )
44
+ prompt = "dw> "
45
+ use_rawinput = True # Ensure we're using raw_input for command reading
46
+
47
+ def __init__(self):
48
+ # Initialize cmd.Cmd first, before setting up our globals
49
+ cmd.Cmd.__init__(self)
50
+ # Initialize globals dictionary from the workspace - in a checkout,
51
+ # whose root is a workspace, these are the ./outputs and ./workflows
52
+ # they have always been
53
+ workspace = set_workspace(resolve_workspace())
54
+ self.globals = {
55
+ "workspace": workspace.root, # Where the two directories below live
56
+ "output_dir": workspace.outputs, # Default output directory
57
+ "log_level": "INFO", # Default log level
58
+ "workflow_dir": workspace.workflows, # Default workflow directory
59
+ }
60
+ self.current_workflow = None
61
+ self.workflow_args = {} # Store workflow arguments
62
+
63
+ # Initialize worker manager
64
+ self.worker_manager = WorkerManager()
65
+
66
+ # Initialize command handlers
67
+ self.config_commands = ConfigCommands(self)
68
+ self.arg_commands = ArgCommands(self)
69
+ self.memory_commands = MemoryCommands(self)
70
+ self.workflow_commands = WorkflowCommands(self)
71
+
72
+ def preloop(self):
73
+ """Hook method executed once when cmdloop() is called."""
74
+ try:
75
+ import readline
76
+
77
+ history_file = os.path.expanduser("~/.dw_history")
78
+ readline.read_history_file(history_file)
79
+ except (ImportError, FileNotFoundError):
80
+ pass
81
+
82
+ def postloop(self):
83
+ """Hook method executed once when cmdloop() is about to return."""
84
+ try:
85
+ import readline
86
+
87
+ history_file = os.path.expanduser("~/.dw_history")
88
+ readline.write_history_file(history_file)
89
+ except (ImportError, FileNotFoundError):
90
+ pass
91
+
92
+ def emptyline(self):
93
+ """Override emptyline to do nothing instead of repeating last command."""
94
+ pass
95
+
96
+ # Group commands whose detailed help lives in the group handler - 'help
97
+ # workflow' and 'workflow ?' must tell the same story
98
+ COMMAND_GROUPS = ("workflow", "arg", "memory", "config")
99
+
100
+ def do_help(self, arg):
101
+ """List available commands with "help" or detailed help with "help cmd"."""
102
+ if not arg:
103
+ print("\nDiffusers Workflow REPL")
104
+ print("=" * 60)
105
+ print("\nTypical session:")
106
+ print(" workflow list See available workflows")
107
+ print(" workflow load FluxDev Load one (validated immediately)")
108
+ print(" arg show See its variables and defaults")
109
+ print(' arg set prompt="a cat" Override a variable')
110
+ print(" workflow run Run it")
111
+ print(" workflow run steps=30 Set arguments and run in one line")
112
+ print("\nModels stay loaded in a worker process between runs, so the")
113
+ print("second run of a workflow skips straight to inference.")
114
+ print("\nCommand groups ('help <group>' or '<group> ?' for details):")
115
+ print(" workflow - list, load, reload, status, run, restart")
116
+ print(" arg - show, set, clear")
117
+ print(" memory - show, clear")
118
+ print(" config - show, set")
119
+ print("\nShortcuts:")
120
+ print(" run [<name>=<value> ...] same as 'workflow run'")
121
+ print(" load <name> same as 'workflow load'")
122
+ print(" set <name>=<value> same as 'arg set'")
123
+ print(" <TAB> completes commands, workflow names,")
124
+ print(" and argument names")
125
+ print("\nWhile a workflow runs:")
126
+ print(" Progress prints per step and per denoise step. Ctrl+C cancels")
127
+ print(" the run (models stay cached); a second Ctrl+C stops the worker.")
128
+ print("\n'exit' or 'quit' leaves the REPL.")
129
+ print()
130
+ elif arg.strip() in self.COMMAND_GROUPS:
131
+ # Route to the group's own help so there is one source of truth
132
+ getattr(self, f"do_{arg.strip()}")("?")
133
+ else:
134
+ super().do_help(arg)
135
+
136
+ def do_exit(self, arg):
137
+ """Exit the REPL"""
138
+ self.worker_manager.shutdown_worker()
139
+ print("Goodbye!")
140
+ return True
141
+
142
+ def do_quit(self, arg):
143
+ """Exit the REPL (alias for exit)"""
144
+ return self.do_exit(arg)
145
+
146
+ # ========================================================================
147
+ # Command delegation to specialized handlers
148
+ # ========================================================================
149
+
150
+ def do_config(self, arg):
151
+ """Configure global settings."""
152
+ self.config_commands.do_config(arg)
153
+
154
+ def do_arg(self, arg):
155
+ """Manage workflow arguments."""
156
+ self.arg_commands.do_arg(arg)
157
+
158
+ def do_memory(self, arg):
159
+ """Manage GPU memory."""
160
+ self.memory_commands.do_memory(arg)
161
+
162
+ def do_workflow(self, arg):
163
+ """Manage workflows. 'workflow ?' lists subcommands."""
164
+ self.workflow_commands.do_workflow(arg)
165
+
166
+ # ========================================================================
167
+ # Shortcuts for the hot loop: run / load / set
168
+ # ========================================================================
169
+
170
+ def do_run(self, arg):
171
+ """Run the loaded workflow. Shortcut for 'workflow run [<name>=<value> ...]'."""
172
+ self.workflow_commands.do_workflow(f"run {arg}".strip())
173
+
174
+ def do_load(self, arg):
175
+ """Load a workflow. Shortcut for 'workflow load <name>'."""
176
+ self.workflow_commands.do_workflow(f"load {arg}".strip())
177
+
178
+ def do_set(self, arg):
179
+ """Set a workflow argument. Shortcut for 'arg set <name>=<value>'."""
180
+ self.arg_commands.do_arg(f"set {arg}".strip())
181
+
182
+ # ========================================================================
183
+ # Tab completion
184
+ # ========================================================================
185
+
186
+ WORKFLOW_SUBCOMMANDS = ("list", "load", "reload", "status", "run", "restart")
187
+ ARG_SUBCOMMANDS = ("show", "set", "clear")
188
+ MEMORY_SUBCOMMANDS = ("show", "clear")
189
+ CONFIG_SUBCOMMANDS = ("show", "set")
190
+ CONFIG_KEYS = ("workspace", "output_dir", "log_level", "workflow_dir")
191
+
192
+ @staticmethod
193
+ def _matches(candidates, text):
194
+ return [candidate for candidate in candidates if candidate.startswith(text)]
195
+
196
+ def _variable_candidates(self):
197
+ """The loaded workflow's variable names, ready for name=value entry."""
198
+ if not self.current_workflow:
199
+ return []
200
+ return [f"{name}=" for name in self.current_workflow.variables]
201
+
202
+ def complete_workflow(self, text, line, begidx, endidx):
203
+ words = line.split()
204
+ # Completing the subcommand itself
205
+ if len(words) == 1 or (len(words) == 2 and not line.endswith(" ")):
206
+ return self._matches(self.WORKFLOW_SUBCOMMANDS, text)
207
+ if words[1] == "load":
208
+ return self._matches(self.workflow_commands.workflow_names(), text)
209
+ if words[1] == "run":
210
+ return self._matches(self._variable_candidates(), text)
211
+ return []
212
+
213
+ def complete_arg(self, text, line, begidx, endidx):
214
+ words = line.split()
215
+ if len(words) == 1 or (len(words) == 2 and not line.endswith(" ")):
216
+ return self._matches(self.ARG_SUBCOMMANDS, text)
217
+ if words[1] == "set":
218
+ return self._matches(self._variable_candidates(), text)
219
+ if words[1] == "clear":
220
+ return self._matches(list(self.workflow_args), text)
221
+ return []
222
+
223
+ def complete_memory(self, text, line, begidx, endidx):
224
+ return self._matches(self.MEMORY_SUBCOMMANDS, text)
225
+
226
+ def complete_config(self, text, line, begidx, endidx):
227
+ words = line.split()
228
+ if len(words) == 1 or (len(words) == 2 and not line.endswith(" ")):
229
+ return self._matches(self.CONFIG_SUBCOMMANDS, text)
230
+ if words[1] == "set":
231
+ return self._matches([f"{key}=" for key in self.CONFIG_KEYS], text)
232
+ return []
233
+
234
+ def complete_load(self, text, line, begidx, endidx):
235
+ return self._matches(self.workflow_commands.workflow_names(), text)
236
+
237
+ def complete_run(self, text, line, begidx, endidx):
238
+ return self._matches(self._variable_candidates(), text)
239
+
240
+ def complete_set(self, text, line, begidx, endidx):
241
+ return self._matches(self._variable_candidates(), text)
242
+
243
+ def default(self, line):
244
+ """Handle unknown commands"""
245
+ print(f"Unknown command: {line}")
246
+ command = line.split()[0] if line.split() else ""
247
+ known = [name[3:] for name in dir(self) if name.startswith("do_")]
248
+ suggestions = difflib.get_close_matches(command, known, n=3, cutoff=0.6)
249
+ if suggestions:
250
+ print(f"Did you mean: {', '.join(suggestions)}?")
251
+ print("Type 'help' or '?' for a list of commands")
252
+
253
+ # ========================================================================
254
+ # Helper methods
255
+ # ========================================================================
256
+
257
+ def _print_memory_info(self, info):
258
+ """Print formatted memory information"""
259
+ if not info.get("gpu_available"):
260
+ print("GPU not available")
261
+ self._print_host_memory(info)
262
+ return
263
+
264
+ print("\nGPU Memory Status:")
265
+ print(f" Device: {info.get('gpu_device_name', 'Unknown')}")
266
+ print(f" Allocated: {info.get('gpu_memory_allocated_mb', 0):.1f} MB")
267
+ print(f" Reserved: {info.get('gpu_memory_reserved_mb', 0):.1f} MB")
268
+
269
+ if "gpu_memory_free_mb" in info:
270
+ print(f" Free: {info.get('gpu_memory_free_mb', 0):.1f} MB")
271
+ print(f" Total: {info.get('gpu_memory_total_mb', 0):.1f} MB")
272
+
273
+ print(f" Runs in this session: {info.get('run_count', 0)}")
274
+ self._print_host_memory(info)
275
+ print()
276
+
277
+ def _print_host_memory(self, info):
278
+ """Host RAM, when the platform could be asked - with offloaded
279
+ weights the card says very little about what a run is holding."""
280
+ if "host_memory_rss_mb" not in info:
281
+ return
282
+ print("\nHost Memory:")
283
+ print(f" Worker RSS: {info['host_memory_rss_mb']:.1f} MB")
284
+ if "host_memory_peak_rss_mb" in info:
285
+ print(f" Worker peak RSS: {info['host_memory_peak_rss_mb']:.1f} MB")
286
+ if "host_memory_available_mb" in info:
287
+ print(
288
+ f" Available: {info['host_memory_available_mb']:.1f} MB"
289
+ f" of {info.get('host_memory_total_mb', 0):.1f} MB"
290
+ )
291
+
292
+
293
+ def main():
294
+ """Start the REPL interface"""
295
+ parser = argparse.ArgumentParser(description="Start Diffusers Workflow REPL.")
296
+ parser.add_argument(
297
+ "-l",
298
+ "--log_level",
299
+ type=str,
300
+ default="INFO",
301
+ help="Set the logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",
302
+ )
303
+ parser.add_argument(
304
+ "--trust-workflows",
305
+ action="store_true",
306
+ default=False,
307
+ help="Trust every workflow loaded this session to execute arbitrary "
308
+ "Python: allow pre_load_modules and any dotted "
309
+ "*_type/*_dtype/dtype/config_type value, not just ones inside the "
310
+ "diffusers/torch/transformers/quantization-backend ecosystem the "
311
+ "tool already depends on. Off by default - see docs/SECURITY.md's "
312
+ "Trust model.",
313
+ )
314
+ args = parser.parse_args()
315
+
316
+ # Set before the worker subprocess is ever spawned - 'spawn' launches a
317
+ # fresh interpreter that inherits this environment variable, so
318
+ # 'workflow load/run' in the worker sees the same trust choice
319
+ from .security import set_trust_workflows
320
+
321
+ set_trust_workflows(args.trust_workflows)
322
+
323
+ # Initialize logging
324
+ startup(args.log_level)
325
+
326
+ try:
327
+ repl = DiffusersWorkflowREPL()
328
+ repl.cmdloop()
329
+ except KeyboardInterrupt:
330
+ print("\nGoodbye!")
331
+ sys.exit(0)
332
+ except Exception as e:
333
+ logger.error(f"Error in REPL: {str(e)}", exc_info=True)
334
+ sys.exit(1)
335
+
336
+
337
+ if __name__ == "__main__":
338
+ main()