Fundamental_Analysis/scripts/dev.sh
2025-10-31 22:14:19 +08:00

136 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Colors
RESET="\033[0m"
GREEN="\033[32m"
CYAN="\033[36m"
YELLOW="\033[33m"
RED="\033[31m"
REPO_ROOT="$(cd "$(dirname "$0")"/.. && pwd)"
BACKEND_DIR="$REPO_ROOT/backend"
FRONTEND_DIR="$REPO_ROOT/frontend"
CONFIG_FILE="$REPO_ROOT/config/config.json"
# Port configuration
BACKEND_PORT=8000
FRONTEND_PORT=3000
# Kill process using specified port
kill_port() {
local port=$1
local pids=$(lsof -nP -ti tcp:"$port" 2>/dev/null || true)
if [[ -n "$pids" ]]; then
echo -e "${YELLOW}[CLEANUP]${RESET} Killing process(es) using port $port: $pids"
echo "$pids" | xargs kill -9 2>/dev/null || true
sleep 1
fi
}
ensure_backend() {
cd "$BACKEND_DIR"
if [[ ! -d .venv ]]; then
echo -e "${YELLOW}[SETUP]${RESET} Creating Python venv and installing backend requirements..."
python3 -m venv .venv
source .venv/bin/activate
# Upgrade pip first
pip install --upgrade pip --timeout 100 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
pip install --upgrade pip --timeout 100
# Install requirements with timeout and mirror
pip install -r requirements.txt --timeout 300 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
pip install -r requirements.txt --timeout 300
else
source .venv/bin/activate
# Upgrade pip if needed
pip install --upgrade pip --timeout 100 -i https://pypi.tuna.tsinghua.edu.cn/simple 2>/dev/null || \
pip install --upgrade pip --timeout 100 2>/dev/null || true
# Check if key dependencies are installed
if ! python -c "import uvicorn" 2>/dev/null; then
echo -e "${YELLOW}[SETUP]${RESET} Installing missing backend requirements..."
pip install -r requirements.txt --timeout 300 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
pip install -r requirements.txt --timeout 300
fi
fi
# Export TUSHARE_TOKEN from config if available (prefer jq, fallback to node)
if [[ -f "$CONFIG_FILE" ]]; then
if command -v jq >/dev/null 2>&1; then
TUSHARE_TOKEN_VAL=$(jq -r '.data_sources.tushare.api_key // empty' "$CONFIG_FILE" 2>/dev/null || true)
else
TUSHARE_TOKEN_VAL=$(node -e "const fs=require('fs');try{const c=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));const v=c?.data_sources?.tushare?.api_key||'';if(v)process.stdout.write(v)}catch{}" "$CONFIG_FILE" 2>/dev/null || true)
fi
if [[ -n "${TUSHARE_TOKEN_VAL:-}" ]]; then
export TUSHARE_TOKEN="$TUSHARE_TOKEN_VAL"
fi
fi
}
run_backend() {
ensure_backend
cd "$BACKEND_DIR"
# Run and colorize output (avoid stdbuf on macOS)
UVICORN_CMD=(uvicorn app.main:app --reload --port "$BACKEND_PORT")
"${UVICORN_CMD[@]}" 2>&1 | awk -v p="[BACKEND]" -v color="$GREEN" -v reset="$RESET" '{print color p " " $0 reset}'
}
ensure_frontend() {
cd "$FRONTEND_DIR"
if [[ ! -d node_modules ]]; then
echo -e "${YELLOW}[SETUP]${RESET} Installing frontend dependencies (npm install)..."
npm install --no-fund --no-audit
fi
}
run_frontend() {
ensure_frontend
cd "$FRONTEND_DIR"
npm run dev 2>&1 | awk -v p="[FRONTEND]" -v color="$CYAN" -v reset="$RESET" '{print color p " " $0 reset}'
}
cleanup() {
echo -e "\n${YELLOW}[CLEANUP]${RESET} Stopping services..."
# Kill process groups to ensure all child processes are terminated
if [[ -n "${BACKEND_PID:-}" ]]; then
kill -TERM -"$BACKEND_PID" 2>/dev/null || kill "$BACKEND_PID" 2>/dev/null || true
fi
if [[ -n "${FRONTEND_PID:-}" ]]; then
kill -TERM -"$FRONTEND_PID" 2>/dev/null || kill "$FRONTEND_PID" 2>/dev/null || true
fi
sleep 1
# Force kill any remaining processes on these ports
kill_port "$BACKEND_PORT"
kill_port "$FRONTEND_PORT"
wait 2>/dev/null || true
echo -e "${GREEN}[CLEANUP]${RESET} All services stopped."
}
main() {
echo -e "${CYAN}Dev Launcher${RESET}: Starting Backend ($BACKEND_PORT) and Frontend ($FRONTEND_PORT)\n"
# Clean up ports before starting
kill_port "$BACKEND_PORT"
kill_port "$FRONTEND_PORT"
echo -e "${GREEN}[BACKEND]${RESET} API: http://127.0.0.1:$BACKEND_PORT"
echo -e "${CYAN}[FRONTEND]${RESET} APP: http://127.0.0.1:$FRONTEND_PORT\n"
run_backend & BACKEND_PID=$!
run_frontend & FRONTEND_PID=$!
trap cleanup INT TERM EXIT
# Wait on both; if either exits, we exit (portable)
while true; do
if ! kill -0 "$BACKEND_PID" 2>/dev/null; then break; fi
if ! kill -0 "$FRONTEND_PID" 2>/dev/null; then break; fi
sleep 1
done
}
main "$@"