#!/usr/bin/env python3 """ Complete Supabase Setup Script for Unified Assistant Handles both local testing and Hugging Face deployment configuration """ import os import sys import asyncio import secrets from pathlib import Path from urllib.parse import urlparse def print_banner(): """Print setup banner.""" print("Unified Assistant - Complete Supabase Setup") print("=" * 60) print("This script will help you set up Supabase for both") print("local testing and Hugging Face deployment.") print() def get_user_input(prompt, default="", required=False, secret=False): """Get user input with validation.""" while True: if secret: import getpass value = getpass.getpass(prompt) else: value = input(prompt) if not value and required: print("[ERROR] This field is required. Please enter a value.") continue if not value and default: value = default return value def validate_supabase_url(url): """Validate Supabase database URL format.""" try: # Strip whitespace url = url.strip() # Debug info print(f"Validating URL: {url}") print(f"URL starts with postgresql+asyncpg://: {url.startswith('postgresql+asyncpg://')}") parsed = urlparse(url) if not url.startswith("postgresql+asyncpg://"): return False, f"URL must start with 'postgresql+asyncpg://' (got: {url[:30]}...)" if not parsed.hostname: return False, "Invalid hostname" if not parsed.port: return False, "Port is required" return True, "Valid URL" except Exception as e: return False, f"Invalid URL format: {e}" def create_env_file(env_data, filename=".env"): """Create .env file with the provided data.""" env_path = Path(filename) # Check if file exists if env_path.exists(): response = get_user_input(f"{filename} already exists. Overwrite it? (y/N): ", "N") if response.lower() != 'y': print(f"Keeping existing {filename}") return False # Write environment file with open(env_path, 'w') as f: f.write("# Unified Assistant Environment Configuration\n") f.write("# Generated by setup_supabase_complete.py\n\n") for key, value in env_data.items(): f.write(f"{key}={value}\n") print(f"[OK] Created {filename}") return True def create_hf_secrets_template(env_data): """Create Hugging Face secrets template.""" template_path = Path("huggingface_secrets_template.txt") with open(template_path, 'w') as f: f.write("# Hugging Face Spaces Secrets Template\n") f.write("# Copy these values to your Hugging Face Space secrets\n") f.write("# Go to: Your Space -> Settings -> Repository secrets\n\n") for key, value in env_data.items(): f.write(f"{key}={value}\n") print("[OK] Created huggingface_secrets_template.txt") return template_path async def test_supabase_connection(supabase_url): """Test Supabase connection.""" print("\nTesting Supabase connection...") # Set environment variable temporarily os.environ["SUPABASE_DB_URL"] = supabase_url os.environ["ENVIRONMENT"] = "production" try: # Import after setting environment sys.path.insert(0, str(Path(__file__).parent)) from database import async_engine, create_tables # Test connection async with async_engine.begin() as conn: result = await conn.execute("SELECT 1 as test") row = await result.fetchone() print(f"[OK] Connection test successful: {row}") # Test table creation await create_tables() print("[OK] Table creation test successful") return True except Exception as e: print(f"[ERROR] Connection test failed: {e}") return False def setup_supabase(): """Setup Supabase configuration.""" print("SUPABASE CONFIGURATION") print("-" * 30) print("1. Go to https://supabase.com and create a new project") print("2. Get your database connection string from:") print(" Settings -> Database -> Connection string") print("3. Make sure to add '+asyncpg' after 'postgresql'") print() while True: supabase_url = get_user_input( "Enter your Supabase database URL: ", required=True ) is_valid, message = validate_supabase_url(supabase_url) if is_valid: break else: print(f"[ERROR] {message}") print("Example: postgresql+asyncpg://postgres:password@host:5432/postgres") return supabase_url def setup_openai(): """Setup OpenAI configuration.""" print("\nOPENAI CONFIGURATION") print("-" * 30) print("Get your API key from: https://platform.openai.com/api-keys") print() openai_key = get_user_input( "Enter your OpenAI API key (sk-...): ", required=True, secret=True ) return openai_key def setup_security(): """Setup security configuration.""" print("\nSECURITY CONFIGURATION") print("-" * 30) # Generate secure secret key secret_key = secrets.token_urlsafe(32) print(f"Auto-generated secret key: {secret_key}") use_generated = get_user_input( "Use this generated key? (Y/n): ", "Y" ) if use_generated.lower() != 'y': secret_key = get_user_input( "Enter your custom secret key: ", required=True, secret=True ) return secret_key def setup_environment_mode(): """Setup environment mode.""" print("\nENVIRONMENT CONFIGURATION") print("-" * 30) print("Choose your setup mode:") print("1. Local development (SQLite + Supabase)") print("2. Production only (Supabase only)") print("3. Both (recommended)") print() mode = get_user_input( "Choose mode (1/2/3): ", "3" ) return mode def main(): """Main setup function.""" print_banner() # Setup Supabase supabase_url = setup_supabase() # Setup OpenAI openai_key = setup_openai() # Setup security secret_key = setup_security() # Setup environment mode mode = setup_environment_mode() # Prepare environment data env_data = { "SUPABASE_DB_URL": supabase_url, "OPENAI_API_KEY": openai_key, "SECRET_KEY": secret_key, "ENVIRONMENT": "production", "DEBUG": "false", "HOST": "0.0.0.0", "PORT": "7860" } # Add local development settings if needed if mode in ["1", "3"]: env_data["DATABASE_URL"] = "sqlite:///./unified_assistant.db" env_data["ENVIRONMENT"] = "development" env_data["DEBUG"] = "true" print("\nCreating configuration files...") # Create .env file env_created = create_env_file(env_data) # Create Hugging Face secrets template hf_template = create_hf_secrets_template(env_data) # Test connection print("\nTesting Supabase connection...") test_success = asyncio.run(test_supabase_connection(supabase_url)) print("\n" + "=" * 60) if test_success: print("Setup completed successfully!") print() print("Files created:") if env_created: print(" [OK] .env (local development)") print(" [OK] huggingface_secrets_template.txt") print() print("Next steps:") print("1. For local testing: python main.py") print("2. For Hugging Face deployment:") print(" - Copy values from huggingface_secrets_template.txt") print(" - Paste into your Hugging Face Space secrets") print(" - Deploy your space") print() print("Test your setup:") print(" python test_database_config.py") print(" python setup_database.py") else: print("Setup completed with connection issues") print("Please check your Supabase configuration and try again") if __name__ == "__main__": main()