Initial project baseline
This commit is contained in:
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
VENV_DIR="$ROOT_DIR/.venv"
|
||||
BACKEND_PORT="${BACKEND_PORT:-8000}"
|
||||
|
||||
# ── find python ──────────────────────────────────────────
|
||||
PYTHON=""
|
||||
for cmd in python3.13 python3.12 python3.11 python3.10 python3.9 python3; do
|
||||
if command -v "$cmd" >/dev/null 2>&1; then
|
||||
PYTHON="$cmd"
|
||||
break
|
||||
fi
|
||||
done
|
||||
[[ -n "$PYTHON" ]] || { echo "[ERROR] 找不到 python3"; exit 1; }
|
||||
|
||||
# verify version >= 3.9
|
||||
if ! "$PYTHON" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3,9) else 1)'; then
|
||||
echo "[ERROR] 需要 Python 3.9+"; exit 1
|
||||
fi
|
||||
|
||||
# ── deps check & install ─────────────────────────────────
|
||||
DEPS_OK=0
|
||||
if "$PYTHON" -c "
|
||||
import importlib.util, sys
|
||||
mods = ('fastapi','uvicorn','pandas','PIL','numpy','matplotlib','pydantic','openpyxl')
|
||||
for m in mods:
|
||||
if importlib.util.find_spec(m) is None:
|
||||
sys.exit(1)
|
||||
" 2>/dev/null; then
|
||||
DEPS_OK=1
|
||||
fi
|
||||
|
||||
if [[ "$DEPS_OK" == "0" ]]; then
|
||||
# try venv first
|
||||
if [[ -f "$VENV_DIR/bin/python" ]] && "$VENV_DIR/bin/python" --version >/dev/null 2>&1; then
|
||||
PYTHON="$VENV_DIR/bin/python"
|
||||
if "$PYTHON" -c "
|
||||
import importlib.util, sys
|
||||
for m in ('fastapi','uvicorn','pandas','PIL','numpy','matplotlib','pydantic','openpyxl'):
|
||||
if importlib.util.find_spec(m) is None: sys.exit(1)
|
||||
" 2>/dev/null; then
|
||||
DEPS_OK=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$DEPS_OK" == "0" ]]; then
|
||||
echo "[INFO] 安装依赖 (首次或缺失) ..."
|
||||
# create venv if needed
|
||||
if [[ ! -f "$VENV_DIR/bin/python" ]]; then
|
||||
"$PYTHON" -m venv "$VENV_DIR"
|
||||
fi
|
||||
PYTHON="$VENV_DIR/bin/python"
|
||||
"$PYTHON" -m pip install -q --upgrade pip
|
||||
"$PYTHON" -m pip install -q fastapi uvicorn python-multipart pydantic pandas openpyxl pillow numpy matplotlib
|
||||
fi
|
||||
|
||||
# ── C++ extension ────────────────────────────────────────
|
||||
EXT=$($PYTHON -c 'import importlib.machinery; print(importlib.machinery.EXTENSION_SUFFIXES[0])')
|
||||
EWC_SO="$ROOT_DIR/EfficientWordCloud/efficient_wordcloud/ewc_core${EXT}"
|
||||
EWC_CPP="$ROOT_DIR/EfficientWordCloud/efficient_wordcloud/src/ewc_core.cpp"
|
||||
|
||||
if [[ ! -f "$EWC_SO" ]] || [[ "$EWC_CPP" -nt "$EWC_SO" ]]; then
|
||||
echo "[INFO] 编译 ewc_core ..."
|
||||
(cd "$ROOT_DIR/EfficientWordCloud" && "$PYTHON" setup.py build_ext --inplace >/dev/null)
|
||||
echo "[OK] 编译完成"
|
||||
else
|
||||
echo "[OK] ewc_core 就绪"
|
||||
fi
|
||||
|
||||
# ── ensure runtime dirs ──────────────────────────────────
|
||||
mkdir -p "$ROOT_DIR/service_workspace" "$ROOT_DIR/service_assets" "$ROOT_DIR/service_projects"
|
||||
|
||||
# ── port: auto-kill occupant ─────────────────────────────
|
||||
if ss -tln 2>/dev/null | grep -q ":$BACKEND_PORT "; then
|
||||
echo "[INFO] 端口 $BACKEND_PORT 被占用,正在释放 ..."
|
||||
fuser -k "$BACKEND_PORT/tcp" >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# ── start ────────────────────────────────────────────────
|
||||
echo "[INFO] 启动后端 http://0.0.0.0:${BACKEND_PORT}"
|
||||
|
||||
PYTHONPATH="$ROOT_DIR/EfficientWordCloud" \
|
||||
"$PYTHON" -m uvicorn service.app:app \
|
||||
--app-dir "$ROOT_DIR" \
|
||||
--host 0.0.0.0 --port "$BACKEND_PORT" \
|
||||
--reload &
|
||||
PID=$!
|
||||
|
||||
echo "[OK] PID: $PID"
|
||||
echo "[OK] API: http://0.0.0.0:${BACKEND_PORT}/docs"
|
||||
|
||||
trap 'echo; echo "[INFO] 停止 ..."; kill $PID 2>/dev/null || true; wait $PID 2>/dev/null || true; echo "[OK] 已停止"; exit 0' INT TERM
|
||||
wait "$PID"
|
||||
Reference in New Issue
Block a user