easyai/start.ps1
wangbo fe370bd5bc
Some checks are pending
Test start.ps1 (Windows) / test-windows (push) Waiting to run
fix: 修复 Windows start.ps1 闪退,保持终端不关闭便于 Debug
- 增加 trap 错误捕获与堆栈输出
- 增加 Wait-ForExit 结束时暂停,避免窗口闪退
- 使用 $PSScriptRoot 获取脚本目录
- README 补充 Windows 权限配置与启动说明

Made-with: Cursor
2026-03-10 22:13:12 +08:00

286 lines
10 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#Requires -Version 5.1
# EasyAI Windows 一键部署脚本
# 仅支持 IP 访问(本地/局域网),不含域名与 HTTPS
# 一行命令: git clone https://git.51easyai.com/wangbo/easyai; cd easyai; .\start.ps1
$ErrorActionPreference = "Stop"
trap {
Write-Host ""
Write-Host "========================================" -ForegroundColor Red
Write-Host " 发生错误(便于 Debug" -ForegroundColor Red
Write-Host "========================================" -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
if ($_.ScriptStackTrace) { Write-Host "`n$($_.ScriptStackTrace)" }
Wait-ForExit
exit 1
}
# 结束时保持窗口不关闭,便于查看输出和 DebugCI 环境自动跳过)
function Wait-ForExit {
if ($env:CI -eq "true") { return }
Write-Host ""
Read-Host "按 Enter 键退出"
}
# 仅配置模式DEPLOY_DRY_RUN=1 只生成配置文件,不执行 Docker 安装和启动
$script:DeployDryRun = if ($env:DEPLOY_DRY_RUN -eq "1") { $true } else { $false }
$script:DeployIP = ""
$script:DeployModeSkip = $false
# Docker Desktop for Windows 下载链接
$DockerDesktopUrl = "https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe"
function Write-Step { param($Msg) Write-Host $Msg }
function Write-Ok { param($Msg) Write-Host "$Msg" -ForegroundColor Green }
function Write-Err { param($Msg) Write-Host "$Msg" -ForegroundColor Red; throw $Msg }
function Write-Warn { param($Msg) Write-Host "⚠️ $Msg" -ForegroundColor Yellow }
# ==================== 项目初始化 ====================
function Init-ProjectDir {
$scriptDir = $PSScriptRoot
if (-not $scriptDir) { throw "无法获取脚本所在目录。请在 easyai 目录下打开 PowerShell 执行: .\start.ps1" }
$composePath = Join-Path $scriptDir "docker-compose.yml"
if (Test-Path $composePath) {
Set-Location $scriptDir
Write-Step "📁 项目目录: $scriptDir"
return
}
Write-Err "未找到 docker-compose.yml请在 easyai 项目目录下运行 start.ps1"
}
# ==================== 配置问答 ====================
function Run-DeployQuestions {
Write-Host ""
Write-Host "================================"
Write-Host " EasyAI 部署配置Windows"
Write-Host "================================"
Write-Host ""
# 非交互模式:环境变量 DEPLOY_IP 已设置
if ($env:DEPLOY_IP) {
$script:DeployIP = $env:DEPLOY_IP.Trim()
Write-Step "使用环境变量: DEPLOY_IP=$($script:DeployIP)"
return
}
Write-Host "请选择访问方式:"
Write-Host " [1] 本地访问 (127.0.0.1) - 仅本机访问,无需放行端口"
Write-Host " [2] 局域网访问 - 同网段设备访问,需放行 3001、3002、3003 端口"
$choice = Read-Host "请选择 [1/2]"
switch ($choice) {
"1" {
$script:DeployIP = "127.0.0.1"
Write-Step "已选择本地访问"
}
"2" {
Write-Host " 提示: 可在本机运行 ipconfig 查看 IPv4 地址"
$lanIp = Read-Host "请输入本机局域网 IP 地址"
$lanIp = $lanIp.Trim()
if ([string]::IsNullOrWhiteSpace($lanIp)) {
Write-Err "IP 不能为空"
}
$script:DeployIP = $lanIp
Write-Warn "请确保防火墙已放行 3001、3002、3003 端口"
}
default {
Write-Err "无效选择"
}
}
}
# ==================== 生成配置文件 ====================
function Setup-EnvFiles {
Write-Host ""
Write-Step "📝 配置环境文件..."
# 复制 .env.tools 和 .env.ASG
if (-not (Test-Path ".env.tools")) {
Copy-Item ".env.tools.sample" ".env.tools"
Write-Ok ".env.tools"
}
if (-not (Test-Path ".env.ASG")) {
Copy-Item ".env.ASG.sample" ".env.ASG"
Write-Ok ".env.ASG"
}
# 配置 .env
if (-not (Test-Path ".env")) {
Copy-Item ".env.sample" ".env"
}
$content = Get-Content ".env" -Raw -Encoding UTF8
if (-not $content) { $content = "" }
$content = $content -replace '(?m)^NUXT_PUBLIC_BASE_APIURL=.*', "NUXT_PUBLIC_BASE_APIURL=http://$($script:DeployIP):3001"
$content = $content -replace '(?m)^NUXT_PUBLIC_BASE_SOCKETURL=.*', "NUXT_PUBLIC_BASE_SOCKETURL=ws://$($script:DeployIP):3002"
$content = $content -replace '(?m)^NUXT_PUBLIC_SG_APIURL=.*', "NUXT_PUBLIC_SG_APIURL=http://$($script:DeployIP):3003"
# 保持文件末尾换行
if ($content -and -not $content.EndsWith("`n")) { $content += "`n" }
$envPath = Join-Path (Get-Location) ".env"
[System.IO.File]::WriteAllText($envPath, $content, [System.Text.UTF8Encoding]::new($false))
Write-Ok ".env 已配置为 IP 模式 ($($script:DeployIP))"
}
# ==================== Docker 检测 ====================
function Test-DockerInstalled {
$docker = Get-Command docker -ErrorAction SilentlyContinue
if (-not $docker) { return $false }
try {
$null = & docker --version 2>&1
return $true
} catch {
return $false
}
}
function Install-DockerDesktop {
$isWin = ($env:OS -eq "Windows_NT") -or ($PSVersionTable.PSVersion.Major -ge 6 -and $IsWindows)
if (-not $isWin) {
Write-Warn "自动安装仅支持 Windows。请手动安装 Docker Desktop。"
Write-Host "下载地址: $DockerDesktopUrl"
Wait-ForExit; exit 1
}
# 优先 winget其次 Chocolatey
if (Get-Command winget -ErrorAction SilentlyContinue) {
Write-Step "正在通过 winget 安装 Docker Desktop for Windows..."
winget install --id Docker.DockerDesktop -e --accept-source-agreements --accept-package-agreements
if ($LASTEXITCODE -eq 0) {
Write-Ok "安装已启动。安装完成后请重启终端,然后重新运行本脚本。"
exit 0
}
}
if (Get-Command choco -ErrorAction SilentlyContinue) {
Write-Step "正在通过 Chocolatey 安装 Docker Desktop for Windows..."
choco install docker-desktop -y
if ($LASTEXITCODE -eq 0) {
Write-Ok "安装已启动。安装完成后请重启终端,然后重新运行本脚本。"
exit 0
}
}
Write-Warn "未找到 winget 或 Chocolatey请手动安装 Docker Desktop。"
Write-Host "下载地址: $DockerDesktopUrl"
Wait-ForExit; exit 1
}
function Test-Docker {
Write-Host ""
Write-Host "================================"
Write-Host " Docker 检查"
Write-Host "================================"
Write-Host ""
if (Test-DockerInstalled) {
Write-Ok "Docker 已安装"
$v = docker --version 2>$null
if ($v) { Write-Host " $v" }
return
}
Write-Warn "未检测到 Docker Desktop for Windows"
Write-Host ""
Write-Host "请选择:"
Write-Host " [1] 手动安装 - 打开下载页面,退出脚本"
Write-Host " [2] 自动安装 - 通过 winget 或 Chocolatey 安装(需管理员权限)"
$choice = Read-Host "请选择 [1/2]"
switch ($choice) {
"1" {
Write-Host ""
Write-Host "Docker Desktop for Windows 下载地址:"
Write-Host " $DockerDesktopUrl"
Write-Host ""
Write-Host "安装完成后请重新运行本脚本。"
if ($env:OS -eq "Windows_NT") {
Start-Process $DockerDesktopUrl
}
Wait-ForExit; exit 1
}
"2" {
Install-DockerDesktop
}
default {
Write-Err "无效选择"
}
}
}
# ==================== 启动服务 ====================
function Start-Services {
Write-Host ""
Write-Step "🚀 启动 EasyAI 服务..."
$hasComposeV2 = $false
try {
$null = docker compose version 2>&1
$hasComposeV2 = $true
} catch { }
if ($hasComposeV2) {
docker compose pull
if ($LASTEXITCODE -ne 0) { Write-Err "docker compose pull 失败" }
docker compose up -d
if ($LASTEXITCODE -ne 0) { Write-Err "docker compose up 失败" }
} else {
docker-compose pull
if ($LASTEXITCODE -ne 0) { Write-Err "docker-compose pull 失败" }
docker-compose up -d
if ($LASTEXITCODE -ne 0) { Write-Err "docker-compose up 失败" }
}
Write-Host "🎉 EasyAI 应用启动成功"
}
# ==================== 主流程 ====================
function Main {
Init-ProjectDir
# 检查是否已有 .env 且非强制重新配置
if ((Test-Path ".env") -and -not $env:DEPLOY_FORCE_RECONFIG -and -not $env:DEPLOY_IP) {
Write-Step "📁 检测到已有 .env 配置"
$reconfigure = Read-Host "是否重新配置访问方式?[y/N]"
if ($reconfigure -notmatch '^[yY]') {
Write-Step "使用现有配置继续..."
# 从现有 .env 读取 IP用于最后输出
$line = Get-Content ".env" | Where-Object { $_ -match '^NUXT_PUBLIC_BASE_APIURL=http://([^:]+):3001' } | Select-Object -First 1
if ($line -match 'http://([^:]+):3001') { $script:DeployIP = $Matches[1] }
$script:DeployModeSkip = $true
}
}
if (-not $script:DeployModeSkip) {
Run-DeployQuestions
}
if (-not $script:DeployModeSkip) {
Setup-EnvFiles
} else {
if (-not (Test-Path ".env.tools")) { Copy-Item ".env.tools.sample" ".env.tools" }
if (-not (Test-Path ".env.ASG")) { Copy-Item ".env.ASG.sample" ".env.ASG" }
}
if ($script:DeployDryRun) {
Write-Host ""
Write-Warn "dry-run 模式:跳过 Docker 安装和服务启动"
Write-Host " 配置文件已生成,可直接运行 .\start.ps1 完成部署"
} else {
Test-Docker
Start-Services
}
Write-Host ""
Write-Host "================================"
Write-Host " 部署完成"
Write-Host "================================"
$accessIp = if ($script:DeployIP) { $script:DeployIP } else { "127.0.0.1" }
Write-Host "访问地址: http://${accessIp}:3010"
Write-Host ""
Wait-ForExit
}
Write-Host "EasyAI Windows 部署脚本启动中..." -ForegroundColor Cyan
Write-Host ""
Main