From 0cebb2411e0c4ddea66a2abafdc888c30fe0606a Mon Sep 17 00:00:00 2001 From: Till JS Date: Fri, 24 Apr 2026 13:56:29 +0200 Subject: [PATCH] =?UTF-8?q?fix(wardrobe):=20prompt=20Ganzk=C3=B6rperfoto?= =?UTF-8?q?=20instead=20of=20Portrait=20for=20full=20try-on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The non-accessory Try-On prompts started with "Fotorealistisches Portrait von mir", and both gpt-image-1 and gpt-image-2 read that as a photographic framing hint ("head-and-shoulders crop") rather than a general "picture of a person". Result: even with body-ref supplied and a 1024×1536 portrait canvas, the model rendered a headshot and ignored the body reference. Keep "Portrait" only for the accessory path (brille/schmuck/hut) — there the tight head framing is what we actually want for legibility. Full-garment/outfit paths now say "Fotorealistisches Ganzkörperfoto von mir im/in … stehend, von Kopf bis Fuß sichtbar" which reliably biases the model to full-length framing. Applies to both runGarmentTryOn (single-garment) and runOutfitTryOn (outfit) — they share the same framing mistake. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../apps/web/src/lib/modules/wardrobe/api/try-on.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/mana/apps/web/src/lib/modules/wardrobe/api/try-on.ts b/apps/mana/apps/web/src/lib/modules/wardrobe/api/try-on.ts index a5b7b6673..25b6d294e 100644 --- a/apps/mana/apps/web/src/lib/modules/wardrobe/api/try-on.ts +++ b/apps/mana/apps/web/src/lib/modules/wardrobe/api/try-on.ts @@ -130,10 +130,16 @@ export function isAccessoryOnlyOutfit(garments: Garment[]): boolean { function composeDefaultPrompt(outfit: Outfit, accessoryOnly: boolean): string { if (accessoryOnly) { + // Portrait is the right framing for accessories — we want a tight + // head-and-shoulders shot so the Brille/Schmuck/Hut is legible. return `Fotorealistisches Portrait von mir mit ${outfit.name}, frontal, studio-Licht, neutraler Hintergrund, Fokus auf dem Accessoire`; } + // Explicitly ask for a full-body frame — gpt-image-1/2 otherwise read + // "Portrait" as "headshot" and crop to head-and-shoulders, ignoring + // the body-ref. "Ganzkörperfoto … stehend, von Kopf bis Fuß sichtbar" + // is the German idiom that reliably biases the model to full-length. const occasionHint = outfit.occasion ? ` (Anlass: ${outfit.occasion})` : ''; - return `Fotorealistisches Portrait von mir im Outfit ${outfit.name}${occasionHint}, natürliches Licht, neutraler Hintergrund`; + return `Fotorealistisches Ganzkörperfoto von mir im Outfit ${outfit.name}${occasionHint}, stehend, von Kopf bis Fuß sichtbar, natürliches Licht, neutraler Hintergrund`; } export async function runOutfitTryOn(params: RunOutfitTryOnParams): Promise { @@ -237,9 +243,12 @@ export function isAccessoryGarment(garment: Garment): boolean { function composeGarmentPrompt(garment: Garment, accessoryOnly: boolean): string { if (accessoryOnly) { + // Headshot framing for face-only categories (Brille/Schmuck/Hut). return `Fotorealistisches Portrait von mir mit ${garment.name}, frontal, studio-Licht, neutraler Hintergrund, Fokus auf dem Accessoire`; } - return `Fotorealistisches Portrait von mir im/in ${garment.name}, natürliches Licht, neutraler Hintergrund`; + // Explicit full-body framing — see composeDefaultPrompt for the + // rationale. "Portrait" biases to headshot, "Ganzkörperfoto" doesn't. + return `Fotorealistisches Ganzkörperfoto von mir im/in ${garment.name}, stehend, von Kopf bis Fuß sichtbar, natürliches Licht, neutraler Hintergrund`; } /**