← back to Whatsmystyle
fix: surface Gemini refusal reason; honest verdict on identity preservation
6ace428587643cc348330cdbc0180216ff089174 · 2026-05-11 23:04:47 -0700 · Steve Abrams
Worker now logs Gemini finishReason + safetyRatings + text refusal when
'returned no image' fires, instead of silently re-raising. Helps diagnose
the SAFETY refusal mode that's currently breaking avatar try-on.
Verdict from 3 live Gemini calls on Steve's portrait + Loro Piana cashmere:
- Garment rendered correctly (camel cashmere crewneck, every call)
- Identity preservation FAILED 3/3 — generic stock-photo man each time
- 2 of 3 charged (7.8¢ total); the 3rd failed (no image), no charge
- Pattern: Gemini's safety refuses real-person identity-clone on this
prompt shape (clean studio background + 'keep face/hair/skin')
Path forward per Steve: Dopple. Awaiting DOPPLE_API_KEY paste. If Dopple
also fails identity preservation, fallback is local IDM-VTON (free,
self-hosted, ~3GB model).
Files touched
M data/whatsmystyle.db-shmM data/whatsmystyle.db-walM scripts/tryon-worker.js
Diff
commit 6ace428587643cc348330cdbc0180216ff089174
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon May 11 23:04:47 2026 -0700
fix: surface Gemini refusal reason; honest verdict on identity preservation
Worker now logs Gemini finishReason + safetyRatings + text refusal when
'returned no image' fires, instead of silently re-raising. Helps diagnose
the SAFETY refusal mode that's currently breaking avatar try-on.
Verdict from 3 live Gemini calls on Steve's portrait + Loro Piana cashmere:
- Garment rendered correctly (camel cashmere crewneck, every call)
- Identity preservation FAILED 3/3 — generic stock-photo man each time
- 2 of 3 charged (7.8¢ total); the 3rd failed (no image), no charge
- Pattern: Gemini's safety refuses real-person identity-clone on this
prompt shape (clean studio background + 'keep face/hair/skin')
Path forward per Steve: Dopple. Awaiting DOPPLE_API_KEY paste. If Dopple
also fails identity preservation, fallback is local IDM-VTON (free,
self-hosted, ~3GB model).
---
data/whatsmystyle.db-shm | Bin 32768 -> 32768 bytes
data/whatsmystyle.db-wal | Bin 2867552 -> 2929352 bytes
scripts/tryon-worker.js | 10 +++++++++-
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/data/whatsmystyle.db-shm b/data/whatsmystyle.db-shm
index 2a60945..ff57dc8 100644
Binary files a/data/whatsmystyle.db-shm and b/data/whatsmystyle.db-shm differ
diff --git a/data/whatsmystyle.db-wal b/data/whatsmystyle.db-wal
index 7b0a5e4..227ff6e 100644
Binary files a/data/whatsmystyle.db-wal and b/data/whatsmystyle.db-wal differ
diff --git a/scripts/tryon-worker.js b/scripts/tryon-worker.js
index 1fead3f..af12b75 100644
--- a/scripts/tryon-worker.js
+++ b/scripts/tryon-worker.js
@@ -51,7 +51,15 @@ async function gemini(personImgBuf, garmentImgBuf, instruction) {
const j = await r.json();
const part = j.candidates?.[0]?.content?.parts?.find(p => p.inline_data || p.inlineData);
const data = part?.inline_data?.data || part?.inlineData?.data;
- if (!data) throw new Error('Gemini returned no image');
+ if (!data) {
+ // Log the actual response so we can see WHY (safety refusal, quota, etc.)
+ const text = j.candidates?.[0]?.content?.parts?.find(p => p.text)?.text;
+ const finish = j.candidates?.[0]?.finishReason;
+ const safety = j.candidates?.[0]?.safetyRatings;
+ const err = new Error(`Gemini returned no image (finishReason=${finish}, text="${(text || '').slice(0, 200)}", safety=${JSON.stringify(safety || [])})`);
+ err.gemini_response = j;
+ throw err;
+ }
return Buffer.from(data, 'base64');
}
← ac1cfa6 feat: paid Gemini 2.5 Flash Image try-on + budget HUD
·
back to Whatsmystyle
·
feat: FASHN AI + OpenAI gpt-image-1 try-on providers (per dr 302dac8 →