#!/usr/bin/env node // Prints the image-edit request for one virtual try-on. It does not call any API. // Consent: the agent must ask the user whether the person photo is their own or whether they have the person's written consent, // quote the answer, and pass --consent only after the user said yes. Never pass --consent on your own initiative. // Usage: // node scripts/build-input.mjs --person https://... --garment https://... --describe "cream linen button-up shirt" \ // --replaces "the white t-shirt" --colour "oatmeal cream" --fabric "slubby matte linen, not shiny" \ // [--worn "buttoned, top button open, sleeves down"] [--extra "..."] [--portrait] --consent import { readFileSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' const root = join(dirname(fileURLToPath(import.meta.url)), '..') const usage = 'Usage: node scripts/build-input.mjs --person https://... --garment https://... --describe "..." --replaces "..." --colour "..." --fabric "..." [--worn "..."] [--extra "..."] [--portrait] --consent' const flags = new Set(['portrait', 'consent']) const known = new Set(['person','garment','describe','replaces','colour','fabric','worn','extra','portrait','consent']) const options = {} const args = process.argv.slice(2) for (let index = 0; index < args.length; index += 1) { const key = args[index] if (!key.startsWith('--')) { console.error(`Unexpected argument: ${key}`) process.exit(1) } const name = key.slice(2) if (!known.has(name)) { console.error(`Unknown flag: ${key}`) console.error(usage) process.exit(1) } if (flags.has(name)) { options[name] = true continue } const value = args[index + 1] if (value === undefined || value.startsWith('--')) { console.error(`Flag ${key} needs a value.`) process.exit(1) } options[name] = value index += 1 } if (!options.consent) { console.error('Refusing: ask the user whether the person photo is their own or whether they have the person\'s written consent, quote their answer, and only then pass --consent. Never pass it on your own.') process.exit(1) } const { person, garment, describe, replaces, colour, fabric } = options if (!person || !garment || !describe || !replaces || !colour || !fabric) { console.error(usage) process.exit(1) } for (const url of [person, garment]) { if (!/^https:\/\//.test(url)) { console.error('Both photos must be public https URLs.') process.exit(1) } } const template = readFileSync(join(root, 'assets/prompt-template.md'), 'utf8').trim() const settings = JSON.parse(readFileSync(join(root, 'assets/generation-input.json'), 'utf8')) const prompt = template .replace('{{garment}}', () => describe) .replace('{{replaces}}', () => replaces) .replace('{{worn}}', () => options.worn || 'naturally, as it is meant to be worn') .replace('{{colour}}', () => colour) .replace('{{fabric}}', () => fabric) .replace('{{extra}}', () => options.extra || '') .replace(/\s{2,}/g, ' ') const input = { ...settings.input, ...(options.portrait ? { image_size: settings.portrait_image_size } : {}), image_urls: [person, garment], prompt, } console.log(JSON.stringify({ model: settings.model, input }, null, 2))