- Add debug_font_path, demo_docs_dir, e2e_api_base_url to config.py - Fix hardcoded paths in pp_structure_debug.py, create_demo_images.py - Fix hardcoded paths in test files - Update .env.example with new configuration options - Update .gitignore to exclude AI development files (.claude/, openspec/, AGENTS.md, CLAUDE.md) - Add production startup script (start-prod.sh) - Add README.md with project documentation - Add 1panel Docker deployment files (docker-compose.yml, Dockerfiles, nginx.conf) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
351 lines
9.6 KiB
Bash
Executable File
351 lines
9.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# Tool_OCR - Unified Development Server Startup Script
|
|
# Usage:
|
|
# ./start.sh Start all services (backend + frontend)
|
|
# ./start.sh backend Start only backend
|
|
# ./start.sh frontend Start only frontend
|
|
# ./start.sh --stop Stop all services
|
|
# ./start.sh --status Show service status
|
|
# ./start.sh --help Show help
|
|
|
|
# Note: We don't use 'set -e' here because stop commands may fail gracefully
|
|
|
|
# Colors
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
# Configuration
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PID_DIR="$SCRIPT_DIR/.pid"
|
|
BACKEND_PID_FILE="$PID_DIR/backend.pid"
|
|
FRONTEND_PID_FILE="$PID_DIR/frontend.pid"
|
|
BACKEND_HOST=${BACKEND_HOST:-0.0.0.0}
|
|
BACKEND_PORT=${BACKEND_PORT:-8000}
|
|
FRONTEND_HOST=${FRONTEND_HOST:-0.0.0.0}
|
|
FRONTEND_PORT=${FRONTEND_PORT:-5173}
|
|
|
|
# Create PID directory
|
|
mkdir -p "$PID_DIR"
|
|
|
|
# Functions
|
|
print_header() {
|
|
echo ""
|
|
echo -e "${BLUE}================================${NC}"
|
|
echo -e "${BLUE} Tool_OCR Development Server${NC}"
|
|
echo -e "${BLUE}================================${NC}"
|
|
echo ""
|
|
}
|
|
|
|
show_help() {
|
|
echo "Tool_OCR - Development Server Manager"
|
|
echo ""
|
|
echo "Usage: ./start.sh [command]"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " (none) Start all services (backend + frontend)"
|
|
echo " backend Start only backend service"
|
|
echo " frontend Start only frontend service"
|
|
echo " --stop Stop all running services"
|
|
echo " --status Show status of services"
|
|
echo " --help Show this help message"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " ./start.sh # Start everything"
|
|
echo " ./start.sh backend # Start only backend"
|
|
echo " ./start.sh --stop # Stop all services"
|
|
echo ""
|
|
}
|
|
|
|
check_requirements() {
|
|
local missing=0
|
|
|
|
# Check virtual environment
|
|
if [ ! -d "$SCRIPT_DIR/venv" ]; then
|
|
echo -e "${RED}Error: Python virtual environment not found${NC}"
|
|
echo "Please run: ./setup_dev_env.sh"
|
|
missing=1
|
|
fi
|
|
|
|
# Check node_modules
|
|
if [ ! -d "$SCRIPT_DIR/frontend/node_modules" ]; then
|
|
echo -e "${RED}Error: Frontend dependencies not found${NC}"
|
|
echo "Please run: ./setup_dev_env.sh"
|
|
missing=1
|
|
fi
|
|
|
|
# Check .env.local
|
|
if [ ! -f "$SCRIPT_DIR/.env.local" ]; then
|
|
echo -e "${RED}Error: .env.local not found${NC}"
|
|
echo "Please copy .env.example to .env.local and configure"
|
|
missing=1
|
|
fi
|
|
|
|
return $missing
|
|
}
|
|
|
|
load_env() {
|
|
# Load environment variables from root .env.local (if present).
|
|
# This keeps backend/frontend config in sync without hardcoding ports/URLs in scripts.
|
|
if [ -f "$SCRIPT_DIR/.env.local" ]; then
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
source "$SCRIPT_DIR/.env.local"
|
|
set +a
|
|
fi
|
|
}
|
|
|
|
is_running() {
|
|
local pid_file=$1
|
|
if [ -f "$pid_file" ]; then
|
|
local pid=$(cat "$pid_file")
|
|
if ps -p "$pid" > /dev/null 2>&1; then
|
|
return 0
|
|
else
|
|
# PID file exists but process is not running, clean up
|
|
rm -f "$pid_file"
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
get_pid() {
|
|
local pid_file=$1
|
|
if [ -f "$pid_file" ]; then
|
|
cat "$pid_file"
|
|
fi
|
|
}
|
|
|
|
start_backend() {
|
|
if is_running "$BACKEND_PID_FILE"; then
|
|
echo -e "${YELLOW}Backend already running (PID: $(get_pid $BACKEND_PID_FILE))${NC}"
|
|
return 0
|
|
fi
|
|
|
|
echo -e "${GREEN}Starting backend server...${NC}"
|
|
|
|
# Activate virtual environment
|
|
source "$SCRIPT_DIR/venv/bin/activate"
|
|
|
|
# Load environment variables
|
|
load_env
|
|
|
|
# Start backend in background
|
|
cd "$SCRIPT_DIR/backend"
|
|
|
|
# Create necessary directories
|
|
mkdir -p uploads/{temp,processed,images}
|
|
mkdir -p storage/{markdown,json,exports,results}
|
|
mkdir -p models/paddleocr
|
|
mkdir -p logs
|
|
|
|
# Start uvicorn
|
|
nohup uvicorn app.main:app --reload --host "$BACKEND_HOST" --port "$BACKEND_PORT" > "$SCRIPT_DIR/.pid/backend.log" 2>&1 &
|
|
local pid=$!
|
|
echo $pid > "$BACKEND_PID_FILE"
|
|
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Wait a moment and verify
|
|
sleep 2
|
|
if is_running "$BACKEND_PID_FILE"; then
|
|
echo -e "${GREEN}Backend started (PID: $pid)${NC}"
|
|
echo -e " API Docs: http://localhost:$BACKEND_PORT/docs"
|
|
echo -e " Health: http://localhost:$BACKEND_PORT/health"
|
|
else
|
|
echo -e "${RED}Backend failed to start. Check .pid/backend.log${NC}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
start_frontend() {
|
|
if is_running "$FRONTEND_PID_FILE"; then
|
|
echo -e "${YELLOW}Frontend already running (PID: $(get_pid $FRONTEND_PID_FILE))${NC}"
|
|
return 0
|
|
fi
|
|
|
|
echo -e "${GREEN}Starting frontend server...${NC}"
|
|
|
|
# Load environment variables so Vite config can use FRONTEND_PORT/FRONTEND_HOST/etc.
|
|
load_env
|
|
|
|
# Load nvm
|
|
export NVM_DIR="$HOME/.nvm"
|
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
|
|
cd "$SCRIPT_DIR/frontend"
|
|
|
|
# Start vite in background
|
|
nohup npm run dev > "$SCRIPT_DIR/.pid/frontend.log" 2>&1 &
|
|
local pid=$!
|
|
echo $pid > "$FRONTEND_PID_FILE"
|
|
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Wait a moment and verify
|
|
sleep 3
|
|
if is_running "$FRONTEND_PID_FILE"; then
|
|
echo -e "${GREEN}Frontend started (PID: $pid)${NC}"
|
|
echo -e " URL: http://localhost:$FRONTEND_PORT"
|
|
else
|
|
echo -e "${RED}Frontend failed to start. Check .pid/frontend.log${NC}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
kill_process_tree() {
|
|
local pid=$1
|
|
# Kill all child processes first
|
|
pkill -TERM -P "$pid" 2>/dev/null || true
|
|
# Then kill the parent
|
|
kill -TERM "$pid" 2>/dev/null || true
|
|
}
|
|
|
|
force_kill_process_tree() {
|
|
local pid=$1
|
|
# Force kill all child processes
|
|
pkill -9 -P "$pid" 2>/dev/null || true
|
|
# Force kill the parent
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
}
|
|
|
|
kill_by_port() {
|
|
local port=$1
|
|
local pids=$(lsof -ti :$port 2>/dev/null)
|
|
if [ -n "$pids" ]; then
|
|
echo "$pids" | xargs kill -TERM 2>/dev/null || true
|
|
sleep 1
|
|
# Force kill if still running
|
|
pids=$(lsof -ti :$port 2>/dev/null)
|
|
if [ -n "$pids" ]; then
|
|
echo "$pids" | xargs kill -9 2>/dev/null || true
|
|
fi
|
|
fi
|
|
}
|
|
|
|
stop_service() {
|
|
local name=$1
|
|
local pid_file=$2
|
|
local port=$3
|
|
|
|
if is_running "$pid_file"; then
|
|
local pid=$(get_pid "$pid_file")
|
|
echo -e "${YELLOW}Stopping $name (PID: $pid)...${NC}"
|
|
|
|
# Kill the entire process tree
|
|
kill_process_tree "$pid"
|
|
|
|
# Wait up to 5 seconds
|
|
local count=0
|
|
while [ $count -lt 5 ] && is_running "$pid_file"; do
|
|
sleep 1
|
|
count=$((count + 1))
|
|
done
|
|
|
|
# Force kill if still running
|
|
if is_running "$pid_file"; then
|
|
force_kill_process_tree "$pid"
|
|
fi
|
|
|
|
rm -f "$pid_file"
|
|
fi
|
|
|
|
# Also kill any orphaned processes by port (fallback)
|
|
if [ -n "$port" ]; then
|
|
local port_pids=$(lsof -ti :$port 2>/dev/null)
|
|
if [ -n "$port_pids" ]; then
|
|
echo -e "${YELLOW}Cleaning up orphaned processes on port $port...${NC}"
|
|
kill_by_port "$port"
|
|
fi
|
|
fi
|
|
|
|
echo -e "${GREEN}$name stopped${NC}"
|
|
}
|
|
|
|
stop_all() {
|
|
echo -e "${YELLOW}Stopping all services...${NC}"
|
|
stop_service "Backend" "$BACKEND_PID_FILE" "$BACKEND_PORT"
|
|
stop_service "Frontend" "$FRONTEND_PID_FILE" "$FRONTEND_PORT"
|
|
echo -e "${GREEN}All services stopped${NC}"
|
|
}
|
|
|
|
show_status() {
|
|
echo -e "${BLUE}Service Status:${NC}"
|
|
echo ""
|
|
|
|
if is_running "$BACKEND_PID_FILE"; then
|
|
local pid=$(get_pid "$BACKEND_PID_FILE")
|
|
echo -e " Backend: ${GREEN}Running${NC} (PID: $pid)"
|
|
echo -e " http://localhost:$BACKEND_PORT"
|
|
else
|
|
echo -e " Backend: ${RED}Stopped${NC}"
|
|
fi
|
|
|
|
if is_running "$FRONTEND_PID_FILE"; then
|
|
local pid=$(get_pid "$FRONTEND_PID_FILE")
|
|
echo -e " Frontend: ${GREEN}Running${NC} (PID: $pid)"
|
|
echo -e " http://localhost:$FRONTEND_PORT"
|
|
else
|
|
echo -e " Frontend: ${RED}Stopped${NC}"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Main
|
|
case "${1:-all}" in
|
|
--help|-h)
|
|
show_help
|
|
;;
|
|
--stop)
|
|
stop_all
|
|
;;
|
|
--status)
|
|
show_status
|
|
;;
|
|
backend)
|
|
print_header
|
|
check_requirements || exit 1
|
|
start_backend
|
|
echo ""
|
|
echo -e "${YELLOW}Press Ctrl+C to stop (or use ./start.sh --stop)${NC}"
|
|
echo -e "${YELLOW}Logs: tail -f .pid/backend.log${NC}"
|
|
;;
|
|
frontend)
|
|
print_header
|
|
check_requirements || exit 1
|
|
start_frontend
|
|
echo ""
|
|
echo -e "${YELLOW}Press Ctrl+C to stop (or use ./start.sh --stop)${NC}"
|
|
echo -e "${YELLOW}Logs: tail -f .pid/frontend.log${NC}"
|
|
;;
|
|
all|"")
|
|
print_header
|
|
check_requirements || exit 1
|
|
start_backend
|
|
start_frontend
|
|
echo ""
|
|
echo -e "${GREEN}================================${NC}"
|
|
echo -e "${GREEN}All services started!${NC}"
|
|
echo -e "${GREEN}================================${NC}"
|
|
echo ""
|
|
echo "Access the application:"
|
|
echo -e " Frontend: ${BLUE}http://localhost:$FRONTEND_PORT${NC}"
|
|
echo -e " API Docs: ${BLUE}http://localhost:$BACKEND_PORT/docs${NC}"
|
|
echo ""
|
|
echo -e "${YELLOW}Use ./start.sh --stop to stop all services${NC}"
|
|
echo -e "${YELLOW}Use ./start.sh --status to check status${NC}"
|
|
echo ""
|
|
echo "Logs:"
|
|
echo " Backend: tail -f .pid/backend.log"
|
|
echo " Frontend: tail -f .pid/frontend.log"
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unknown command: $1${NC}"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|