# AGV GLB 一键启动 # 用法: # .\start.ps1 启动服务并打开播放页 # .\start.ps1 -Setup 首次部署:创建 .venv 并安装 requirements.txt # .\start.ps1 -NoBrowser 仅启动服务,不打开浏览器 param( [switch]$Setup, [switch]$NoBrowser, [int]$Port = 8765 ) $ErrorActionPreference = "Stop" $Root = Split-Path -Parent $MyInvocation.MyCommand.Path Set-Location $Root function Write-Step([string]$Msg) { Write-Host ('>> ' + $Msg) -ForegroundColor Cyan } function Find-Python { foreach ($cmd in @('py -3', 'python3', 'python')) { try { $ver = Invoke-Expression ($cmd + ' --version 2>&1') | Out-String if ($ver -match 'Python (\d+)\.(\d+)') { $major = [int]$Matches[1] $minor = [int]$Matches[2] if ($major -gt 3 -or ($major -eq 3 -and $minor -ge 10)) { return @{ Cmd = $cmd; Version = ($major.ToString() + '.' + $minor.ToString()) } } } } catch { } } return $null } function Get-VenvPython { $winPy = Join-Path $Root '.venv\Scripts\python.exe' if (Test-Path $winPy) { return $winPy } $unixPy = Join-Path $Root '.venv/bin/python' if (Test-Path $unixPy) { return $unixPy } return $null } function Test-PortInUse([int]$P) { try { $conn = Get-NetTCPConnection -LocalPort $P -State Listen -ErrorAction SilentlyContinue return [bool]$conn } catch { $out = netstat -ano | Select-String (':' + $P + '\s+.*LISTENING') return [bool]$out } } function Wait-ServerReady([string]$BaseUrl, [int]$TimeoutSec = 30) { $deadline = (Get-Date).AddSeconds($TimeoutSec) while ((Get-Date) -lt $deadline) { try { $resp = Invoke-WebRequest -Uri ($BaseUrl + '/api/catalog') -UseBasicParsing -TimeoutSec 2 if ($resp.StatusCode -eq 200) { return $true } } catch { Start-Sleep -Milliseconds 400 } } return $false } Write-Host '' Write-Host ' AGV GLB 本地服务' -ForegroundColor Green Write-Host '==================' -ForegroundColor Green Write-Host '' $pyInfo = Find-Python if (-not $pyInfo) { Write-Host '错误: 未找到 Python 3.10+,请从 https://www.python.org/downloads/ 安装' -ForegroundColor Red exit 1 } Write-Step ('Python ' + $pyInfo.Version + ' (' + $pyInfo.Cmd + ')') $venvPy = Get-VenvPython if ($Setup) { Write-Step '创建虚拟环境 .venv ...' if (-not $venvPy) { Invoke-Expression ($pyInfo.Cmd + ' -m venv .venv') $venvPy = Get-VenvPython if (-not $venvPy) { Write-Host '错误: 虚拟环境创建失败' -ForegroundColor Red exit 1 } } Write-Step '安装 Python 依赖 (analyze_agv.py 等工具需要) ...' & $venvPy -m pip install --upgrade pip & $venvPy -m pip install -r requirements.txt Write-Host '依赖安装完成。' -ForegroundColor Green } if ($venvPy) { Write-Step '使用虚拟环境: .venv' } else { Write-Step '使用系统 Python(serve.py 无需额外依赖)' Write-Host '提示: 运行 .\start.ps1 -Setup 可安装 analyze_agv.py 所需依赖' -ForegroundColor DarkYellow } $baseUrl = 'http://127.0.0.1:' + $Port if (Test-PortInUse $Port) { Write-Host ('警告: 端口 ' + $Port + ' 已被占用。若 serve.py 已在运行,可直接访问:') -ForegroundColor Yellow Write-Host (' 播放页: ' + $baseUrl + '/viewer/play.html') -ForegroundColor White Write-Host (' 配置页: ' + $baseUrl + '/viewer/index.html') -ForegroundColor White if (-not $NoBrowser) { Start-Process ($baseUrl + '/viewer/play.html') } exit 0 } $env:PORT = $Port.ToString() Write-Step ('启动 serve.py,端口 ' + $Port + ' ...') if ($venvPy) { $proc = Start-Process -FilePath $venvPy -ArgumentList 'serve.py' -WorkingDirectory $Root -PassThru -WindowStyle Normal } else { $arg = '/k ' + $pyInfo.Cmd + ' serve.py' $proc = Start-Process -FilePath 'cmd.exe' -ArgumentList $arg -WorkingDirectory $Root -PassThru -WindowStyle Normal } Write-Step '等待服务就绪 ...' if (-not (Wait-ServerReady $baseUrl)) { Write-Host '错误: 服务 30 秒内未响应,请查看 serve.py 窗口中的报错。' -ForegroundColor Red exit 1 } Write-Host '' Write-Host ('服务已启动 (PID ' + $proc.Id + ')') -ForegroundColor Green Write-Host (' 播放页: ' + $baseUrl + '/viewer/play.html') -ForegroundColor White Write-Host (' 配置页: ' + $baseUrl + '/viewer/index.html') -ForegroundColor White Write-Host (' API: GET ' + $baseUrl + '/api/catalog | POST ' + $baseUrl + '/api/agv') -ForegroundColor White Write-Host '' Write-Host ('关闭服务: 在 serve.py 窗口按 Ctrl+C,或结束 PID ' + $proc.Id) -ForegroundColor DarkGray Write-Host '' if (-not $NoBrowser) { Start-Process ($baseUrl + '/viewer/play.html') }