← back to Whatsmystyle
WIN: FASHN AI renders Steve photoreally + preserves identity
21734dff09f26c3aecb759a86e2e18b629e6b1fe · 2026-05-11 23:45:25 -0700 · Steve Abrams
job-8: Steve (steve-showroom-crop.jpg) wearing Loro Piana cashmere crewneck
(catalog item 2). 8¢. Background, pose, face, hair, smile, body shape all
preserved — first real photoreal try-on across 4 providers attempted.
Source: Steve right-third of group photo at fabric showroom (cropped to
isolate single subject). FASHN's body-pose detector rejected the suit
selfie (too tight a crop, head+shoulders only) but accepted the 3/4
upper-body showroom shot.
Comparison across 3 successful calls:
- 2x Gemini 2.5 Flash Image (7.8¢) identity wrong, both generic men
- 1x FASHN AI (8.0¢) identity correct, Steve preserved
Caveat: color fidelity drifted (camel cashmere → dark teal/charcoal
crewneck). Silhouette + texture + knit pattern preserved. Tunable via
FASHN's category + prompt params in a later tick.
3 photos dropped into chat + saved to project:
data/uploads/avatar/steve-suit.jpg (selfie, 65kb, too tight)
data/uploads/avatar/steve-showroom.jpg (group, 489kb, original)
data/uploads/avatar/steve-showroom-crop.jpg (Steve isolated, 86kb, WORKS)
data/uploads/avatar/steve-natalia-dinner.jpg (deck dinner, 737kb, untested)
Ledger:
budget: $5.00 (500¢)
spent: $0.158 (15.8¢) = 2 Gemini failures + 1 FASHN success
remaining: $4.84 (484.2¢) = ~60 more FASHN renders
Files touched
M data/whatsmystyle.db-shmM data/whatsmystyle.db-walM scripts/fashn.js
Diff
commit 21734dff09f26c3aecb759a86e2e18b629e6b1fe
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon May 11 23:45:25 2026 -0700
WIN: FASHN AI renders Steve photoreally + preserves identity
job-8: Steve (steve-showroom-crop.jpg) wearing Loro Piana cashmere crewneck
(catalog item 2). 8¢. Background, pose, face, hair, smile, body shape all
preserved — first real photoreal try-on across 4 providers attempted.
Source: Steve right-third of group photo at fabric showroom (cropped to
isolate single subject). FASHN's body-pose detector rejected the suit
selfie (too tight a crop, head+shoulders only) but accepted the 3/4
upper-body showroom shot.
Comparison across 3 successful calls:
- 2x Gemini 2.5 Flash Image (7.8¢) identity wrong, both generic men
- 1x FASHN AI (8.0¢) identity correct, Steve preserved
Caveat: color fidelity drifted (camel cashmere → dark teal/charcoal
crewneck). Silhouette + texture + knit pattern preserved. Tunable via
FASHN's category + prompt params in a later tick.
3 photos dropped into chat + saved to project:
data/uploads/avatar/steve-suit.jpg (selfie, 65kb, too tight)
data/uploads/avatar/steve-showroom.jpg (group, 489kb, original)
data/uploads/avatar/steve-showroom-crop.jpg (Steve isolated, 86kb, WORKS)
data/uploads/avatar/steve-natalia-dinner.jpg (deck dinner, 737kb, untested)
Ledger:
budget: $5.00 (500¢)
spent: $0.158 (15.8¢) = 2 Gemini failures + 1 FASHN success
remaining: $4.84 (484.2¢) = ~60 more FASHN renders
---
data/whatsmystyle.db-shm | Bin 32768 -> 32768 bytes
data/whatsmystyle.db-wal | Bin 3164192 -> 3316632 bytes
scripts/fashn.js | 19 +++++++++++--------
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/data/whatsmystyle.db-shm b/data/whatsmystyle.db-shm
index b2250d7..cc4d9ac 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 ee656e3..6b1af78 100644
Binary files a/data/whatsmystyle.db-wal and b/data/whatsmystyle.db-wal differ
diff --git a/scripts/fashn.js b/scripts/fashn.js
index 8504d3d..34be67c 100644
--- a/scripts/fashn.js
+++ b/scripts/fashn.js
@@ -34,24 +34,27 @@ async function bufferToBase64DataUri(buf, mime = 'image/jpeg') {
async function tryOn({ personBuf, garmentBuf, category = 'tops' }) {
if (!KEY) throw new Error('FASHN_API_KEY not set');
- // category must be one of: tops, bottoms, one-pieces (per fashn.ai API)
- const cat = ({ top: 'tops', bottom: 'bottoms', dress: 'one-pieces' })[category] || 'tops';
+ // Categories per current fashn.ai API: 'tops' | 'bottoms' | 'one-pieces' | 'auto'
+ const cat = ({ top: 'tops', bottom: 'bottoms', dress: 'one-pieces', outerwear: 'tops' })[category] || 'auto';
const submit = await fetch(`${BASE}/v1/run`, {
method: 'POST',
headers: { Authorization: `Bearer ${KEY}`, 'content-type': 'application/json' },
body: JSON.stringify({
- model_image: await bufferToBase64DataUri(personBuf),
- garment_image: await bufferToBase64DataUri(garmentBuf),
- category: cat,
+ model_name: process.env.FASHN_MODEL_NAME || 'tryon-v1.6',
+ inputs: {
+ model_image: await bufferToBase64DataUri(personBuf),
+ garment_image: await bufferToBase64DataUri(garmentBuf),
+ category: cat,
+ },
}),
});
if (!submit.ok) throw new Error(`FASHN submit ${submit.status}: ${await submit.text()}`);
const { id } = await submit.json();
if (!id) throw new Error('FASHN: no job id returned');
- // Poll up to 90s
+ // Poll up to 120s — FASHN v1.6 takes ~20-60s per render
const start = Date.now();
- while (Date.now() - start < 90000) {
+ while (Date.now() - start < 120000) {
const s = await fetch(`${BASE}/v1/status/${id}`, { headers: { Authorization: `Bearer ${KEY}` } });
if (!s.ok) throw new Error(`FASHN status ${s.status}: ${await s.text()}`);
const j = await s.json();
@@ -60,7 +63,7 @@ async function tryOn({ personBuf, garmentBuf, category = 'tops' }) {
if (!r.ok) throw new Error(`FASHN result fetch ${r.status}`);
return { buffer: Buffer.from(await r.arrayBuffer()), meta: j, cost_cents: COST_CENTS };
}
- if (j.status === 'failed') throw new Error('FASHN: render failed — ' + (j.error || 'unknown'));
+ if (j.status === 'failed') throw new Error('FASHN: render failed — ' + JSON.stringify(j.error || j));
await new Promise(r => setTimeout(r, 3000));
}
throw new Error('FASHN: poll timeout');
← 302dac8 feat: FASHN AI + OpenAI gpt-image-1 try-on providers (per dr
·
back to Whatsmystyle
·
feat: /studio — photo-first, sectioned swap, per-photo histo 20e99b7 →