Spaces:
Runtime error
Runtime error
| # Shared helpers for Research-Link-AI dev scripts. Source this file. | |
| set -euo pipefail | |
| ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" | |
| RUNTIME="$ROOT/.runtime" | |
| mkdir -p "$RUNTIME" | |
| # Load .env if present (export all keys). | |
| if [ -f "$ROOT/.env" ]; then | |
| set -a; . "$ROOT/.env"; set +a | |
| fi | |
| # detect_ip β the machine's primary LAN IPv4 (falls back to 127.0.0.1) | |
| detect_ip() { | |
| local ip | |
| ip="$(python - <<'PY' 2>/dev/null | |
| import socket | |
| s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
| try: | |
| s.connect(("8.8.8.8", 80)); print(s.getsockname()[0]) | |
| except Exception: | |
| print("") | |
| finally: | |
| s.close() | |
| PY | |
| )" | |
| if [ -z "$ip" ] && command -v hostname >/dev/null 2>&1; then | |
| ip="$(hostname -I 2>/dev/null | awk '{print $1}')" | |
| fi | |
| echo "${ip:-127.0.0.1}" | |
| } | |
| # Bind on all interfaces so the server is reachable from other machines. | |
| BIND_HOST="${RESEARCHLINK_BIND_HOST:-0.0.0.0}" | |
| BACKEND_PORT="${RESEARCHLINK_BACKEND_PORT:-8000}" | |
| FRONTEND_PORT="${RESEARCHLINK_FRONTEND_PORT:-5173}" | |
| LLM_MODE="${RESEARCHLINK_LLM_MODE:-offline}" | |
| LLM_MODEL="${RESEARCHLINK_LLM_MODEL:-researchlink-local}" | |
| # Advertised host shown in URLs: explicit override β auto-detected LAN IP. | |
| if [ -n "${RESEARCHLINK_PUBLIC_HOST:-}" ]; then | |
| ADV_HOST="$RESEARCHLINK_PUBLIC_HOST" | |
| elif [ "$BIND_HOST" = "127.0.0.1" ] || [ "$BIND_HOST" = "localhost" ]; then | |
| ADV_HOST="127.0.0.1" | |
| else | |
| ADV_HOST="$(detect_ip)" | |
| fi | |
| BACKEND_URL="http://${ADV_HOST}:${BACKEND_PORT}" # for the browser | |
| HEALTH_URL="http://127.0.0.1:${BACKEND_PORT}" # for local health checks | |
| FRONTEND_HOST="${RESEARCHLINK_FRONTEND_HOST:-0.0.0.0}" | |
| FRONTEND_DIR="$ROOT/frontend" # optional Node frontend (auto-detected) | |
| BACKEND_PID="$RUNTIME/backend.pid" | |
| FRONTEND_PID="$RUNTIME/frontend.pid" | |
| BACKEND_LOG="$RUNTIME/backend.log" | |
| FRONTEND_LOG="$RUNTIME/frontend.log" | |
| c_green() { printf '\033[32m%s\033[0m\n' "$1"; } | |
| c_red() { printf '\033[31m%s\033[0m\n' "$1"; } | |
| c_yellow(){ printf '\033[33m%s\033[0m\n' "$1"; } | |
| c_dim() { printf '\033[2m%s\033[0m\n' "$1"; } | |
| # pid_alive <pidfile> β 0 if the recorded PID is running | |
| pid_alive() { | |
| local f="$1" | |
| [ -f "$f" ] || return 1 | |
| local pid; pid="$(cat "$f" 2>/dev/null || true)" | |
| [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null | |
| } | |
| # port_in_use <host> <port> β 0 if something is listening | |
| port_in_use() { | |
| local host="$1" port="$2" | |
| if command -v lsof >/dev/null 2>&1; then | |
| lsof -iTCP:"$port" -sTCP:LISTEN -n >/dev/null 2>&1 && return 0 || return 1 | |
| fi | |
| (exec 3<>"/dev/tcp/${host}/${port}") 2>/dev/null && { exec 3>&- 3<&- || true; return 0; } || return 1 | |
| } | |
| # key_configured β echoes "yes"/"no"/"n/a" for the current LLM_MODE | |
| key_configured() { | |
| case "$LLM_MODE" in | |
| anthropic) [ -n "${ANTHROPIC_API_KEY:-}" ] && echo yes || echo no ;; | |
| openai) [ -n "${OPENAI_API_KEY:-}" ] && echo yes || echo no ;; | |
| openrouter) [ -n "${OPENROUTER_API_KEY:-}" ] && echo yes || echo no ;; | |
| *) echo "n/a" ;; | |
| esac | |
| } | |
| is_external_mode() { | |
| case "$LLM_MODE" in offline) return 1 ;; *) return 0 ;; esac | |
| } | |
| # http_ok <url> β 0 if the URL returns a 2xx within the timeout | |
| http_ok() { | |
| python - "$1" <<'PY' 2>/dev/null | |
| import sys, urllib.request | |
| try: | |
| urllib.request.urlopen(sys.argv[1], timeout=2).read() | |
| except Exception: | |
| sys.exit(1) | |
| PY | |
| } | |
| # wait_health <url> <tries> β 0 once healthy, 1 if it never comes up | |
| wait_health() { | |
| local url="$1" tries="${2:-40}" | |
| for _ in $(seq 1 "$tries"); do | |
| http_ok "$url" && return 0 | |
| sleep 0.5 | |
| done | |
| return 1 | |
| } | |