forked from sagnik/Project_Velocity
Built the Sentinel Tab
This commit is contained in:
BIN
backend/scripts/__pycache__/cctv_ocr_bridge.cpython-314.pyc
Normal file
BIN
backend/scripts/__pycache__/cctv_ocr_bridge.cpython-314.pyc
Normal file
Binary file not shown.
40
backend/scripts/cctv_ocr_bridge.py
Normal file
40
backend/scripts/cctv_ocr_bridge.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
Bridge OCR/plate-recognition output into the Velocity CCTV ingestion API.
|
||||
|
||||
Usage:
|
||||
python backend/scripts/cctv_ocr_bridge.py --api-base https://host --session-id <uuid> payload.json
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description='Forward OCR bridge payloads to Velocity CCTV API.')
|
||||
parser.add_argument('payload', type=Path, help='Path to a JSON payload file from the OCR bridge.')
|
||||
parser.add_argument('--api-base', default='http://127.0.0.1:8000', help='Velocity API base URL.')
|
||||
parser.add_argument('--session-id', default=None, help='Optional auto mode perception session UUID.')
|
||||
parser.add_argument('--token', default=None, help='Optional bearer token for protected ingestion.')
|
||||
args = parser.parse_args()
|
||||
|
||||
body = json.loads(args.payload.read_text(encoding='utf-8'))
|
||||
if args.session_id:
|
||||
body['session_id'] = args.session_id
|
||||
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
if args.token:
|
||||
headers['Authorization'] = f'Bearer {args.token}'
|
||||
|
||||
response = httpx.post(f"{args.api_base.rstrip('/')}/api/cctv/event", json=body, headers=headers, timeout=30.0)
|
||||
response.raise_for_status()
|
||||
print(json.dumps(response.json(), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
394
backend/scripts/nemoclaw_deploy.sh
Normal file
394
backend/scripts/nemoclaw_deploy.sh
Normal file
@@ -0,0 +1,394 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# nemoclaw_deploy.sh
|
||||
# Deploys NemoClaw on the AWS G6.12xlarge instance.
|
||||
# - All data/install paths on NVMe (/opt/dlami/nvme/)
|
||||
# - Configures OpenShell to use existing Ollama (qwen3.5:27b, port 11434)
|
||||
# - GPUs 0+1 are Ollama's. Do NOT reassign them.
|
||||
# - ComfyUI owns GPUs 2+3. Do NOT touch.
|
||||
# - Creates a systemd service for the NemoClaw gateway.
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
NVME="/opt/dlami/nvme"
|
||||
AGENT_NAME="velocity-sentinel"
|
||||
OLLAMA_URL="http://127.0.0.1:11434"
|
||||
OLLAMA_MODEL="qwen3.5:27b"
|
||||
OPENCLAW_PORT=8080 # Port our FastAPI backend targets
|
||||
|
||||
echo "================================================================"
|
||||
echo " Project Velocity — NemoClaw + OpenShell Deploy Script"
|
||||
echo " Instance: G6.12xlarge | NVMe: $NVME"
|
||||
echo "================================================================"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 0. Safety checks
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "[ERROR] Run as root or with sudo"; exit 1
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$NVME" 2>/dev/null && [ ! -d "$NVME" ]; then
|
||||
echo "[WARN] NVMe not mounted at $NVME — using /home/ubuntu/nvme as fallback"
|
||||
NVME="/home/ubuntu/nvme"
|
||||
mkdir -p "$NVME"
|
||||
fi
|
||||
|
||||
echo "[✓] NVMe target: $NVME"
|
||||
|
||||
# Confirm Ollama is alive before proceeding
|
||||
if ! curl -sf "$OLLAMA_URL/api/tags" | grep -q "qwen"; then
|
||||
echo "[WARN] Ollama at $OLLAMA_URL doesn't show qwen3.5:27b yet — proceeding anyway"
|
||||
else
|
||||
echo "[✓] Ollama confirmed running with qwen3.5:27b"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 1. Node.js 22 (NemoClaw requirement: >=22.16)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[1/7] Installing Node.js 22..."
|
||||
|
||||
NODE_VERSION=$(node --version 2>/dev/null | sed 's/v//' | cut -d. -f1 || echo "0")
|
||||
if [ "$NODE_VERSION" -ge 22 ]; then
|
||||
echo "[✓] Node.js $(node --version) already installed"
|
||||
else
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||
apt-get install -y nodejs
|
||||
echo "[✓] Node.js $(node --version) installed"
|
||||
fi
|
||||
|
||||
npm --version
|
||||
echo "[✓] npm $(npm --version)"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 2. Docker (required for OpenShell container runtime)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[2/7] Ensuring Docker is installed..."
|
||||
|
||||
if command -v docker &>/dev/null && docker info &>/dev/null; then
|
||||
echo "[✓] Docker $(docker --version | awk '{print $3}') already running"
|
||||
else
|
||||
echo " Installing Docker..."
|
||||
apt-get install -y ca-certificates curl gnupg lsb-release
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
|
||||
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
|
||||
| tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
apt-get update -q
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
systemctl enable docker
|
||||
systemctl start docker
|
||||
echo "[✓] Docker installed"
|
||||
fi
|
||||
|
||||
# Move Docker data root to NVMe so images don't fill root disk
|
||||
DOCKER_DAEMON_JSON="/etc/docker/daemon.json"
|
||||
if ! grep -q "nvme" "$DOCKER_DAEMON_JSON" 2>/dev/null; then
|
||||
echo " Moving Docker data-root → $NVME/docker"
|
||||
mkdir -p "$NVME/docker"
|
||||
# Preserve existing config if any
|
||||
EXISTING=$(cat "$DOCKER_DAEMON_JSON" 2>/dev/null || echo "{}")
|
||||
python3 -c "
|
||||
import json, sys
|
||||
cfg = json.loads('''$EXISTING''')
|
||||
cfg['data-root'] = '$NVME/docker'
|
||||
print(json.dumps(cfg, indent=2))
|
||||
" > "$DOCKER_DAEMON_JSON"
|
||||
systemctl restart docker
|
||||
echo "[✓] Docker data-root → $NVME/docker"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 3. Install NemoClaw (headless via env vars)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[3/7] Installing NemoClaw..."
|
||||
|
||||
# Set HOME so NemoClaw installs to NVMe-backed location
|
||||
export NEMOCLAW_HOME="$NVME/nemoclaw"
|
||||
export OPENSHELL_HOME="$NVME/openshell"
|
||||
export HOME_OVERRIDE="$NVME/home"
|
||||
mkdir -p "$NEMOCLAW_HOME" "$OPENSHELL_HOME" "$HOME_OVERRIDE"
|
||||
|
||||
# Link ~/.nemoclaw and ~/.openshell to NVMe
|
||||
ln -sfn "$NEMOCLAW_HOME" /root/.nemoclaw 2>/dev/null || true
|
||||
ln -sfn "$NEMOCLAW_HOME" /home/ubuntu/.nemoclaw 2>/dev/null || true
|
||||
ln -sfn "$OPENSHELL_HOME" /root/.openshell 2>/dev/null || true
|
||||
ln -sfn "$OPENSHELL_HOME" /home/ubuntu/.openshell 2>/dev/null || true
|
||||
|
||||
if command -v nemoclaw &>/dev/null; then
|
||||
echo "[✓] nemoclaw already installed: $(nemoclaw --version 2>/dev/null || echo 'version unknown')"
|
||||
else
|
||||
echo " Downloading NemoClaw installer..."
|
||||
INSTALLER_SCRIPT="$NVME/nemoclaw_install.sh"
|
||||
curl -fsSL https://www.nvidia.com/nemoclaw.sh -o "$INSTALLER_SCRIPT"
|
||||
chmod +x "$INSTALLER_SCRIPT"
|
||||
|
||||
# Run the installer non-interactively
|
||||
# NEMOCLAW_SKIP_ONBOARD=1 bypasses the interactive wizard (undocumented but standard pattern)
|
||||
# We'll do manual onboarding after install using CLI flags
|
||||
NEMOCLAW_SKIP_ONBOARD=1 \
|
||||
NEMOCLAW_HOME="$NEMOCLAW_HOME" \
|
||||
bash "$INSTALLER_SCRIPT" || true
|
||||
|
||||
# Reload PATH
|
||||
export PATH="$PATH:/usr/local/bin:/root/.local/bin"
|
||||
source ~/.bashrc 2>/dev/null || true
|
||||
|
||||
if ! command -v nemoclaw &>/dev/null; then
|
||||
echo "[WARN] nemoclaw not in PATH yet — checking common locations..."
|
||||
for p in /usr/local/bin/nemoclaw /root/.local/bin/nemoclaw "$NVME/bin/nemoclaw"; do
|
||||
if [ -f "$p" ]; then
|
||||
ln -sfn "$p" /usr/local/bin/nemoclaw
|
||||
echo "[✓] Linked nemoclaw from $p"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "[✓] nemoclaw installed"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 4. Onboard the Velocity Sentinel agent sandbox
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[4/7] Onboarding '$AGENT_NAME' NemoClaw sandbox..."
|
||||
|
||||
# Check if sandbox already exists
|
||||
if nemoclaw "$AGENT_NAME" status &>/dev/null; then
|
||||
echo "[✓] Sandbox '$AGENT_NAME' already exists — skipping creation"
|
||||
else
|
||||
echo " Running nemoclaw onboard (this may take a few minutes)..."
|
||||
# --provider compatible-endpoint: use our local Ollama instead of NVIDIA cloud
|
||||
# --yes: skip confirmation prompts
|
||||
nemoclaw onboard \
|
||||
--name "$AGENT_NAME" \
|
||||
--provider compatible-endpoint \
|
||||
--endpoint "$OLLAMA_URL/v1" \
|
||||
--model "$OLLAMA_MODEL" \
|
||||
--yes \
|
||||
--no-messaging-bridge \
|
||||
--no-skills || {
|
||||
echo "[WARN] Structured onboard failed — trying minimal onboard..."
|
||||
# Fallback: let it run with defaults if flags are not supported in this alpha version
|
||||
yes "" | nemoclaw onboard --name "$AGENT_NAME" 2>&1 | head -60 || true
|
||||
}
|
||||
echo "[✓] Sandbox onboarded"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 5. Configure OpenShell to use Ollama (compatible endpoint)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[5/7] Configuring OpenShell inference → Ollama (qwen3.5:27b)..."
|
||||
|
||||
# Set inference route to our local Ollama
|
||||
openshell inference set \
|
||||
--provider compatible-endpoint \
|
||||
--base-url "$OLLAMA_URL/v1" \
|
||||
--api-key "ollama" \
|
||||
--model "$OLLAMA_MODEL" \
|
||||
--context-window 32768 \
|
||||
--max-tokens 4096 || {
|
||||
echo "[WARN] openshell inference set failed — trying alternate syntax..."
|
||||
openshell inference set \
|
||||
--provider compatible-endpoint \
|
||||
--model "$OLLAMA_MODEL" || true
|
||||
}
|
||||
|
||||
# Also set the context window on the Ollama model side
|
||||
echo " Setting Ollama num_ctx=32768..."
|
||||
curl -s -X POST "$OLLAMA_URL/api/generate" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"model\":\"$OLLAMA_MODEL\",\"prompt\":\"\",\"options\":{\"num_ctx\":32768},\"stream\":false}" \
|
||||
> /dev/null 2>&1 || true
|
||||
|
||||
echo "[✓] OpenShell inference configured → $OLLAMA_URL ($OLLAMA_MODEL)"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 6. Write OpenShell network policy (allow Velocity backend egress)
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[6/7] Writing OpenShell network policy..."
|
||||
|
||||
POLICY_DIR="$OPENSHELL_HOME/policy"
|
||||
mkdir -p "$POLICY_DIR"
|
||||
|
||||
cat > "$POLICY_DIR/velocity_egress.yaml" << 'POLICY'
|
||||
# OpenShell Network Egress Policy — Project Velocity Sentinel
|
||||
# Applied to the velocity-sentinel sandbox.
|
||||
# All non-listed hosts are blocked by default.
|
||||
|
||||
version: "1"
|
||||
sandbox: velocity-sentinel
|
||||
|
||||
egress:
|
||||
# Local Ollama inference (Qwen 3.5 27B)
|
||||
- host: "127.0.0.1"
|
||||
ports: [11434]
|
||||
description: "Ollama LLM inference"
|
||||
action: allow
|
||||
|
||||
# OpenShell gateway itself (loopback)
|
||||
- host: "127.0.0.1"
|
||||
ports: [8080, 8081, 8082, 8083, 8084, 8085]
|
||||
description: "OpenShell gateway ports"
|
||||
action: allow
|
||||
|
||||
# Velocity FastAPI backend (same host)
|
||||
- host: "127.0.0.1"
|
||||
ports: [8000, 8001, 8288]
|
||||
description: "Velocity FastAPI backend"
|
||||
action: allow
|
||||
|
||||
# PostgreSQL (same host)
|
||||
- host: "127.0.0.1"
|
||||
ports: [5432]
|
||||
description: "PostgreSQL DB"
|
||||
action: allow
|
||||
|
||||
# Block everything else
|
||||
- host: "*"
|
||||
action: deny
|
||||
description: "Default deny — data sovereignty (India/Abu Dhabi)"
|
||||
POLICY
|
||||
|
||||
# Apply the policy if openshell supports it
|
||||
openshell policy apply "$POLICY_DIR/velocity_egress.yaml" 2>/dev/null || \
|
||||
echo "[WARN] Policy apply not supported yet in this alpha — YAML written for future use"
|
||||
|
||||
echo "[✓] Network policy written → $POLICY_DIR/velocity_egress.yaml"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# 7. Write NemoClaw systemd service
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[7/7] Installing systemd service: nemoclaw-velocity.service..."
|
||||
|
||||
NEMOCLAW_BIN=$(command -v nemoclaw || echo "/usr/local/bin/nemoclaw")
|
||||
OPENSHELL_BIN=$(command -v openshell || echo "/usr/local/bin/openshell")
|
||||
|
||||
cat > /etc/systemd/system/nemoclaw-velocity.service << SERVICE
|
||||
[Unit]
|
||||
Description=NemoClaw Velocity Sentinel Gateway
|
||||
Documentation=https://github.com/NVIDIA/NemoClaw
|
||||
After=network.target ollama.service docker.service
|
||||
Wants=ollama.service docker.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=ubuntu
|
||||
Group=ubuntu
|
||||
WorkingDirectory=$NVME/nemoclaw
|
||||
|
||||
# GPU constraint: NemoClaw itself is CPU-bound (inference goes to Ollama)
|
||||
# Ollama already owns GPUs 0,1. ComfyUI owns GPUs 2,3.
|
||||
Environment=CUDA_VISIBLE_DEVICES=""
|
||||
Environment=NEMOCLAW_HOME=$NVME/nemoclaw
|
||||
Environment=OPENSHELL_HOME=$NVME/openshell
|
||||
Environment=OLLAMA_BASE_URL=http://127.0.0.1:11434
|
||||
Environment=VELOCITY_NEMO_MODEL=qwen3.5:27b
|
||||
Environment=GATEWAY_PORT=$OPENCLAW_PORT
|
||||
|
||||
ExecStart=$NEMOCLAW_BIN $AGENT_NAME connect --gateway-port $OPENCLAW_PORT
|
||||
ExecReload=/bin/kill -HUP \$MAINPID
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=append:$NVME/logs/nemoclaw-velocity.log
|
||||
StandardError=append:$NVME/logs/nemoclaw-velocity.log
|
||||
|
||||
# Limits
|
||||
LimitNOFILE=65536
|
||||
TimeoutStopSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
SERVICE
|
||||
|
||||
mkdir -p "$NVME/logs"
|
||||
systemctl daemon-reload
|
||||
systemctl enable nemoclaw-velocity.service
|
||||
systemctl start nemoclaw-velocity.service || true # May fail on first boot if onboard not done
|
||||
|
||||
echo "[✓] nemoclaw-velocity.service enabled and started"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# Finalize: Detect gateway port & write env file
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "================================================================"
|
||||
echo " Writing Velocity backend environment file..."
|
||||
echo "================================================================"
|
||||
|
||||
VELOCITY_ENV="$NVME/velocity/env"
|
||||
mkdir -p "$(dirname "$VELOCITY_ENV")"
|
||||
|
||||
# Detect actual OpenShell gateway URL
|
||||
GATEWAY_URL="http://127.0.0.1:$OPENCLAW_PORT"
|
||||
GATEWAY_CHAT_URL="$GATEWAY_URL/v1/chat/completions"
|
||||
|
||||
# Quick connectivity test (will succeed once nemoclaw starts)
|
||||
echo " Testing gateway at $GATEWAY_CHAT_URL ..."
|
||||
sleep 5
|
||||
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" \
|
||||
-X POST "$GATEWAY_CHAT_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"qwen3.5:27b","messages":[{"role":"user","content":"ping"}],"max_tokens":5}' \
|
||||
2>/dev/null || echo "000")
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then
|
||||
echo "[✓] Gateway responding at $GATEWAY_CHAT_URL (HTTP $HTTP_CODE)"
|
||||
else
|
||||
echo "[WARN] Gateway not yet responding (HTTP $HTTP_CODE) — it may still be starting up"
|
||||
fi
|
||||
|
||||
cat > "$VELOCITY_ENV" << ENV
|
||||
# Project Velocity — Backend Environment
|
||||
# Generated by nemoclaw_deploy.sh
|
||||
# Loaded by: source $VELOCITY_ENV
|
||||
|
||||
# ── NemoClaw / OpenShell Gateway ──────────────────────────────────
|
||||
NEMOCLAW_BASE_URL=$GATEWAY_URL
|
||||
NEMOCLAW_CHAT_URL=$GATEWAY_CHAT_URL
|
||||
NEMOCLAW_MODEL=qwen3.5:27b
|
||||
NEMOCLAW_TIMEOUT_S=30.0
|
||||
NEMOCLAW_TEMPERATURE=0.2
|
||||
|
||||
# ── Ollama (direct fallback if OpenShell gateway not up) ──────────
|
||||
OLLAMA_BASE_URL=http://127.0.0.1:11434
|
||||
|
||||
# ── NemoClaw Prompts ──────────────────────────────────────────────
|
||||
NEMOCLAW_PROMPT_DIR=$NVME/nemoclaw/prompts
|
||||
|
||||
# ── JWT / Auth ────────────────────────────────────────────────────
|
||||
# VELOCITY_JWT_SECRET=<SET_THIS>
|
||||
|
||||
# ── PostgreSQL ────────────────────────────────────────────────────
|
||||
# VELOCITY_DB_DSN=postgresql://velocity_app:<PW>@127.0.0.1:5432/velocity
|
||||
ENV
|
||||
|
||||
echo "[✓] Environment file written → $VELOCITY_ENV"
|
||||
echo ""
|
||||
echo "================================================================"
|
||||
echo " DONE. Summary:"
|
||||
echo ""
|
||||
echo " Agent name : $AGENT_NAME"
|
||||
echo " Gateway URL : $GATEWAY_URL"
|
||||
echo " Chat endpoint: $GATEWAY_CHAT_URL"
|
||||
echo " Model : $OLLAMA_MODEL (via Ollama on port 11434)"
|
||||
echo " GPUs 0,1 : Ollama (unchanged)"
|
||||
echo " GPUs 2,3 : ComfyUI (unchanged)"
|
||||
echo " Env file : $VELOCITY_ENV"
|
||||
echo " Service log : $NVME/logs/nemoclaw-velocity.log"
|
||||
echo ""
|
||||
echo " Next commands to verify:"
|
||||
echo " nemoclaw $AGENT_NAME status"
|
||||
echo " nemoclaw $AGENT_NAME logs --follow"
|
||||
echo " curl $GATEWAY_CHAT_URL (POST with messages[])"
|
||||
echo "================================================================"
|
||||
Reference in New Issue
Block a user