# ============================================================================== # lf_mri_platform -- Full launch: install (if needed) -> containers -> GUI # Usage: # .\launch.ps1 -- install if needed, start services + GUI # .\launch.ps1 -Mode real -- hardware mode # .\launch.ps1 -SkipInstall -- skip dependency check # .\launch.ps1 -ServicesOnly -- do not open GUI # ============================================================================== param( [ValidateSet("plug", "real")] [string]$Mode = "plug", [switch]$SkipInstall, [switch]$ServicesOnly ) $ErrorActionPreference = "Stop" $Root = $PSScriptRoot $GuiDir = Join-Path $Root "apps\gui" $LibsDir = Join-Path $Root "libs\lf-scanner" $VenvPython = Join-Path $GuiDir ".venv\Scripts\python.exe" $VenvPip = Join-Path $GuiDir ".venv\Scripts\pip.exe" $AppScript = Join-Path $GuiDir "app.py" $EnvFile = Join-Path $Root ".env" $EnvExample = Join-Path $Root ".env.example" function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan } function Write-OK($msg) { Write-Host " [OK] $msg" -ForegroundColor Green } function Write-Warn($msg) { Write-Host " [!!] $msg" -ForegroundColor Yellow } function Write-Fail($msg) { Write-Host "`n[FAIL] $msg" -ForegroundColor Red; exit 1 } # -- 1. Install dependencies if venv is missing -------------------------------- if (-not $SkipInstall) { Write-Step "Checking GUI environment" $needsInstall = $false if (-not (Test-Path $VenvPython)) { Write-Warn "Virtual environment not found -- running install" $needsInstall = $true } else { # Check that key packages are present $checkPkg = & $VenvPython -c "import PyQt6" 2>&1 if ($LASTEXITCODE -ne 0) { Write-Warn "GUI packages missing -- running install" $needsInstall = $true } else { Write-OK "Virtual environment ready" } } if ($needsInstall) { $installScript = Join-Path $Root "install.ps1" if (-not (Test-Path $installScript)) { Write-Fail "install.ps1 not found at $installScript" } & powershell.exe -ExecutionPolicy Bypass -File $installScript if ($LASTEXITCODE -ne 0) { Write-Fail "install.ps1 failed" } } } # -- 2. Ensure Docker is running ----------------------------------------------- Write-Step "Checking Docker" $dockerOk = $false try { & docker info *>$null; $dockerOk = $true } catch {} if (-not $dockerOk) { Write-Warn "Docker not responding -- attempting to start Docker Desktop..." $dockerExe = "C:\Program Files\Docker\Docker\Docker Desktop.exe" if (Test-Path $dockerExe) { Start-Process $dockerExe } else { Write-Fail "Docker Desktop not found. Install it from https://www.docker.com/products/docker-desktop/" } Write-Host " Waiting up to 60 s for Docker to start..." -ForegroundColor DarkGray $waited = 0 while ($waited -lt 60) { Start-Sleep 5 $waited += 5 try { & docker info *>$null; $dockerOk = $true; break } catch {} Write-Host " ... $waited/60 s" -ForegroundColor DarkGray } if (-not $dockerOk) { Write-Fail "Docker did not start in time. Start Docker Desktop manually and re-run." } } Write-OK "Docker is running" # -- 3. Prepare .env ----------------------------------------------------------- if (-not (Test-Path $EnvFile)) { if (Test-Path $EnvExample) { Copy-Item $EnvExample $EnvFile Write-Warn ".env not found -- created from .env.example" } else { Write-Warn ".env and .env.example both missing -- using Docker Compose defaults" } } # -- 4. Build and start containers --------------------------------------------- Write-Step "Starting Docker services (mode: $Mode)" $env:ORCHESTRATOR_MODE = $Mode $envArgs = if (Test-Path $EnvFile) { @("--env-file", $EnvFile) } else { @() } & docker compose @envArgs up --build -d if ($LASTEXITCODE -ne 0) { Write-Fail "docker compose up failed" } Write-OK "Containers started" # -- 5. Wait for all services to become healthy -------------------------------- Write-Step "Waiting for services to become healthy" # Read ports from .env if available; fall back to compose defaults function Get-EnvPort($key, $default) { if (Test-Path $EnvFile) { $line = Get-Content $EnvFile | Select-String "^$key=(\d+)" if ($line) { return $line.Matches[0].Groups[1].Value } } return $default } $services = @( @{ Name = "Orchestrator"; Url = "http://localhost:$(Get-EnvPort 'ORCHESTRATOR_PORT' '1717')/health" }, @{ Name = "Seq-Interp"; Url = "http://localhost:$(Get-EnvPort 'SEQ_INTERP_PORT' '7475')/health" }, @{ Name = "Reconstructor"; Url = "http://localhost:$(Get-EnvPort 'RECONSTRUCTOR_PORT' '8081')/health" }, @{ Name = "Spectroscopy"; Url = "http://localhost:$(Get-EnvPort 'SPECTROSCOPY_PORT' '8002')/health" }, @{ Name = "Spectrometer"; Url = "http://localhost:$(Get-EnvPort 'SPECTROMETER_PORT' '8000')/api/" } ) $maxWait = 120 $interval = 3 $elapsed = 0 while ($elapsed -lt $maxWait) { $pending = @() foreach ($svc in $services) { try { $r = Invoke-WebRequest $svc.Url -UseBasicParsing -TimeoutSec 2 -ErrorAction Stop if ($r.StatusCode -lt 400) { continue } } catch {} $pending += $svc.Name } if ($pending.Count -eq 0) { Write-OK "All services healthy" break } Write-Host (" ... {0}/{1} s waiting: {2}" -f $elapsed, $maxWait, ($pending -join ", ")) -ForegroundColor DarkGray Start-Sleep $interval $elapsed += $interval } if ($elapsed -ge $maxWait) { Write-Warn "Some services did not respond within ${maxWait}s -- GUI will start anyway" foreach ($svc in $services) { try { $r = Invoke-WebRequest $svc.Url -UseBasicParsing -TimeoutSec 2 -ErrorAction Stop $icon = if ($r.StatusCode -lt 400) { "[OK]" } else { "[--]" } } catch { $icon = "[--]" } Write-Host (" {0,-6} {1,-15} {2}" -f $icon, $svc.Name, $svc.Url) -ForegroundColor $(if ($icon -eq "[OK]") {"Green"} else {"Yellow"}) } } # -- 6. Launch GUI in a separate window ---------------------------------------- if (-not $ServicesOnly) { Write-Step "Launching GUI" if (-not (Test-Path $VenvPython)) { Write-Warn "Venv not found -- falling back to system Python" $VenvPython = "python" } if (-not (Test-Path $AppScript)) { Write-Fail "GUI entry point not found: $AppScript" } Start-Process $VenvPython ` -ArgumentList "`"$AppScript`"" ` -WorkingDirectory $Root ` -WindowStyle Normal Write-OK "GUI launched" } # -- 7. Summary ---------------------------------------------------------------- Write-Host "" Write-Host "============================================================" -ForegroundColor Green Write-Host " LF-MRI platform is running" -ForegroundColor Green Write-Host "============================================================" -ForegroundColor Green Write-Host "" Write-Host " Service endpoints:" foreach ($svc in $services) { Write-Host (" {0,-15} {1}" -f $svc.Name, $svc.Url) } Write-Host "" Write-Host " Stop services: .\stop.ps1" Write-Host ""