Initial commit: Pixel AI comic/video creation platform
- FastAPI backend with SQLModel, Alembic migrations, AgentScope agents - Next.js 15 frontend with React 19, Tailwind, Zustand, React Flow - Multi-provider AI system (DashScope, Kling, MiniMax, Volcengine, OpenAI, etc.) - All HTTP clients migrated from sync requests to async httpx - Admin-managed API keys via environment variables - SSRF vulnerability fixed in ensure_url()
This commit is contained in:
343
start.sh
Normal file
343
start.sh
Normal file
@@ -0,0 +1,343 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
BACKEND_PORT=8000
|
||||
FRONTEND_PORT=3000
|
||||
BACKEND_DIR="backend"
|
||||
FRONTEND_DIR="frontend"
|
||||
LOG_DIR="logs"
|
||||
|
||||
# Create logs directory if it doesn't exist
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Log files
|
||||
BACKEND_LOG="$LOG_DIR/backend.log"
|
||||
FRONTEND_LOG="$LOG_DIR/frontend.log"
|
||||
|
||||
# Function to print colored messages
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗${NC} $1"
|
||||
}
|
||||
|
||||
# Function to kill background processes on exit
|
||||
cleanup() {
|
||||
echo ""
|
||||
print_info "Stopping all services..."
|
||||
|
||||
# Kill all background jobs
|
||||
jobs -p | xargs -r kill 2>/dev/null
|
||||
|
||||
# Wait a moment for graceful shutdown
|
||||
sleep 1
|
||||
|
||||
# Force kill if still running
|
||||
jobs -p | xargs -r kill -9 2>/dev/null
|
||||
|
||||
print_success "All services stopped"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Function to check prerequisites
|
||||
check_prerequisites() {
|
||||
print_info "Checking prerequisites..."
|
||||
|
||||
local missing_deps=()
|
||||
|
||||
# Check for required commands
|
||||
if ! command_exists "uv"; then
|
||||
missing_deps+=("uv (Python package manager)")
|
||||
fi
|
||||
|
||||
if ! command_exists "node"; then
|
||||
missing_deps+=("node (Node.js)")
|
||||
fi
|
||||
|
||||
if ! command_exists "pnpm"; then
|
||||
missing_deps+=("pnpm (Node package manager)")
|
||||
fi
|
||||
|
||||
if ! command_exists "curl"; then
|
||||
missing_deps+=("curl")
|
||||
fi
|
||||
|
||||
if ! command_exists "lsof"; then
|
||||
print_warning "lsof not found, port checking will be limited"
|
||||
fi
|
||||
|
||||
if [ ${#missing_deps[@]} -gt 0 ]; then
|
||||
print_error "Missing required dependencies:"
|
||||
for dep in "${missing_deps[@]}"; do
|
||||
echo " - $dep"
|
||||
done
|
||||
echo ""
|
||||
echo "Please install missing dependencies and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "All prerequisites satisfied"
|
||||
}
|
||||
|
||||
# Function to check and free port
|
||||
check_and_free_port() {
|
||||
local port=$1
|
||||
local name=$2
|
||||
|
||||
if ! command_exists "lsof"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if port is in use
|
||||
if lsof -i :$port >/dev/null 2>&1; then
|
||||
print_warning "Port $port ($name) is in use"
|
||||
|
||||
# Get PIDs using the port
|
||||
local pids=$(lsof -ti :$port)
|
||||
|
||||
# Ask user for confirmation
|
||||
read -p "Kill processes on port $port? (y/N): " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
for pid in $pids; do
|
||||
print_info "Killing process $pid on port $port..."
|
||||
kill -9 $pid 2>/dev/null
|
||||
done
|
||||
sleep 1
|
||||
|
||||
# Verify if port is still in use
|
||||
if lsof -i :$port >/dev/null 2>&1; then
|
||||
print_error "Failed to free port $port. Please free it manually."
|
||||
exit 1
|
||||
else
|
||||
print_success "Port $port freed successfully"
|
||||
fi
|
||||
else
|
||||
print_error "Cannot start service on port $port. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if directory exists
|
||||
check_directory() {
|
||||
local dir=$1
|
||||
local name=$2
|
||||
|
||||
if [ ! -d "$dir" ]; then
|
||||
print_error "$name directory not found: $dir"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to start backend
|
||||
start_backend() {
|
||||
print_info "Starting Backend on port $BACKEND_PORT..."
|
||||
|
||||
cd "$BACKEND_DIR" || exit 1
|
||||
|
||||
# Check if .env file exists
|
||||
if [ ! -f ".env" ]; then
|
||||
print_warning "Backend .env file not found. Using default configuration."
|
||||
fi
|
||||
|
||||
# Set PYTHONPATH
|
||||
export PYTHONPATH=$PYTHONPATH:$(pwd)
|
||||
|
||||
# Start backend with logging
|
||||
uv run uvicorn src.main:app --reload --port $BACKEND_PORT > "../$BACKEND_LOG" 2>&1 &
|
||||
BACKEND_PID=$!
|
||||
|
||||
cd ..
|
||||
|
||||
print_info "Backend PID: $BACKEND_PID (logs: $BACKEND_LOG)"
|
||||
}
|
||||
|
||||
# Function to wait for backend to be ready
|
||||
wait_for_backend() {
|
||||
print_info "Waiting for backend to be ready..."
|
||||
|
||||
local max_retries=30
|
||||
local retry_count=0
|
||||
local health_url="http://localhost:$BACKEND_PORT/health"
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
if curl -s "$health_url" > /dev/null 2>&1; then
|
||||
print_success "Backend is ready!"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if backend process is still running
|
||||
if ! kill -0 $BACKEND_PID 2>/dev/null; then
|
||||
print_error "Backend process died. Check logs: $BACKEND_LOG"
|
||||
tail -n 20 "$BACKEND_LOG"
|
||||
return 1
|
||||
fi
|
||||
|
||||
retry_count=$((retry_count + 1))
|
||||
|
||||
# Show progress
|
||||
printf "\r Attempt %d/%d..." $retry_count $max_retries
|
||||
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo ""
|
||||
print_error "Backend failed to start after $max_retries seconds"
|
||||
print_info "Last 20 lines of backend log:"
|
||||
tail -n 20 "$BACKEND_LOG"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to start frontend
|
||||
start_frontend() {
|
||||
print_info "Starting Frontend on port $FRONTEND_PORT..."
|
||||
|
||||
cd "$FRONTEND_DIR" || exit 1
|
||||
|
||||
# Check if node_modules exists
|
||||
if [ ! -d "node_modules" ]; then
|
||||
print_warning "node_modules not found. Running pnpm install..."
|
||||
pnpm install
|
||||
fi
|
||||
|
||||
# Start frontend with logging
|
||||
pnpm dev > "../$FRONTEND_LOG" 2>&1 &
|
||||
FRONTEND_PID=$!
|
||||
|
||||
cd ..
|
||||
|
||||
print_info "Frontend PID: $FRONTEND_PID (logs: $FRONTEND_LOG)"
|
||||
}
|
||||
|
||||
# Function to wait for frontend to be ready
|
||||
wait_for_frontend() {
|
||||
print_info "Waiting for frontend to be ready..."
|
||||
|
||||
local max_retries=30
|
||||
local retry_count=0
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
if curl -s "http://localhost:$FRONTEND_PORT" > /dev/null 2>&1; then
|
||||
print_success "Frontend is ready!"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if frontend process is still running
|
||||
if ! kill -0 $FRONTEND_PID 2>/dev/null; then
|
||||
print_error "Frontend process died. Check logs: $FRONTEND_LOG"
|
||||
tail -n 20 "$FRONTEND_LOG"
|
||||
return 1
|
||||
fi
|
||||
|
||||
retry_count=$((retry_count + 1))
|
||||
|
||||
# Show progress
|
||||
printf "\r Attempt %d/%d..." $retry_count $max_retries
|
||||
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo ""
|
||||
print_error "Frontend failed to start after $max_retries seconds"
|
||||
print_info "Last 20 lines of frontend log:"
|
||||
tail -n 20 "$FRONTEND_LOG"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to display service information
|
||||
display_info() {
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
print_success "All services started successfully!"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 📡 Backend API: http://localhost:$BACKEND_PORT"
|
||||
echo " 📚 API Docs: http://localhost:$BACKEND_PORT/docs"
|
||||
echo " 📖 ReDoc: http://localhost:$BACKEND_PORT/redoc"
|
||||
echo " 🏥 Health Check: http://localhost:$BACKEND_PORT/health"
|
||||
echo " 📊 Metrics: http://localhost:$BACKEND_PORT/metrics"
|
||||
echo ""
|
||||
echo " 🎨 Frontend: http://localhost:$FRONTEND_PORT"
|
||||
echo ""
|
||||
echo " 📝 Backend Logs: $BACKEND_LOG"
|
||||
echo " 📝 Frontend Logs: $FRONTEND_LOG"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
print_info "Press Ctrl+C to stop all services"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════╗"
|
||||
echo "║ Pixel Development Environment Startup ║"
|
||||
echo "╚═══════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Trap SIGINT (Ctrl+C) and call cleanup
|
||||
trap cleanup SIGINT SIGTERM
|
||||
|
||||
# Check prerequisites
|
||||
check_prerequisites
|
||||
|
||||
# Check directories
|
||||
check_directory "$BACKEND_DIR" "Backend"
|
||||
check_directory "$FRONTEND_DIR" "Frontend"
|
||||
|
||||
# Check and free ports
|
||||
check_and_free_port $BACKEND_PORT "Backend"
|
||||
check_and_free_port $FRONTEND_PORT "Frontend"
|
||||
|
||||
# Start backend
|
||||
start_backend
|
||||
|
||||
# Wait for backend to be ready
|
||||
if ! wait_for_backend; then
|
||||
cleanup
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start frontend
|
||||
start_frontend
|
||||
|
||||
# Wait for frontend to be ready
|
||||
if ! wait_for_frontend; then
|
||||
cleanup
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display service information
|
||||
display_info
|
||||
|
||||
# Wait for processes
|
||||
wait
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
Reference in New Issue
Block a user