Files

519 lines
14 KiB
Markdown

# Metadata System Usage Guide
This guide provides detailed instructions and examples for using the Metadata System for ComfyUI. It covers basic and advanced usage, as well as integration with ComfyUI nodes.
## Table of Contents
- [Basic Usage](#basic-usage)
- [Initialization](#initialization)
- [Writing Metadata](#writing-metadata)
- [Reading Metadata](#reading-metadata)
- [Merging Metadata](#merging-metadata)
- [Metadata Structure](#metadata-structure)
- [Basic Section](#basic-section)
- [Analysis Section](#analysis-section)
- [AI Info Section](#ai-info-section)
- [Regions Section](#regions-section)
- [ComfyUI Node Usage](#comfyui-node-usage)
- [Metadata Save Image Node](#metadata-save-image-node)
- [Metadata Entry Node](#metadata-entry-node)
- [Metadata Query Node](#metadata-query-node)
- [Workflow Extractor Node](#workflow-extractor-node)
- [Advanced Features](#advanced-features)
- [Human-readable Text Format](#human-readable-text-format)
- [Database Queries](#database-queries)
- [Resource Identifiers](#resource-identifiers)
- [Batch Operations](#batch-operations)
- [Troubleshooting](#troubleshooting)
- [Common Issues](#common-issues)
- [Debug Mode](#debug-mode)
## Basic Usage
### Initialization
Initialize the MetadataService to start working with the system:
```python
from Metadata_system import MetadataService
# Basic initialization
service = MetadataService()
# With debug mode enabled for troubleshooting
service = MetadataService(debug=True)
# With human-readable text format
service = MetadataService(human_readable_text=True)
# Using as a context manager (ensures proper cleanup)
with MetadataService() as service:
# Your code here
pass
```
### Writing Metadata
Write metadata to one or more storage formats:
```python
# Create metadata dictionary
metadata = {
'basic': {
'title': 'Mountain Landscape',
'description': 'AI generated mountain landscape',
'keywords': ['mountains', 'landscape', 'nature', 'AI'],
'rating': 4
},
'ai_info': {
'generation': {
'model': 'stable-diffusion-v1-5',
'prompt': 'majestic mountains with snow caps',
'negative_prompt': 'ugly, blurry',
'sampler': 'euler_a',
'steps': 30,
'cfg_scale': 7.5,
'seed': 1234567890
}
}
}
# Write to all supported formats
result = service.write_metadata('path/to/image.png', metadata)
# Write to specific formats
result = service.write_metadata('path/to/image.png', metadata,
targets=['embedded', 'xmp'])
# Check results
for target, success in result.items():
print(f"{target}: {'Succeeded' if success else 'Failed'}")
```
### Reading Metadata
Read metadata from storage formats:
```python
# Read from embedded metadata with fallback
metadata = service.read_metadata('path/to/image.png', source='embedded', fallback=True)
# Read from specific source without fallback
xmp_metadata = service.read_metadata('path/to/image.png', source='xmp', fallback=False)
# Access specific sections
if 'basic' in metadata:
print(f"Title: {metadata['basic'].get('title', 'No title')}")
if 'ai_info' in metadata and 'generation' in metadata['ai_info']:
gen = metadata['ai_info']['generation']
print(f"Model: {gen.get('model')}")
print(f"Prompt: {gen.get('prompt')}")
```
### Merging Metadata
Merge new metadata with existing metadata:
```python
# New metadata to merge
new_metadata = {
'basic': {
'keywords': ['new', 'tags', 'to', 'add']
},
'analysis': {
'technical': {
'blur': {
'score': 0.92,
'higher_better': True
}
}
}
}
# Merge with existing metadata
result = service.merge_metadata('path/to/image.png', new_metadata)
# Merge and write to specific targets
result = service.merge_metadata('path/to/image.png', new_metadata,
targets=['embedded', 'txt'])
```
## Metadata Structure
The metadata is organized into sections for different types of information:
### Basic Section
Contains essential image information:
```python
basic = {
'title': 'Image Title', # Image title
'description': 'Detailed description', # Description/caption
'keywords': ['keyword1', 'keyword2'], # Tags/keywords
'rating': 4, # Rating (1-5)
'creator': 'Author Name', # Creator/author
'rights': 'Copyright information', # Copyright/license
'create_date': '2025-03-15T12:34:56' # Creation timestamp
}
```
### Analysis Section
Contains analysis results from various tools:
```python
analysis = {
'technical': {
'blur': {
'score': 0.92, # Blur detection score
'higher_better': True # Whether higher is better
},
'noise': {
'score': 0.08, # Noise detection score
'higher_better': False # Whether higher is better
}
},
'aesthetic': {
'composition': 7.8, # Composition score
'color_harmony': 8.2, # Color harmony score
'overall': 7.9 # Overall aesthetic score
},
'pyiqa': {
'niqe': { # No-reference IQA model
'score': 3.45,
'higher_better': False,
'range': [0, 25]
},
'musiq': { # Multi-scale IQA model
'score': 78.2,
'higher_better': True,
'range': [0, 100]
}
},
'classification': {
'style': 'photorealistic', # Detected style
'content_type': 'landscape', # Content type
'has_text': False # Text detection result
}
}
```
### AI Info Section
Contains AI generation information:
```python
ai_info = {
'generation': {
'model': 'stable-diffusion-v1-5', # Base model
'prompt': 'mountain landscape', # Positive prompt
'negative_prompt': 'ugly, blurry', # Negative prompt
'sampler': 'euler_a', # Sampler name
'steps': 30, # Sampling steps
'cfg_scale': 7.5, # CFG scale
'seed': 1234567890, # Generation seed
'width': 512, # Image width
'height': 512, # Image height
'loras': [ # LoRAs used
{
'name': 'example_lora',
'strength': 0.8
}
]
},
'workflow': { # Full workflow data
# ComfyUI workflow data (simplified for brevity)
'nodes': { ... }
}
}
```
### Regions Section
Contains information about specific regions in the image:
```python
regions = {
'faces': [ # Detected faces
{
'type': 'Face',
'name': 'Person 1',
'area': { # Face coordinates
'x': 0.2, # Normalized (0-1)
'y': 0.3,
'w': 0.1,
'h': 0.15
},
'extensions': { # Extended face data
'eiqa': {
'face_analysis': {
'gender': 'female',
'age': 28,
'emotion': 'happy'
}
}
}
}
],
'areas': [ # Other detected areas
{
'type': 'Object',
'name': 'Mountain',
'area': {
'x': 0.1,
'y': 0.2,
'w': 0.8,
'h': 0.5
}
}
],
'summary': { # Summary statistics
'face_count': 1,
'detector_type': 'deepface'
}
}
```
## ComfyUI Node Usage
### Metadata Save Image Node
The `eric_metadata_save_image` node saves images with metadata:
1. Connect your image output to the node's `images` input
2. Connect workflow data (optional) to the `workflow_data` input
3. Set basic parameters:
- `save_path`: Directory to save images
- `filename_prefix`: Prefix for generated filenames
- `filename_number_padding`: Number of digits for sequential numbering
- `filename_number_start`: Starting number for sequential filenames
4. Metadata options:
- `title`: Image title
- `description`: Image description
- `keywords`: Comma-separated keywords
- `save_metadata_to`: Formats to save metadata (embedded,xmp,txt,db)
- `human_readable_text`: Use human-readable text format
This node automatically captures workflow data, generation parameters, and technical image information.
### Metadata Entry Node
The `eric_metadata_entry` node allows adding custom metadata:
1. Connect to any workflow position
2. Fill in metadata fields:
- Basic information (title, description, keywords)
- Analysis scores
- Custom fields
3. Connect to other nodes that process metadata
### Metadata Query Node
The `eric_metadata_query_node` filters and retrieves metadata:
1. Connect to image input
2. Set query parameters:
- `query_type`: Type of query to perform
- `field_path`: Path to the metadata field to query
- `comparison`: Comparison operator (equals, greater_than, etc.)
- `value`: Value to compare against
3. Use outputs:
- `result`: Query result
- `metadata`: Full metadata dictionary
- `image`: Passed-through image
### Workflow Extractor Node
The `eric_workflow_extractor` node extracts workflow data from images:
1. Connect to image input
2. Set extraction parameters:
- `extraction_mode`: How to extract workflow data
- `include_basic_metadata`: Whether to include basic metadata
3. Use outputs:
- `workflow_data`: Extracted workflow JSON
- `metadata`: Full metadata dictionary
- `image`: Passed-through image
## Advanced Features
### Human-readable Text Format
The system can create human-readable text files for easy viewing:
```python
# Enable human-readable text format
service = MetadataService(human_readable_text=True)
# Or change format at runtime
service.set_text_format(human_readable=True)
# Write metadata (will use human-readable format for text files)
service.write_metadata('path/to/image.png', metadata)
```
Example output:
```
Last update: 2025-03-15T10:23:45.123456
Metadata for image.png
Basic Information:
Title: Mountain Landscape
Description: AI generated mountain landscape
Keywords: mountains, landscape, nature, AI
AI Generation Information:
Prompt: majestic mountains with snow caps
Negative prompt: ugly, blurry
Model: stable-diffusion-v1-5
Sampler: euler_a
Steps: 30
Cfg_scale: 7.5
Seed: 1234567890
```
### Database Queries
Perform advanced queries on the database:
```python
from Metadata_system.handlers.db import DatabaseHandler
db = DatabaseHandler()
# Search for high-quality mountain images
results = db.search_images({
'scores': [
('aesthetic', 'overall', '>', 7.0),
('technical', 'blur.score', '>', 0.8)
],
'keywords': ['mountains'],
'classifications': [('style', 'photorealistic')],
'orientation': 'landscape',
'order_by': 'images.created_date DESC',
'limit': 10
})
# Process results
for image in results:
print(f"Found image: {image['filepath']}")
print(f"Rating: {image.get('rating', 'N/A')}")
```
### Resource Identifiers
Set custom resource identifiers for XMP metadata:
```python
# Set resource identifier for all handlers
service.set_resource_identifier("file:///custom/path/to/resource.jpg")
# Write metadata with custom resource identifier
service.write_metadata('path/to/image.jpg', metadata)
```
### Batch Operations
Perform operations on multiple files:
```python
# Using DatabaseHandler for batch operations
from Metadata_system.handlers.db import DatabaseHandler
db = DatabaseHandler()
# Define file paths
file_paths = [
'path/to/image1.png',
'path/to/image2.jpg',
'path/to/image3.webp'
]
# Read metadata from multiple files
results = db.batch_operation('read', file_paths)
# Update metadata for multiple files
new_metadata = {
'basic': {
'keywords': ['batch', 'processed']
}
}
results = db.batch_operation('write', file_paths, new_metadata)
# Check results
for filepath, success in results.items():
print(f"{filepath}: {'Succeeded' if success else 'Failed'}")
```
## Troubleshooting
### Common Issues
**Issue**: Cannot write embedded metadata to PNG file
**Solution**: Ensure PyExiv2 is installed or use ExifTool as a fallback
```python
# Check if PyExiv2 is available
try:
import pyexiv2
print("PyExiv2 is available")
except ImportError:
print("PyExiv2 is not available, using ExifTool fallback")
```
**Issue**: Files not showing metadata in other applications
**Solution**: Verify format compatibility and try XMP sidecars
```python
# Force write to XMP sidecar
service.write_metadata('path/to/image.png', metadata, targets=['xmp'])
```
**Issue**: Database errors
**Solution**: Check SQLite installation and file permissions
```python
# Use try-except to handle database errors
try:
from Metadata_system.handlers.db import DatabaseHandler
db = DatabaseHandler()
# Operations with db
except Exception as e:
print(f"Database error: {str(e)}")
# Fall back to file-based storage
service.write_metadata('path/to/image.png', metadata, targets=['embedded', 'xmp', 'txt'])
```
### Debug Mode
Enable debug mode for detailed logging:
```python
# Initialize with debug mode
service = MetadataService(debug=True)
# Operations will now produce detailed logs
service.write_metadata('path/to/image.png', metadata)
```
Debug logs include:
- Format detection results
- Handler selection details
- Operation traces
- Error messages with stack traces
Access error history from handlers:
```python
# Get embedded handler
embedded_handler = service._get_embedded_handler()
# Print error history
for error in embedded_handler.error_history:
print(f"[{error['timestamp']}] {error['level']}: {error['message']}")
if error['error']:
print(f"Error: {error['error']}")
print("---")
```