- Add default_config.yaml with customizable settings - Model selection (minicpm-v, llama3.2-vision, llava) - Customizable vision prompt for better responses - Timing parameters (idle threshold, response delay) - Approval keywords configuration - User config at ~/.config/claude-vision-auto/config.yaml - New command: claude-vision-config to generate user config - Environment variables still override config files - Added PyYAML dependency Configuration priority: 1. Environment variables (highest) 2. User config (~/.config/claude-vision-auto/config.yaml) 3. Default config (package default) Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Jean-Philippe Brule <jp@svrnty.io>
172 lines
5.4 KiB
Python
172 lines
5.4 KiB
Python
"""
|
||
Configuration for Claude Vision Auto
|
||
"""
|
||
|
||
import os
|
||
import yaml
|
||
from pathlib import Path
|
||
from typing import Dict, Any
|
||
|
||
|
||
def get_config_dir() -> Path:
|
||
"""Get configuration directory"""
|
||
config_dir = Path.home() / ".config" / "claude-vision-auto"
|
||
config_dir.mkdir(parents=True, exist_ok=True)
|
||
return config_dir
|
||
|
||
|
||
def get_cache_dir() -> Path:
|
||
"""Get cache directory for screenshots"""
|
||
cache_dir = Path.home() / ".cache" / "claude-vision-auto"
|
||
cache_dir.mkdir(parents=True, exist_ok=True)
|
||
return cache_dir
|
||
|
||
|
||
def load_config() -> Dict[str, Any]:
|
||
"""
|
||
Load configuration from YAML files with priority:
|
||
1. User config (~/.config/claude-vision-auto/config.yaml)
|
||
2. Default config (package default_config.yaml)
|
||
3. Environment variables (highest priority)
|
||
"""
|
||
# Load default config
|
||
default_config_path = Path(__file__).parent / "default_config.yaml"
|
||
with open(default_config_path, 'r') as f:
|
||
config = yaml.safe_load(f)
|
||
|
||
# Load user config if exists
|
||
user_config_path = get_config_dir() / "config.yaml"
|
||
if user_config_path.exists():
|
||
with open(user_config_path, 'r') as f:
|
||
user_config = yaml.safe_load(f)
|
||
# Deep merge user config
|
||
if user_config:
|
||
config = deep_merge(config, user_config)
|
||
|
||
# Override with environment variables
|
||
if os.getenv("OLLAMA_URL"):
|
||
config['ollama']['url'] = os.getenv("OLLAMA_URL")
|
||
if os.getenv("VISION_MODEL"):
|
||
config['ollama']['model'] = os.getenv("VISION_MODEL")
|
||
if os.getenv("IDLE_THRESHOLD"):
|
||
config['timing']['idle_threshold'] = float(os.getenv("IDLE_THRESHOLD"))
|
||
if os.getenv("RESPONSE_DELAY"):
|
||
config['timing']['response_delay'] = float(os.getenv("RESPONSE_DELAY"))
|
||
if os.getenv("DEBUG"):
|
||
config['debug'] = os.getenv("DEBUG", "false").lower() in ("true", "1", "yes")
|
||
|
||
return config
|
||
|
||
|
||
def deep_merge(base: Dict, override: Dict) -> Dict:
|
||
"""Deep merge two dictionaries"""
|
||
result = base.copy()
|
||
for key, value in override.items():
|
||
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 create_user_config():
|
||
"""Create user config file with defaults"""
|
||
config_dir = get_config_dir()
|
||
user_config_path = config_dir / "config.yaml"
|
||
|
||
if not user_config_path.exists():
|
||
# Copy default config to user config
|
||
default_config_path = Path(__file__).parent / "default_config.yaml"
|
||
with open(default_config_path, 'r') as f:
|
||
default_content = f.read()
|
||
|
||
with open(user_config_path, 'w') as f:
|
||
f.write(default_content)
|
||
|
||
return user_config_path
|
||
return None
|
||
|
||
|
||
def create_user_config_cli():
|
||
"""CLI command to create user configuration file"""
|
||
import sys
|
||
|
||
config_path = create_user_config()
|
||
|
||
if config_path:
|
||
print(f"✅ Created user configuration file:")
|
||
print(f" {config_path}")
|
||
print()
|
||
print("Edit this file to customize:")
|
||
print(f" - Vision model (minicpm-v, llama3.2-vision, llava)")
|
||
print(f" - Vision prompt for better responses")
|
||
print(f" - Timing settings (idle threshold, response delay)")
|
||
print(f" - Approval keywords")
|
||
print()
|
||
print(f"Edit with: nano {config_path}")
|
||
else:
|
||
config_dir = get_config_dir()
|
||
config_path = config_dir / "config.yaml"
|
||
print(f"ℹ️ Configuration file already exists:")
|
||
print(f" {config_path}")
|
||
print()
|
||
print(f"Edit with: nano {config_path}")
|
||
|
||
sys.exit(0)
|
||
|
||
|
||
# Load configuration
|
||
_config = load_config()
|
||
|
||
# Export commonly used values
|
||
OLLAMA_URL = _config['ollama']['url']
|
||
VISION_MODEL = _config['ollama']['model']
|
||
VISION_TIMEOUT = _config['ollama']['timeout']
|
||
|
||
IDLE_THRESHOLD = _config['timing']['idle_threshold']
|
||
RESPONSE_DELAY = _config['timing']['response_delay']
|
||
SCREENSHOT_TIMEOUT = _config['timing']['screenshot_timeout']
|
||
|
||
VISION_PROMPT = _config['vision_prompt']
|
||
RESPONSE_MAPPING = _config['response_mapping']
|
||
APPROVAL_KEYWORDS = _config['approval_keywords']
|
||
|
||
OUTPUT_BUFFER_SIZE = _config['buffer']['size']
|
||
SCREENSHOT_TOOLS = _config['screenshot']['tools']
|
||
SCREENSHOT_CACHE_CLEANUP = _config['screenshot']['cache_cleanup_seconds']
|
||
|
||
DEBUG = _config['debug']
|
||
|
||
|
||
def get_config() -> Dict[str, Any]:
|
||
"""Get full configuration dict"""
|
||
return _config.copy()
|
||
|
||
|
||
def reload_config():
|
||
"""Reload configuration from files"""
|
||
global _config, OLLAMA_URL, VISION_MODEL, VISION_TIMEOUT
|
||
global IDLE_THRESHOLD, RESPONSE_DELAY, SCREENSHOT_TIMEOUT
|
||
global VISION_PROMPT, RESPONSE_MAPPING, APPROVAL_KEYWORDS
|
||
global OUTPUT_BUFFER_SIZE, SCREENSHOT_TOOLS, SCREENSHOT_CACHE_CLEANUP, DEBUG
|
||
|
||
_config = load_config()
|
||
|
||
OLLAMA_URL = _config['ollama']['url']
|
||
VISION_MODEL = _config['ollama']['model']
|
||
VISION_TIMEOUT = _config['ollama']['timeout']
|
||
|
||
IDLE_THRESHOLD = _config['timing']['idle_threshold']
|
||
RESPONSE_DELAY = _config['timing']['response_delay']
|
||
SCREENSHOT_TIMEOUT = _config['timing']['screenshot_timeout']
|
||
|
||
VISION_PROMPT = _config['vision_prompt']
|
||
RESPONSE_MAPPING = _config['response_mapping']
|
||
APPROVAL_KEYWORDS = _config['approval_keywords']
|
||
|
||
OUTPUT_BUFFER_SIZE = _config['buffer']['size']
|
||
SCREENSHOT_TOOLS = _config['screenshot']['tools']
|
||
SCREENSHOT_CACHE_CLEANUP = _config['screenshot']['cache_cleanup_seconds']
|
||
|
||
DEBUG = _config['debug']
|