chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
199
start-host.ps1
Normal file
199
start-host.ps1
Normal file
@@ -0,0 +1,199 @@
|
||||
# native process mode (called by start.ps1 when Docker is unavailable)
|
||||
param(
|
||||
[switch]$Rebuild,
|
||||
[switch]$NoBrowser,
|
||||
[switch]$ShowConsole # show service windows (debug); default: hidden
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Root = $PSScriptRoot
|
||||
Set-Location -LiteralPath $Root
|
||||
$LogDir = Join-Path $Root ".runtime\logs"
|
||||
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
|
||||
|
||||
# Always wipe previous native/docker leftovers before binding ports
|
||||
Write-Host "==> Pre-clean before native start" -ForegroundColor DarkGray
|
||||
& (Join-Path $Root "scripts\Stop-Stack.ps1") -Quiet
|
||||
Start-Sleep -Seconds 1
|
||||
|
||||
Write-Host "==> Native mode: need Go / Python / Node / PostgreSQL" -ForegroundColor Yellow
|
||||
if (-not $ShowConsole) {
|
||||
Write-Host " services run hidden; logs -> .runtime\logs\" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
function Clear-Port([int]$port) {
|
||||
$conns = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
|
||||
foreach ($c in $conns) {
|
||||
$procId = $c.OwningProcess
|
||||
if ($procId -gt 0) {
|
||||
Write-Host " free port $port (pid=$procId)"
|
||||
& taskkill.exe /F /T /PID $procId 2>$null | Out-Null
|
||||
Stop-Process -Id $procId -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "==> Clearing ports 8888/8001/8180/5173"
|
||||
foreach ($p in 8888, 8001, 8180, 5173) { Clear-Port $p }
|
||||
Start-Sleep -Seconds 1
|
||||
|
||||
function Reset-LogFile([string]$path) {
|
||||
try {
|
||||
if (Test-Path -LiteralPath $path) {
|
||||
# 句柄未释放时 Set-Content 会失败:先挪走旧文件
|
||||
$prev = "$path.prev"
|
||||
Remove-Item -LiteralPath $prev -Force -ErrorAction SilentlyContinue
|
||||
Move-Item -LiteralPath $path -Destination $prev -Force -ErrorAction Stop
|
||||
}
|
||||
Set-Content -LiteralPath $path -Value "" -Encoding UTF8
|
||||
return $path
|
||||
} catch {
|
||||
$alt = ($path -replace '\.log$', ".$(Get-Date -Format 'HHmmss').log")
|
||||
Set-Content -LiteralPath $alt -Value "" -Encoding UTF8
|
||||
return $alt
|
||||
}
|
||||
}
|
||||
|
||||
function Start-Svc($name, $workDir, $filePath, $argumentList) {
|
||||
$outLog = Reset-LogFile (Join-Path $LogDir "$name.out.log")
|
||||
$errLog = Reset-LogFile (Join-Path $LogDir "$name.err.log")
|
||||
$pidFile = Join-Path $LogDir "$name.pid"
|
||||
|
||||
if ($ShowConsole) {
|
||||
$argStr = ""
|
||||
if ($argumentList) {
|
||||
$parts = @()
|
||||
foreach ($a in $argumentList) {
|
||||
if ($a -match '\s') { $parts += ('"' + $a + '"') } else { $parts += $a }
|
||||
}
|
||||
$argStr = $parts -join ' '
|
||||
}
|
||||
$cmd = "Set-Location -LiteralPath '$workDir'; Write-Host '[$name]' -ForegroundColor Cyan; & '$filePath' $argStr"
|
||||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
||||
"-NoExit", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", $cmd
|
||||
) -WorkingDirectory $workDir -PassThru
|
||||
} else {
|
||||
$p = Start-Process -FilePath $filePath `
|
||||
-ArgumentList $argumentList `
|
||||
-WorkingDirectory $workDir `
|
||||
-WindowStyle Hidden `
|
||||
-RedirectStandardOutput $outLog `
|
||||
-RedirectStandardError $errLog `
|
||||
-PassThru
|
||||
}
|
||||
if ($p) { Set-Content -LiteralPath $pidFile -Value $p.Id -Encoding ASCII }
|
||||
Write-Host " started $name (pid=$($p.Id))" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
$plat = Join-Path $Root "platform\platform.exe"
|
||||
$gw = Join-Path $Root "gateway\gateway.exe"
|
||||
# 默认重编译,避免改 Go 源码后 restart 仍跑旧 exe
|
||||
$needPlat = $Rebuild -or -not (Test-Path $plat)
|
||||
$needGw = $Rebuild -or -not (Test-Path $gw)
|
||||
if (-not $needPlat -and (Test-Path $plat)) {
|
||||
$exeTime = (Get-Item $plat).LastWriteTime
|
||||
$newer = Get-ChildItem -Path (Join-Path $Root "platform") -Recurse -Include *.go -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.LastWriteTime -gt $exeTime } |
|
||||
Select-Object -First 1
|
||||
if ($newer) { $needPlat = $true }
|
||||
}
|
||||
if (-not $needGw -and (Test-Path $gw)) {
|
||||
$exeTime = (Get-Item $gw).LastWriteTime
|
||||
$newer = Get-ChildItem -Path (Join-Path $Root "gateway") -Recurse -Include *.go -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.LastWriteTime -gt $exeTime } |
|
||||
Select-Object -First 1
|
||||
if ($newer) { $needGw = $true }
|
||||
}
|
||||
if ($needPlat) {
|
||||
Write-Host " building platform.exe ..." -ForegroundColor DarkGray
|
||||
Push-Location (Join-Path $Root "platform")
|
||||
go build -o platform.exe .
|
||||
Pop-Location
|
||||
}
|
||||
if ($needGw) {
|
||||
Write-Host " building gateway.exe ..." -ForegroundColor DarkGray
|
||||
Push-Location (Join-Path $Root "gateway")
|
||||
go build -o gateway.exe .
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Write-Host "==> Ensure web frontend (vite /#/preview)" -ForegroundColor DarkGray
|
||||
& (Join-Path $Root "scripts\Ensure-Web.ps1")
|
||||
# $? 判断 PS 脚本成败;勿单靠 $LASTEXITCODE(会残留 docker/compose 等 native 失败码)
|
||||
if (-not $?) { throw "Ensure-Web failed" }
|
||||
|
||||
$pyCmd = Get-Command python -ErrorAction SilentlyContinue
|
||||
if (-not $pyCmd) { $pyCmd = Get-Command py -ErrorAction SilentlyContinue }
|
||||
if (-not $pyCmd) { throw "python not found" }
|
||||
$py = $pyCmd.Source
|
||||
|
||||
$npmCmd = Get-Command npm.cmd -ErrorAction SilentlyContinue
|
||||
if (-not $npmCmd) { $npmCmd = Get-Command npm -ErrorAction SilentlyContinue }
|
||||
if (-not $npmCmd) { throw "npm not found" }
|
||||
|
||||
# AI 截图直达本机 Vite
|
||||
$env:WEB_BASE = "http://127.0.0.1:5173"
|
||||
$env:PLATFORM_BASE = "http://127.0.0.1:8888"
|
||||
$env:GATEWAY_BASE = "http://127.0.0.1:8180"
|
||||
$env:GENERATE_LOG_DIR = Join-Path $Root ".runtime\logs\generate"
|
||||
$env:FIDELITY_SHOT_DIR = Join-Path $Root ".runtime\fidelity_shots"
|
||||
|
||||
Start-Svc "platform" (Join-Path $Root "platform") $plat @("-f", "etc/platform.yaml")
|
||||
Start-Sleep -Seconds 2
|
||||
Start-Svc "ai-service" (Join-Path $Root "ai-service") $py @("-m", "uvicorn", "app:app", "--host", "127.0.0.1", "--port", "8001", "--reload")
|
||||
Start-Sleep -Seconds 1
|
||||
Start-Svc "gateway" (Join-Path $Root "gateway") $gw @("-f", "etc/gateway.yaml")
|
||||
Start-Sleep -Seconds 1
|
||||
Start-Svc "web" (Join-Path $Root "web") $npmCmd.Source @("run", "dev", "--", "--host", "127.0.0.1", "--port", "5173", "--strictPort")
|
||||
|
||||
Write-Host "==> Waiting for services..."
|
||||
$deadline = (Get-Date).AddSeconds(45)
|
||||
do {
|
||||
$webOk = $false
|
||||
$gwOk = $false
|
||||
try {
|
||||
$r = Invoke-WebRequest -Uri "http://127.0.0.1:5173/" -UseBasicParsing -TimeoutSec 2
|
||||
if ($r.StatusCode -lt 500) { $webOk = $true }
|
||||
} catch {}
|
||||
try {
|
||||
$r = Invoke-WebRequest -Uri "http://127.0.0.1:8180/gateway/health" -UseBasicParsing -TimeoutSec 2
|
||||
if ($r.StatusCode -lt 500) { $gwOk = $true }
|
||||
} catch {}
|
||||
if ($webOk -and $gwOk) { break }
|
||||
Start-Sleep -Seconds 1
|
||||
} while ((Get-Date) -lt $deadline)
|
||||
|
||||
if ($webOk -and $gwOk) {
|
||||
Write-Host "OK Web http://127.0.0.1:5173 Gateway http://127.0.0.1:8180 account demo/demo123" -ForegroundColor Green
|
||||
Write-Host " logs $LogDir" -ForegroundColor DarkGray
|
||||
} else {
|
||||
Write-Host "WARN some services not ready yet. Check logs:" -ForegroundColor Yellow
|
||||
Write-Host " $LogDir"
|
||||
Write-Host " web=$webOk gateway=$gwOk"
|
||||
Write-Host " (debug with visible windows: .\start-host.ps1 -ShowConsole)"
|
||||
}
|
||||
|
||||
# 后台看门狗:ai-service / gateway 挂掉自动拉起
|
||||
$watchPidFile = Join-Path $LogDir "watchdog.pid"
|
||||
if (Test-Path $watchPidFile) {
|
||||
$oldWatch = Get-Content $watchPidFile -ErrorAction SilentlyContinue
|
||||
if ($oldWatch) { Stop-Process -Id ([int]$oldWatch) -Force -ErrorAction SilentlyContinue }
|
||||
}
|
||||
$watchScript = Join-Path $Root "watch-services.ps1"
|
||||
$watchOut = Join-Path $LogDir "watchdog.out.log"
|
||||
$watchErr = Join-Path $LogDir "watchdog.err.log"
|
||||
Set-Content -LiteralPath $watchOut -Value "" -Encoding UTF8
|
||||
Set-Content -LiteralPath $watchErr -Value "" -Encoding UTF8
|
||||
$wp = Start-Process -FilePath "powershell.exe" `
|
||||
-ArgumentList @("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $watchScript) `
|
||||
-WorkingDirectory $Root `
|
||||
-WindowStyle Hidden `
|
||||
-RedirectStandardOutput $watchOut `
|
||||
-RedirectStandardError $watchErr `
|
||||
-PassThru
|
||||
if ($wp) {
|
||||
Set-Content -LiteralPath $watchPidFile -Value $wp.Id -Encoding ASCII
|
||||
Write-Host " started watchdog (pid=$($wp.Id)) - auto-restarts ai-service if down" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
if (-not $NoBrowser) { Start-Process "http://127.0.0.1:5173" }
|
||||
Reference in New Issue
Block a user