Files
step-parse/api-test.sh
T
Jason Stedwell b3c3e2a3b2 Phase 1: FastAPI backend with async job model
- backend/app: FastAPI API wrapping the CAD skill modules
  - upload -> job -> poll -> model / BOM / artifacts -> geometry query
  - SQLite via SQLModel (Model, Job, BomRow, QueryLog)
  - ThreadPoolExecutor worker, serialized, with live stage updates
- docker-compose.yml: dev server (mounts source, --reload) on :8000
- api-test.sh: end-to-end live validation script
- requirements.txt: add fastapi, uvicorn, python-multipart, sqlmodel
- external_diagram.py: port active-area detection OCC.Core -> OCP
- .gitignore, PHASE1.md

Validated live: MR16 round-trip passes (28 BOM rows, 12 artifacts,
bounding-box query, xlsx download; active-area detection working).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:38:26 -05:00

62 lines
2.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Phase 1 live validation — exercises the API end to end against a running server
# (docker compose up). Upload a sample, poll the job, read model detail, download
# an artifact, run a geometry query.
#
# docker compose up -d && ./api-test.sh
set -uo pipefail
cd "$(dirname "$0")"
BASE="${BASE:-http://localhost:8000}"
SAMPLE="${SAMPLE:-skill.src/MR16s Gen1_EN.step}"
PYJ() { python3 -c "import sys,json$1"; } # tiny JSON helper
echo "== health =="
curl -fsS "$BASE/api/health"; echo
echo "== upload ($SAMPLE) =="
resp=$(curl -fsS -F "file=@${SAMPLE}" -F "diagram=true" "$BASE/api/upload")
echo "$resp"
job_id=$(PYJ ";print(json.load(sys.stdin)['job_id'])" <<<"$resp")
model_id=$(PYJ ";print(json.load(sys.stdin)['model_id'])" <<<"$resp")
echo "== poll job $job_id =="
status=""
for i in $(seq 1 200); do
j=$(curl -fsS "$BASE/api/jobs/$job_id")
status=$(PYJ ";print(json.load(sys.stdin)['status'])" <<<"$j")
stage=$(PYJ ";print(json.load(sys.stdin).get('stage'))" <<<"$j")
echo " [$i] status=$status stage=$stage"
[ "$status" = "done" ] && break
[ "$status" = "error" ] && { echo "$j"; exit 1; }
sleep 3
done
[ "$status" = "done" ] || { echo "TIMEOUT waiting for job"; exit 1; }
echo "== model $model_id detail =="
detail=$(curl -fsS "$BASE/api/models/$model_id")
echo "$detail" | PYJ "
d=json.load(sys.stdin); m=d['model']
print(' backend:', m['backend'], '| faces:', m['face_count'], '| parts:', m['part_count'])
print(' bbox(mm):', m['bbox_x_mm'], m['bbox_y_mm'], m['bbox_z_mm'], '| chinese:', m['has_chinese'])
print(' bom rows:', len(d['bom']))
print(' artifacts:', d['artifacts'])
"
echo "== download .xlsx artifact =="
art=$(echo "$detail" | PYJ ";print(next((a for a in json.load(sys.stdin)['artifacts'] if a.endswith('.xlsx')),''))")
if [ -n "$art" ]; then
enc=$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1]))" "$art")
curl -fsS -o /tmp/api_test_bom.xlsx "$BASE/api/models/$model_id/artifacts/$enc"
echo " downloaded '$art' -> $(wc -c < /tmp/api_test_bom.xlsx) bytes"
else
echo " no .xlsx artifact found"; exit 1
fi
echo "== geometry query =="
curl -fsS -X POST -H 'Content-Type: application/json' \
-d '{"query":"bounding box"}' "$BASE/api/models/$model_id/query" \
| PYJ ";print(json.load(sys.stdin)['result'][:500])"
echo "== API TEST PASSED =="