Files
moss-ai/script/start/start_moss_ai.ps1
雷雨 8635b84b2d init
2025-12-15 22:05:56 +08:00

409 lines
16 KiB
PowerShell
Raw Permalink 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.
#!/usr/bin/env pwsh
# -*- coding: utf-8 -*-
# 智能家居代理系统启动脚本 (PowerShell)
# Smart Home Agent System Startup Script (PowerShell)
#
# 架构设计:
# - 环境检查模块:统一检查所有运行环境
# - 配置管理模块:集中处理配置文件读取
# - 服务管理模块:统一启动/停止服务
# - 工具函数模块:提供可复用的通用功能
# ========================================
# 初始化设置
# ========================================
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
try { chcp 65001 > $null } catch { }
# ========================================
# 全局变量
# ========================================
$script:Config = @{}
$script:Jobs = @()
$script:ProjectRoot = ""
# ========================================
# 工具函数模块
# ========================================
function Write-ColorText {
param(
[string]$Text,
[string]$Color = "White"
)
Write-Host $Text -ForegroundColor $Color
}
function Write-Section {
param([string]$Title)
Write-Host ""
Write-ColorText "========================================" "Cyan"
Write-ColorText $Title "Cyan"
Write-ColorText "========================================" "Cyan"
Write-Host ""
}
function Write-Step {
param(
[string]$TextCN,
[string]$TextEN
)
Write-ColorText $TextCN "Yellow"
Write-ColorText $TextEN "Yellow"
Write-Host ""
}
# ========================================
# 环境检查模块 - 统一检查所有必要的运行环境
# ========================================
function Test-CommandExists {
param(
[string]$Command,
[string]$DisplayName,
[string]$InstallHint
)
try {
$version = & $Command --version 2>&1
if ($LASTEXITCODE -ne 0) { throw }
Write-ColorText "$DisplayName`: $version" "Green"
return $true
}
catch {
Write-ColorText "✗ 错误: 未找到 $DisplayName" "Red"
Write-ColorText "✗ Error: $DisplayName not found" "Red"
Write-ColorText " $InstallHint" "Yellow"
return $false
}
}
function Test-Environment {
Write-Step "检查运行环境..." "Checking runtime environment..."
$checks = @(
@{ Command = "python"; Name = "Python"; Hint = "请安装 Python 3.8+ / Please install Python 3.8+" },
@{ Command = "node"; Name = "Node.js"; Hint = "请安装 Node.js 16+ / Please install Node.js 16+" },
@{ Command = "pnpm"; Name = "pnpm"; Hint = "请运行: npm install -g pnpm" },
@{ Command = "uv"; Name = "uv"; Hint = "请运行: pip install uv 或访问 https://docs.astral.sh/uv/" }
)
$allPassed = $true
foreach ($check in $checks) {
if (-not (Test-CommandExists -Command $check.Command -DisplayName $check.Name -InstallHint $check.Hint)) {
$allPassed = $false
}
}
if (-not $allPassed) {
Read-Host "按Enter键退出 / Press Enter to exit"
exit 1
}
}
# ========================================
# 项目定位模块 - 自动定位项目根目录
# ========================================
function Find-ProjectRoot {
Write-Step "定位项目根目录..." "Locating project root directory..."
$paths = @(".", "..", "..\..")
foreach ($path in $paths) {
$configPath = Join-Path $path "config.yaml"
if (Test-Path $configPath) {
Set-Location $path
$script:ProjectRoot = (Get-Location).Path
Write-ColorText "✓ 配置文件已找到: $script:ProjectRoot" "Green"
Write-ColorText "✓ Configuration file found: $script:ProjectRoot" "Green"
return $true
}
}
Write-ColorText "✗ 错误: 未找到配置文件 config.yaml" "Red"
Write-ColorText "✗ Error: Configuration file config.yaml not found" "Red"
Write-ColorText " 当前目录: $PWD" "Yellow"
Read-Host "按Enter键退出 / Press Enter to exit"
exit 1
}
# ========================================
# 配置管理模块 - 集中处理配置读取和默认值
# ========================================
function Read-YamlConfig {
param([string]$Pattern, [int]$DefaultValue)
$yamlContent = Get-Content "config.yaml" -Raw
if ($yamlContent -match $Pattern) {
return [int]$matches[1]
}
return $DefaultValue
}
function Initialize-Config {
Write-Step "读取配置文件..." "Reading configuration file..."
# 定义配置映射Pattern, Key, DefaultValue
$configMappings = @(
@{ Pattern = "backend:[\s\S]*?python:[\s\S]*?port:\s*(\d+)"; Key = "BackendPort"; Default = 3000 },
@{ Pattern = "frontend:[\s\S]*?dev_server:[\s\S]*?port:\s*(\d+)"; Key = "FrontendPort"; Default = 1420 },
@{ Pattern = "conductor:[\s\S]*?port:\s*(\d+)"; Key = "ConductorPort"; Default = 12000 },
@{ Pattern = "air_conditioner:[\s\S]*?port:\s*(\d+)"; Key = "AirCondPort"; Default = 12001 },
@{ Pattern = "air_cleaner:[\s\S]*?port:\s*(\d+)"; Key = "AirCleanPort"; Default = 12002 },
@{ Pattern = "bedside_lamp:[\s\S]*?port:\s*(\d+)"; Key = "BedsideLampPort"; Default = 12004 }
)
foreach ($mapping in $configMappings) {
$script:Config[$mapping.Key] = Read-YamlConfig -Pattern $mapping.Pattern -DefaultValue $mapping.Default
}
Write-ColorText "✓ 配置读取完成" "Green"
Write-ColorText " - 后端端口 / Backend Port: $($script:Config.BackendPort)" "Gray"
Write-ColorText " - 前端端口 / Frontend Port: $($script:Config.FrontendPort)" "Gray"
Write-ColorText " - Conductor端口: $($script:Config.ConductorPort)" "Gray"
}
# ========================================
# 目录准备模块 - 创建必要的目录
# ========================================
function Initialize-Directories {
Write-Step "创建必要的目录..." "Creating necessary directories..."
$directories = @("logs", "temp")
foreach ($dir in $directories) {
if (-not (Test-Path $dir)) {
New-Item -ItemType Directory -Path $dir | Out-Null
Write-ColorText "✓ 创建目录: $dir" "Green"
}
}
}
# ========================================
# 环境准备模块 - Python虚拟环境和依赖
# ========================================
function Initialize-PythonEnvironment {
Write-Step "检查 Python 虚拟环境..." "Checking Python virtual environment..."
if (-not (Test-Path ".venv")) {
Write-ColorText "✗ 虚拟环境不存在,正在创建..." "Yellow"
Write-ColorText " 执行: uv venv" "Gray"
& uv venv
if ($LASTEXITCODE -ne 0) {
Write-ColorText "✗ 虚拟环境创建失败!" "Red"
throw "Virtual environment creation failed"
}
Write-ColorText "✓ 虚拟环境创建完成" "Green"
}
else {
Write-ColorText "✓ 虚拟环境已存在" "Green"
}
Write-Host ""
Write-Step "安装 Python 依赖..." "Installing Python dependencies..."
Write-ColorText " 执行: uv sync" "Gray"
& uv sync
if ($LASTEXITCODE -ne 0) {
Write-ColorText "✗ Python 依赖安装失败!" "Red"
throw "Python dependencies installation failed"
}
Write-ColorText "✓ Python 依赖已安装" "Green"
}
function Initialize-FrontendDependencies {
Write-Step "检查前端依赖..." "Checking frontend dependencies..."
if (-not (Test-Path "app\node_modules")) {
Write-ColorText "✗ 前端依赖未安装,正在安装..." "Yellow"
Write-Host ""
Push-Location "app"
Write-ColorText " 执行: pnpm install" "Gray"
& pnpm install
if ($LASTEXITCODE -ne 0) {
Pop-Location
Write-ColorText "✗ 依赖安装失败!" "Red"
throw "Frontend dependencies installation failed"
}
Pop-Location
Write-ColorText "✓ 依赖安装完成" "Green"
}
else {
Write-ColorText "✓ 前端依赖已安装" "Green"
}
}
# ========================================
# 服务启动模块 - 统一管理所有服务启动
# ========================================
function Start-ServiceProcess {
param(
[int]$Index,
[string]$NameCN,
[string]$NameEN,
[string]$Directory,
[string]$Command,
[int]$Port,
[int]$Delay
)
Write-ColorText "[$Index/6] 启动$NameCN (端口 $Port)..." "Cyan"
Write-ColorText "[$Index/6] Starting $NameEN (Port $Port)..." "Cyan"
$fullPath = Join-Path $script:ProjectRoot $Directory
$job = Start-Job -ScriptBlock {
param($Path, $Cmd)
Set-Location $Path
Invoke-Expression $Cmd
} -ArgumentList $fullPath, $Command -Name $NameEN
$script:Jobs += @{
Job = $job
Name = $NameEN
Port = $Port
}
Start-Sleep -Seconds $Delay
Write-ColorText "$NameCN`已启动" "Green"
Write-ColorText "$NameEN started" "Green"
Write-Host ""
}
function Start-AllServices {
Write-Section "正在启动 Moss AI 本地开发环境...`nStarting Moss AI Local Development Environment..."
# 定义服务配置Index, NameCN, NameEN, Directory, Command, PortKey, Delay
$services = @(
@{Index=1; NameCN="后端服务"; NameEN="Backend Service"; Dir="app\backend-python"; Cmd="python __main__.py"; PortKey="BackendPort"; Delay=3},
@{Index=2; NameCN="总管理代理"; NameEN="Conductor Agent"; Dir="agents\conductor_agent"; Cmd="python __main__.py"; PortKey="ConductorPort"; Delay=3},
@{Index=3; NameCN="空调代理"; NameEN="Air Conditioner Agent"; Dir="agents\air_conditioner_agent"; Cmd="python __main__.py"; PortKey="AirCondPort"; Delay=2},
@{Index=4; NameCN="空气净化器代理"; NameEN="Air Cleaner Agent"; Dir="agents\air_cleaner_agent"; Cmd="python __main__.py"; PortKey="AirCleanPort"; Delay=2},
@{Index=5; NameCN="床头灯代理"; NameEN="Bedside Lamp Agent"; Dir="agents\bedside_lamp_agent"; Cmd="python __main__.py"; PortKey="BedsideLampPort"; Delay=2},
@{Index=6; NameCN="前端开发服务器"; NameEN="Frontend Dev Server"; Dir="app"; Cmd="pnpm dev"; PortKey="FrontendPort"; Delay=3}
)
foreach ($service in $services) {
Start-ServiceProcess -Index $service.Index -NameCN $service.NameCN -NameEN $service.NameEN `
-Directory $service.Dir -Command $service.Cmd -Port $script:Config[$service.PortKey] -Delay $service.Delay
}
}
# ========================================
# 信息显示模块 - 显示服务地址和使用说明
# ========================================
function Show-ServiceInfo {
Write-Section "所有服务已启动完成!`nAll services started successfully!"
Write-ColorText "╔════════════════════════════════════════════════════════════╗" "Cyan"
Write-ColorText "║ 服务地址 / Service URLs ║" "Cyan"
Write-ColorText "╠════════════════════════════════════════════════════════════╣" "Cyan"
Write-ColorText "║ ║" "Cyan"
Write-ColorText "║ 【前端应用 / Frontend】 ║" "Cyan"
Write-ColorText "║ http://localhost:$($script:Config.FrontendPort)" "Yellow"
Write-ColorText "║ ★ 请在浏览器中打开此地址使用应用 ║" "Cyan"
Write-ColorText "║ ║" "Cyan"
Write-ColorText "║ 【后端服务 / Backend】 ║" "Cyan"
Write-ColorText "║ http://localhost:$($script:Config.BackendPort)" "White"
Write-ColorText "║ ║" "Cyan"
Write-ColorText "║ 【智能代理 / Agents】 ║" "Cyan"
Write-ColorText "║ 总管理代理 / Conductor: http://localhost:$($script:Config.ConductorPort)" "White"
Write-ColorText "║ 空调代理 / Air Conditioner: http://localhost:$($script:Config.AirCondPort)" "White"
Write-ColorText "║ 空气净化器 / Air Cleaner: http://localhost:$($script:Config.AirCleanPort)" "White"
Write-ColorText "║ 床头灯 / Bedside Lamp: http://localhost:$($script:Config.BedsideLampPort)" "White"
Write-ColorText "║ ║" "Cyan"
Write-ColorText "╚════════════════════════════════════════════════════════════╝" "Cyan"
Write-Host ""
}
# ========================================
# 服务停止模块 - 统一停止所有服务
# ========================================
function Stop-AllServices {
Write-Host ""
Write-ColorText "正在停止所有服务..." "Yellow"
Write-ColorText "Stopping all services..." "Yellow"
Write-Host ""
# 停止所有后台任务
foreach ($jobInfo in $script:Jobs) {
if ($jobInfo.Job.State -eq 'Running') {
Write-ColorText "停止服务: $($jobInfo.Name)" "Gray"
Stop-Job -Job $jobInfo.Job
Remove-Job -Job $jobInfo.Job -Force
}
}
# 停止端口占用的进程
$ports = @(
$script:Config.FrontendPort,
$script:Config.BackendPort,
$script:Config.ConductorPort,
$script:Config.AirCondPort,
$script:Config.AirCleanPort,
$script:Config.BedsideLampPort
)
foreach ($port in $ports) {
$connections = Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue
foreach ($conn in $connections) {
$process = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue
if ($process) {
Write-ColorText "停止端口 $port 的进程: $($process.Name) (PID: $($process.Id))" "Gray"
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
}
}
}
Write-ColorText "✓ 所有服务已停止" "Green"
Write-ColorText "✓ All services stopped" "Green"
}
# ========================================
# 主流程
# ========================================
function Main {
try {
Clear-Host
Write-Section "智能家居代理系统启动脚本`nSmart Home Agent System Startup Script"
Test-Environment
Find-ProjectRoot
Initialize-Config
Initialize-Directories
Initialize-PythonEnvironment
Initialize-FrontendDependencies
Start-AllServices
Show-ServiceInfo
Write-ColorText "提示:按 Ctrl+C 停止所有服务并退出" "Yellow"
Write-ColorText "Note: Press Ctrl+C to stop all services and exit" "Yellow"
Write-Host ""
# 等待用户中断
try {
while ($true) {
Start-Sleep -Seconds 1
}
}
catch {
# Ctrl+C 被按下
}
}
catch {
Write-ColorText "`n✗ 发生错误: $_" "Red"
Write-ColorText "✗ Error occurred: $_" "Red"
}
finally {
Stop-AllServices
Start-Sleep -Seconds 2
}
}
# 运行主程序
Main