Major Features: - Backward compatibility: VALIDATE_INPUTS handles old boolean True/False values for enable_runtime_hooks parameter - Phase 3: XMP region metadata with MWG-RS compliance (faces, areas, coordinates, extensions) - Phase 4.4: Per-node UI toggle for runtime hooks (dropdown: Auto/Enabled/Disabled) - Runtime hooks enhancements: performance tracking, disagreement logging, configurable limits New Files: - config.json: Configuration file for runtime hooks and metadata settings - eric_metadata/hooks/runtime_capture.py: Runtime hook infrastructure - eric_metadata/utils/config.py: Configuration loader with priority system - eric_metadata/utils/version.py: Version helper for generated_by labels - eric_metadata/utils/a1111.py: Automatic1111 parameter string generation - eric_metadata/utils/jpeg_fallback.py: 4-stage JPEG metadata fallback - eric_metadata/workflow/: Workflow parsing and generation helpers - tests/test_backward_compatibility.py: 7 tests for parameter migration - tests/test_xmp_regions.py: 6 tests for XMP region round-trip - tests/test_per_node_runtime_hooks.py: 9 tests for per-node toggle Documentation: - CONFIG_GUIDE.md: Configuration options and usage - RUNTIME_HOOKS_QUICK_REFERENCE.md: Quick reference for runtime hooks - RUNTIME_HOOKS_ENHANCEMENTS_SUMMARY.md: Detailed enhancement documentation - SAFE_RUNTIME_HOOKS_RESEARCH.md: Safety analysis and validation - edit_log.md: Complete change history Test Results: All 143 tests passing - 7 backward compatibility tests - 6 XMP region tests - 9 per-node toggle tests - 17 runtime hooks enhancement tests - 104 existing tests Breaking Changes: None - fully backward compatible
5.7 KiB
Image Classification Metadata Integration Guide
This guide explains how custom classification nodes can send their analysis results into the Metadata System so everything is captured alongside saved outputs.
When to use this guide
Use these steps for any node that:
- Analyzes an image (classification, tagging, detection, etc.).
- Produces structured information that should persist in XMP, TXT, or database sidecars.
- Already runs inside the AAA Metadata System environment (custom node folder) and can rely on its utilities.
Implementation checklist
-
Import the helpers
from custom_nodes.AAA_Metadata_System import MetadataService from custom_nodes.AAA_Metadata_System.eric_metadata.utils.version import get_metadata_system_version_label -
Cache the version label once per module
METADATA_SYSTEM_GENERATED_BY = get_metadata_system_version_label()Do this at module scope; the helper caches
version.txtso other consumers stay in sync. -
Instantiate (or receive) a
MetadataService- Reuse the service from parent nodes when it is already provided.
- Otherwise create one with
metadata_service = MetadataService(debug=self.debug)and keep it around; avoid recreating it per call.
-
Build a metadata payload Follow the existing structure used by save-image nodes:
classification_metadata = { "ai_info": { "analysis": { "generated_by": METADATA_SYSTEM_GENERATED_BY, "classifier": node_name, "version": classifier_version, "source_image": image_identifier, "labels": labels, # list of {name, confidence} "top_label": labels[0] if labels else None, } } }Key points:
- Keep new data under
ai_info.analysis(or a more specific namespace) to avoid colliding with generation metadata. - Add short summaries (
top_label, counts, scores) so humans can read the TXT sidecar easily. - Include provenance (
generated_by, classifier name/version, run timestamp).
- Keep new data under
-
Optionally attach raw model outputs
- Place longer arrays or heatmaps under
analysis["details"]oranalysis["attachments"]. - Use lightweight structures (lists/dicts) and keep binary data out of the metadata; store large artifacts as separate files.
- Place longer arrays or heatmaps under
-
Merge with existing metadata If the node already receives a metadata dict, use
_deep_mergeor similar logic so you do not overwrite user-provided fields. Example:merged = metadata_service._merge_metadata(existing_metadata, classification_metadata) -
Select storage targets Decide where to persist your payload:
- XMP sidecar:
targets=["xmp"] - TXT summary:
targets=["txt"] - Both:
targets=["xmp", "txt"] - Embedded metadata (PNG/JPEG) should only be used if the file format supports it and the data volume is small.
- XMP sidecar:
-
Write the metadata
metadata_service.write_metadata( image_path, classification_metadata, targets=["xmp", "txt"], resource_identifier=image_path, # or a logical URI )- Supply the absolute path (or URI) for the image being annotated.
- When working on batches, call
write_metadatafor each output or create a shared resource identifier before looping.
-
Respect discovery/logging hooks
- When discovery mode is enabled (
metadata_service.discovery_mode), capture any unfamiliar classifier names or label schemas so the central logs stay current.
- When discovery mode is enabled (
Best practices
- Keep structures flat where possible. Deeply nested dictionaries make sidecar TXT files hard to read.
- Avoid mutable global state. Store node-specific context on
selfin the node class. - Validate numeric ranges. Clamp confidence values to
[0, 1](or[0, 100]) before writing them. - Fallback gracefully. If the node cannot fetch metadata service, log a warning and still return image outputs.
- Document new keys. Update the metadata schema docs and add a regression test that asserts the new keys appear when the node runs.
Example integration snippet
class MetadataAwareClassifier:
def __init__(self, debug: bool = False):
self.debug = debug
self.metadata_service = MetadataService(debug=debug)
self.generated_by = get_metadata_system_version_label()
def classify_and_store(self, image_path: str, image_tensor):
labels = self._run_classifier(image_tensor)
metadata = {
"ai_info": {
"analysis": {
"generated_by": self.generated_by,
"classifier": "ExampleClassifier",
"version": "1.2.0",
"labels": labels,
"top_label": labels[0] if labels else None,
}
}
}
self.metadata_service.write_metadata(
image_path,
metadata,
targets=["xmp", "txt"],
)
return labels
Testing and validation
- Run the targeted regression suite:
A:/Comfy25/ComfyUI_windows_portable/python_embeded/python.exe -m pytest tests/prep/test_module_boundaries.py - Load an output image in an XMP viewer to confirm the
ai_info.analysisblock exists. - Open the generated TXT sidecar and verify the classifier summary is human-readable.
- (Optional) Query the metadata database if the DB handler is enabled to ensure records are inserted as expected.
Following this checklist keeps every classification node aligned with the core Metadata System and ensures downstream consumers (UI, discovery reports, external integrations) see consistent generated_by and provenance fields.