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:
+6
-1
@@ -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
@@ -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 ""
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}")
|
||||||
|
|||||||
@@ -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()
|
||||||
Reference in New Issue
Block a user