| |
| |
|
|
| param( |
| [string]$Mode = "local", |
| [switch]$SkipDeps, |
| [switch]$SkipDb, |
| [switch]$SkipFrontend, |
| [switch]$Verbose, |
| [switch]$Detached, |
| [switch]$Stop, |
| [switch]$Status, |
| [switch]$Logs, |
| [switch]$Help |
| ) |
|
|
| |
| $Red = "Red" |
| $Green = "Green" |
| $Yellow = "Yellow" |
| $Blue = "Cyan" |
| $Purple = "Magenta" |
|
|
| |
| $ProjectRoot = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path) |
| $BackendDir = Join-Path $ProjectRoot "backend" |
| $FrontendDir = Join-Path $ProjectRoot "frontend" |
| $DataDir = Join-Path $ProjectRoot "data" |
| $LogsDir = Join-Path $ProjectRoot "logs" |
|
|
| function Write-Header { |
| param([string]$Message) |
| Write-Host "================================" -ForegroundColor $Purple |
| Write-Host $Message -ForegroundColor $Purple |
| Write-Host "================================" -ForegroundColor $Purple |
| } |
|
|
| function Write-Status { |
| param([string]$Message) |
| Write-Host "[INFO] $Message" -ForegroundColor $Blue |
| } |
|
|
| function Write-Success { |
| param([string]$Message) |
| Write-Host "[SUCCESS] $Message" -ForegroundColor $Green |
| } |
|
|
| function Write-Warning { |
| param([string]$Message) |
| Write-Host "[WARNING] $Message" -ForegroundColor $Yellow |
| } |
|
|
| function Write-Error { |
| param([string]$Message) |
| Write-Host "[ERROR] $Message" -ForegroundColor $Red |
| } |
|
|
| function Show-Usage { |
| Write-Host "Usage: .\run_local.ps1 [OPTIONS]" |
| Write-Host "" |
| Write-Host "Options:" |
| Write-Host " -Help Show this help message" |
| Write-Host " -Mode MODE Set deployment mode (local|cloud) [default: local]" |
| Write-Host " -SkipDeps Skip dependency installation" |
| Write-Host " -SkipDb Skip database initialization" |
| Write-Host " -SkipFrontend Skip frontend serving" |
| Write-Host " -Verbose Enable verbose output" |
| Write-Host " -Detached Run services in detached mode" |
| Write-Host " -Stop Stop all running services" |
| Write-Host " -Status Show status of running services" |
| Write-Host " -Logs Show logs from all services" |
| Write-Host "" |
| Write-Host "Examples:" |
| Write-Host " .\run_local.ps1 Start all services in local mode" |
| Write-Host " .\run_local.ps1 -Mode cloud Start with cloud configuration" |
| Write-Host " .\run_local.ps1 -SkipDeps Start without installing dependencies" |
| Write-Host " .\run_local.ps1 -Detached Start services in background" |
| Write-Host " .\run_local.ps1 -Stop Stop all running services" |
| } |
|
|
| function Test-Prerequisites { |
| Write-Status "Checking prerequisites..." |
| |
| |
| try { |
| $pythonVersion = python --version 2>&1 |
| Write-Status "Python version: $pythonVersion" |
| } catch { |
| Write-Error "Python is not installed. Please install Python 3.8 or higher." |
| exit 1 |
| } |
| |
| |
| try { |
| pip --version | Out-Null |
| } catch { |
| Write-Error "pip is not installed. Please install pip." |
| exit 1 |
| } |
| |
| |
| if (-not $SkipFrontend) { |
| try { |
| $nodeVersion = node --version |
| Write-Status "Node.js version: $nodeVersion" |
| } catch { |
| Write-Warning "Node.js not found. Frontend serving will be disabled." |
| $script:SkipFrontend = $true |
| } |
| } |
| |
| |
| $requiredDirs = @($BackendDir, $FrontendDir, $DataDir) |
| foreach ($dir in $requiredDirs) { |
| if (-not (Test-Path $dir)) { |
| Write-Error "Required directory not found: $dir" |
| exit 1 |
| } |
| } |
| |
| Write-Success "Prerequisites check completed" |
| } |
|
|
| function New-Directories { |
| Write-Status "Creating necessary directories..." |
| |
| @($LogsDir, $DataDir, (Join-Path $ProjectRoot ".env")) | ForEach-Object { |
| if (-not (Test-Path $_)) { |
| New-Item -ItemType Directory -Path $_ -Force | Out-Null |
| } |
| } |
| |
| Write-Success "Directories created" |
| } |
|
|
| function Install-Dependencies { |
| if ($SkipDeps) { |
| Write-Warning "Skipping dependency installation" |
| return |
| } |
| |
| Write-Status "Installing Python dependencies..." |
| |
| Set-Location $BackendDir |
| |
| |
| if (-not (Test-Path "venv")) { |
| Write-Status "Creating Python virtual environment..." |
| python -m venv venv |
| } |
| |
| |
| & ".\venv\Scripts\Activate.ps1" |
| |
| |
| pip install --upgrade pip |
| |
| |
| if (Test-Path "requirements.txt") { |
| pip install -r requirements.txt |
| } else { |
| Write-Error "requirements.txt not found in backend directory" |
| exit 1 |
| } |
| |
| Write-Success "Python dependencies installed" |
| |
| |
| if (-not $SkipFrontend -and (Test-Path (Join-Path $FrontendDir "package.json"))) { |
| Write-Status "Installing frontend dependencies..." |
| Set-Location $FrontendDir |
| npm install |
| Write-Success "Frontend dependencies installed" |
| } |
| } |
|
|
| function Initialize-Database { |
| if ($SkipDb) { |
| Write-Warning "Skipping database initialization" |
| return |
| } |
| |
| Write-Status "Initializing database..." |
| |
| Set-Location $BackendDir |
| & ".\venv\Scripts\Activate.ps1" |
| |
| |
| if (Test-Path "init_db.py") { |
| python init_db.py --mode $Mode |
| Write-Success "Database initialized" |
| } else { |
| Write-Warning "Database initialization script not found, skipping..." |
| } |
| } |
|
|
| function Set-Environment { |
| Write-Status "Setting up environment variables..." |
| |
| |
| $envFile = Join-Path $ProjectRoot ".env" |
| if (-not (Test-Path $envFile)) { |
| Write-Status "Creating .env file..." |
| |
| $envContent = @" |
| # Misinformation Heatmap Configuration |
| MODE=$Mode |
| DEBUG=true |
| LOG_LEVEL=INFO |
| |
| # Database Configuration |
| DATABASE_URL=sqlite:///./data/heatmap.db |
| |
| # API Configuration |
| API_HOST=0.0.0.0 |
| API_PORT=8000 |
| CORS_ORIGINS=["http://localhost:3000", "http://localhost:8000"] |
| |
| # NLP Configuration |
| HUGGINGFACE_TOKEN= |
| MODEL_CACHE_DIR=./models |
| |
| # Pub/Sub Configuration (Local) |
| PUBSUB_EMULATOR_HOST=localhost:8085 |
| PUBSUB_PROJECT_ID=misinformation-heatmap-local |
| |
| # Google Cloud Configuration (for cloud mode) |
| GOOGLE_CLOUD_PROJECT= |
| GOOGLE_APPLICATION_CREDENTIALS= |
| |
| # IBM Watson Configuration (for cloud mode) |
| WATSON_DISCOVERY_API_KEY= |
| WATSON_DISCOVERY_URL= |
| |
| # Monitoring Configuration |
| ENABLE_METRICS=true |
| METRICS_PORT=9090 |
| "@ |
| |
| Set-Content -Path $envFile -Value $envContent |
| Write-Success ".env file created" |
| } else { |
| Write-Status ".env file already exists" |
| } |
| } |
|
|
| function Start-PubSubEmulator { |
| if ($Mode -ne "local") { |
| return |
| } |
| |
| Write-Status "Starting Pub/Sub emulator..." |
| |
| |
| try { |
| gcloud version | Out-Null |
| } catch { |
| Write-Warning "gcloud CLI not found. Installing Pub/Sub emulator..." |
| pip install google-cloud-pubsub |
| } |
| |
| |
| $pubsubLog = Join-Path $LogsDir "pubsub-emulator.log" |
| |
| if ($Detached) { |
| $pubsubProcess = Start-Process -FilePath "gcloud" -ArgumentList "beta", "emulators", "pubsub", "start", "--host-port=localhost:8085" -RedirectStandardOutput $pubsubLog -RedirectStandardError $pubsubLog -PassThru |
| $pubsubProcess.Id | Out-File (Join-Path $LogsDir "pubsub.pid") |
| Write-Success "Pub/Sub emulator started (PID: $($pubsubProcess.Id))" |
| } else { |
| Write-Status "Starting Pub/Sub emulator (press Ctrl+C to stop all services)" |
| $pubsubProcess = Start-Process -FilePath "gcloud" -ArgumentList "beta", "emulators", "pubsub", "start", "--host-port=localhost:8085" -PassThru |
| $pubsubProcess.Id | Out-File (Join-Path $LogsDir "pubsub.pid") |
| } |
| |
| |
| Start-Sleep -Seconds 3 |
| |
| |
| $env:PUBSUB_EMULATOR_HOST = "localhost:8085" |
| |
| $createTopicsScript = @" |
| import os |
| from google.cloud import pubsub_v1 |
| |
| os.environ['PUBSUB_EMULATOR_HOST'] = 'localhost:8085' |
| project_id = 'misinformation-heatmap-local' |
| |
| publisher = pubsub_v1.PublisherClient() |
| subscriber = pubsub_v1.SubscriberClient() |
| |
| # Create topics |
| topics = ['events-raw', 'events-processed', 'events-validated'] |
| for topic_name in topics: |
| topic_path = publisher.topic_path(project_id, topic_name) |
| try: |
| publisher.create_topic(request={'name': topic_path}) |
| print(f'Created topic: {topic_name}') |
| except Exception as e: |
| print(f'Topic {topic_name} may already exist: {e}') |
| |
| # Create subscriptions |
| subscriptions = [ |
| ('events-raw', 'events-raw-sub'), |
| ('events-processed', 'events-processed-sub'), |
| ('events-validated', 'events-validated-sub') |
| ] |
| |
| for topic_name, sub_name in subscriptions: |
| topic_path = publisher.topic_path(project_id, topic_name) |
| subscription_path = subscriber.subscription_path(project_id, sub_name) |
| try: |
| subscriber.create_subscription( |
| request={'name': subscription_path, 'topic': topic_path} |
| ) |
| print(f'Created subscription: {sub_name}') |
| except Exception as e: |
| print(f'Subscription {sub_name} may already exist: {e}') |
| "@ |
| |
| python -c $createTopicsScript |
| } |
|
|
| function Start-Backend { |
| Write-Status "Starting backend API server..." |
| |
| Set-Location $BackendDir |
| & ".\venv\Scripts\Activate.ps1" |
| |
| $apiLog = Join-Path $LogsDir "api.log" |
| |
| if ($Detached) { |
| $apiProcess = Start-Process -FilePath "python" -ArgumentList "api.py" -RedirectStandardOutput $apiLog -RedirectStandardError $apiLog -PassThru |
| $apiProcess.Id | Out-File (Join-Path $LogsDir "api.pid") |
| Write-Success "Backend API started (PID: $($apiProcess.Id))" |
| } else { |
| Write-Status "Starting backend API (press Ctrl+C to stop all services)" |
| $apiProcess = Start-Process -FilePath "python" -ArgumentList "api.py" -PassThru |
| $apiProcess.Id | Out-File (Join-Path $LogsDir "api.pid") |
| } |
| } |
|
|
| function Start-Frontend { |
| if ($SkipFrontend) { |
| Write-Warning "Skipping frontend server" |
| return |
| } |
| |
| Write-Status "Starting frontend server..." |
| |
| Set-Location $FrontendDir |
| |
| $frontendLog = Join-Path $LogsDir "frontend.log" |
| |
| |
| if ($Detached) { |
| $frontendProcess = Start-Process -FilePath "python" -ArgumentList "-m", "http.server", "3000" -RedirectStandardOutput $frontendLog -RedirectStandardError $frontendLog -PassThru |
| $frontendProcess.Id | Out-File (Join-Path $LogsDir "frontend.pid") |
| Write-Success "Frontend server started (PID: $($frontendProcess.Id))" |
| } else { |
| Write-Status "Starting frontend server (press Ctrl+C to stop all services)" |
| $frontendProcess = Start-Process -FilePath "python" -ArgumentList "-m", "http.server", "3000" -PassThru |
| $frontendProcess.Id | Out-File (Join-Path $LogsDir "frontend.pid") |
| } |
| } |
|
|
| function Test-HealthChecks { |
| Write-Status "Performing health checks..." |
| |
| |
| Start-Sleep -Seconds 5 |
| |
| |
| try { |
| Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing | Out-Null |
| Write-Success "Backend API is healthy" |
| } catch { |
| Write-Warning "Backend API health check failed" |
| } |
| |
| |
| if (-not $SkipFrontend) { |
| try { |
| Invoke-WebRequest -Uri "http://localhost:3000" -UseBasicParsing | Out-Null |
| Write-Success "Frontend server is healthy" |
| } catch { |
| Write-Warning "Frontend server health check failed" |
| } |
| } |
| |
| |
| if ($Mode -eq "local") { |
| try { |
| Invoke-WebRequest -Uri "http://localhost:8085" -UseBasicParsing | Out-Null |
| Write-Success "Pub/Sub emulator is healthy" |
| } catch { |
| Write-Warning "Pub/Sub emulator health check failed" |
| } |
| } |
| } |
|
|
| function Show-Status { |
| Write-Header "Service Status" |
| |
| |
| $apiPidFile = Join-Path $LogsDir "api.pid" |
| if (Test-Path $apiPidFile) { |
| $apiPid = Get-Content $apiPidFile |
| if (Get-Process -Id $apiPid -ErrorAction SilentlyContinue) { |
| Write-Success "Backend API running (PID: $apiPid)" |
| } else { |
| Write-Warning "Backend API not running (stale PID file)" |
| } |
| } else { |
| Write-Warning "Backend API not started" |
| } |
| |
| |
| $frontendPidFile = Join-Path $LogsDir "frontend.pid" |
| if (Test-Path $frontendPidFile) { |
| $frontendPid = Get-Content $frontendPidFile |
| if (Get-Process -Id $frontendPid -ErrorAction SilentlyContinue) { |
| Write-Success "Frontend server running (PID: $frontendPid)" |
| } else { |
| Write-Warning "Frontend server not running (stale PID file)" |
| } |
| } else { |
| Write-Warning "Frontend server not started" |
| } |
| |
| |
| $pubsubPidFile = Join-Path $LogsDir "pubsub.pid" |
| if (Test-Path $pubsubPidFile) { |
| $pubsubPid = Get-Content $pubsubPidFile |
| if (Get-Process -Id $pubsubPid -ErrorAction SilentlyContinue) { |
| Write-Success "Pub/Sub emulator running (PID: $pubsubPid)" |
| } else { |
| Write-Warning "Pub/Sub emulator not running (stale PID file)" |
| } |
| } else { |
| Write-Warning "Pub/Sub emulator not started" |
| } |
| } |
|
|
| function Show-Logs { |
| Write-Header "Service Logs" |
| |
| $apiLog = Join-Path $LogsDir "api.log" |
| if (Test-Path $apiLog) { |
| Write-Host "=== Backend API Logs ===" -ForegroundColor $Blue |
| Get-Content $apiLog -Tail 20 |
| Write-Host "" |
| } |
| |
| $frontendLog = Join-Path $LogsDir "frontend.log" |
| if (Test-Path $frontendLog) { |
| Write-Host "=== Frontend Server Logs ===" -ForegroundColor $Blue |
| Get-Content $frontendLog -Tail 20 |
| Write-Host "" |
| } |
| |
| $pubsubLog = Join-Path $LogsDir "pubsub-emulator.log" |
| if (Test-Path $pubsubLog) { |
| Write-Host "=== Pub/Sub Emulator Logs ===" -ForegroundColor $Blue |
| Get-Content $pubsubLog -Tail 20 |
| Write-Host "" |
| } |
| } |
|
|
| function Stop-Services { |
| Write-Header "Stopping Services" |
| |
| |
| $apiPidFile = Join-Path $LogsDir "api.pid" |
| if (Test-Path $apiPidFile) { |
| $apiPid = Get-Content $apiPidFile |
| if (Get-Process -Id $apiPid -ErrorAction SilentlyContinue) { |
| Stop-Process -Id $apiPid -Force |
| Write-Success "Backend API stopped" |
| } |
| Remove-Item $apiPidFile -Force |
| } |
| |
| |
| $frontendPidFile = Join-Path $LogsDir "frontend.pid" |
| if (Test-Path $frontendPidFile) { |
| $frontendPid = Get-Content $frontendPidFile |
| if (Get-Process -Id $frontendPid -ErrorAction SilentlyContinue) { |
| Stop-Process -Id $frontendPid -Force |
| Write-Success "Frontend server stopped" |
| } |
| Remove-Item $frontendPidFile -Force |
| } |
| |
| |
| $pubsubPidFile = Join-Path $LogsDir "pubsub.pid" |
| if (Test-Path $pubsubPidFile) { |
| $pubsubPid = Get-Content $pubsubPidFile |
| if (Get-Process -Id $pubsubPid -ErrorAction SilentlyContinue) { |
| Stop-Process -Id $pubsubPid -Force |
| Write-Success "Pub/Sub emulator stopped" |
| } |
| Remove-Item $pubsubPidFile -Force |
| } |
| |
| Write-Success "All services stopped" |
| } |
|
|
| function Show-ServiceUrls { |
| Write-Header "Service URLs" |
| Write-Host "Backend API: http://localhost:8000" -ForegroundColor $Green |
| Write-Host "API Documentation: http://localhost:8000/docs" -ForegroundColor $Green |
| Write-Host "Health Check: http://localhost:8000/health" -ForegroundColor $Green |
| |
| if (-not $SkipFrontend) { |
| Write-Host "Frontend: http://localhost:3000" -ForegroundColor $Green |
| } |
| |
| if ($Mode -eq "local") { |
| Write-Host "Pub/Sub Emulator: http://localhost:8085" -ForegroundColor $Green |
| } |
| |
| Write-Host "" |
| Write-Host "Logs Directory: $LogsDir" -ForegroundColor $Yellow |
| Write-Host "Data Directory: $DataDir" -ForegroundColor $Yellow |
| } |
|
|
| |
| function Main { |
| if ($Help) { |
| Show-Usage |
| return |
| } |
| |
| if ($Stop) { |
| Stop-Services |
| return |
| } |
| |
| if ($Status) { |
| Show-Status |
| return |
| } |
| |
| if ($Logs) { |
| Show-Logs |
| return |
| } |
| |
| Write-Header "Misinformation Heatmap - Local Development Setup" |
| |
| Test-Prerequisites |
| New-Directories |
| Set-Environment |
| Install-Dependencies |
| Initialize-Database |
| |
| |
| if ($Mode -eq "local") { |
| Start-PubSubEmulator |
| } |
| |
| Start-Backend |
| Start-Frontend |
| |
| |
| Test-HealthChecks |
| |
| |
| Show-ServiceUrls |
| |
| if ($Detached) { |
| Write-Success "All services started in detached mode" |
| Write-Status "Use '.\run_local.ps1 -Status' to check service status" |
| Write-Status "Use '.\run_local.ps1 -Logs' to view service logs" |
| Write-Status "Use '.\run_local.ps1 -Stop' to stop all services" |
| } else { |
| Write-Success "All services started successfully!" |
| Write-Status "Press Ctrl+C to stop all services" |
| |
| |
| try { |
| while ($true) { |
| Start-Sleep -Seconds 1 |
| } |
| } finally { |
| if (-not $Detached) { |
| Write-Status "Cleaning up..." |
| Stop-Services |
| } |
| } |
| } |
| } |
|
|
| |
| Main |