#!/bin/sh
# taifoon grid bench — what this box can bring to the Taifoon Grid, and what it could earn.
#
#   curl -fsSL https://www.taifoon.io/grid/bench.sh | sh
#
# Reads the NVIDIA card(s) (nvidia-smi), CPU, RAM and disk; picks the open-weight
# model the box can serve; prints the live quote from the Grid — the bootstrap
# budget share, the hire price and how a paid hire splits (70 provider / 20
# reviewers / 10 ecosystem), and the price of one verified AI call.
#
# To join after you have a model serving behind your own https hostname:
#   curl -fsSL https://www.taifoon.io/grid/bench.sh | \
#     TAIFOON_OWNER=0xYourWallet TAIFOON_ENDPOINT=https://gpu.example.org TAIFOON_MODEL=hypernova-60b sh
# The gateway then ASKS your model an arithmetic battery (3/3 to pass) — a spec
# sheet is never believed. Nothing here sends your keys, IPs or files anywhere;
# the only calls are to www.taifoon.io.
set -eu
GW="${TAIFOON_GATEWAY:-https://www.taifoon.io}"
UPTIME="${TAIFOON_UPTIME:-95}"
say(){ printf '%s\n' "$*"; }
line(){ printf '%-34s %s\n' "$1" "$2"; }
command -v python3 >/dev/null 2>&1 || { say "python3 is needed (apt-get install -y python3)"; exit 1; }
command -v curl >/dev/null 2>&1 || { say "curl is needed"; exit 1; }

# ── 1. the box ────────────────────────────────────────────────────────────
GPUS=0; VRAM_GB=0; GPU_NAME="none"; DRIVER="-"
if command -v nvidia-smi >/dev/null 2>&1; then
  Q=$(nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader,nounits 2>/dev/null || true)
  if [ -n "$Q" ]; then
    GPUS=$(printf '%s\n' "$Q" | wc -l | tr -d ' ')
    GPU_NAME=$(printf '%s\n' "$Q" | head -1 | cut -d, -f1 | sed 's/^ *//;s/ *$//')
    VRAM_GB=$(printf '%s\n' "$Q" | head -1 | cut -d, -f2 | tr -d ' ' | awk '{printf "%d", $1/1024}')
    DRIVER=$(printf '%s\n' "$Q" | head -1 | cut -d, -f3 | tr -d ' ')
  fi
fi
CPUS=$(nproc 2>/dev/null || echo 1)
RAM_GB=$(awk '/MemTotal/ {printf "%d", $2/1048576}' /proc/meminfo 2>/dev/null || echo 0)
DISK_GB=$(df -Pk / 2>/dev/null | awk 'NR==2 {printf "%d", $4/1048576}')

# ── 2. the model this box can serve (Multiverse Computing open weights, Apache-2.0) ──
if [ "$GPUS" -gt 0 ] && [ "$VRAM_GB" -ge 44 ]; then
  MODEL=hypernova-60b; HF=MultiverseComputingCAI/Hypernova-60B-2605
  SERVE="vllm serve $HF --port 8000 --served-model-name $MODEL"
  WHY="${VRAM_GB} GB VRAM: Hypernova-60B (gpt-oss-120b class, ~32 GB weights) fits on one card"
elif [ "$GPUS" -gt 0 ]; then
  MODEL=littlelamb; HF=MultiverseComputingCAI/LittleLamb-ToolCalling
  SERVE="vllm serve $HF --port 8000 --served-model-name $MODEL"
  WHY="${VRAM_GB} GB VRAM: below the ~44 GB Hypernova needs; LittleLamb (0.29B, tool calling) — or any open model you can serve that answers the battery"
else
  MODEL=littlelamb; HF=MultiverseComputingCAI/LittleLamb-ToolCalling
  SERVE="pip install vllm && vllm serve $HF --device cpu --port 8000 --served-model-name $MODEL   # or llama.cpp / any OpenAI-compatible server"
  WHY="no NVIDIA GPU: LittleLamb runs on CPU — the gateway verifies answers, not silicon; storage and RPC pay too (see /join)"
fi

# ── 3. the live quote ─────────────────────────────────────────────────────
UNITS=$GPUS; [ "$UNITS" -gt 0 ] || UNITS=1
W=$(curl -fsS --max-time 60 "$GW/api/grid/wanted?kind=gpu&units=$UNITS&uptime=$UPTIME" 2>/dev/null || echo '{}')
E=$(curl -fsS --max-time 30 "$GW/api/grid/economics" 2>/dev/null || echo '{}')

