feat: virtual company module, team projects, PWA dishes app, and startup scripts overhaul
- Add company module (3-tier org, CEO planning, parallel departments) - Add company orchestrator, knowledge extractor, presets, scheduler - Add company API endpoints, models, and frontend views - Add 今天吃啥 PWA app (69 dishes, real images, offline support) - Add team_projects output directory structure - Add unified manage.ps1 for service lifecycle - Add Windows startup guide v1.0 - Add TTS troubleshooting doc - Update frontend (AgentChat UX overhaul, new views) - Update backend (voice engine fix, multi-tenant, RBAC) - Remove deprecated startup scripts and old docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
354
scripts/startup/manage.ps1
Normal file
354
scripts/startup/manage.ps1
Normal file
@@ -0,0 +1,354 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Tiangang AI Agent Platform - Unified Management Script v2.0
|
||||
.DESCRIPTION
|
||||
status - Check all services
|
||||
start - Start all (Redis -> API -> Celery -> Frontend)
|
||||
stop - Stop all
|
||||
restart - Stop all, then start all
|
||||
.EXAMPLE
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\startup\manage.ps1 status
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\startup\manage.ps1 restart
|
||||
#>
|
||||
|
||||
param(
|
||||
[ValidateSet("status", "start", "stop", "restart")]
|
||||
[string]$Action = "status"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
|
||||
$Backend = Join-Path $RepoRoot "backend"
|
||||
$Frontend = Join-Path $RepoRoot "frontend"
|
||||
$RedisExe = Join-Path $Backend "redis\redis-server.exe"
|
||||
|
||||
$RedisPort = 6379
|
||||
$PrimaryApiPort = 8037
|
||||
$FallbackApiPort = 8041
|
||||
$FrontendPort = 3001
|
||||
$script:ApiPort = $PrimaryApiPort
|
||||
|
||||
# ========== UTILITY FUNCTIONS ==========
|
||||
|
||||
function Write-Step { param([string]$Msg) Write-Host ">>> $Msg" -ForegroundColor Cyan }
|
||||
function Write-OK { param([string]$Msg) Write-Host " [OK] $Msg" -ForegroundColor Green }
|
||||
function Write-Fail { param([string]$Msg) Write-Host " [FAIL] $Msg" -ForegroundColor Red }
|
||||
function Write-Warn { param([string]$Msg) Write-Host " [WARN] $Msg" -ForegroundColor Yellow }
|
||||
function Write-Info { param([string]$Msg) Write-Host " [INFO] $Msg" -ForegroundColor Gray }
|
||||
|
||||
function Test-PortListening([int]$Port) {
|
||||
$conn = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue
|
||||
return ($conn -ne $null)
|
||||
}
|
||||
|
||||
function Stop-ByPattern([string]$Pattern, [string]$Label) {
|
||||
$procs = Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match $Pattern
|
||||
}
|
||||
if (-not $procs) {
|
||||
Write-Info "$Label - not running"
|
||||
return
|
||||
}
|
||||
foreach ($p in $procs) {
|
||||
try {
|
||||
Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue
|
||||
Write-OK "Stopped $Label (PID=$($p.ProcessId))"
|
||||
} catch {
|
||||
Write-Fail "Failed to stop $Label (PID=$($p.ProcessId)): $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Start-Background([string]$WorkDir, [string]$Command, [string]$Label) {
|
||||
$fullCmd = "Set-Location '$WorkDir'; .\venv\Scripts\Activate.ps1 2>`$null; $Command"
|
||||
$proc = Start-Process powershell -ArgumentList @(
|
||||
"-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden",
|
||||
"-Command", $fullCmd
|
||||
) -PassThru
|
||||
Write-OK "$Label started (PID=$($proc.Id))"
|
||||
return $proc
|
||||
}
|
||||
|
||||
function Start-Visible([string]$WorkDir, [string]$Command, [string]$Label) {
|
||||
$fullCmd = "Set-Location '$WorkDir'; .\venv\Scripts\Activate.ps1 2>`$null; $Command; Write-Host ''; Write-Host '>>> $Label exited. Press any key to close...'; `$null = `$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')"
|
||||
$proc = Start-Process powershell -ArgumentList @(
|
||||
"-NoExit", "-NoProfile", "-ExecutionPolicy", "Bypass",
|
||||
"-Command", $fullCmd
|
||||
) -PassThru
|
||||
Write-OK "$Label started in new window (PID=$($proc.Id))"
|
||||
return $proc
|
||||
}
|
||||
|
||||
function Start-Frontend([string]$FeDir, [int]$FePort, [int]$ApiPort, [string]$Label) {
|
||||
# Resolve npx full path first (hidden PowerShell windows lack user PATH)
|
||||
$npxPath = (Get-Command npx.cmd -ErrorAction SilentlyContinue).Source
|
||||
if (-not $npxPath) { $npxPath = (Get-Command npx -ErrorAction SilentlyContinue).Source }
|
||||
if (-not $npxPath) { $npxPath = "npx" }
|
||||
|
||||
# Use cmd /k (stay open) to run the whole command chain in a single visible window.
|
||||
# Avoids "cmd /c start" which breaks && chains: start only receives the first
|
||||
# command after the title, and the rest runs in the outer cmd (wrong cwd).
|
||||
$feCmd = "cd /d `"$FeDir`" && set AIAGENT_API_PROXY=http://127.0.0.1:$ApiPort && `"$npxPath`" vite --port $FePort --host 0.0.0.0"
|
||||
$proc = Start-Process cmd -ArgumentList @(
|
||||
"/k", $feCmd
|
||||
) -PassThru
|
||||
Write-OK "$Label started (PID=$($proc.Id), npx=$npxPath)"
|
||||
return $proc
|
||||
}
|
||||
|
||||
function Test-HealthEndpoint([int]$Port) {
|
||||
try {
|
||||
$result = curl.exe -s -o NUL -w "%{http_code}" --connect-timeout 5 "http://127.0.0.1:${Port}/docs" 2>$null
|
||||
return ($result -eq "200")
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# ========== STATUS ==========
|
||||
|
||||
function Invoke-Status {
|
||||
Write-Host ""
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host " Service Status" -ForegroundColor Cyan
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Redis
|
||||
if (Test-PortListening $RedisPort) {
|
||||
Write-OK "Redis port $RedisPort - running"
|
||||
} else {
|
||||
Write-Fail "Redis port $RedisPort - NOT running"
|
||||
}
|
||||
|
||||
# API
|
||||
$apiPort = 0
|
||||
if (Test-PortListening $PrimaryApiPort) {
|
||||
$apiPort = $PrimaryApiPort
|
||||
} elseif (Test-PortListening $FallbackApiPort) {
|
||||
$apiPort = $FallbackApiPort
|
||||
}
|
||||
|
||||
if ($apiPort -gt 0) {
|
||||
$healthy = Test-HealthEndpoint $apiPort
|
||||
$mark = if ($healthy) { "OK" } else { "no response" }
|
||||
Write-OK "Backend API port $apiPort - running [/docs $mark]"
|
||||
} else {
|
||||
Write-Fail "Backend API ports $PrimaryApiPort/$FallbackApiPort - NOT running"
|
||||
}
|
||||
|
||||
# Celery Worker
|
||||
$workers = Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match "celery.*worker"
|
||||
}
|
||||
if ($workers) {
|
||||
Write-OK "Celery Worker $($workers.Count) process(es)"
|
||||
} else {
|
||||
Write-Fail "Celery Worker NOT running"
|
||||
}
|
||||
|
||||
# Celery Beat
|
||||
$beats = Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match "celery.*beat"
|
||||
}
|
||||
if ($beats) {
|
||||
Write-OK "Celery Beat running"
|
||||
} else {
|
||||
Write-Warn "Celery Beat NOT running (scheduled tasks will not trigger)"
|
||||
}
|
||||
|
||||
# Frontend
|
||||
if (Test-PortListening $FrontendPort) {
|
||||
Write-OK "Frontend Vite port $FrontendPort - running"
|
||||
} else {
|
||||
Write-Fail "Frontend Vite port $FrontendPort - NOT running"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "URLs:" -ForegroundColor White
|
||||
if ($apiPort -gt 0) {
|
||||
Write-Host " API docs: http://127.0.0.1:${apiPort}/docs" -ForegroundColor Gray
|
||||
}
|
||||
Write-Host " Frontend: http://localhost:${FrontendPort}" -ForegroundColor Gray
|
||||
Write-Host " AgentChat: http://localhost:${FrontendPort}/agent-chat" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# ========== STOP ==========
|
||||
|
||||
function Invoke-Stop {
|
||||
Write-Host ""
|
||||
Write-Host "== Stop All Services ==" -ForegroundColor Cyan
|
||||
|
||||
Stop-ByPattern "uvicorn\s+app\.main:app" "Backend API"
|
||||
Stop-ByPattern "celery\s+-A\s+app\.core\.celery_app\s+worker" "Celery Worker"
|
||||
Stop-ByPattern "celery\s+-A\s+app\.core\.celery_app\s+beat" "Celery Beat"
|
||||
Stop-ByPattern "vite.*3001|vite.*--port" "Frontend Vite"
|
||||
|
||||
# Redis
|
||||
$redisProcs = Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match "redis-server"
|
||||
}
|
||||
if ($redisProcs) {
|
||||
foreach ($p in $redisProcs) {
|
||||
try {
|
||||
Stop-Process -Id $p.ProcessId -Force
|
||||
Write-OK "Stopped Redis (PID=$($p.ProcessId))"
|
||||
} catch {
|
||||
Write-Fail "Failed to stop Redis (PID=$($p.ProcessId))"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Info "Redis - not running"
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Port status:" -ForegroundColor Cyan
|
||||
foreach ($port in @($RedisPort, $PrimaryApiPort, $FallbackApiPort, $FrontendPort)) {
|
||||
$busy = Test-PortListening $port
|
||||
$label = if ($busy) { "BUSY" } else { "free" }
|
||||
$color = if ($busy) { "Yellow" } else { "Green" }
|
||||
Write-Host " port $port : $label" -ForegroundColor $color
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "DONE: All services stopped" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# ========== START ==========
|
||||
|
||||
function Invoke-Start {
|
||||
Write-Host ""
|
||||
Write-Host "== Start All Services ==" -ForegroundColor Cyan
|
||||
|
||||
# 1. Redis
|
||||
Write-Step "1/5 Redis"
|
||||
if (Test-PortListening $RedisPort) {
|
||||
Write-OK "Redis already running"
|
||||
} else {
|
||||
if (Test-Path $RedisExe) {
|
||||
Start-Process $RedisExe -ArgumentList "--port", $RedisPort -WindowStyle Hidden
|
||||
Start-Sleep -Seconds 1
|
||||
if (Test-PortListening $RedisPort) {
|
||||
Write-OK "Redis started (port $RedisPort)"
|
||||
} else {
|
||||
Write-Fail "Redis failed to start"
|
||||
}
|
||||
} else {
|
||||
Write-Fail "redis-server.exe not found: $RedisExe"
|
||||
}
|
||||
}
|
||||
|
||||
# 2. API port detection
|
||||
Write-Step "2/5 Backend API port check"
|
||||
if (Test-PortListening $PrimaryApiPort) {
|
||||
Write-Warn "Port $PrimaryApiPort is busy, using fallback $FallbackApiPort"
|
||||
$script:ApiPort = $FallbackApiPort
|
||||
} else {
|
||||
$script:ApiPort = $PrimaryApiPort
|
||||
Write-OK "Port $($script:ApiPort) available"
|
||||
}
|
||||
|
||||
# 3. API (uvicorn)
|
||||
Write-Step "3/5 Backend API (port $($script:ApiPort))"
|
||||
$existingApi = @(Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match "uvicorn\s+app\.main:app"
|
||||
})
|
||||
if ($existingApi.Count -gt 0) {
|
||||
Write-OK "Backend API already running"
|
||||
} else {
|
||||
$null = Start-Background $Backend "python -m uvicorn app.main:app --host 0.0.0.0 --port $($script:ApiPort)" "Backend API"
|
||||
}
|
||||
|
||||
# 4. Celery
|
||||
Write-Step "4/5 Celery Worker + Beat"
|
||||
|
||||
$existingWorker = @(Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match "celery.*worker"
|
||||
})
|
||||
if ($existingWorker.Count -gt 0) {
|
||||
Write-OK "Celery Worker already running"
|
||||
} else {
|
||||
$null = Start-Visible $Backend "python -m celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8" "Celery Worker"
|
||||
}
|
||||
|
||||
$existingBeat = @(Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match "celery.*beat"
|
||||
})
|
||||
if ($existingBeat.Count -gt 0) {
|
||||
Write-OK "Celery Beat already running"
|
||||
} else {
|
||||
$null = Start-Visible $Backend "python -m celery -A app.core.celery_app beat --loglevel=info" "Celery Beat"
|
||||
}
|
||||
|
||||
# 5. Frontend
|
||||
Write-Step "5/5 Frontend Vite (port $FrontendPort)"
|
||||
if (Test-PortListening $FrontendPort) {
|
||||
Write-OK "Frontend already running"
|
||||
} else {
|
||||
$null = Start-Frontend $Frontend $FrontendPort $script:ApiPort "Frontend-Vite"
|
||||
}
|
||||
|
||||
# Health check
|
||||
Write-Host ""
|
||||
Write-Step "Health check (waiting up to 30s for services)"
|
||||
|
||||
$maxWait = 30
|
||||
$apiReady = $false
|
||||
$feReady = $false
|
||||
|
||||
for ($i = 1; $i -le $maxWait; $i++) {
|
||||
if (-not $apiReady) {
|
||||
$apiReady = Test-HealthEndpoint $script:ApiPort
|
||||
}
|
||||
if (-not $feReady) {
|
||||
$feReady = Test-PortListening $FrontendPort
|
||||
}
|
||||
|
||||
if ($apiReady -and $feReady) {
|
||||
Write-OK "All services ready (${i}s)"
|
||||
break
|
||||
}
|
||||
|
||||
if ($i % 5 -eq 0) {
|
||||
Write-Info "Waiting... (${i}s) API=$apiReady Frontend=$feReady"
|
||||
}
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
|
||||
if (-not $apiReady) {
|
||||
Write-Fail "Backend API not ready within ${maxWait}s, check logs"
|
||||
}
|
||||
if (-not $feReady) {
|
||||
Write-Fail "Frontend not ready within ${maxWait}s, check logs"
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host ""
|
||||
Write-Host "=============================================" -ForegroundColor Green
|
||||
Write-Host " Startup Complete" -ForegroundColor Green
|
||||
Write-Host "=============================================" -ForegroundColor Green
|
||||
Write-Host " API docs: http://127.0.0.1:$($script:ApiPort)/docs" -ForegroundColor White
|
||||
Write-Host " Frontend: http://localhost:${FrontendPort}" -ForegroundColor White
|
||||
Write-Host " AgentChat: http://localhost:${FrontendPort}/agent-chat" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# ========== RESTART ==========
|
||||
|
||||
function Invoke-Restart {
|
||||
Invoke-Stop
|
||||
Start-Sleep -Seconds 3
|
||||
Invoke-Start
|
||||
}
|
||||
|
||||
# ========== ENTRY ==========
|
||||
|
||||
switch ($Action) {
|
||||
"status" { Invoke-Status }
|
||||
"start" { Invoke-Start }
|
||||
"stop" { Invoke-Stop }
|
||||
"restart" { Invoke-Restart }
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
# Restart backend API (uvicorn) + Celery worker + Celery Beat (scheduler)
|
||||
# 同时确保 Redis 在运行(不会停止 Redis)
|
||||
# Does not stop frontend/Redis.
|
||||
$ErrorActionPreference = "Continue"
|
||||
# Repo root = two levels up from scripts/startup/
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
|
||||
$Backend = Join-Path $RepoRoot "backend"
|
||||
$RedisExe = Join-Path $Backend "redis\redis-server.exe"
|
||||
$RedisPort = 6379
|
||||
$ApiPort = 8037
|
||||
|
||||
Write-Host "== Stop API + Celery worker + Celery Beat ==" -ForegroundColor Cyan
|
||||
@@ -67,7 +70,33 @@ Write-Host "[DONE] 已在新窗口启动 API + Celery Worker + Celery Beat" -For
|
||||
Write-Host "API: http://127.0.0.1:$ApiPort/docs" -ForegroundColor Cyan
|
||||
Write-Host "Celery Beat 负责每分钟检查定时任务,如果定时推送没触发,请确认 Beat 窗口正在运行" -ForegroundColor Yellow
|
||||
|
||||
# ── Redis 守护:确保 Redis 在运行(不会停止 Redis,只补启动)──
|
||||
Write-Host ""
|
||||
Write-Host "== Redis 守护检查 ==" -ForegroundColor Cyan
|
||||
$redisRunning = Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match "redis-server"
|
||||
}
|
||||
if ($redisRunning) {
|
||||
Write-Host "[OK] Redis 已在运行" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[WARN] Redis 未运行,正在启动..." -ForegroundColor Yellow
|
||||
if (Test-Path $RedisExe) {
|
||||
Start-Process $RedisExe -ArgumentList "--port", $RedisPort -WindowStyle Hidden
|
||||
Start-Sleep -Seconds 1
|
||||
$redisNow = Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -and $_.CommandLine -match "redis-server" }
|
||||
if ($redisNow) {
|
||||
Write-Host "[OK] Redis 已启动 (端口 $RedisPort)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Redis 启动失败,请手动启动: $RedisExe --port $RedisPort" -ForegroundColor Red
|
||||
}
|
||||
} else {
|
||||
Write-Host "[FAIL] 未找到 redis-server.exe: $RedisExe" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 2
|
||||
Write-Host ""
|
||||
Write-Host "Port $ApiPort :" -ForegroundColor Cyan
|
||||
netstat -ano | findstr ":$ApiPort"
|
||||
Write-Host "Port $RedisPort :" -ForegroundColor Cyan
|
||||
netstat -ano | findstr ":$RedisPort"
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
param(
|
||||
[int]$ApiPort = 8037,
|
||||
[int]$FallbackApiPort = 8041,
|
||||
[int]$FrontendPort = 3001
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
|
||||
$Backend = Join-Path $RepoRoot "backend"
|
||||
$Frontend = Join-Path $RepoRoot "frontend"
|
||||
$RedisDir = Join-Path $Backend "redis"
|
||||
$RedisExe = Join-Path $RedisDir "redis-server.exe"
|
||||
$RedisCli = Join-Path $RedisDir "redis-cli.exe"
|
||||
|
||||
function Test-PortListening([int]$Port) {
|
||||
$line = netstat -ano | Select-String ":$Port\s+.*LISTENING" | Select-Object -First 1
|
||||
return [bool]$line
|
||||
}
|
||||
|
||||
function Ensure-Redis {
|
||||
if (Test-PortListening 6379) {
|
||||
Write-Host '[OK] Redis already listening on 6379' -ForegroundColor Green
|
||||
return
|
||||
}
|
||||
if (-not (Test-Path $RedisExe)) {
|
||||
throw "Redis executable not found: $RedisExe"
|
||||
}
|
||||
Write-Host '[RUN] Starting Redis on 6379 ...' -ForegroundColor Yellow
|
||||
Start-Process -FilePath $RedisExe -ArgumentList "--port 6379" -WorkingDirectory $RedisDir | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
if (-not (Test-PortListening 6379)) {
|
||||
throw "Redis failed: port 6379 not listening"
|
||||
}
|
||||
if (Test-Path $RedisCli) {
|
||||
& $RedisCli -p 6379 ping | Out-Null
|
||||
}
|
||||
Write-Host '[OK] Redis started' -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Resolve-ApiPort {
|
||||
if (-not (Test-PortListening $ApiPort)) {
|
||||
return $ApiPort
|
||||
}
|
||||
Write-Host ('[WARN] Port {0} is occupied, switching to {1}' -f $ApiPort, $FallbackApiPort) -ForegroundColor Yellow
|
||||
if (Test-PortListening $FallbackApiPort) {
|
||||
throw "Ports $ApiPort and $FallbackApiPort are in use; free one first"
|
||||
}
|
||||
return $FallbackApiPort
|
||||
}
|
||||
|
||||
Write-Host '== AIAgent one-click start ==' -ForegroundColor Cyan
|
||||
Write-Host "Repo: $RepoRoot"
|
||||
|
||||
Ensure-Redis
|
||||
$RealApiPort = Resolve-ApiPort
|
||||
$ApiBase = "http://127.0.0.1:$RealApiPort"
|
||||
|
||||
Write-Host ('[RUN] Starting backend API on {0} ...' -f $RealApiPort) -ForegroundColor Yellow
|
||||
Start-Process powershell -ArgumentList @(
|
||||
"-NoExit",
|
||||
"-Command",
|
||||
"cd '$Backend'; .\venv\Scripts\Activate.ps1; python -m uvicorn app.main:app --host 0.0.0.0 --port $RealApiPort"
|
||||
)
|
||||
|
||||
Write-Host '[RUN] Starting Celery worker ...' -ForegroundColor Yellow
|
||||
Start-Process powershell -ArgumentList @(
|
||||
"-NoExit",
|
||||
"-Command",
|
||||
"cd '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8"
|
||||
)
|
||||
|
||||
Write-Host '[RUN] Starting Celery Beat (scheduler) ...' -ForegroundColor Yellow
|
||||
Start-Process powershell -ArgumentList @(
|
||||
"-NoExit",
|
||||
"-Command",
|
||||
"cd '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app beat --loglevel=info"
|
||||
)
|
||||
|
||||
Write-Host ('[RUN] Starting frontend on {0} (proxy -> {1}) ...' -f $FrontendPort, $ApiBase) -ForegroundColor Yellow
|
||||
Start-Process powershell -ArgumentList @(
|
||||
"-NoExit",
|
||||
"-Command",
|
||||
"`$env:AIAGENT_API_PROXY='$ApiBase'; cd '$Frontend'; pnpm dev --port $FrontendPort"
|
||||
)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host '[DONE] Start commands issued (check new PowerShell windows)' -ForegroundColor Green
|
||||
Write-Host "Frontend: http://localhost:$FrontendPort" -ForegroundColor Cyan
|
||||
Write-Host "API docs: $ApiBase/docs" -ForegroundColor Cyan
|
||||
Write-Host "Redis: 127.0.0.1:6379" -ForegroundColor Cyan
|
||||
@@ -1,112 +0,0 @@
|
||||
# 静默后台启动脚本(无弹窗,日志写文件)
|
||||
# 用于 Windows 任务计划程序开机自启
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
|
||||
$Backend = Join-Path $RepoRoot "backend"
|
||||
$Frontend = Join-Path $RepoRoot "frontend"
|
||||
$RedisDir = Join-Path $Backend "redis"
|
||||
$RedisExe = Join-Path $RedisDir "redis-server.exe"
|
||||
$RedisCli = Join-Path $RedisDir "redis-cli.exe"
|
||||
$LogDir = Join-Path $RepoRoot "logs"
|
||||
$LogFile = Join-Path $LogDir "autostart_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
|
||||
|
||||
if (-not (Test-Path $LogDir)) {
|
||||
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
|
||||
}
|
||||
|
||||
function Write-Log($msg) {
|
||||
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
"$ts $msg" | Out-File -Append -FilePath $LogFile -Encoding UTF8
|
||||
}
|
||||
|
||||
Write-Log "========== AIAgent background start =========="
|
||||
Write-Log "Repo: $RepoRoot"
|
||||
|
||||
# ── 1) Redis ──────────────────────────────────
|
||||
$redisPort = 6379
|
||||
$redisListening = netstat -ano | Select-String ":$redisPort\s+.*LISTENING"
|
||||
if ($redisListening) {
|
||||
Write-Log "Redis already listening on $redisPort"
|
||||
} else {
|
||||
if (-not (Test-Path $RedisExe)) {
|
||||
Write-Log "ERROR: Redis not found at $RedisExe"
|
||||
} else {
|
||||
Write-Log "Starting Redis on $redisPort ..."
|
||||
$redisProc = Start-Process -FilePath $RedisExe `
|
||||
-ArgumentList "--port $redisPort" `
|
||||
-WorkingDirectory $RedisDir `
|
||||
-WindowStyle Hidden `
|
||||
-PassThru
|
||||
Start-Sleep -Seconds 2
|
||||
if (Test-Path $RedisCli) {
|
||||
& $RedisCli -p $redisPort ping 2>&1 | Out-File -Append $LogFile -Encoding UTF8
|
||||
}
|
||||
Write-Log "Redis PID=$($redisProc.Id) started"
|
||||
}
|
||||
}
|
||||
|
||||
# ── 2) Backend API ────────────────────────────
|
||||
$apiPort = 8037
|
||||
$apiListening = netstat -ano | Select-String ":$apiPort\s+.*LISTENING"
|
||||
if ($apiListening) {
|
||||
Write-Log "Backend API already listening on $apiPort"
|
||||
} else {
|
||||
Write-Log "Starting backend API on $apiPort ..."
|
||||
$apiLog = Join-Path $LogDir "api.log"
|
||||
Start-Process powershell `
|
||||
-WindowStyle Hidden `
|
||||
-ArgumentList @(
|
||||
"-NoProfile", "-ExecutionPolicy", "Bypass",
|
||||
"-Command",
|
||||
"Set-Location '$Backend'; .\venv\Scripts\Activate.ps1; python -m uvicorn app.main:app --host 0.0.0.0 --port $apiPort 2>&1 | Out-File -Append '$apiLog' -Encoding UTF8"
|
||||
)
|
||||
Write-Log "Backend API starting (log: $apiLog)"
|
||||
}
|
||||
|
||||
# ── 3) Celery Worker ──────────────────────────
|
||||
Write-Log "Starting Celery worker ..."
|
||||
$celeryLog = Join-Path $LogDir "celery.log"
|
||||
Start-Process powershell `
|
||||
-WindowStyle Hidden `
|
||||
-ArgumentList @(
|
||||
"-NoProfile", "-ExecutionPolicy", "Bypass",
|
||||
"-Command",
|
||||
"Set-Location '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8 2>&1 | Out-File -Append '$celeryLog' -Encoding UTF8"
|
||||
)
|
||||
Write-Log "Celery worker starting (log: $celeryLog)"
|
||||
|
||||
# ── 3.5) Celery Beat (scheduler) ──────────────
|
||||
Write-Log "Starting Celery Beat ..."
|
||||
$beatLog = Join-Path $LogDir "celery_beat.log"
|
||||
Start-Process powershell `
|
||||
-WindowStyle Hidden `
|
||||
-ArgumentList @(
|
||||
"-NoProfile", "-ExecutionPolicy", "Bypass",
|
||||
"-Command",
|
||||
"Set-Location '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app beat --loglevel=info 2>&1 | Out-File -Append '$beatLog' -Encoding UTF8"
|
||||
)
|
||||
Write-Log "Celery Beat starting (log: $beatLog)"
|
||||
|
||||
# ── 4) Frontend (pnpm dev) ────────────────────
|
||||
$frontendPort = 3001
|
||||
$frontendListening = netstat -ano | Select-String ":$frontendPort\s+.*LISTENING"
|
||||
if ($frontendListening) {
|
||||
Write-Log "Frontend already listening on $frontendPort"
|
||||
} else {
|
||||
Write-Log "Starting frontend on $frontendPort ..."
|
||||
$frontendLog = Join-Path $LogDir "frontend.log"
|
||||
Start-Process powershell `
|
||||
-WindowStyle Hidden `
|
||||
-ArgumentList @(
|
||||
"-NoProfile", "-ExecutionPolicy", "Bypass",
|
||||
"-Command",
|
||||
"`$env:AIAGENT_API_PROXY='http://127.0.0.1:$apiPort'; Set-Location '$Frontend'; pnpm dev --port $frontendPort 2>&1 | Out-File -Append '$frontendLog' -Encoding UTF8"
|
||||
)
|
||||
Write-Log "Frontend starting (log: $frontendLog)"
|
||||
}
|
||||
|
||||
Write-Log "========== All services issued =========="
|
||||
Write-Log "Frontend: http://localhost:$frontendPort"
|
||||
Write-Log "API docs: http://127.0.0.1:$apiPort/docs"
|
||||
@@ -1,219 +0,0 @@
|
||||
@echo off
|
||||
echo ==============================================
|
||||
echo 天工智能体平台 - Windows 启动脚本
|
||||
echo ==============================================
|
||||
echo.
|
||||
|
||||
REM 检查Python是否安装
|
||||
python --version >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo ❌ Python 未安装或未添加到系统PATH
|
||||
echo 请安装 Python 3.11+ 并确保在PATH中
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 检查Node.js是否安装
|
||||
node --version >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo ❌ Node.js 未安装或未添加到系统PATH
|
||||
echo 请安装 Node.js 18+ 并确保在PATH中
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 检查pnpm是否安装
|
||||
pnpm --version >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo ⚠️ pnpm 未安装,正在安装...
|
||||
npm install -g pnpm
|
||||
if errorlevel 1 (
|
||||
echo ❌ pnpm 安装失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo ✅ 环境检查通过
|
||||
echo.
|
||||
|
||||
REM 进入项目目录
|
||||
cd /d "%~dp0"
|
||||
|
||||
echo ==============================================
|
||||
echo 1. Redis 检查
|
||||
echo ==============================================
|
||||
echo.
|
||||
|
||||
REM 检查Redis服务是否运行
|
||||
sc query Redis >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo ❌ Redis 服务未运行
|
||||
echo.
|
||||
echo 请按以下步骤安装Redis:
|
||||
echo 1. 下载 Redis Windows 版本:https://github.com/microsoftarchive/redis/releases
|
||||
echo 2. 下载 Redis-x64-3.2.100.msi
|
||||
echo 3. 运行安装程序,按照默认设置安装
|
||||
echo 4. Redis 将作为 Windows 服务运行在 6379 端口
|
||||
echo.
|
||||
echo 安装完成后,请重新运行此脚本
|
||||
pause
|
||||
exit /b 1
|
||||
) else (
|
||||
echo ✅ Redis 服务正在运行
|
||||
)
|
||||
|
||||
echo ==============================================
|
||||
echo 2. 启动后端服务
|
||||
echo ==============================================
|
||||
echo.
|
||||
|
||||
REM 进入backend目录
|
||||
cd backend
|
||||
|
||||
REM 检查虚拟环境
|
||||
if not exist "venv\Scripts\activate" (
|
||||
echo ⚠️ 虚拟环境不存在,正在创建...
|
||||
python -m venv venv
|
||||
if errorlevel 1 (
|
||||
echo ❌ 虚拟环境创建失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo ✅ 虚拟环境检查通过
|
||||
|
||||
REM 激活虚拟环境并安装依赖
|
||||
call venv\Scripts\activate
|
||||
|
||||
echo 📦 检查Python依赖...
|
||||
pip list | findstr "fastapi" >nul
|
||||
if errorlevel 1 (
|
||||
echo ⚠️ 正在安装Python依赖...
|
||||
pip install -r requirements.txt
|
||||
if errorlevel 1 (
|
||||
echo ❌ Python依赖安装失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo ✅ Python依赖安装完成
|
||||
) else (
|
||||
echo ✅ Python依赖已安装
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
echo 🔧 配置环境变量...
|
||||
if not exist ".env" (
|
||||
copy env.example .env >nul
|
||||
echo ⚠️ 已创建 .env 文件,请检查配置
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
echo 🗄️ 运行数据库迁移...
|
||||
alembic upgrade head
|
||||
if errorlevel 1 (
|
||||
echo ⚠️ 数据库迁移失败,继续启动...
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
echo 🌐 启动后端服务...
|
||||
echo 后端服务将在 http://localhost:8037 启动
|
||||
echo API文档:http://localhost:8037/docs
|
||||
echo.
|
||||
|
||||
start cmd /k "uvicorn app.main:app --host 0.0.0.0 --port 8037 --reload"
|
||||
|
||||
echo ⏳ 等待后端服务启动...
|
||||
timeout /t 3 /nobreak >nul
|
||||
|
||||
echo.
|
||||
|
||||
echo ==============================================
|
||||
echo 3. 启动 Celery Worker
|
||||
echo ==============================================
|
||||
echo.
|
||||
|
||||
echo 🔄 启动 Celery Worker...
|
||||
start cmd /k "celery -A app.core.celery_app worker --loglevel=info"
|
||||
|
||||
echo ⏳ 等待 Celery Worker 启动...
|
||||
timeout /t 2 /nobreak >nul
|
||||
|
||||
echo.
|
||||
|
||||
echo ==============================================
|
||||
echo 4. 启动前端服务
|
||||
echo ==============================================
|
||||
echo.
|
||||
|
||||
REM 返回项目根目录
|
||||
cd ..
|
||||
|
||||
REM 进入frontend目录
|
||||
cd frontend
|
||||
|
||||
echo 📦 检查前端依赖...
|
||||
if not exist "node_modules" (
|
||||
echo ⚠️ 正在安装前端依赖...
|
||||
pnpm install
|
||||
if errorlevel 1 (
|
||||
echo ❌ 前端依赖安装失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo ✅ 前端依赖安装完成
|
||||
) else (
|
||||
echo ✅ 前端依赖已安装
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
echo 🖥️ 启动前端服务...
|
||||
echo 前端服务将在 http://localhost:3000 启动
|
||||
echo.
|
||||
|
||||
start cmd /k "pnpm dev"
|
||||
|
||||
echo ⏳ 等待前端服务启动...
|
||||
timeout /t 5 /nobreak >nul
|
||||
|
||||
echo.
|
||||
|
||||
echo ==============================================
|
||||
echo 🎉 启动完成!
|
||||
echo ==============================================
|
||||
echo.
|
||||
echo 服务访问地址:
|
||||
echo 📍 前端界面: http://localhost:3000
|
||||
echo 📍 后端API: http://localhost:8037
|
||||
echo 📍 API文档: http://localhost:8037/docs
|
||||
echo.
|
||||
echo 服务状态:
|
||||
echo ✅ Redis 服务: 运行中
|
||||
echo ✅ 后端服务: 已启动
|
||||
echo ✅ Celery Worker: 已启动
|
||||
echo ✅ 前端服务: 已启动
|
||||
echo.
|
||||
echo 📋 重要提示:
|
||||
echo 1. 首次访问需要注册新用户
|
||||
echo 2. 保持所有命令行窗口打开
|
||||
echo 3. 停止服务:关闭所有命令行窗口
|
||||
echo.
|
||||
echo ==============================================
|
||||
echo.
|
||||
|
||||
REM 返回项目根目录
|
||||
cd ..
|
||||
|
||||
echo 按任意键打开浏览器访问前端界面...
|
||||
pause >nul
|
||||
start http://localhost:3000
|
||||
|
||||
echo.
|
||||
echo 脚本执行完成!
|
||||
echo 按任意键退出...
|
||||
pause >nul
|
||||
@@ -1,239 +0,0 @@
|
||||
# 天工智能体平台 - Windows PowerShell 启动脚本
|
||||
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host "天工智能体平台 - Windows 启动脚本" -ForegroundColor Cyan
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# 检查Python是否安装
|
||||
try {
|
||||
$pythonVersion = python --version 2>&1
|
||||
Write-Host "✅ Python 版本: $pythonVersion" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "❌ Python 未安装或未添加到系统PATH" -ForegroundColor Red
|
||||
Write-Host "请安装 Python 3.11+ 并确保在PATH中"
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 检查Node.js是否安装
|
||||
try {
|
||||
$nodeVersion = node --version
|
||||
Write-Host "✅ Node.js 版本: $nodeVersion" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "❌ Node.js 未安装或未添加到系统PATH" -ForegroundColor Red
|
||||
Write-Host "请安装 Node.js 18+ 并确保在PATH中"
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 检查pnpm是否安装
|
||||
try {
|
||||
$pnpmVersion = pnpm --version
|
||||
Write-Host "✅ pnpm 版本: $pnpmVersion" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "⚠️ pnpm 未安装,正在安装..." -ForegroundColor Yellow
|
||||
npm install -g pnpm
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "❌ pnpm 安装失败" -ForegroundColor Red
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
Write-Host "✅ pnpm 安装成功" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "✅ 环境检查通过" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# 设置项目目录
|
||||
$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
Set-Location $projectRoot
|
||||
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host "1. Redis 检查" -ForegroundColor Cyan
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# 检查Redis服务是否运行
|
||||
$redisService = Get-Service -Name "Redis" -ErrorAction SilentlyContinue
|
||||
if ($null -eq $redisService -or $redisService.Status -ne "Running") {
|
||||
Write-Host "❌ Redis 服务未运行" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "请按以下步骤安装Redis:" -ForegroundColor Yellow
|
||||
Write-Host "1. 下载 Redis Windows 版本:https://github.com/microsoftarchive/redis/releases"
|
||||
Write-Host "2. 下载 Redis-x64-3.2.100.msi"
|
||||
Write-Host "3. 运行安装程序,按照默认设置安装"
|
||||
Write-Host "4. Redis 将作为 Windows 服务运行在 6379 端口"
|
||||
Write-Host ""
|
||||
Write-Host "安装完成后,请重新运行此脚本" -ForegroundColor Yellow
|
||||
pause
|
||||
exit 1
|
||||
} else {
|
||||
Write-Host "✅ Redis 服务正在运行 (状态: $($redisService.Status))" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host "2. 启动后端服务" -ForegroundColor Cyan
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# 进入backend目录
|
||||
Set-Location "$projectRoot\backend"
|
||||
|
||||
# 检查虚拟环境
|
||||
if (-not (Test-Path "venv\Scripts\activate")) {
|
||||
Write-Host "⚠️ 虚拟环境不存在,正在创建..." -ForegroundColor Yellow
|
||||
python -m venv venv
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "❌ 虚拟环境创建失败" -ForegroundColor Red
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
Write-Host "✅ 虚拟环境创建成功" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "✅ 虚拟环境检查通过" -ForegroundColor Green
|
||||
|
||||
# 激活虚拟环境
|
||||
$activateScript = "$projectRoot\backend\venv\Scripts\Activate.ps1"
|
||||
if (Test-Path $activateScript) {
|
||||
& $activateScript
|
||||
} else {
|
||||
Write-Host "❌ 虚拟环境激活脚本不存在: $activateScript" -ForegroundColor Red
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "📦 检查Python依赖..." -ForegroundColor Cyan
|
||||
$fastapiInstalled = pip list | Select-String "fastapi"
|
||||
if (-not $fastapiInstalled) {
|
||||
Write-Host "⚠️ 正在安装Python依赖..." -ForegroundColor Yellow
|
||||
pip install -r requirements.txt
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "❌ Python依赖安装失败" -ForegroundColor Red
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
Write-Host "✅ Python依赖安装完成" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "✅ Python依赖已安装" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🔧 配置环境变量..." -ForegroundColor Cyan
|
||||
if (-not (Test-Path ".env")) {
|
||||
Copy-Item env.example .env -ErrorAction SilentlyContinue
|
||||
Write-Host "⚠️ 已创建 .env 文件,请检查配置" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🗄️ 运行数据库迁移..." -ForegroundColor Cyan
|
||||
alembic upgrade head
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "⚠️ 数据库迁移失败,继续启动..." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🌐 启动后端服务..." -ForegroundColor Cyan
|
||||
Write-Host "后端服务将在 http://localhost:8037 启动" -ForegroundColor Green
|
||||
Write-Host "API文档:http://localhost:8037/docs" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# 启动后端服务(新窗口)
|
||||
Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$projectRoot\backend'; .\venv\Scripts\Activate.ps1; uvicorn app.main:app --host 0.0.0.0 --port 8037 --reload"
|
||||
|
||||
Write-Host "⏳ 等待后端服务启动..." -ForegroundColor Cyan
|
||||
Start-Sleep -Seconds 3
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host "3. 启动 Celery Worker" -ForegroundColor Cyan
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🔄 启动 Celery Worker..." -ForegroundColor Cyan
|
||||
# Windows 下 prefork 池易卡住任务(Redis 出现大量 unacked),使用线程池更稳定
|
||||
Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$projectRoot\backend'; .\venv\Scripts\Activate.ps1; celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8"
|
||||
|
||||
Write-Host "⏳ 等待 Celery Worker 启动..." -ForegroundColor Cyan
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host "4. 启动前端服务" -ForegroundColor Cyan
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# 返回项目根目录
|
||||
Set-Location $projectRoot
|
||||
|
||||
# 进入frontend目录
|
||||
Set-Location "$projectRoot\frontend"
|
||||
|
||||
Write-Host "📦 检查前端依赖..." -ForegroundColor Cyan
|
||||
if (-not (Test-Path "node_modules")) {
|
||||
Write-Host "⚠️ 正在安装前端依赖..." -ForegroundColor Yellow
|
||||
pnpm install
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "❌ 前端依赖安装失败" -ForegroundColor Red
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
Write-Host "✅ 前端依赖安装完成" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "✅ 前端依赖已安装" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🖥️ 启动前端服务..." -ForegroundColor Cyan
|
||||
Write-Host "前端服务将在 http://localhost:3000 启动" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# 启动前端服务(新窗口)
|
||||
Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$projectRoot\frontend'; pnpm dev"
|
||||
|
||||
Write-Host "⏳ 等待前端服务启动..." -ForegroundColor Cyan
|
||||
Start-Sleep -Seconds 5
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host "🎉 启动完成!" -ForegroundColor Green
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "服务访问地址:" -ForegroundColor White
|
||||
Write-Host " 📍 前端界面: http://localhost:3000" -ForegroundColor Yellow
|
||||
Write-Host " 📍 后端API: http://localhost:8037" -ForegroundColor Yellow
|
||||
Write-Host " 📍 API文档: http://localhost:8037/docs" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "服务状态:" -ForegroundColor White
|
||||
Write-Host " ✅ Redis 服务: 运行中" -ForegroundColor Green
|
||||
Write-Host " ✅ 后端服务: 已启动" -ForegroundColor Green
|
||||
Write-Host " ✅ Celery Worker: 已启动" -ForegroundColor Green
|
||||
Write-Host " ✅ 前端服务: 已启动" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "📋 重要提示:" -ForegroundColor White
|
||||
Write-Host " 1. 首次访问需要注册新用户" -ForegroundColor Gray
|
||||
Write-Host " 2. 保持所有PowerShell窗口打开" -ForegroundColor Gray
|
||||
Write-Host " 3. 停止服务:关闭所有PowerShell窗口" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# 返回项目根目录
|
||||
Set-Location $projectRoot
|
||||
|
||||
Write-Host "是否要打开浏览器访问前端界面?(Y/N)" -ForegroundColor Cyan
|
||||
$response = Read-Host
|
||||
if ($response -eq "Y" -or $response -eq "y") {
|
||||
Start-Process "http://localhost:3000"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "脚本执行完成!" -ForegroundColor Green
|
||||
Write-Host "按任意键退出..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
@@ -1,96 +0,0 @@
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
|
||||
Write-Host "== AIAgent stop ==" -ForegroundColor Cyan
|
||||
|
||||
function Get-PidsListeningOnPort([int]$Port) {
|
||||
$pids = New-Object System.Collections.Generic.HashSet[int]
|
||||
try {
|
||||
# ForEach-Object 里写 return 会从「外层函数」返回,不能只跳过当前行。
|
||||
foreach ($raw in (netstat -ano)) {
|
||||
$ln = $raw.Trim()
|
||||
if ($ln -notmatch "LISTENING") { continue }
|
||||
$norm = $ln -replace '\s+', ' '
|
||||
$parts = $norm.Split(' ')
|
||||
if ($parts.Length -lt 5) { continue }
|
||||
$local = $parts[1]
|
||||
$ci = $local.LastIndexOf(':')
|
||||
if ($ci -lt 0) { continue }
|
||||
if ($local.Substring($ci + 1) -ne "$Port") { continue }
|
||||
$pidStr = $parts[$parts.Length - 1]
|
||||
if ($pidStr -match '^\d+$') {
|
||||
$procId = [int]$pidStr
|
||||
if ($procId -gt 4) { [void]$pids.Add($procId) }
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
return @($pids)
|
||||
}
|
||||
|
||||
function Stop-OnPorts([int[]]$ports, [string]$name) {
|
||||
$all = New-Object System.Collections.Generic.HashSet[int]
|
||||
foreach ($p in $ports) {
|
||||
foreach ($listenPid in (Get-PidsListeningOnPort $p)) {
|
||||
[void]$all.Add($listenPid)
|
||||
}
|
||||
}
|
||||
if ($all.Count -eq 0) {
|
||||
Write-Host "[SKIP] ${name}: no listener on ports $($ports -join ',')" -ForegroundColor DarkGray
|
||||
return
|
||||
}
|
||||
foreach ($procId in $all) {
|
||||
if ($procId -le 4) { continue }
|
||||
try {
|
||||
Stop-Process -Id $procId -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "[OK] stopped ${name} PID=$procId" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "[WARN] failed to stop ${name} PID=$procId" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 后端 API(8037 / 8041 备用)
|
||||
Stop-OnPorts @(8037, 8041) "backend-api"
|
||||
|
||||
# 前端 Vite(3001)
|
||||
Stop-OnPorts @(3001) "frontend-dev"
|
||||
|
||||
# Redis(6379,仅当监听在本地开发端口时结束;若与其它项目共用请谨慎)
|
||||
Stop-OnPorts @(6379) "redis"
|
||||
|
||||
# Celery Worker / Beat(不监听端口,需要按命令行匹配)
|
||||
$celeryPatterns = @(
|
||||
@{Pattern='celery\s+-A\s+app\.core\.celery_app\s+worker'; Name='celery-worker'},
|
||||
@{Pattern='celery\s+-A\s+app\.core\.celery_app\s+beat'; Name='celery-beat'}
|
||||
)
|
||||
foreach ($cp in $celeryPatterns) {
|
||||
$targets = Get-CimInstance Win32_Process | Where-Object {
|
||||
$_.CommandLine -and $_.CommandLine -match $cp.Pattern
|
||||
}
|
||||
if (-not $targets) {
|
||||
Write-Host "[SKIP] $($cp.Name): no matching process" -ForegroundColor DarkGray
|
||||
}
|
||||
foreach ($p in $targets) {
|
||||
try {
|
||||
Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "[OK] stopped $($cp.Name) PID=$($p.ProcessId)" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "[WARN] failed to stop $($cp.Name) PID=$($p.ProcessId)" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Start-Sleep -Milliseconds 600
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Port check:" -ForegroundColor Cyan
|
||||
foreach ($port in 3001, 8037, 8041, 6379) {
|
||||
$line = netstat -ano | Select-String ":$port\s+.*LISTENING" | Select-Object -First 1
|
||||
if ($line) {
|
||||
Write-Host " - ${port}: LISTEN" -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host " - ${port}: free" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "DONE: stop script finished" -ForegroundColor Green
|
||||
Reference in New Issue
Block a user