#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" RUN_DIR="$ROOT_DIR/.run" LOG_DIR="$ROOT_DIR/logs" BACKEND_PID_FILE="$RUN_DIR/backend.pid" FRONTEND_PID_FILE="$RUN_DIR/frontend.pid" BACKEND_LOG_FILE="$LOG_DIR/backend.log" FRONTEND_LOG_FILE="$LOG_DIR/frontend.log" 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:-8451}" CORS_ORIGINS="${CORS_ORIGINS:-http://localhost:${FRONTEND_PORT},http://127.0.0.1:${FRONTEND_PORT}}" VITE_PROXY_TARGET="${VITE_PROXY_TARGET:-http://127.0.0.1:${BACKEND_PORT}}" mkdir -p "$RUN_DIR" "$LOG_DIR" require_command() { if ! command -v "$1" >/dev/null 2>&1; then echo "Missing command: $1" >&2 exit 1 fi } cleanup_stale_pid() { local pid_file="$1" if [[ -f "$pid_file" ]]; then local pid pid="$(cat "$pid_file")" if [[ -n "$pid" ]] && kill -0 "$pid" >/dev/null 2>&1; then return 0 fi rm -f "$pid_file" fi return 1 } wait_for_port() { local host="$1" local port="$2" local name="$3" local retries=30 while (( retries > 0 )); do if python3 - "$host" "$port" <<'PY' import socket import sys host = sys.argv[1] port = int(sys.argv[2]) sock = socket.socket() sock.settimeout(0.5) try: sock.connect((host, port)) except OSError: sys.exit(1) finally: sock.close() sys.exit(0) PY then echo "$name is ready on ${host}:${port}" return 0 fi sleep 1 retries=$((retries - 1)) done echo "$name failed to start on ${host}:${port}. Check logs in $LOG_DIR" >&2 return 1 } require_command python3 require_command node require_command npm require_command ffmpeg if ! python3 - <<'PY' >/dev/null 2>&1 import fastapi import uvicorn import multipart PY then echo "Missing Python packages. Run: cd backend && python3 -m pip install --user -r requirements.txt" >&2 exit 1 fi if [[ ! -d "$ROOT_DIR/frontend/node_modules" ]]; then echo "Installing frontend dependencies..." ( cd "$ROOT_DIR/frontend" npm install ) fi if cleanup_stale_pid "$BACKEND_PID_FILE"; then echo "Backend already running with PID $(cat "$BACKEND_PID_FILE")" else echo "Starting backend..." ( cd "$ROOT_DIR/backend" nohup env \ CORS_ORIGINS="$CORS_ORIGINS" \ python3 -m uvicorn app.main:app \ --host "$BACKEND_HOST" \ --port "$BACKEND_PORT" \ >"$BACKEND_LOG_FILE" 2>&1 & echo $! > "$BACKEND_PID_FILE" ) fi wait_for_port "127.0.0.1" "$BACKEND_PORT" "backend" if cleanup_stale_pid "$FRONTEND_PID_FILE"; then echo "Frontend already running with PID $(cat "$FRONTEND_PID_FILE")" else echo "Starting frontend..." ( cd "$ROOT_DIR/frontend" nohup env \ VITE_PROXY_TARGET="$VITE_PROXY_TARGET" \ npm run dev -- --host "$FRONTEND_HOST" --port "$FRONTEND_PORT" \ >"$FRONTEND_LOG_FILE" 2>&1 & echo $! > "$FRONTEND_PID_FILE" ) fi wait_for_port "127.0.0.1" "$FRONTEND_PORT" "frontend" SERVER_IP="$(hostname -I 2>/dev/null | awk '{print $1}')" if [[ -z "$SERVER_IP" ]]; then SERVER_IP="127.0.0.1" fi cat <