say ""
say "TAIFOON GRID · BENCH"
say "────────────────────────────────────────────────────────────────"
line "GPU" "$GPU_NAME × $GPUS  (${VRAM_GB} GB VRAM each, driver $DRIVER)"
line "CPU / RAM / free disk" "$CPUS cores / ${RAM_GB} GB / ${DISK_GB} GB"
line "Model to serve" "$MODEL"
say "  $WHY"
say ""
W="$W" E="$E" UNITS="$UNITS" python3 - <<'PY'
import json, os
def load(k):
    try: return json.loads(os.environ.get(k) or '{}')
    except Exception: return {}
w, e = load('W'), load('E')
units = int(os.environ.get('UNITS', '1'))
peg = (e.get('rule') or {}).get('gridUsdc') or 0.01
gpu = next((k for k in e.get('kinds', []) if k.get('kind') == 'gpu'), None)
pool = next((r for r in ((w.get('lands') or {}).get('resources') or []) if r.get('kind') == 'gpu'), None)
p = w.get('projection') or {}
st = ((w.get('rule') or {}).get('settlement') or {})
def usd(g):
    if not isinstance(g, (int, float)): return '—'
    v = g * peg
    return f"${v:,.4f}" if 0 < v < 0.01 else f"${v:,.2f}"
def row(k, v): print(f"{k:<34} {v}")
if pool: row('GPU pool', f"{pool.get('usable')} usable of {pool.get('target')} · bonus {pool.get('bonus') or 0:.2f}× · demand {pool.get('demandUnitHours24h')} unit-h/24h")
if p:
    frac = p.get('budgetFraction')
    row('Settled for measured work, /month', f"{p.get('budgetPaidPerMonth'):,} GRID ({usd(p.get('budgetPaidPerMonth'))})  — {'in full' if frac == 1 else f'{round((frac or 0) * 100)}% of the rate'}")
    row('How it settles', f"soulbound GRID on Taifoon mainnet every {st.get('everyHours', 6)} h; today's cap {st.get('dailyCapToday', '—')} GRID vs the network's {st.get('networkClaimsPerDay', '—')}")
if gpu and gpu.get('gridPerHour'):
    h = gpu['gridPerHour'] * units
    print('')
    row('If agents hire it, per hour', f"{h:,.1f} GRID ({usd(h)}) paid by the hirer")
    row('  → you (70%)', f"{h*0.7:,.1f} GRID ({usd(h*0.7)})")
    row('  → reviewers (20%)', f"{h*0.2:,.1f} GRID ({usd(h*0.2)})")
    row('  → ecosystem (10%)', f"{h*0.1:,.1f} GRID ({usd(h*0.1)})")
    call = gpu['gridPerHour'] * 2 / 3600
    row('One verified AI call (2 s)', f"{call:,.4f} GRID ({usd(call)}) — priced from the live rate")
elif not pool:
    print('The Grid did not answer — the quote is unknown, not zero. Try again, or read', os.environ.get('GW', 'https://www.taifoon.io') + '/join')
print('')
print('Only verified work pays: the gateway asks your model before it counts; no hire means no money yet.')
PY

# ── 4. join (optional) ────────────────────────────────────────────────────
say ""
if [ -n "${TAIFOON_OWNER:-}" ] && [ -n "${TAIFOON_ENDPOINT:-}" ]; then
  M="${TAIFOON_MODEL:-$MODEL}"
  say "Joining: $TAIFOON_ENDPOINT serving $M for $TAIFOON_OWNER — the gateway runs the battery now…"
  curl -fsS --max-time 120 -X POST "$GW/api/grid/join" -H 'content-type: application/json' \
    -d "{\"kind\":\"gpu\",\"endpoint\":\"$TAIFOON_ENDPOINT\",\"owner\":\"$TAIFOON_OWNER\"${TAIFOON_REF:+,\"ref\":\"$TAIFOON_REF\"},\"meta\":{\"service\":\"inference\",\"model\":\"$M\"}}" \
    | python3 -c 'import json,sys; d=json.load(sys.stdin); print("accepted:", d.get("accepted"), "| probe:", (d.get("probe") or {}).get("ok"), "|", (d.get("probe") or {}).get("reason") or (d.get("probe") or {}).get("battery") or "", "|", "; ".join(d.get("errors") or []))' \
    || say "join request failed — check the endpoint is https, public, and serving /v1/chat/completions"
else
  say "Next:"
  say "  1. serve the model:   $SERVE"
  say "  2. put it behind your own https hostname (never a raw IP), then join in one line:"
  say "     curl -fsSL $GW/grid/bench.sh | TAIFOON_OWNER=0xYourWallet TAIFOON_ENDPOINT=https://your-gpu.example TAIFOON_MODEL=$MODEL sh"
  say "  More ways to join (storage, RPC, a full node): $GW/join · the board: $GW/spinners"
fi
