Board Management¶
Learn how to create, manage, and organize images using InvokeAI boards.
What are Boards?¶
Boards are containers for organizing images in InvokeAI. Think of them as folders or albums that group related images together.
Board Basics¶
List All Boards¶
# Get all boards including uncategorized
boards = client.board_repo.list_boards(include_uncategorized=True)
for board in boards:
print(f"Board: {board.board_name}")
print(f" ID: {board.board_id}")
print(f" Images: {board.image_count}")
print(f" Created: {board.created_at}")
The Uncategorized Board¶
The special "none" board (ID = "none"
) holds uncategorized images:
# Access uncategorized board
uncategorized = client.board_repo.get_board_handle("none")
images = uncategorized.list_images()
print(f"Uncategorized images: {len(images)}")
String 'none' vs Python None
The uncategorized board uses the string "none"
as its ID, not Python's None
object.
Creating Boards¶
Create a New Board¶
# Create board
new_board = client.board_repo.create_board(
name="My Project",
description="Images for my project"
)
print(f"Created board: {new_board.board_id}")
Board Naming¶
# Board names should be descriptive
good_names = [
"SDXL_Landscapes_2024",
"Character_Concepts_v2",
"Test_Outputs_Batch_5"
]
# Avoid generic names
bad_names = [
"Board1",
"Test",
"Images"
]
Board Handles¶
Get Board Handle¶
# Get handle for board operations
board = client.board_repo.get_board_handle("board_id_here")
# Board handle provides methods for:
# - Uploading images
# - Downloading images
# - Listing images
# - Managing metadata
Board Handle Cache¶
Handles are cached for efficiency:
# First call creates handle
board1 = client.board_repo.get_board_handle("my_board")
# Second call returns cached handle
board2 = client.board_repo.get_board_handle("my_board")
assert board1 is board2 # Same object
Board Operations¶
List Images in Board¶
board = client.board_repo.get_board_handle("my_board")
# Get all image names
image_names = board.list_images()
print(f"Board contains {len(image_names)} images")
for name in image_names[:10]: # First 10
print(f" - {name}")
Get Board Details¶
# Get board metadata
board_info = client.board_repo.get_board("board_id")
print(f"Name: {board_info.board_name}")
print(f"Description: {board_info.description}")
print(f"Image count: {board_info.image_count}")
print(f"Cover image: {board_info.cover_image_name}")
Update Board¶
# Update board properties
client.board_repo.update_board(
board_id="my_board",
name="Updated Name",
description="New description"
)
Delete Board¶
# Delete board (images move to uncategorized)
client.board_repo.delete_board("board_id")
# Or delete with images
client.board_repo.delete_board(
board_id="board_id",
delete_images=True # Also delete contained images
)
Board Selection in Workflows¶
Setting Output Board¶
# Find board field in workflow
for inp in wf.list_inputs():
if inp.field_name == "board":
board_field = wf.get_input_value(inp.input_index)
# Set to specific board
board_field.value = "my_output_board"
# Or use uncategorized
board_field.value = "none"
Dynamic Board Selection¶
def select_board_by_name(client, name):
"""Find board ID by name."""
boards = client.board_repo.list_boards()
for board in boards:
if board.board_name == name:
return board.board_id
# Not found, create it
new_board = client.board_repo.create_board(name=name)
return new_board.board_id
# Use in workflow
board_id = select_board_by_name(client, "Daily Outputs")
wf.get_input_value(BOARD_IDX).value = board_id
Board Organization Strategies¶
By Project¶
# Organize by project
projects = [
"Project_Alpha_Characters",
"Project_Alpha_Environments",
"Project_Beta_Concepts"
]
for project in projects:
client.board_repo.create_board(name=project)
By Date¶
from datetime import datetime
# Daily boards
today = datetime.now().strftime("%Y-%m-%d")
board_name = f"Outputs_{today}"
board = client.board_repo.create_board(name=board_name)
By Workflow Type¶
# Boards for different workflows
workflow_boards = {
"txt2img": "Text_to_Image_Results",
"img2img": "Image_to_Image_Results",
"inpaint": "Inpainting_Results",
"upscale": "Upscaled_Images"
}
for workflow_type, board_name in workflow_boards.items():
client.board_repo.create_board(name=board_name)
Board Management Patterns¶
Board Manager Class¶
class BoardManager:
"""Helper for board management."""
def __init__(self, client):
self.client = client
self.board_repo = client.board_repo
def ensure_board_exists(self, name, description=""):
"""Create board if it doesn't exist."""
boards = self.board_repo.list_boards()
for board in boards:
if board.board_name == name:
return board.board_id
# Create new
new_board = self.board_repo.create_board(
name=name,
description=description
)
return new_board.board_id
def clean_empty_boards(self):
"""Delete boards with no images."""
boards = self.board_repo.list_boards()
for board in boards:
if board.image_count == 0:
print(f"Deleting empty board: {board.board_name}")
self.board_repo.delete_board(board.board_id)
def archive_board(self, board_id, archive_name=None):
"""Rename board to archive it."""
if not archive_name:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
archive_name = f"Archive_{timestamp}"
self.board_repo.update_board(
board_id=board_id,
name=archive_name
)
# Use it
manager = BoardManager(client)
board_id = manager.ensure_board_exists("My Workflow Outputs")
Batch Board Operations¶
def move_images_between_boards(client, from_board_id, to_board_id):
"""Move all images from one board to another."""
from_board = client.board_repo.get_board_handle(from_board_id)
images = from_board.list_images()
for image_name in images:
# Move image (requires API call)
client.move_image_to_board(image_name, to_board_id)
print(f"Moved {len(images)} images")
Board Statistics¶
def get_board_statistics(client):
"""Get statistics about all boards."""
boards = client.board_repo.list_boards(include_uncategorized=True)
total_boards = len(boards)
total_images = sum(b.image_count for b in boards)
# Find largest board
largest = max(boards, key=lambda b: b.image_count)
# Find oldest board
oldest = min(boards, key=lambda b: b.created_at)
print(f"Total boards: {total_boards}")
print(f"Total images: {total_images}")
print(f"Largest board: {largest.board_name} ({largest.image_count} images)")
print(f"Oldest board: {oldest.board_name}")
return {
'total_boards': total_boards,
'total_images': total_images,
'largest_board': largest,
'oldest_board': oldest
}
Error Handling¶
Board Not Found¶
try:
board = client.board_repo.get_board_handle("invalid_id")
except Exception as e:
print(f"Board not found: {e}")
# Create it or use uncategorized
board = client.board_repo.get_board_handle("none")
Name Conflicts¶
def create_unique_board(client, base_name):
"""Create board with unique name."""
boards = client.board_repo.list_boards()
existing_names = {b.board_name for b in boards}
# Find unique name
name = base_name
counter = 1
while name in existing_names:
name = f"{base_name}_{counter}"
counter += 1
return client.board_repo.create_board(name=name)
Best Practices¶
1. Use Descriptive Names¶
# Good: Descriptive and organized
board_name = f"{workflow_type}_{date}_{project}"
# Bad: Generic
board_name = "board1"
2. Regular Cleanup¶
# Periodically clean up old boards
def cleanup_old_boards(client, days_old=30):
from datetime import datetime, timedelta
cutoff = datetime.now() - timedelta(days=days_old)
boards = client.board_repo.list_boards()
for board in boards:
if board.created_at < cutoff and board.image_count == 0:
client.board_repo.delete_board(board.board_id)
3. Board Templates¶
# Create standard board structure
def setup_project_boards(client, project_name):
templates = [
f"{project_name}_Inputs",
f"{project_name}_Outputs",
f"{project_name}_Finals",
f"{project_name}_Archive"
]
board_ids = {}
for template in templates:
board = client.board_repo.create_board(name=template)
board_ids[template] = board.board_id
return board_ids
Next Steps¶
- Learn about Image Operations for upload/download
- Understand Output Mapping for result organization
- Explore Execution Modes for workflow running
- Master Model Management for AI model handling