Files
gh-christianlouis-docuelevate/app/utils/setup_wizard.py
2026-02-23 20:06:57 +00:00

204 lines
6.6 KiB
Python

"""
Setup wizard utilities for first-time system configuration.
Detects if the system needs initial setup and provides required settings list.
"""
import logging
from typing import Any, Dict, List
from app.config import settings
logger = logging.getLogger(__name__)
def get_required_settings() -> List[Dict[str, Any]]:
"""
Get list of settings that are absolutely required for the system to operate.
Returns:
List of required setting definitions with metadata
"""
return [
{
"key": "database_url",
"label": "Database URL",
"description": "Database connection string (e.g., sqlite:///./app/database.db)",
"type": "string",
"sensitive": False,
"default": "sqlite:///./app/database.db",
"wizard_step": 1,
"wizard_category": "Core Infrastructure",
},
{
"key": "redis_url",
"label": "Redis URL",
"description": "Redis connection for task queue (e.g., redis://localhost:6379/0)",
"type": "string",
"sensitive": False,
"default": "redis://localhost:6379/0",
"wizard_step": 1,
"wizard_category": "Core Infrastructure",
},
{
"key": "workdir",
"label": "Working Directory",
"description": "Directory for temporary file storage and processing",
"type": "string",
"sensitive": False,
"default": "/workdir",
"wizard_step": 1,
"wizard_category": "Core Infrastructure",
},
{
"key": "gotenberg_url",
"label": "Gotenberg URL",
"description": "Gotenberg service URL for document conversion",
"type": "string",
"sensitive": False,
"default": "http://gotenberg:3000",
"wizard_step": 1,
"wizard_category": "Core Infrastructure",
},
{
"key": "session_secret",
"label": "Session Secret",
"description": "Secret key for session encryption (min 32 characters, auto-generate recommended)",
"type": "string",
"sensitive": True,
"default": None, # Should be generated
"wizard_step": 2,
"wizard_category": "Security",
},
{
"key": "admin_username",
"label": "Admin Username",
"description": "Username for the admin account",
"type": "string",
"sensitive": False,
"default": "admin",
"wizard_step": 2,
"wizard_category": "Security",
},
{
"key": "admin_password",
"label": "Admin Password",
"description": "Password for the admin account",
"type": "string",
"sensitive": True,
"default": None, # Must be set
"wizard_step": 2,
"wizard_category": "Security",
},
{
"key": "ai_provider",
"label": "AI Provider",
"description": "AI provider for metadata extraction and OCR refinement (openai, azure, anthropic, gemini, ollama, openrouter, portkey, litellm)",
"type": "string",
"sensitive": False,
"default": "openai",
"options": ["openai", "azure", "anthropic", "gemini", "ollama", "openrouter", "portkey", "litellm"],
"wizard_step": 3,
"wizard_category": "AI Services",
},
{
"key": "openai_api_key",
"label": "API Key (OpenAI / Azure / LiteLLM)",
"description": "API key for OpenAI, Azure OpenAI, or LiteLLM (not required for Ollama)",
"type": "string",
"sensitive": True,
"default": None,
"wizard_step": 3,
"wizard_category": "AI Services",
},
{
"key": "openai_model",
"label": "Default Model",
"description": "Model name used when AI_MODEL is not set (e.g. gpt-4o-mini, claude-3-5-sonnet-20241022, llama3.2)",
"type": "string",
"sensitive": False,
"default": "gpt-4o-mini",
"wizard_step": 3,
"wizard_category": "AI Services",
},
]
def is_setup_required() -> bool:
"""
Check if the system requires initial setup.
Returns True if any critical required settings are missing or have placeholder values.
Returns:
True if setup wizard should be shown, False otherwise
"""
try:
# Critical settings that must be configured
critical_settings = [
("session_secret", ["INSECURE_DEFAULT_FOR_DEVELOPMENT_ONLY_DO_NOT_USE_IN_PRODUCTION_MINIMUM_32_CHARS"]),
("admin_password", [None, "", "your_secure_password", "changeme", "admin"]),
]
for setting_key, invalid_values in critical_settings:
value = getattr(settings, setting_key, None)
if value in invalid_values:
logger.warning(f"Setup required: {setting_key} has placeholder or missing value")
return True
# All critical settings are configured
return False
except Exception as e:
logger.error(f"Error checking if setup required: {e}")
# If we can't check, assume setup is not required (fail open)
return False
def get_missing_required_settings() -> List[str]:
"""
Get list of required settings that are missing or have placeholder values.
Returns:
List of setting keys that need to be configured
"""
missing = []
for required_setting in get_required_settings():
key = required_setting["key"]
value = getattr(settings, key, None)
# Check if value is missing or is a placeholder
placeholder_values = [
None,
"",
f"<{key.upper()}>",
"test-key",
"your_secure_password",
"changeme",
"INSECURE_DEFAULT_FOR_DEVELOPMENT_ONLY_DO_NOT_USE_IN_PRODUCTION_MINIMUM_32_CHARS",
]
if value in placeholder_values:
missing.append(key)
return missing
def get_wizard_steps() -> Dict[int, List[Dict[str, Any]]]:
"""
Get setup wizard steps organized by step number.
Returns:
Dictionary mapping step number to list of settings in that step
"""
steps = {}
for setting in get_required_settings():
step_num = setting.get("wizard_step", 1)
if step_num not in steps:
steps[step_num] = []
steps[step_num].append(setting)
return steps