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

392 lines
13 KiB
Bash
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.
#!/bin/bash
# 智能家居代理系统启动脚本 (Linux/macOS)
# Smart Home Agent System Startup Script (Linux/macOS)
#
# 架构设计:
# - 环境检查模块:统一检查所有运行环境
# - 配置管理模块:集中处理配置文件读取
# - 服务管理模块:统一启动/停止服务
# - 工具函数模块:提供可复用的通用功能
# ========================================
# 初始化设置
# ========================================
set -e # 遇到错误立即退出
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m'
# 全局变量
declare -A CONFIG
declare -a PIDS
PROJECT_ROOT=""
# ========================================
# 工具函数模块
# ========================================
print_section() {
echo
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
echo
}
print_step() {
echo -e "${YELLOW}$1${NC}"
echo -e "${YELLOW}$2${NC}"
echo
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_info() {
echo -e "${GRAY} $1${NC}"
}
# ========================================
# 环境检查模块 - 统一检查所有必要的运行环境
# ========================================
check_command() {
local cmd=$1
local name=$2
local hint=$3
if ! command -v "$cmd" &> /dev/null; then
print_error "错误: 未找到 $name"
print_error "Error: $name not found"
echo -e "${YELLOW} $hint${NC}"
return 1
fi
local version=$("$cmd" --version 2>&1 | head -1)
print_success "$name: $version"
return 0
}
check_environment() {
print_step "检查运行环境..." "Checking runtime environment..."
local all_passed=1
check_command "python3" "Python" "请安装 Python 3.8+ / Please install Python 3.8+" || all_passed=0
check_command "node" "Node.js" "请安装 Node.js 16+ / Please install Node.js 16+" || all_passed=0
check_command "pnpm" "pnpm" "请运行: npm install -g pnpm" || all_passed=0
check_command "uv" "uv" "请运行: pip install uv 或访问 https://docs.astral.sh/uv/" || all_passed=0
echo
if [ $all_passed -eq 0 ]; then
exit 1
fi
}
# ========================================
# 项目定位模块 - 自动定位项目根目录
# ========================================
find_project_root() {
print_step "定位项目根目录..." "Locating project root directory..."
local paths=("." ".." "../..")
for path in "${paths[@]}"; do
if [ -f "$path/config.yaml" ]; then
cd "$path" || exit 1
PROJECT_ROOT=$(pwd)
print_success "配置文件已找到: $PROJECT_ROOT"
print_success "Configuration file found: $PROJECT_ROOT"
return 0
fi
done
print_error "错误: 未找到配置文件 config.yaml"
print_error "Error: Configuration file config.yaml not found"
print_error "当前目录: $PWD"
exit 1
}
# ========================================
# 配置管理模块 - 集中处理配置读取和默认值
# ========================================
read_yaml_port() {
local pattern=$1
local default=$2
local port=$(grep -E "$pattern" config.yaml | head -1 | sed 's/.*port: *\([0-9]*\).*/\1/')
echo "${port:-$default}"
}
initialize_config() {
print_step "读取配置文件..." "Reading configuration file..."
# 定义配置映射pattern|key|default
local configs=(
"backend:.*python:.*port:|BackendPort|3000"
"frontend:.*dev_server:.*port:|FrontendPort|1420"
"conductor:.*port:|ConductorPort|12000"
"air_conditioner:.*port:|AirCondPort|12001"
"air_cleaner:.*port:|AirCleanPort|12002"
"bedside_lamp:.*port:|BedsideLampPort|12004"
)
for config_line in "${configs[@]}"; do
IFS='|' read -r pattern key default <<< "$config_line"
CONFIG[$key]=$(read_yaml_port "$pattern" "$default")
done
print_success "配置读取完成"
print_info "后端端口 / Backend Port: ${CONFIG[BackendPort]}"
print_info "前端端口 / Frontend Port: ${CONFIG[FrontendPort]}"
print_info "Conductor端口: ${CONFIG[ConductorPort]}"
echo
}
# ========================================
# 目录准备模块 - 创建必要的目录
# ========================================
initialize_directories() {
mkdir -p logs temp
}
# ========================================
# 环境准备模块 - Python虚拟环境和依赖
# ========================================
initialize_python_environment() {
print_step "检查 Python 虚拟环境..." "Checking Python virtual environment..."
if [ ! -d ".venv" ]; then
print_error "虚拟环境不存在,正在创建..."
print_error "Virtual environment not found, creating..."
print_info "执行: uv venv"
uv venv
if [ $? -ne 0 ]; then
print_error "虚拟环境创建失败!"
print_error "Virtual environment creation failed!"
exit 1
fi
print_success "虚拟环境创建完成"
else
print_success "虚拟环境已存在"
fi
echo
print_step "安装 Python 依赖..." "Installing Python dependencies..."
print_info "执行: uv sync"
uv sync
if [ $? -ne 0 ]; then
print_error "Python 依赖安装失败!"
print_error "Python dependencies installation failed!"
exit 1
fi
print_success "Python 依赖已安装"
}
initialize_frontend_dependencies() {
print_step "检查前端依赖..." "Checking frontend dependencies..."
if [ ! -d "app/node_modules" ]; then
print_error "前端依赖未安装,正在安装..."
print_error "Frontend dependencies not installed, installing..."
echo
cd app || exit 1
print_info "执行: pnpm install"
pnpm install
if [ $? -ne 0 ]; then
cd ..
print_error "依赖安装失败!"
print_error "Dependency installation failed!"
exit 1
fi
cd ..
print_success "依赖安装完成"
else
print_success "前端依赖已安装"
fi
echo
}
# ========================================
# 服务启动模块 - 统一管理所有服务启动
# ========================================
start_service() {
local index=$1
local name_cn=$2
local name_en=$3
local directory=$4
local command=$5
local port_key=$6
local delay=$7
local port=${CONFIG[$port_key]}
echo -e "${CYAN}[$index/6] 启动$name_cn (端口 $port)...${NC}"
echo -e "${CYAN}[$index/6] Starting $name_en (Port $port)...${NC}"
cd "$PROJECT_ROOT/$directory" || exit 1
# 启动服务并重定向输出到日志
eval "$command" >> "$PROJECT_ROOT/logs/${name_en// /_}.log" 2>&1 &
local pid=$!
PIDS+=($pid)
cd "$PROJECT_ROOT" || exit 1
sleep "$delay"
print_success "$name_cn 已启动"
print_success "$name_en started"
echo
}
start_all_services() {
print_section "正在启动 Moss AI 本地开发环境...
Starting Moss AI Local Development Environment..."
# 定义服务配置index|name_cn|name_en|directory|command|port_key|delay
local services=(
"1|后端服务|Backend Service|app/backend-python|uv run .|BackendPort|3"
"2|总管理代理|Conductor Agent|agents/conductor_agent|uv run .|ConductorPort|3"
"3|空调代理|Air Conditioner Agent|agents/air_conditioner_agent|uv run .|AirCondPort|2"
"4|空气净化器|Air Cleaner Agent|agents/air_cleaner_agent|uv run .|AirCleanPort|2"
"5|床头灯代理|Bedside Lamp Agent|agents/bedside_lamp_agent|uv run .|BedsideLampPort|2"
"6|前端开发服务器|Frontend Dev Server|app|pnpm dev|FrontendPort|3"
)
for service_config in "${services[@]}"; do
IFS='|' read -r idx name_cn name_en dir cmd port_key delay <<< "$service_config"
start_service "$idx" "$name_cn" "$name_en" "$dir" "$cmd" "$port_key" "$delay"
done
print_info "所有服务窗口正在后台运行"
print_info "All services are running in background"
echo
}
# ========================================
# 信息显示模块 - 显示服务地址和使用说明
# ========================================
show_service_info() {
print_section "所有服务已启动完成!
All services started successfully!"
echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ 服务地址 / Service URLs ║${NC}"
echo -e "${CYAN}╠════════════════════════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}║ 【前端应用 / Frontend】 ║${NC}"
echo -e "${YELLOW}║ http://localhost:${CONFIG[FrontendPort]}${NC}"
echo -e "${CYAN}║ ★ 请在浏览器中打开此地址使用应用 ║${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}║ 【后端服务 / Backend】 ║${NC}"
echo -e "${NC}║ http://localhost:${CONFIG[BackendPort]}${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}║ 【智能代理 / Agents】 ║${NC}"
echo -e "${NC}║ 总管理代理 / Conductor: http://localhost:${CONFIG[ConductorPort]}${NC}"
echo -e "${NC}║ 空调代理 / Air Conditioner: http://localhost:${CONFIG[AirCondPort]}${NC}"
echo -e "${NC}║ 空气净化器 / Air Cleaner: http://localhost:${CONFIG[AirCleanPort]}${NC}"
echo -e "${NC}║ 床头灯 / Bedside Lamp: http://localhost:${CONFIG[BedsideLampPort]}${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}"
echo
}
# ========================================
# 服务停止模块 - 统一停止所有服务
# ========================================
stop_all_services() {
echo
print_step "正在停止所有服务..." "Stopping all services..."
# 停止所有启动的进程
for pid in "${PIDS[@]}"; do
if kill -0 "$pid" 2>/dev/null; then
print_info "停止进程 PID: $pid"
kill "$pid" 2>/dev/null || true
fi
done
# 停止端口占用的进程
local ports=(
"${CONFIG[FrontendPort]}"
"${CONFIG[BackendPort]}"
"${CONFIG[ConductorPort]}"
"${CONFIG[AirCondPort]}"
"${CONFIG[AirCleanPort]}"
"${CONFIG[BedsideLampPort]}"
)
for port in "${ports[@]}"; do
# Linux
if command -v lsof &> /dev/null; then
local pid=$(lsof -ti:"$port" 2>/dev/null || true)
if [ -n "$pid" ]; then
print_info "停止端口 $port 的进程 (PID: $pid)"
kill "$pid" 2>/dev/null || true
fi
# macOS alternative
elif command -v netstat &> /dev/null; then
local pid=$(netstat -vanp tcp 2>/dev/null | grep "\.$port " | awk '{print $9}' | head -1)
if [ -n "$pid" ]; then
print_info "停止端口 $port 的进程 (PID: $pid)"
kill "$pid" 2>/dev/null || true
fi
fi
done
print_success "所有服务已停止"
print_success "All services stopped"
}
# ========================================
# 信号处理 - 捕获 Ctrl+C 等中断信号
# ========================================
cleanup() {
stop_all_services
exit 0
}
trap cleanup SIGINT SIGTERM
# ========================================
# 主流程
# ========================================
main() {
clear
print_section "智能家居代理系统启动脚本
Smart Home Agent System Startup Script"
check_environment
find_project_root
initialize_config
initialize_directories
initialize_python_environment
initialize_frontend_dependencies
start_all_services
show_service_info
echo -e "${YELLOW}提示:按 Ctrl+C 停止所有服务并退出${NC}"
echo -e "${YELLOW}Note: Press Ctrl+C to stop all services and exit${NC}"
echo
# 等待用户中断
wait
}
# 运行主程序
main