start.ps1 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. # ============================================================
  2. # LambdaAgentPaaS — Windows 一键启动脚本 (PowerShell)
  3. #
  4. # 用法:
  5. # .\deploy\start.ps1 # 正常启动
  6. # .\deploy\start.ps1 -Build # 强制重新构建镜像
  7. # .\deploy\start.ps1 -Reset # 清除所有数据重新初始化
  8. #
  9. # 要求: Docker Desktop for Windows 已安装并运行
  10. # PowerShell 5.1 或 PowerShell 7+
  11. # ============================================================
  12. param(
  13. [switch]$Build,
  14. [switch]$Reset
  15. )
  16. $ErrorActionPreference = "Stop"
  17. # ── 路径常量 ────────────────────────────────────────────────
  18. $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
  19. $ProjectDir = Split-Path -Parent $ScriptDir
  20. $DataDir = Join-Path $env:USERPROFILE ".agentpaas\data"
  21. $EnvFile = Join-Path $env:USERPROFILE ".agentpaas\.env"
  22. $AppPort = if ($env:AGENTPAAS_PORT) { $env:AGENTPAAS_PORT } else { "8000" }
  23. $AppUrl = "http://localhost:$AppPort"
  24. # ── 颜色输出辅助函数 ─────────────────────────────────────────
  25. function Write-Info { param($msg) Write-Host "ℹ $msg" -ForegroundColor Cyan }
  26. function Write-Success { param($msg) Write-Host "✅ $msg" -ForegroundColor Green }
  27. function Write-Warn { param($msg) Write-Host "⚠️ $msg" -ForegroundColor Yellow }
  28. function Write-Err { param($msg) Write-Host "❌ $msg" -ForegroundColor Red }
  29. function Write-Header { param($msg) Write-Host "`n=== $msg ===`n" -ForegroundColor Magenta }
  30. # ── 检查 Docker ──────────────────────────────────────────────
  31. function Check-Docker {
  32. Write-Header "检查 Docker 环境"
  33. if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
  34. Write-Err "未找到 Docker。请先安装 Docker Desktop:"
  35. Write-Host " https://docs.docker.com/desktop/install/windows-install/"
  36. $open = Read-Host "是否现在打开下载页面? (Y/n)"
  37. if ($open -ne 'n' -and $open -ne 'N') {
  38. Start-Process "https://docs.docker.com/desktop/install/windows-install/"
  39. }
  40. exit 1
  41. }
  42. $dockerRunning = $false
  43. try {
  44. docker info 2>&1 | Out-Null
  45. $dockerRunning = $true
  46. } catch {}
  47. if (-not $dockerRunning) {
  48. Write-Info "Docker Desktop 未运行,尝试启动..."
  49. $dockerDesktopPaths = @(
  50. "$env:ProgramFiles\Docker\Docker\Docker Desktop.exe",
  51. "$env:LOCALAPPDATA\Programs\Docker\Docker\Docker Desktop.exe"
  52. )
  53. $launched = $false
  54. foreach ($path in $dockerDesktopPaths) {
  55. if (Test-Path $path) {
  56. Start-Process $path
  57. $launched = $true
  58. break
  59. }
  60. }
  61. if (-not $launched) {
  62. Write-Warn "无法自动启动 Docker Desktop,请手动启动后重试。"
  63. exit 1
  64. }
  65. Write-Host -NoNewline "等待 Docker 就绪"
  66. $waited = 0
  67. do {
  68. Start-Sleep -Seconds 2
  69. $waited += 2
  70. Write-Host -NoNewline "."
  71. if ($waited -gt 60) {
  72. Write-Host ""
  73. Write-Err "Docker 启动超时(60s)。请手动启动 Docker Desktop 后重试。"
  74. exit 1
  75. }
  76. try { docker info 2>&1 | Out-Null; break } catch {}
  77. } while ($true)
  78. Write-Host ""
  79. Write-Success "Docker 已就绪"
  80. }
  81. # 检测 compose 命令
  82. $script:ComposeCmd = $null
  83. try { docker compose version 2>&1 | Out-Null; $script:ComposeCmd = "docker compose" } catch {}
  84. if (-not $script:ComposeCmd) {
  85. if (Get-Command docker-compose -ErrorAction SilentlyContinue) {
  86. $script:ComposeCmd = "docker-compose"
  87. } else {
  88. Write-Err "未找到 docker compose。请升级 Docker Desktop 到最新版本。"
  89. exit 1
  90. }
  91. }
  92. Write-Success "Docker 环境检查通过"
  93. }
  94. # ── 初始化数据目录 ────────────────────────────────────────────
  95. function Init-DataDir {
  96. $dirs = @(
  97. $DataDir,
  98. (Join-Path $DataDir "instances"),
  99. (Join-Path $DataDir "knowledge_bases"),
  100. (Join-Path $DataDir "logs")
  101. )
  102. foreach ($dir in $dirs) {
  103. if (-not (Test-Path $dir)) {
  104. New-Item -ItemType Directory -Path $dir -Force | Out-Null
  105. }
  106. }
  107. }
  108. # ── 初始化 .env 配置 ─────────────────────────────────────────
  109. function Init-Env {
  110. $configDir = Split-Path -Parent $EnvFile
  111. if (-not (Test-Path $configDir)) {
  112. New-Item -ItemType Directory -Path $configDir -Force | Out-Null
  113. }
  114. if ((Test-Path $EnvFile) -and (-not $Reset)) {
  115. return
  116. }
  117. Write-Header "🔧 首次配置初始化"
  118. # 复制模板
  119. Copy-Item (Join-Path $ProjectDir ".env.template") $EnvFile -Force
  120. # 生成 MASTER_KEY
  121. $masterKey = -join ((1..32) | ForEach-Object {
  122. [System.Security.Cryptography.RandomNumberGenerator]::GetBytes(1) |
  123. ForEach-Object { $_.ToString("x2") }
  124. })
  125. # 更新 .env 文件
  126. $envContent = Get-Content $EnvFile
  127. $envContent = $envContent -replace "^AGENTPAAS_DATA_DIR=.*", "AGENTPAAS_DATA_DIR=$DataDir"
  128. $envContent = $envContent -replace "^AGENTPAAS_MASTER_KEY=.*", "AGENTPAAS_MASTER_KEY=$masterKey"
  129. $envContent | Set-Content $EnvFile -Encoding UTF8
  130. Write-Success "配置文件已创建: $EnvFile"
  131. Write-Host ""
  132. Write-Warn "请编辑配置文件,填写至少一个 LLM API Key:"
  133. Write-Host " DASHSCOPE_API_KEY= (阿里云百炼,国内推荐)"
  134. Write-Host " ANTHROPIC_API_KEY= (Claude)"
  135. Write-Host " OPENAI_API_KEY= (GPT)"
  136. Write-Host ""
  137. $open = Read-Host "是否现在打开配置文件编辑? (Y/n)"
  138. if ($open -ne 'n' -and $open -ne 'N') {
  139. # 尝试用记事本打开
  140. Start-Process notepad $EnvFile
  141. Write-Host "配置完成后,请重新运行此脚本。"
  142. exit 0
  143. }
  144. }
  145. # ── 加载 .env 文件为环境变量 ─────────────────────────────────
  146. function Load-EnvFile {
  147. if (-not (Test-Path $EnvFile)) { return }
  148. Get-Content $EnvFile | ForEach-Object {
  149. if ($_ -match "^\s*([^#][^=]+)=(.*)$") {
  150. $name = $matches[1].Trim()
  151. $value = $matches[2].Trim()
  152. if ($value -ne "" -and -not [System.Environment]::GetEnvironmentVariable($name)) {
  153. [System.Environment]::SetEnvironmentVariable($name, $value, "Process")
  154. }
  155. }
  156. }
  157. }
  158. # ── 检查 API Keys ────────────────────────────────────────────
  159. function Check-ApiKeys {
  160. $keyVars = @("DASHSCOPE_API_KEY","OPENAI_API_KEY","ANTHROPIC_API_KEY",
  161. "DEEPSEEK_API_KEY","ZHIPU_API_KEY","MOONSHOT_API_KEY")
  162. $hasKey = $false
  163. foreach ($var in $keyVars) {
  164. $val = [System.Environment]::GetEnvironmentVariable($var)
  165. if ($val -and $val.Trim() -ne "") { $hasKey = $true; break }
  166. }
  167. if (-not $hasKey) {
  168. Write-Warn "未检测到任何 LLM API Key。Agent 功能将不可用。"
  169. Write-Host "请在 $EnvFile 中配置至少一个 API Key。"
  170. Write-Host ""
  171. $cont = Read-Host "继续启动? (y/N)"
  172. if ($cont -ne 'y' -and $cont -ne 'Y') { exit 0 }
  173. }
  174. }
  175. # ── 启动服务 ─────────────────────────────────────────────────
  176. function Start-Services {
  177. Write-Header "🚀 启动 LambdaAgentPaaS"
  178. # 将 Windows 路径转换为 Docker 可接受格式
  179. # Docker Desktop (WSL2) 可以直接处理 Windows 路径,但统一转换更安全
  180. $env:AGENTPAAS_DATA_DIR = $DataDir
  181. Set-Location $ProjectDir
  182. if ($Reset) {
  183. Write-Info "清除旧容器..."
  184. Invoke-Expression "$($script:ComposeCmd) down --remove-orphans" 2>$null
  185. docker rmi lambdagentpaas:latest 2>$null
  186. }
  187. $buildArg = if ($Build -or $Reset) { "--build" } else { "" }
  188. Write-Info "构建并启动容器(首次构建约 5-10 分钟)..."
  189. Invoke-Expression "$($script:ComposeCmd) --env-file `"$EnvFile`" up -d $buildArg"
  190. }
  191. # ── 等待健康检查 ─────────────────────────────────────────────
  192. function Wait-ForHealth {
  193. Write-Host -NoNewline "等待服务就绪"
  194. $waited = 0
  195. do {
  196. Start-Sleep -Seconds 2
  197. $waited += 2
  198. Write-Host -NoNewline "."
  199. if ($waited -gt 120) {
  200. Write-Host ""
  201. Write-Err "服务启动超时(120s)"
  202. Write-Host "查看日志: docker logs lambdagentpaas"
  203. exit 1
  204. }
  205. try {
  206. $resp = Invoke-WebRequest -Uri "$AppUrl/health" -UseBasicParsing -TimeoutSec 3
  207. if ($resp.StatusCode -eq 200) { break }
  208. } catch {}
  209. } while ($true)
  210. Write-Host ""
  211. }
  212. # ── 打印成功信息 ─────────────────────────────────────────────
  213. function Print-Success {
  214. Write-Host ""
  215. Write-Host "╔══════════════════════════════════════════════╗" -ForegroundColor Green
  216. Write-Host "║ 🎉 LambdaAgentPaaS 已成功启动! ║" -ForegroundColor Green
  217. Write-Host "╠══════════════════════════════════════════════╣" -ForegroundColor Green
  218. Write-Host "║ Web 界面: $AppUrl ║" -ForegroundColor Green
  219. Write-Host "║ API 文档: $AppUrl/docs ║" -ForegroundColor Green
  220. Write-Host "╠══════════════════════════════════════════════╣" -ForegroundColor Green
  221. Write-Host "║ 数据目录: $DataDir" -ForegroundColor Green
  222. Write-Host "║ 配置文件: $EnvFile" -ForegroundColor Green
  223. Write-Host "╠══════════════════════════════════════════════╣" -ForegroundColor Green
  224. Write-Host "║ 停止服务: deploy\stop.bat ║" -ForegroundColor Green
  225. Write-Host "║ 查看日志: docker logs -f lambdagentpaas ║" -ForegroundColor Green
  226. Write-Host "╚══════════════════════════════════════════════╝" -ForegroundColor Green
  227. Write-Host ""
  228. }
  229. # ── 主流程 ───────────────────────────────────────────────────
  230. Write-Header "LambdaAgentPaaS 启动器 (Windows)"
  231. Check-Docker
  232. Init-DataDir
  233. Init-Env
  234. Load-EnvFile
  235. Check-ApiKeys
  236. Start-Services
  237. Wait-ForHealth
  238. Print-Success
  239. # 自动打开浏览器
  240. Start-Process $AppUrl