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:
2026-07-10 22:37:56 +08:00
parent 3483c6b3be
commit f2e65a8fbb
259 changed files with 39239 additions and 3148 deletions

354
scripts/startup/manage.ps1 Normal file
View 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 }
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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")

View File

@@ -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
}
}
}
# 后端 API8037 / 8041 备用)
Stop-OnPorts @(8037, 8041) "backend-api"
# 前端 Vite3001
Stop-OnPorts @(3001) "frontend-dev"
# Redis6379仅当监听在本地开发端口时结束若与其它项目共用请谨慎
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