fix(gemini): read binary response body as Buffer instead of UTF-8 string

customNodeFetch previously used res.setEncoding('utf8') and concatenated
chunks into a string. This corrupted JPEG/PNG binary data with UTF-8
replacement characters, causing Gemini to return:
  400 Unable to process input image.

Now chunks are collected as Buffers and concatenated, preserving binary
integrity when images are fetched from presigned S3 URLs before being
sent to Gemini.
This commit is contained in:
Sven (AAMOS AI)
2026-08-12 20:30:24 +07:00
parent 716e768cd0
commit bf04a12b89
2 changed files with 63 additions and 3 deletions
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
set -euo pipefail
API="https://api.cibello.app"
FIXTURE="apps/worker/src/eval/fixtures/fridge-1.jpg"
EMAIL="e2e-$(date +%s)@example.com"
PASS="E2ETest123!"
echo "[e2e] register $EMAIL"
REG=$(curl -fsS -X POST "$API/v1/auth/register" -H 'content-type: application/json' \
-d "{\"email\":\"$EMAIL\",\"password\":\"$PASS\",\"displayName\":\"E2E\",\"locale\":\"sv-SE\"}")
TOKEN=$(echo "$REG" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d).accessToken))")
echo "[e2e] token OK"
echo "[e2e] create household"
HH=$(curl -fsS -X POST "$API/v1/households" -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"name":"E2E-hushåll"}')
HHID=$(echo "$HH" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d).id))")
echo "[e2e] household $HHID"
echo "[e2e] grant image_training consent"
curl -fsS -X PUT "$API/v1/me/consents" -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"kind":"image_training","granted":true}' >/dev/null
echo "[e2e] consent OK"
echo "[e2e] create scan"
SCAN=$(curl -fsS -X POST "$API/v1/scans" -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"scanType":"fridge","imageCount":1,"contentType":"image/jpeg"}')
SCANID=$(echo "$SCAN" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d).scan.id))")
UPLOAD=$(echo "$SCAN" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.stringify(JSON.parse(d).uploads[0])))")
URL=$(echo "$UPLOAD" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d).uploadUrl))")
KEY=$(echo "$UPLOAD" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d).key))")
echo "[e2e] scan $SCANID, upload key $KEY"
echo "[e2e] PUT image"
curl -fsS -X PUT "$URL" -H 'content-type: image/jpeg' --data-binary "@$FIXTURE" >/dev/null
echo "[e2e] image uploaded"
echo "[e2e] start scan"
curl -fsS -X POST "$API/v1/scans/$SCANID/start" -H "Authorization: Bearer $TOKEN" >/dev/null
echo "[e2e] scan started"
echo "[e2e] poll status"
for i in $(seq 1 30); do
STATUS=$(curl -fsS "$API/v1/scans/$SCANID" -H "Authorization: Bearer $TOKEN" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d).status))")
echo "[e2e] status: $STATUS"
if [ "$STATUS" = "awaiting_confirmation" ] || [ "$STATUS" = "completed" ]; then
echo "$SCANID" > /tmp/e2e-scan-id.txt
echo "$KEY" > /tmp/e2e-s3-key.txt
echo "$EMAIL" > /tmp/e2e-email.txt
exit 0
fi
if [ "$STATUS" = "failed" ]; then
echo "[e2e] scan failed"
exit 1
fi
sleep 2
done
echo "[e2e] timeout"
exit 1