Spaces:
Build error
Build error
| # Centralized Logging Configuration | |
| export LOG_LEVEL=${LOG_LEVEL:-"info"} | |
| export LOG_FILE=${LOG_FILE:-"/app/verdant_claw.log"} | |
| # Mask sensitive env vars in logs | |
| log() { | |
| local msg=$(echo "$1" | sed -E 's/(nvapi|sk|gsk)[a-zA-Z0-9]+/\1*****/g') | |
| echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] [$LOG_LEVEL] $msg" | tee -a $LOG_FILE | |
| } | |
| # Trap SIGTERM for graceful shutdown | |
| cleanup() { | |
| log "Shutting down services gracefully..." | |
| kill $(jobs -p) 2>/dev/null | |
| sleep 2 | |
| log "Shutdown complete" | |
| exit 0 | |
| } | |
| trap cleanup SIGTERM SIGINT | |
| # Parse API_KEYS_JSON secret | |
| if [ -n "$API_KEYS_JSON" ]; then | |
| log "Parsing API keys from JSON..." | |
| export NVIDIA_API_KEY=$(echo $API_KEYS_JSON | jq -r '.nvidia // empty') | |
| export OPENAI_API_KEY=$(echo $API_KEYS_JSON | jq -r '.openai // empty') | |
| export ANTHROPIC_API_KEY=$(echo $API_KEYS_JSON | jq -r '.anthropic // empty') | |
| export GOOGLE_API_KEY=$(echo $API_KEYS_JSON | jq -r '.google // empty') | |
| export GROQ_API_KEY=$(echo $API_KEYS_JSON | jq -r '.groq // empty') | |
| log "β API keys loaded from JSON" | |
| else | |
| log "β οΈ WARNING: API_KEYS_JSON not set!" | |
| fi | |
| # Function to start service with retry | |
| start_with_retry() { | |
| local name=$1 | |
| local cmd=$2 | |
| local max_attempts=3 | |
| for i in $(seq 1 $max_attempts); do | |
| log "Starting $name (attempt $i/$max_attempts)..." | |
| eval "$cmd" & | |
| local pid=$! | |
| sleep 5 | |
| if ps -p $pid > /dev/null; then | |
| log "β $name started (PID: $pid)" | |
| return 0 | |
| fi | |
| log "β οΈ $name failed to start, retrying..." | |
| done | |
| log "β ERROR: $name failed after $max_attempts attempts" | |
| return 1 | |
| } | |
| # Check if ports are available | |
| check_port() { | |
| local port=$1 | |
| if netstat -tlnp 2>/dev/null | grep -q ":$port"; then | |
| log "β ERROR: Port $port already in use!" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| log "Verifying infrastructure ports..." | |
| for port in 7860 7861 7687 20128; do | |
| check_port $port || exit 1 | |
| done | |
| # π Start Services | |
| MEMGRAPH_BIN=$(command -v memgraph || echo "/usr/bin/memgraph") | |
| if [ ! -f "$MEMGRAPH_BIN" ]; then | |
| MEMGRAPH_BIN="/usr/lib/memgraph/memgraph" | |
| fi | |
| start_with_retry "Memgraph" "$MEMGRAPH_BIN --bolt-port 7687" || exit 1 | |
| # Start ZeroClaw on port 7862 | |
| export ZEROCLAW_PORT=7862 | |
| start_with_retry "ZeroClaw" "zeroclaw gateway" || exit 1 | |
| start_with_retry "OmniRoute" "node /app/scripts/omniroute.js --config /app/config/omniroute-masterfile.json --port 20128" || exit 1 | |
| # Start Graph Viewer on port 7861 | |
| GRAPH_VIEWER_PORT=7861 start_with_retry "Graph Viewer" "node /app/scripts/graph-viewer.js" || exit 1 | |
| log "All infrastructure ready! Launching Gradio UI on port 7860..." | |
| # Launch Gradio app (NOT Marimo) | |
| cd /app | |
| nohup python3 app.py > /tmp/gradio.log 2>&1 & | |
| GRADIO_PID=$! | |
| sleep 3 | |
| if ps -p $GRADIO_PID > /dev/null; then | |
| log "β Gradio started (PID: $GRADIO_PID)" | |
| log " Gradio logs: /tmp/gradio.log" | |
| else | |
| log "β ERROR: Gradio failed to start!" | |
| cat /tmp/gradio.log | |
| exit 1 | |
| fi | |
| log "All services active!" | |
| log " - Memgraph: port 7687" | |
| log " - ZeroClaw: port 7862" | |
| log " - OmniRoute: port 20128" | |
| log " - Graph Viewer: port 7861" | |
| log " - Gradio UI: port 7860 (primary)" | |
| # Keep container alive | |
| log "Holding container open. Access the UI at https://your-space.hf.space" | |
| wait | |