Automate SAM download and fix database path issues

- Fix database path mismatch: download_sample_eyes.py now uses
  ai_photo_edit.db instead of photoedit.db
- Add init_database.py script to initialize DB before eye import
- Add AUTO_DOWNLOAD_SAM=true environment variable (default: enabled)
- Update entrypoint.sh to:
  1. Initialize database first
  2. Auto-download SAM model (~375MB) on first startup
  3. Then import eyes (now works since DB exists)
- Update path detection to work in both Docker and local environments
This commit is contained in:
Claude
2026-01-25 20:28:57 +00:00
parent 70cd0d6ea3
commit df4ddc2d8c
5 changed files with 123 additions and 32 deletions
+6 -1
View File
@@ -116,7 +116,12 @@ SECRET_KEY=change-this-to-a-long-random-string-in-production
CORS_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost:3080,http://localhost CORS_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost:3080,http://localhost
# Database path # Database path
DATABASE_URL=sqlite:///./data/photoedit.db DATABASE_URL=sqlite:///./data/ai_photo_edit.db
# Auto-download SAM model on startup (true/false)
# When true (default): Downloads SAM model (~375MB) on first startup for offline Smart Select
# When false: Skips download, Smart Select uses Replicate API (requires REPLICATE_API_KEY)
AUTO_DOWNLOAD_SAM=true
# Allow users to select model per-edit # Allow users to select model per-edit
ALLOW_MODEL_OVERRIDE=true ALLOW_MODEL_OVERRIDE=true
+47 -24
View File
@@ -3,9 +3,10 @@
# AI Photo Edit - Container Startup Script # AI Photo Edit - Container Startup Script
# ============================================================================= # =============================================================================
# This script runs when the container starts. It: # This script runs when the container starts. It:
# 1. Downloads sample eye images if the catalog is empty # 1. Initializes the database
# 2. Ensures all directories exist # 2. Downloads SAM model automatically (can be disabled with AUTO_DOWNLOAD_SAM=false)
# 3. Starts the FastAPI server # 3. Downloads sample eye images if the catalog is empty
# 4. Starts the FastAPI server
# ============================================================================= # =============================================================================
set -e set -e
@@ -18,18 +19,15 @@ echo "=========================================="
mkdir -p /app/data/projects mkdir -p /app/data/projects
mkdir -p /app/data/patches mkdir -p /app/data/patches
mkdir -p /app/data/models mkdir -p /app/data/models
mkdir -p /app/data/patch_library
# Check if eye catalog needs to be populated # Initialize database FIRST (before eye import)
echo "Checking eye catalog..." echo ""
PATCHES_COUNT=$(find /app/data/patches -maxdepth 1 -type d | wc -l) echo "Initializing database..."
echo "------------------------------------------"
if [ "$PATCHES_COUNT" -le 1 ]; then cd /app && python /scripts/init_database.py || echo "Warning: Database init failed (non-fatal)"
echo "Eye catalog is empty. Downloading sample eyes..."
python /scripts/download_sample_eyes.py || echo "Warning: Could not download sample eyes (non-fatal)"
else
echo "Eye catalog has content, skipping download."
fi
# Check and download SAM model automatically
echo "" echo ""
echo "Checking SAM model (Smart Select)..." echo "Checking SAM model (Smart Select)..."
echo "------------------------------------------" echo "------------------------------------------"
@@ -39,17 +37,42 @@ if [ -f "/app/data/models/sam_model.pth" ] || \
[ -f "/app/data/models/sam_vit_h_4b8939.pth" ]; then [ -f "/app/data/models/sam_vit_h_4b8939.pth" ]; then
echo "✓ SAM model found - Smart Select will use local AI (free, offline)" echo "✓ SAM model found - Smart Select will use local AI (free, offline)"
else else
echo "" # Auto-download SAM unless explicitly disabled
echo "⚠ SAM model not found" AUTO_DOWNLOAD_SAM="${AUTO_DOWNLOAD_SAM:-true}"
echo "" if [ "$AUTO_DOWNLOAD_SAM" = "true" ]; then
echo " Smart Select will use Replicate API (requires REPLICATE_API_KEY)" echo "SAM model not found. Downloading automatically..."
echo "" echo "(This is a one-time ~375MB download that persists across rebuilds)"
echo " To enable FREE offline Smart Select, run:" echo ""
echo " docker exec -it ai-photo-edit-backend python /scripts/download_sam_model.py" python /scripts/download_sam_model.py vit_b || {
echo "" echo ""
echo " Model sizes: vit_b (375MB), vit_l (1.2GB), vit_h (2.5GB)" echo "⚠ SAM download failed (non-fatal)"
echo " The model persists across container rebuilds." echo " Smart Select will fall back to Replicate API (requires REPLICATE_API_KEY)"
echo "" echo " To retry later: docker exec -it ai-photo-edit-backend python /scripts/download_sam_model.py"
}
else
echo ""
echo "⚠ SAM model not found (AUTO_DOWNLOAD_SAM=false)"
echo ""
echo " Smart Select will use Replicate API (requires REPLICATE_API_KEY)"
echo ""
echo " To enable FREE offline Smart Select, run:"
echo " docker exec -it ai-photo-edit-backend python /scripts/download_sam_model.py"
echo ""
fi
fi
# Check if eye catalog needs to be populated
echo ""
echo "Checking eye catalog..."
echo "------------------------------------------"
PATCHES_COUNT=$(find /app/data/patches -maxdepth 1 -type d 2>/dev/null | wc -l)
DB_PATCHES_COUNT=$(sqlite3 /app/data/ai_photo_edit.db "SELECT COUNT(*) FROM patches;" 2>/dev/null || echo "0")
if [ "$DB_PATCHES_COUNT" = "0" ] || [ "$PATCHES_COUNT" -le 1 ]; then
echo "Eye catalog is empty. Downloading sample eyes..."
cd /app && python /scripts/download_sample_eyes.py || echo "Warning: Could not download sample eyes (non-fatal)"
else
echo "✓ Eye catalog has $DB_PATCHES_COUNT patches"
fi fi
echo "" echo ""
+1
View File
@@ -20,6 +20,7 @@ services:
- STABILITY_API_KEY=${STABILITY_API_KEY:-} - STABILITY_API_KEY=${STABILITY_API_KEY:-}
- REPLICATE_API_KEY=${REPLICATE_API_KEY:-} - REPLICATE_API_KEY=${REPLICATE_API_KEY:-}
- CORS_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost - CORS_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost
- AUTO_DOWNLOAD_SAM=${AUTO_DOWNLOAD_SAM:-true}
restart: unless-stopped restart: unless-stopped
networks: networks:
- ai-photo-edit-network - ai-photo-edit-network
+24 -7
View File
@@ -106,17 +106,34 @@ def import_eye_to_database(db_path: Path, eye_data: dict, patch_path: str, thumb
return patch_id return patch_id
def main(): def main():
# Determine paths # Determine paths - handle both Docker and local environments
script_dir = Path(__file__).parent # In Docker: script is at /scripts/, data is at /app/data/
project_root = script_dir.parent # Locally: script is at ./scripts/, data is at ./data/
data_dir = project_root / 'data' docker_data_dir = Path('/app/data')
db_path = data_dir / 'photoedit.db' local_data_dir = Path(__file__).parent.parent / 'data'
if docker_data_dir.exists():
data_dir = docker_data_dir
else:
data_dir = local_data_dir
db_path = data_dir / 'ai_photo_edit.db'
# Check if database exists # Check if database exists
if not db_path.exists(): if not db_path.exists():
print(f"Database not found at {db_path}") print(f"Database not found at {db_path}")
print("Please start the backend first to initialize the database.") print("Attempting to initialize database...")
sys.exit(1) # Try to import and initialize database
try:
sys.path.insert(0, str(Path('/app')))
sys.path.insert(0, str(Path(__file__).parent.parent / 'backend'))
from app.database import init_db
init_db()
print("Database initialized successfully.")
except Exception as e:
print(f"Could not initialize database: {e}")
print("Please start the backend first to initialize the database.")
sys.exit(1)
print(f"Using database: {db_path}") print(f"Using database: {db_path}")
print(f"Data directory: {data_dir}") print(f"Data directory: {data_dir}")
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
Initialize the database before other startup scripts run.
This ensures the database exists and has all required tables
before download_sample_eyes.py tries to use it.
"""
import os
import sys
from pathlib import Path
# Add backend to path - handle both Docker and local environments
# In Docker: backend is at /app/
# Locally: backend is at ./backend/
if Path('/app').exists():
sys.path.insert(0, '/app')
else:
sys.path.insert(0, str(Path(__file__).parent.parent / 'backend'))
def main():
# Import after path setup
from app.database import engine, Base, init_db
from app.models import project, user, patch
print("Initializing database...")
# Create all tables
init_db()
# Verify database was created - check both Docker and local paths
docker_db_path = Path('/app/data/ai_photo_edit.db')
local_db_path = Path('./data/ai_photo_edit.db')
if docker_db_path.exists():
print(f"✓ Database initialized at: {docker_db_path}")
elif local_db_path.exists():
print(f"✓ Database initialized at: {local_db_path}")
else:
print("⚠ Database file not found at expected locations, but tables may still be created")
print("Database initialization complete.")
if __name__ == '__main__':
main()