File size: 6,202 Bytes
84b0fa3 276a5e7 84b0fa3 276a5e7 84b0fa3 976eb67 276a5e7 84b0fa3 276a5e7 84b0fa3 276a5e7 976eb67 276a5e7 84b0fa3 276a5e7 84b0fa3 276a5e7 84b0fa3 276a5e7 976eb67 276a5e7 84b0fa3 276a5e7 84b0fa3 276a5e7 84b0fa3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
"""
Robust startup script for Hugging Face Spaces deployment.
Initializes the database and starts the FastAPI server with comprehensive error handling.
"""
import os
import sys
import time
import logging
import asyncio
from pathlib import Path
import subprocess
from datetime import datetime
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/startup.log'),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
def check_environment():
"""Check if required environment variables are set."""
logger.info("π Checking environment variables...")
required_vars = ['OPENAI_API_KEY', 'OPENROUTER_API_KEY']
missing_vars = []
for var in required_vars:
if not os.getenv(var):
missing_vars.append(var)
logger.error(f"β {var} is not set")
else:
logger.info(f"β
{var} is set")
# Optional variables
optional_vars = ['DATABASE_URL', 'QDRANT_URL', 'HF_SPACE_ID']
for var in optional_vars:
if os.getenv(var):
logger.info(f"β
{var} is set")
else:
logger.info(f"β οΈ {var} is not set (optional)")
if missing_vars:
logger.error(f"β Missing required environment variables: {missing_vars}")
return False
return True
def initialize_database():
"""Initialize the database with retries."""
logger.info("π¦ Initializing database...")
max_retries = 3
for attempt in range(max_retries):
try:
# Check if init_database.py exists
if not Path("init_database.py").exists():
logger.warning("β οΈ init_database.py not found, skipping database initialization")
return True
result = subprocess.run(
[sys.executable, "init_database.py"],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
logger.info("β
Database initialization completed successfully!")
if result.stdout:
logger.info(f"Database init output: {result.stdout}")
return True
else:
logger.error(f"β οΈ Database initialization attempt {attempt + 1} failed: {result.stderr}")
if attempt < max_retries - 1:
time.sleep(2)
except subprocess.TimeoutExpired:
logger.error(f"β οΈ Database initialization timeout on attempt {attempt + 1}")
if attempt < max_retries - 1:
time.sleep(2)
except Exception as e:
logger.error(f"β οΈ Database initialization error on attempt {attempt + 1}: {str(e)}")
if attempt < max_retries - 1:
time.sleep(2)
logger.error("β Database initialization failed after all attempts")
return False
def verify_database_file():
"""Check if database file exists and is accessible."""
db_path = Path("database/auth.db")
if db_path.exists():
try:
size = db_path.stat().st_size
logger.info(f"β
Database file found! Size: {size} bytes")
return True
except Exception as e:
logger.error(f"β Error accessing database file: {str(e)}")
return False
else:
logger.info("β οΈ Database file not found. The server will create it on startup.")
return True
def create_directories():
"""Create necessary directories."""
directories = ['database', 'logs', '.cache/huggingface', '.cache/transformers']
for directory in directories:
Path(directory).mkdir(parents=True, exist_ok=True)
logger.info(f"β
Directory {directory} ready")
def start_server():
"""Start the FastAPI server with error handling."""
logger.info("π Starting FastAPI server...")
# Get port from environment or use default
port = int(os.getenv('PORT', 7860))
host = os.getenv('HOST', '0.0.0.0')
workers = int(os.getenv('WORKERS', 1))
cmd = [
sys.executable, "-m", "uvicorn",
"main:app",
"--host", host,
"--port", str(port),
"--workers", str(workers),
"--log-level", "info",
"--access-log"
]
logger.info(f"Command: {' '.join(cmd)}")
try:
# Replace current process with uvicorn
os.execvp(sys.executable, cmd)
except Exception as e:
logger.error(f"β Failed to start server: {str(e)}")
sys.exit(1)
def main():
"""Main startup function."""
logger.info("π Starting server initialization for Hugging Face Spaces...")
logger.info(f"π
Timestamp: {datetime.utcnow().isoformat()}")
logger.info(f"π Python version: {sys.version}")
logger.info(f"π Working directory: {os.getcwd()}")
# Change to backend directory if needed
if os.path.exists("backend") and not os.getcwd().endswith("backend"):
os.chdir("backend")
logger.info(f"Changed to backend directory: {os.getcwd()}")
try:
# Create necessary directories
create_directories()
# Check environment
if not check_environment():
logger.error("β Environment check failed. Exiting...")
sys.exit(1)
# Initialize database
if not initialize_database():
logger.error("β Database initialization failed. Continuing anyway...")
# Verify database file
verify_database_file()
# Print final status
logger.info("π Initialization completed successfully!")
logger.info(f"π Environment: {'HF Spaces' if os.getenv('SPACE_ID') else 'Local'}")
logger.info(f"π§ Port: {os.getenv('PORT', 7860)}")
# Start server
start_server()
except KeyboardInterrupt:
logger.info("βΉοΈ Startup interrupted by user")
sys.exit(0)
except Exception as e:
logger.error(f"π₯ Fatal error during startup: {str(e)}", exc_info=True)
sys.exit(1)
if __name__ == "__main__":
main() |