#!/usr/bin/env python3 """ ALwrity Backend Server - Comprehensive Startup Script Handles setup, dependency installation, and server startup. Run this from the backend directory to set up and start the FastAPI server. """ import os import sys import subprocess import time import argparse from pathlib import Path def install_requirements(): """Install required Python packages.""" print("šŸ“¦ Installing required packages...") requirements_file = Path(__file__).parent / "requirements.txt" try: subprocess.check_call([ sys.executable, "-m", "pip", "install", "-r", str(requirements_file) ]) print("āœ… All packages installed successfully!") return True except subprocess.CalledProcessError as e: print(f"āŒ Error installing packages: {e}") return False def create_env_file(): """Create a .env file with default configuration.""" env_file = Path(__file__).parent / ".env" if env_file.exists(): print("ā„¹ļø .env file already exists") return True print("šŸ”§ Creating .env file with default configuration...") env_content = """# ALwrity Backend Configuration # API Keys (Configure these in the onboarding process) # OPENAI_API_KEY=your_openai_api_key_here # GEMINI_API_KEY=your_gemini_api_key_here # ANTHROPIC_API_KEY=your_anthropic_api_key_here # MISTRAL_API_KEY=your_mistral_api_key_here # Research API Keys (Optional) # TAVILY_API_KEY=your_tavily_api_key_here # SERPER_API_KEY=your_serper_api_key_here # METAPHOR_API_KEY=your_metaphor_api_key_here # FIRECRAWL_API_KEY=your_firecrawl_api_key_here # Server Configuration HOST=0.0.0.0 PORT=8000 DEBUG=true # Logging LOG_LEVEL=INFO """ try: with open(env_file, 'w') as f: f.write(env_content) print("āœ… .env file created successfully!") return True except Exception as e: print(f"āŒ Error creating .env file: {e}") return False def setup_monitoring_tables(): """Set up API monitoring database tables.""" print("šŸ“Š Setting up API monitoring tables...") try: # Import and run the monitoring table creation sys.path.append(str(Path(__file__).parent)) from scripts.create_monitoring_tables import create_monitoring_tables if create_monitoring_tables(): print("āœ… API monitoring tables created successfully!") return True else: print("āš ļø Warning: Failed to create monitoring tables, continuing anyway...") return True # Don't fail startup for monitoring issues except Exception as e: print(f"āš ļø Warning: Could not set up monitoring tables: {e}") print(" Monitoring will be disabled. Continuing startup...") return True # Don't fail startup for monitoring issues def setup_billing_tables(): """Set up billing and subscription database tables.""" print("šŸ’³ Setting up billing and subscription tables...") try: # Import and run the billing table creation sys.path.append(str(Path(__file__).parent)) from scripts.create_billing_tables import create_billing_tables, check_existing_tables from services.database import DATABASE_URL from sqlalchemy import create_engine # Create engine to check existing tables engine = create_engine(DATABASE_URL, echo=False) # Check existing tables if not check_existing_tables(engine): print("āœ… Billing tables already exist, skipping creation") return True if create_billing_tables(): print("āœ… Billing and subscription tables created successfully!") return True else: print("āš ļø Warning: Failed to create billing tables, continuing anyway...") return True # Don't fail startup for billing issues except Exception as e: print(f"āš ļø Warning: Could not set up billing tables: {e}") print(" Billing system will be disabled. Continuing startup...") return True # Don't fail startup for billing issues def setup_monitoring_middleware(): """Set up monitoring middleware in app.py if not already present.""" print("šŸ” Setting up API monitoring middleware...") app_file = Path(__file__).parent / "app.py" if not app_file.exists(): print("āš ļø Warning: app.py not found, skipping middleware setup") return True try: with open(app_file, 'r') as f: content = f.read() # Check if monitoring middleware is already set up if "monitoring_middleware" in content: print("āœ… Monitoring middleware already configured") return True # Add monitoring middleware import and setup monitoring_import = "from middleware.monitoring_middleware import monitoring_middleware\n" monitoring_setup = "app.middleware(\"http\")(monitoring_middleware)\n" # Find the right place to add the import (after other imports) lines = content.split('\n') import_end_index = 0 for i, line in enumerate(lines): if line.strip().startswith('import ') or line.strip().startswith('from '): import_end_index = i + 1 elif line.strip() and not line.strip().startswith('#'): break # Insert monitoring import lines.insert(import_end_index, monitoring_import) # Find the right place to add middleware setup (after app creation) app_creation_index = -1 for i, line in enumerate(lines): if 'app = FastAPI(' in line or 'app = FastAPI()' in line: app_creation_index = i break if app_creation_index != -1: # Find the end of app configuration setup_index = app_creation_index + 1 for i in range(app_creation_index + 1, len(lines)): if lines[i].strip() and not lines[i].strip().startswith('#'): setup_index = i + 1 break lines.insert(setup_index, monitoring_setup) # Write back to file with open(app_file, 'w') as f: f.write('\n'.join(lines)) print("āœ… Monitoring middleware configured successfully!") return True except Exception as e: print(f"āš ļø Warning: Could not set up monitoring middleware: {e}") print(" Monitoring will be disabled. Continuing startup...") return True # Don't fail startup for monitoring issues def check_dependencies(): """Check if required dependencies are installed.""" print("šŸ” Checking dependencies...") required_packages = [ 'fastapi', 'uvicorn', 'pydantic', 'loguru', 'openai', 'google.generativeai', 'anthropic', 'mistralai', 'sqlalchemy' ] missing_packages = [] for package in required_packages: try: __import__(package.replace('-', '_')) print(f" āœ… {package}") except ImportError: print(f" āŒ {package} - MISSING") missing_packages.append(package) if missing_packages: print(f"\nāŒ Missing packages: {', '.join(missing_packages)}") print("Installing missing packages...") return install_requirements() else: print("\nāœ… All dependencies are available!") return True def setup_environment(): """Set up the environment for the backend.""" print("šŸ”§ Setting up environment...") # Create necessary directories directories = [ "lib/workspace/alwrity_content", "lib/workspace/alwrity_web_research", "lib/workspace/alwrity_prompts", "lib/workspace/alwrity_config" ] for directory in directories: Path(directory).mkdir(parents=True, exist_ok=True) print(f" āœ… Created directory: {directory}") # Create .env file if it doesn't exist create_env_file() # Set up monitoring setup_monitoring_tables() setup_monitoring_middleware() # Set up billing and subscription system setup_billing_tables() # Set up persona tables if setup_persona_tables(): # Verify persona tables were created successfully verify_persona_tables() else: print("āš ļø Warning: Persona tables setup failed, but continuing...") print("āœ… Environment setup complete") def setup_persona_tables(): """Set up persona database tables.""" print("šŸ”§ Setting up persona tables...") try: from services.database import engine from models.persona_models import Base as PersonaBase # Create persona tables PersonaBase.metadata.create_all(bind=engine) print("āœ… Persona tables created successfully") # Verify tables were created from sqlalchemy import inspect inspector = inspect(engine) tables = inspector.get_table_names() persona_tables = [ 'writing_personas', 'platform_personas', 'persona_analysis_results', 'persona_validation_results' ] created_tables = [table for table in persona_tables if table in tables] print(f"āœ… Verified persona tables created: {created_tables}") if len(created_tables) != len(persona_tables): missing = [table for table in persona_tables if table not in created_tables] print(f"āš ļø Warning: Missing persona tables: {missing}") return False return True except Exception as e: print(f"āŒ Error setting up persona tables: {e}") return False def verify_persona_tables(): """Verify that persona tables exist and are accessible.""" print("šŸ” Verifying persona tables...") try: from services.database import get_db_session from models.persona_models import WritingPersona, PlatformPersona, PersonaAnalysisResult, PersonaValidationResult session = get_db_session() if session: # Try to query all persona tables to verify they exist session.query(WritingPersona).first() session.query(PlatformPersona).first() session.query(PersonaAnalysisResult).first() session.query(PersonaValidationResult).first() session.close() print("āœ… All persona tables verified successfully") return True else: print("āš ļø Warning: Could not get database session") return False except Exception as e: print(f"āš ļø Warning: Could not verify persona tables: {e}") return False def verify_billing_tables(): """Verify that billing and subscription tables exist and are accessible.""" print("šŸ” Verifying billing and subscription tables...") try: from services.database import get_db_session from models.subscription_models import ( SubscriptionPlan, UserSubscription, APIUsageLog, UsageSummary, APIProviderPricing, UsageAlert ) session = get_db_session() if session: # Try to query all billing tables to verify they exist session.query(SubscriptionPlan).first() session.query(UserSubscription).first() session.query(APIUsageLog).first() session.query(UsageSummary).first() session.query(APIProviderPricing).first() session.query(UsageAlert).first() session.close() print("āœ… All billing and subscription tables verified successfully") return True else: print("āš ļø Warning: Could not get database session") return False except Exception as e: print(f"āš ļø Warning: Could not verify billing tables: {e}") return False def start_backend(enable_reload=False): """Start the backend server.""" print("šŸš€ Starting ALwrity Backend...") # Set environment variables os.environ.setdefault("HOST", "0.0.0.0") os.environ.setdefault("PORT", "8000") # Set reload based on argument or environment variable if enable_reload: os.environ.setdefault("RELOAD", "true") print(" šŸ”„ Development mode: Auto-reload enabled") else: os.environ.setdefault("RELOAD", "false") print(" šŸ­ Production mode: Auto-reload disabled") host = os.getenv("HOST", "0.0.0.0") port = int(os.getenv("PORT", "8000")) reload = os.getenv("RELOAD", "false").lower() == "true" print(f" šŸ“ Host: {host}") print(f" šŸ”Œ Port: {port}") print(f" šŸ”„ Reload: {reload}") try: # Import and run the app from app import app from services.database import init_database import uvicorn # Explicitly initialize database before starting server print("šŸ—„ļø Initializing database...") init_database() print("āœ… Database initialized successfully") # Verify persona tables exist verify_persona_tables() # Verify billing tables exist verify_billing_tables() print("\n🌐 Backend is starting...") print(" šŸ“– API Documentation: http://localhost:8000/api/docs") print(" šŸ” Health Check: http://localhost:8000/health") print(" šŸ“Š ReDoc: http://localhost:8000/api/redoc") print(" šŸ“ˆ API Monitoring: http://localhost:8000/api/content-planning/monitoring/health") print(" šŸ’³ Billing Dashboard: http://localhost:8000/api/subscription/plans") print(" šŸ“Š Usage Tracking: http://localhost:8000/api/subscription/usage/demo") print("\nā¹ļø Press Ctrl+C to stop the server") print("=" * 60) print("\nšŸ’” Usage:") print(" Production mode (default): python start_alwrity_backend.py") print(" Development mode: python start_alwrity_backend.py --dev") print(" With auto-reload: python start_alwrity_backend.py --reload") print("=" * 60) uvicorn.run( "app:app", host=host, port=port, reload=reload, reload_excludes=[ "*.pyc", "*.pyo", "*.pyd", "__pycache__", "*.log", "*.sqlite", "*.db", "*.tmp", "*.temp", "test_*.py", "temp_*.py", "monitoring_data_service.py", "test_monitoring_save.py", "*.json", "*.yaml", "*.yml", ".env*", "logs/*", "cache/*", "tmp/*", "temp/*", "middleware/*", "models/*", "scripts/*" ], reload_includes=[ "app.py", "api/**/*.py", "services/**/*.py" ], log_level="info" ) except KeyboardInterrupt: print("\n\nšŸ›‘ Backend stopped by user") except Exception as e: print(f"\nāŒ Error starting backend: {e}") return False return True def main(): """Main function to set up and start the backend.""" # Parse command line arguments parser = argparse.ArgumentParser(description="ALwrity Backend Server") parser.add_argument("--reload", action="store_true", help="Enable auto-reload for development") parser.add_argument("--dev", action="store_true", help="Enable development mode (auto-reload)") args = parser.parse_args() print("šŸŽÆ ALwrity Backend Server") print("=" * 40) # Check if we're in the right directory if not os.path.exists("app.py"): print("āŒ Error: app.py not found. Please run this script from the backend directory.") print(" Current directory:", os.getcwd()) print(" Expected files:", [f for f in os.listdir('.') if f.endswith('.py')]) return False # Check and install dependencies if not check_dependencies(): print("āŒ Failed to install dependencies") return False # Setup environment setup_environment() # Start backend with reload option enable_reload = args.reload or args.dev return start_backend(enable_reload=enable_reload) if __name__ == "__main__": success = main() if not success: sys.exit(1)