Utilities and Helper Patterns¶
This section provides practical helper functions and patterns that exist in the current client implementation, focusing on copy-pasteable code snippets with direct links to concrete implementations in the repository. Note that previously documented utility classes like "AssetManager", "TypeConverter", "ProgressTracker", and validator classes do not exist in the codebase—instead, use the patterns documented below with WorkflowHandle, BoardRepository/BoardHandle, and the main Client class.
Input Discovery and Drift Management¶
Utilities for managing workflow inputs and detecting changes when GUI workflows are modified.
preview()
- Input Summary Display¶
Generate a quick summary of all workflow inputs with current values for debugging and inspection.
Returns:
- list[dict]
: List of input summaries with keys:
- index
(int): Stable input index
- label
(str): Display name or field name
- type
(str): Field type name
- value
(Any): Current field value
- required
(bool): Whether input is mandatory
Example:
# Display all inputs with values
rows = wf.preview()
for r in rows:
required = "* " if r['required'] else " "
print(f"{required}[{r['index']:02d}] {r['label']} ({r['type']}) -> {r['value']}")
# Output:
# * [00] Positive Prompt (IvkStringField) -> A beautiful landscape
# [01] Negative Prompt (IvkStringField) -> blur, artifacts
# * [02] Width (IvkIntegerField) -> 1024
Source: WorkflowHandle.preview()
Index Map Management - Workflow Change Detection¶
When GUI workflows are modified, input indices can change. These utilities help track and detect changes.
export_input_index_map()
- Create Baseline Snapshot¶
Export current input-to-index mapping to a file for change detection.
Parameters:
- filepath
(str): Path where to save the index map JSON
Use Case: - Run after finalizing GUI workflow structure - Commit the generated file to version control - Use as baseline for detecting future changes
Example:
# Save current input mapping
wf.export_input_index_map("workflow-inputs.json")
# Commit to version control
# git add workflow-inputs.json
# git commit -m "Add input index baseline for stable automation"
verify_input_index_map()
- Detect Changes¶
Compare current workflow inputs against a saved index map to detect changes.
Parameters:
- filepath
(str): Path to previously saved index map
Returns:
- dict[str, Any]
: Change report with keys:
- unchanged
(list): Inputs that stayed the same
- moved
(list): Inputs that changed index positions
- missing
(list): Inputs that were removed
- new
(list): Inputs that were added
Example:
# Check for workflow changes
report = wf.verify_input_index_map("workflow-inputs.json")
print(f"Unchanged inputs: {len(report['unchanged'])}")
print(f"Moved inputs: {len(report['moved'])}")
print(f"Missing inputs: {len(report['missing'])}")
print(f"New inputs: {len(report['new'])}")
# Handle moved inputs
for moved in report["moved"]:
old_idx = moved["old_index"]
new_idx = moved["new_index"]
name = moved["name"]
print(f"Input '{name}' moved from [{old_idx}] to [{new_idx}]")
Change Management Workflow:
1. Create baseline with export_input_index_map()
after GUI editing
2. Use verify_input_index_map()
before automation scripts
3. Update scripts if indices have changed
4. Re-export new baseline if changes are accepted
Source: WorkflowHandle.export_input_index_map()
| WorkflowHandle.verify_input_index_map()
Submission and monitoring patterns¶
Blocking submit + poll
# Submit (raises early on invalid inputs)
submission = wf.submit_sync()
# Poll for terminal status; optional progress callback logs transitions
queue_item = wf.wait_for_completion_sync(
poll_interval=2.0,
timeout=180.0,
progress_callback=lambda qi: print("Status:", qi.get("status")),
)
WorkflowHandle.submit_sync()
, WorkflowHandle.wait_for_completion_sync()
Async submit with event callbacks (Socket.IO)
async def on_progress(evt: dict):
if evt.get("session_id") == wf.session_id:
print(f"Progress: {evt.get('progress', 0)*100:.0f}%")
result = await wf.submit(
subscribe_events=True,
on_invocation_progress=on_progress,
)
# Later, wait on completion with events instead of polling:
completed = await wf.wait_for_completion(timeout=300)
WorkflowHandle.submit()
, WorkflowHandle.wait_for_completion()
Hybrid streaming: simple submit + async event stream
async for evt in wf.submit_sync_monitor_async():
et = evt.get("event_type")
if et == "submission":
print("Batch:", evt["batch_id"])
elif et == "invocation_progress":
print("Progress:", evt.get("progress"))
elif et in ("graph_complete", "queue_item_status_changed"):
print("Done:", et)
WorkflowHandle.submit_sync_monitor_async()
Cancel a running job
Source:WorkflowHandle.cancel()
, WorkflowHandle.cancel_async()
Output mapping (node → image filenames)¶
Map output-capable nodes (with board fields exposed in the Form) to their produced images:
mappings = wf.map_outputs_to_images(queue_item)
for m in mappings:
print(
f"idx={m['input_index']:02d} node={m['node_id'][:8]} "
f"board={m['board_id']} images={m.get('image_names')}"
)
WorkflowHandle.map_outputs_to_images()
Get just the set of output nodes (their board inputs) if you need to pre-inspect:
Source:WorkflowHandle.list_outputs()
Boards and images (quick recipes)¶
Resolve a board and upload/download images
# List boards (include uncategorized)
boards = client.board_repo.list_boards(include_uncategorized=True)
# Get a handle (None or "none" gives uncategorized)
bh = client.board_repo.get_board_handle(None)
# Upload from bytes (lands in Assets; uncategorized omits board_id intentionally)
img = bh.upload_image_data(open("sample.png","rb").read(), filename="sample.png")
# Download (guarded by membership in this board)
data = bh.download_image(img.image_name, full_resolution=True)
open(img.image_name, "wb").write(data)
BoardRepository.list_boards()
- BoardRepository.get_board_handle()
- BoardHandle.upload_image_data()
- BoardHandle.download_image()
Validation helpers¶
Validate all inputs before submit (aggregates per-index errors)
errors = wf.validate_inputs()
if errors:
for idx, msgs in errors.items():
print(f"[{idx}] {', '.join(msgs)}")
raise SystemExit("Fix inputs and retry")
WorkflowHandle.validate_inputs()
Type-safe setting pattern (work with the concrete field you get)
from invokeai_py_client.ivk_fields import IvkStringField
fld = wf.get_input_value(0)
if isinstance(fld, IvkStringField):
fld.value = "A futuristic city at night"
WorkflowHandle.get_input_value()
Reliability patterns (generic)¶
Simple retry wrapper for transient HTTP errors (copy-paste)
import time, requests
def retry(fn, attempts=3, delay=1.0, backoff=2.0):
for i in range(attempts):
try:
return fn()
except requests.RequestException as e:
if i == attempts - 1:
raise
time.sleep(delay)
delay *= backoff
# Example: robust board listing
boards = retry(lambda: client.board_repo.list_boards(include_uncategorized=True))
Cross-references¶
- Workflows: docs/api-reference/workflow.md
- Client: docs/api-reference/client.md
- Boards: docs/api-reference/boards.md
- User guides and examples:
- Inputs: docs/user-guide/inputs.md
- Output mapping: docs/user-guide/output-mapping.md
- Examples index: docs/examples/index.md