[object Object]

← 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

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 →