Skip to content

AI Workflows

An AI feature commonly has four stages: prepare isolated dependencies, download models, reuse inference objects, and import outputs into Blender. BlendJob organizes these stages around one Runtime and Storage Root.

1. Declare inference dependencies

environment = {
    "python": "3.10",
    "packages": [
        "numpy==2.4.2",
        "huggingface-hub==1.4.1",
    ],
    "platform_packages": {
        "windows": ["onnxruntime-directml==1.24.4"],
        "default": ["onnxruntime==1.24.4"],
    },
}

The Blender side stays lightweight. These packages are installed in storage_root/.venv and imported by Server Handlers.

2. Manage models with a Resource

class ModelManager:
    def __init__(self, root):
        self.root = root
        self.root.mkdir(parents=True, exist_ok=True)
        self.sessions = {}

    def download(self, name, progress):
        path = self.root / name
        download_model(name, path, progress=progress)
        return path

    def get(self, name):
        if name not in self.sessions:
            self.sessions[name] = load_session(self.root / name)
        return self.sessions[name]

    def snapshot(self):
        return {
            "downloaded": sorted(path.name for path in self.root.iterdir()),
            "loaded": sorted(self.sessions),
        }

    def clear(self):
        self.sessions.clear()


@server.resource("models")
def create_models(job_server):
    return ModelManager(job_server.storage_root / "models")

Model files live in persistent storage, while sessions live in Server memory. The model directory remains available after rebuilding the environment.

3. Register a model download job

@server.job("download-model")
def download_model_job(context, parameters):
    manager = context.resource("models")

    def progress(value, message):
        context.progress(value, message)
        context.check_cancelled()

    path = manager.download(parameters["model"], progress)
    return {"model": path.name}

Modeling downloads as jobs gives Blender consistent progress, cancellation, error handling, and logs.

4. Prepare a default model after installation

Provide post_install when the extension should be ready with a default model:

def post_install(runtime):
    runtime.request(
        "download-model",
        {"model": "depth-v1"},
    )


runtime = JobRuntime(
    "server:server",
    entrypoint_root=Path(__file__).parent,
    storage_root=Path.home() / ".my-addon",
    environment=environment,
    post_install=post_install,
    namespace="my_addon",
)

After the environment is ready and the Server can start, BlendJob runs post_install(runtime) in the background. Progress from the model-download job continues in the status bar. The installation Operator finishes after default-model preparation.

For user-selected, on-demand models, omit post_install and invoke the same download-model job from a model-management panel.

5. Register an inference job

@server.job("estimate-depth")
def estimate_depth(context, parameters):
    models = context.resource("models")
    context.progress(0.1, "Loading model")
    session = models.get(parameters["model"])
    context.check_cancelled()

    context.progress(0.3, "Running inference")
    depth = run_depth(session, parameters["input"])

    output = context.directory / "depth.npz"
    save_depth(output, depth)
    return {"depth": output.name}

The model session loads on first use and is reused by later jobs.

6. Submit from Blender and import the result

class EstimateDepth(JobOperatorBase, bpy.types.Operator):
    bl_idname = "my_addon.estimate_depth"
    bl_label = "Estimate Depth"
    job_type = "estimate-depth"

    input_path: bpy.props.StringProperty(subtype="FILE_PATH")
    model: bpy.props.StringProperty(default="depth-v1")

    def response(self, context, result):
        build_depth_object(context, result.file("depth"))

Blender data handling stays in response(), while inference dependencies and model lifecycle stay in the Server. UI, computation, and persistent resources each have a clear role.

Production guidance

  • Pin Python package versions so the environment hash is reproducible.
  • Add an application-level file lock when multiple processes can download into the same model directory.
  • Expose model state through snapshot() so the UI reflects backend facts.
  • Call check_cancelled() at natural inference checkpoints.
  • Keep rebuildable sessions in memory and model weights under storage_root/models.
  • Offer a clear() action to release memory or GPU memory.