Files
Eric Rollei 1f9fa9b670 Add backward compatibility, XMP regions, per-node hooks toggle, and enhancements
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
2025-11-20 01:26:04 -08:00

207 lines
5.3 KiB
Python

"""Configuration loader for AAA Metadata System."""
import json
import os
from pathlib import Path
from typing import Any, Dict, Optional
_CONFIG_CACHE: Optional[Dict[str, Any]] = None
_CONFIG_PATH: Optional[Path] = None
def get_config_path() -> Path:
"""Get the path to the config.json file."""
global _CONFIG_PATH
if _CONFIG_PATH is not None:
return _CONFIG_PATH
# Get the root directory of the AAA_Metadata_System
current_file = Path(__file__).resolve()
root_dir = current_file.parent.parent
config_path = root_dir / "config.json"
_CONFIG_PATH = config_path
return config_path
def load_config() -> Dict[str, Any]:
"""
Load configuration from config.json file.
Returns:
dict: Configuration dictionary with defaults for missing values
"""
global _CONFIG_CACHE
# Return cached config if available
if _CONFIG_CACHE is not None:
return _CONFIG_CACHE
# Default configuration
default_config = {
"runtime_hooks": {
"enabled": False,
"log_disagreements": False,
"log_performance": False,
"inline_size_limit_kb": 32
},
"debug": {
"enabled": False
},
"metadata": {
"enable_hash_cache": True
}
}
config_path = get_config_path()
# Try to load config file
if config_path.exists():
try:
with open(config_path, 'r', encoding='utf-8') as f:
file_config = json.load(f)
# Merge with defaults (file config takes precedence)
merged_config = _deep_merge(default_config, file_config)
_CONFIG_CACHE = merged_config
return merged_config
except Exception as e:
print(f"[AAA Metadata Config] Warning: Failed to load config.json: {e}")
print(f"[AAA Metadata Config] Using default configuration")
# No config file or failed to load - use defaults
_CONFIG_CACHE = default_config
return default_config
def _deep_merge(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
"""
Deep merge two dictionaries, with override values taking precedence.
Args:
base: Base dictionary with defaults
override: Override dictionary with user values
Returns:
dict: Merged dictionary
"""
result = base.copy()
for key, value in override.items():
# Skip comment fields
if key.startswith('_'):
continue
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = _deep_merge(result[key], value)
else:
result[key] = value
return result
def get_runtime_hooks_enabled() -> bool:
"""
Check if runtime hooks should be enabled.
Priority order:
1. Environment variable AAA_METADATA_ENABLE_HOOKS
2. config.json runtime_hooks.enabled setting
3. Default: False
Returns:
bool: True if runtime hooks should be enabled
"""
# Check environment variable first (highest priority)
env_value = os.environ.get("AAA_METADATA_ENABLE_HOOKS", "").strip().lower()
if env_value in {"1", "true", "yes", "on"}:
return True
if env_value in {"0", "false", "no", "off"}:
return False
# Check config file
config = load_config()
return config.get("runtime_hooks", {}).get("enabled", False)
def get_debug_enabled() -> bool:
"""
Check if debug mode should be enabled.
Returns:
bool: True if debug mode should be enabled
"""
config = load_config()
return config.get("debug", {}).get("enabled", False)
def get_hash_cache_enabled() -> bool:
"""
Check if hash caching should be enabled.
Returns:
bool: True if hash caching should be enabled
"""
config = load_config()
return config.get("metadata", {}).get("enable_hash_cache", True)
def get_runtime_log_disagreements() -> bool:
"""
Check if parser/hook disagreements should be logged.
Returns:
bool: True if disagreements should be logged
"""
config = load_config()
return config.get("runtime_hooks", {}).get("log_disagreements", False)
def get_runtime_log_performance() -> bool:
"""
Check if runtime performance metrics should be logged.
Returns:
bool: True if performance should be logged
"""
config = load_config()
return config.get("runtime_hooks", {}).get("log_performance", False)
def get_runtime_inline_limit() -> int:
"""
Get the inline size limit for runtime data in bytes.
Returns:
int: Size limit in bytes (default 32KB)
"""
config = load_config()
limit_kb = config.get("runtime_hooks", {}).get("inline_size_limit_kb", 32)
return limit_kb * 1024
def reload_config() -> Dict[str, Any]:
"""
Reload configuration from disk, clearing the cache.
Returns:
dict: Reloaded configuration
"""
global _CONFIG_CACHE
_CONFIG_CACHE = None
return load_config()
__all__ = [
"load_config",
"get_config_path",
"get_runtime_hooks_enabled",
"get_debug_enabled",
"get_hash_cache_enabled",
"get_runtime_log_disagreements",
"get_runtime_log_performance",
"get_runtime_inline_limit",
"reload_config",
]