← back to Dw Pairs Well

deploy/block2-clip-flip.sh

57 lines

#!/bin/bash
# Block 2 — update Kamatera's visual-search service + flip CLIP defaults for pairs-well.
# HARD-GATED version (contrarian findings 2026-07-13): link-check must PASS first,
# Steve must type PASS at the prompt, and the pm2 process name is validated (no guessing).
# RUN FROM MAC2:  bash ~/Projects/dw-pairs-well/deploy/block2-clip-flip.sh
set -euo pipefail
cd "$(dirname "$0")/.."

echo "── precondition: live link check must PASS (run after Item 1 / fix-osp-kamatera.sh) ──"
RES=$(BASE=https://pairs.designerwallcoverings.com STORE=https://designerwallcoverings.com N=5 bash tools/live-link-check.sh | tail -1)
echo "$RES"
[[ "$RES" == *PASS* ]] || { echo "ABORT: link guarantee not PASS — run fix-osp-kamatera.sh first"; exit 1; }

echo
echo "── customer-facing default flip ahead: PAIRS_CLIP_DEFAULT=1 + SIMILAR_CLIP_DEFAULT=1 ──"
echo "Eyeball first if you want: https://pairs.designerwallcoverings.com/api/similar?dw_sku=BGA-47951&engine=clip&limit=6"
read -p "Type PASS to proceed with the CLIP flip, anything else aborts: " ans
[ "$ans" = "PASS" ] || { echo "aborted by operator"; exit 1; }

echo "── push updated visual-search service + gap embedder ──"
rsync -az ~/Projects/dw-photo-capture/visual-search/search_service.py \
          ~/Projects/dw-photo-capture/visual-search/embed_shopify_gap.py \
          root@45.61.58.125:/root/public-projects/dwphoto/visual-search/

ssh root@45.61.58.125 'set -e
  # validate the pm2 process that owns :9914 — abort loudly rather than guess
  PROC=$(pm2 jlist | python3 -c "
import sys, json
for p in json.load(sys.stdin):
    port = str(p.get(\"pm2_env\", {}).get(\"env\", {}).get(\"VS_PORT\", \"\"))
    name = p[\"name\"]
    if port == \"9914\" or \"visual\" in name.lower():
        print(name); break
")
  [ -n "$PROC" ] || { echo "ABORT: no pm2 process matches visual-search/:9914 — find it with pm2 ls"; exit 1; }
  echo "restarting pm2 process: $PROC"
  pm2 restart "$PROC"
  sleep 25
  curl -sf http://127.0.0.1:9914/health || { echo "ABORT: :9914 unhealthy after restart"; exit 1; }

  # embed the shopify-only gap on Kamatera (resumable, background)
  cd /root/public-projects/dwphoto/visual-search
  export DW_UNIFIED_DB="$(grep ^DW_UNIFIED_DB= ../.env | cut -d= -f2-)"
  nohup nice -n 15 python3 embed_shopify_gap.py --workers 16 > gap-embed.log 2>&1 &

  # flip CLIP defaults — update-or-append so an existing =0 line cannot silently win
  cd /root/Projects/dw-pairs-well
  for K in PAIRS_CLIP_DEFAULT SIMILAR_CLIP_DEFAULT; do
    if grep -q "^${K}=" .env 2>/dev/null; then sed -i "s/^${K}=.*/${K}=1/" .env
    else echo "${K}=1" >> .env; fi
  done
  pm2 restart dw-pairs-well
  sleep 6
  curl -sf https://pairs.designerwallcoverings.com/healthz >/dev/null && echo "pairs-well healthy, CLIP defaults ON"
'
echo "── done. Re-verify: BASE=https://pairs.designerwallcoverings.com N=8 bash tools/live-link-check.sh ──"