매일 조금씩 굽고 모을 것이므로, 다음 날의 내가 같은 시행착오를 안 겪게 적는다.
2026-09-01 첫 배치(18장 발행) 실측 기준.
창업자 질문: "뭔가 과정이 복잡하고 이상하게 하는 건 아니야?"
아니다. 복잡했던 건 처음 한 번의 탐색이었지 매일 하는 일이 아니다.
앞으로 하루치는 이게 전부다:
# ① 오늘 구울 20개 고르기 (아직 안 쓴 것에서)
node scripts/recipe-pick.cjs --count 20 > /tmp/today.json
# ② 굽고 큐에 넣기 (시험 키. 실제로 팔 것이면 --real-key)
node scripts/recipe-generate-batch.cjs --picks /tmp/today.json
# ③ 카드 채우고(제목·훅·프롬프트·태그) 발행
node scripts/recipe-describe.cjs && node scripts/recipe-publish.cjs
나머지는 전부 이미 밟아 본 지뢰를 코드가 대신 피해 주는 것이다.
핀터레스트 레퍼런스 우리 대표 모델 얼굴
│ │
└──────────┬──────────────┘
▼
nano-banana-2-lite/edit ← 베끼지 않는다. 구도·조명만 가져온다
▼
R2 recipe-out/ ← 우리 것으로 고정
▼
samples (status=queued) ← 기존 큐. 새 테이블 안 만든다
▼
Haiku 4.5 vision ← 제목·훅·복사용 프롬프트·태그
▼
/recipes 에 발행
실측에서 lite 는 포즈를 그대로 안 따라오고 옷도 바꿨다. 나는 이걸 실패로 보고
nano-banana-2 를 추천했는데, 창업자 판정은 반대였다:
"그대로 베끼는 것도 마음에 안 들고 포즈도 완벽히 같을 필요 없다.
오히려 2차 저작물로 만드는 데 더 적합하지 않냐."
베끼기가 목적이 아니다. 그래서 lite 를 쓰고, 프롬프트도 "정확히 재현하라"가 아니라
"구도·조명·무드만 가져오고 의상은 비슷하되 분명히 다르게, 포즈는 자연스러운 변주로"라고 쓴다.
| 실측 | |
|---|---|
| 원본 얼굴이 남는다 | Y2K 블록 10장은 얼굴이 잘 바뀌었는데, 미니멀 블록 8장은 원본 인상이 꽤 남았다. 원인은 원본 해상도다 — 미니멀 원본은 고화질에 얼굴이 정면으로 크게 박혀 있어 lite 가 거기 강하게 붙는다. 저화질 원본이 오히려 결과가 좋다. |
| 우리 모델도 안 나온다 | 차서윤·윤라온을 넣어도 결과는 "제3의 인물"이다. lite 는 정체성 전이가 약하다. "우리 대표 모델이 나오는 화보"가 목적이면 lite 로는 안 된다 — 그때는 nano-banana-2/edit($0.08). |
/recipes 는 발행해도 안 보인다 (3중 관문)status='published' 만 켜면 안 뜬다. lib/prompts/queries.ts 의 toCard() 가 거른다:
if (!r.slug || !prompt || !image) return null // prompt = metadata.prompt
필수 4종: is_public=true · slug(비면 탈락) · metadata.prompt(비면 탈락) · 이미지.
거기에 태그는 lib/prompts/tags.ts 의 8개 중에서만 필터에 잡힌다
(뷰티·패션·잡화·식품음료·리빙·디지털·모델인물·매장). 임의 태그는 카운트가 0이 된다.
→ 실제로 18장을 발행해 놓고 화면에 하나도 안 떠서 되짚었다.
samples.source 는 4개만 허용된다CHECK (source = ANY (ARRAY['app','curated','featured','base']))
recipe-ref 를 넣다가 23514 로 막혔다. 우리 것은 curated.
AI_GATEWAY_BASE_URL 을 그대로 쓰면 404환경변수 값은 https://ai-gateway.vercel.sh/v1/ai 인데 이건 AI SDK 전용 경로다.
REST(OpenAI 호환)로 칠 때는 /v1/chat/completions.
❌ {BASE}/chat/completions → 404 not_found
✅ https://ai-gateway.vercel.sh/v1/chat/completions
.jpg 로 저장한다확장자를 믿고 image/jpeg 로 vision 에 보내면 Anthropic 이 400 으로 거절한다:
"specified using the image/jpeg media type, but the image appears to be a image/png image"
→ 매직바이트로 실제 타입을 읽는다 (89504e47 = PNG). 코드에 반영돼 있다.
urllib.request.urlopen(url) → 403. curl 이나 User-Agent 헤더를 넣어야 한다.
같은 입력인데 한 번은 빈 배열, 다음엔 정상. 재시도 1회가 배치에 들어 있다.
그래도 안 되면 안전 필터일 가능성이 높다 — 노출이 큰 컷에서 나온다(087·095).
버린다. 매달리지 마라 (창업자 지시: "실패했어? 버려").
받은 136개 중 8개가 이미 죽어 있었다(6%). 그래서 무엇을 하기 전에 R2 로 복사한다.
scripts/recipe-source-import.cjs 가 그 일을 하고 sha256 을 남긴다.
| 무엇 | 어디 |
|---|---|
| 원본 128장 | R2 assets/recipe-source/{a-y2k,b-minimal}/<nnn>.jpg |
| 생성물 | R2 assets/recipe-out/<coll>-<nnn>-<model>.jpg |
| 대표 모델 얼굴 | R2 assets/samples/images/presets-signature/{cha-seoyoon,yoon-raon,jin-taeyoon}-source.jpg |
| 레코드 | samples (app_id=recipes, source=curated) |
| 공개 화면 | /recipes · 상세 /recipes/[slug] |
| 검수 화면 | /admin/recipes (로그인 필요) |
| 반입 | scripts/recipe-source-import.cjs |
| 굽기 | scripts/recipe-generate-batch.cjs |
| 카드 채우기 | scripts/recipe-describe.cjs |
| 장당 | 20장/일 | |
|---|---|---|
| nb2-lite 굽기 | ~$0.05 | ~$1.0 |
| Haiku vision 카드 | ~$0.002 | ~$0.04 |
| 합계 | ~$1/일 |
키는 기본 FAL_KEY_TEST(시험용). 실제로 팔 발행분을 구울 때만 --real-key.
| 반입한 원본 | 128장 (a-y2k 63 · b-minimal 65) |
| 구운 것 | 18장 (2026-09-01) |
| 발행 | 18장 — /recipes 총 34개 |
| 남은 원본 | 107장 → 하루 20장이면 6일 |
| 실패 | 087 · 095 (안전 필터 추정) — 버림 |
근거: 2026-09-01 실측. 커밋 a8256f6c 이후.