#!/bin/bash # 开发模式启动脚本 - 前台启动前后端应用(带实时日志) # 作者: Qwen Assistant # 功能: 在前台启动后端和前端,直接在终端显示实时日志 set -e # 遇到错误立即退出 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color # 打印带颜色的消息 print_message() { local color=$1 local message=$2 echo -e "${color}${message}${NC}" } # 检查端口是否被占用 check_port() { local port=$1 if lsof -i :$port > /dev/null 2>&1; then return 0 # 端口被占用 else return 1 # 端口未被占用 fi } # 生成随机可用端口 get_available_port() { local start_port=$1 local max_attempts=50 local port=$start_port local attempts=0 while check_port $port && [ $attempts -lt $max_attempts ]; do port=$((port + 1)) attempts=$((attempts + 1)) done if [ $attempts -eq $max_attempts ]; then print_message $RED "❌ 无法找到可用端口,请手动释放相关端口" exit 1 fi echo $port } print_message $BLUE "🚀 开始启动 WordMaster Pro 系统 (开发模式 - 实时日志)..." # 获取脚本目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # 加载环境变量 if [ -f ".env" ]; then print_message $BLUE "🔧 加载环境变量配置..." export $(grep -v '^#' .env | xargs) BACKEND_PORT=${BACKEND_PORT:-8888} FRONTEND_PORT=${FRONTEND_PORT:-3008} DATABASE_URL=${DATABASE_URL:-"sqlite:///./wordmaster.db"} else print_message $YELLOW "⚠️ 未找到 .env 文件,使用默认配置" BACKEND_PORT=8888 FRONTEND_PORT=3008 DATABASE_URL="sqlite:///./wordmaster.db" fi print_message $BLUE "🔧 使用配置信息:" print_message $GREEN " 后端端口: $BACKEND_PORT" print_message $GREEN " 前端端口: $FRONTEND_PORT" print_message $GREEN " 数据库: $DATABASE_URL" # 检查端口占用情况 print_message $BLUE "🔍 检查端口占用情况..." if check_port $BACKEND_PORT; then print_message $YELLOW "⚠️ 后端端口 $BACKEND_PORT 被占用,寻找可用端口..." BACKEND_PORT=$(get_available_port 8888) print_message $GREEN "ℹ️ 使用后端端口: $BACKEND_PORT" fi if check_port $FRONTEND_PORT; then print_message $YELLOW "⚠️ 前端端口 $FRONTEND_PORT 被占用,寻找可用端口..." FRONTEND_PORT=$(get_available_port 3008) print_message $GREEN "ℹ️ 使用前端端口: $FRONTEND_PORT" fi # 检查并清理之前的进程 print_message $BLUE "🧹 检查并清理之前的进程..." if [ -f ".backend.pid" ]; then OLD_BACKEND_PID=$(cat .backend.pid) if ps -p $OLD_BACKEND_PID > /dev/null 2>&1; then print_message $YELLOW "⚠️ 发现已存在的后端进程 $OLD_BACKEND_PID,正在停止..." kill $OLD_BACKEND_PID 2>/dev/null || true sleep 2 # 等待进程终止 attempts=0 while ps -p $OLD_BACKEND_PID > /dev/null 2>&1 && [ $attempts -lt 10 ]; do sleep 1 attempts=$((attempts + 1)) done # 如果仍未终止,强制杀死 if ps -p $OLD_BACKEND_PID > /dev/null 2>&1; then print_message $YELLOW "⏳ 强制终止后端进程..." kill -9 $OLD_BACKEND_PID 2>/dev/null || true fi fi rm -f .backend.pid fi if [ -f ".frontend.pid" ]; then OLD_FRONTEND_PID=$(cat .frontend.pid) if ps -p $OLD_FRONTEND_PID > /dev/null 2>&1; then print_message $YELLOW "⚠️ 发现已存在的前端进程 $OLD_FRONTEND_PID,正在停止..." kill $OLD_FRONTEND_PID 2>/dev/null || true sleep 2 # 等待进程终止 attempts=0 while ps -p $OLD_FRONTEND_PID > /dev/null 2>&1 && [ $attempts -lt 10 ]; do sleep 1 attempts=$((attempts + 1)) done # 如果仍未终止,强制杀死 if ps -p $OLD_FRONTEND_PID > /dev/null 2>&1; then print_message $YELLOW "⏳ 强制终止前端进程..." kill -9 $OLD_FRONTEND_PID 2>/dev/null || true fi fi rm -f .frontend.pid fi # 检查依赖状态 check_dependencies() { local missing_deps=() # 检查 Python 依赖 if ! command -v python3 &> /dev/null; then missing_deps+=("python3") else if ! python3 -c "import fastapi, uvicorn, sqlalchemy, pydantic, jwt, bcrypt, pandas, fitz, dotenv" > /dev/null 2>&1; then missing_deps+=("python_backend_deps") fi fi # 检查 Node.js 依赖 if ! command -v node &> /dev/null; then missing_deps+=("nodejs") fi if ! command -v npm &> /dev/null; then missing_deps+=("npm") fi # 检查前端依赖 if [ -f "frontend/package.json" ] && [ ! -d "frontend/node_modules" ]; then missing_deps+=("frontend_deps") fi if [ ${#missing_deps[@]} -ne 0 ]; then print_message $YELLOW "⚠️ 检测到以下依赖缺失或未安装:" for dep in "${missing_deps[@]}"; do echo " - $dep" done return 1 fi return 0 } print_message $BLUE "🔍 检查依赖安装状态..." if ! check_dependencies; then print_message $YELLOW "⚠️ 检测到依赖缺失,正在尝试自动安装..." # 检查并创建后端虚拟环境 if [ ! -d "backend/venv" ]; then print_message $BLUE "🔧 创建后端虚拟环境..." python3 -m venv backend/venv print_message $GREEN "✅ 虚拟环境创建成功" fi # 激活虚拟环境 source backend/venv/bin/activate # 检查并安装后端依赖 if ! python -c "import fastapi, uvicorn, sqlalchemy, pydantic, jwt, bcrypt, pandas, fitz, dotenv" > /dev/null 2>&1; then print_message $BLUE "🔧 安装后端依赖..." cd backend if [ ! -f "requirements.txt" ]; then print_message $RED "❌ requirements.txt 不存在" exit 1 fi pip install --upgrade pip if ! pip install -r requirements.txt; then print_message $RED "❌ 后端依赖安装失败" exit 1 fi cd .. print_message $GREEN "✅ 后端依赖安装完成" fi # 检查并安装前端依赖 if [ -f "frontend/package.json" ] && [ ! -d "frontend/node_modules" ]; then print_message $BLUE "🔧 安装前端依赖..." cd frontend if ! npm install; then print_message $RED "❌ 前端依赖安装失败" exit 1 fi cd .. print_message $GREEN "✅ 前端依赖安装完成" fi else print_message $GREEN "✅ 依赖检查通过" fi # 激活后端虚拟环境 print_message $BLUE "🔧 激活后端虚拟环境..." source backend/venv/bin/activate # 确保 uploads/images 目录存在 if [ ! -d "backend/uploads/images" ]; then mkdir -p "backend/uploads/images" print_message $GREEN "✅ 创建了 uploads/images 目录" fi print_message $BLUE "📡 启动后端服务 (端口: $BACKEND_PORT)..." print_message $YELLOW "ℹ️ 后端日志将直接显示在当前终端..." cd backend # 启动后端服务(前台模式,直接显示日志) if command -v uvicorn &> /dev/null; then print_message $GREEN "✅ 后端启动命令: uvicorn main:app --host 0.0.0.0 --port $BACKEND_PORT --log-level info --reload" echo "" echo "========== 后端日志开始 ==========" uvicorn main:app --host 0.0.0.0 --port $BACKEND_PORT --log-level info --reload else # 如果uvicorn不在PATH中,使用虚拟环境中的 echo "========== 后端日志开始 ==========" ../backend/venv/bin/uvicorn main:app --host 0.0.0.0 --port $BACKEND_PORT --log-level info --reload fi