# 이미지 파이프라인 기술 설계 v3

> Updated: 2026-03-22

---

## 1. 파이프라인 DAG

```
entity_style ──→ entity_review ──→ entity_detail_batch ──→ entity_t2i ─┐
                                                                        │
scene_segmentation ──→ scene_split ──┬──→ scene_director ──→ outlook_extraction ──┐
                                     │                                             │
                                     └──→ scene_dependency ────────────────────────┤
                                                                                   │
                                              ┌────────────────────────────────────┘
                                              ↓
                                     scene_detail ──→ scene_verify
                                              │
                                              ↓
                              world_guide ──→ ref_image_gen ──→ composite_image_gen
                                                                        │
                                                                        ↓
                                                            scene_image_pipeline
```

## 2. scene_director (전체 씬 일괄)

### 입력
- 전체 씬 JSON: `[{scene_index, heading, text}, ...]`
- 확정 캐릭터 목록
- visual_world_rules

### 처리
1회 LLM 호출로 전체 씬 분석. 앞쪽 씬 맥락 추적하여 접속/빙의 상태 유지.

### 출력
```json
{
  "scenes": [
    {
      "scene_index": 8,
      "primary_location": "야산",
      "scene_type": "normal",
      "characters": [
        {"name": "동녘", "presence": "PRESENT", "reason": ""},
        {"name": "강의원", "presence": "NOT_PRESENT", "reason": "동녘 몸에 소울라이드 접속 중"}
      ]
    }
  ],
  "scene_present_characters": {
    "8": ["동녘"]
  }
}
```

### 모델: Gemini Pro
- 전체 시나리오 25K자 + 45씬 JSON = ~35K 토큰
- 1회 호출, 비용 효율적

## 3. 참조 이미지 생성 3단계

### Phase 1: 기본 참조
| 타입 | 비율 | 프롬프트 | 저장 |
|------|------|---------|------|
| 얼굴 | 1:1 | `character_ref.md` | entity_id=char_id, is_primary=1 |
| 배경 | 16:9 | `location_ref.md` | entity_id=loc_id, is_primary=1 |
| 소품 | 1:1 | `prop_ref.md` | entity_id=prop_id, is_primary=1 |

### Phase 2: 아웃룩 단독
| 비율 | 프롬프트 | 저장 |
|------|---------|------|
| 1:1 | `character_outlook_ref.md` (마네킹, 얼굴 없이) | entity_id=outlook_id, is_primary=1, prompt_used=`[outfit:{id}]` |

중복 방지: `seen_outlook_ids` — 같은 아웃룩 1장만

### Phase 3: 합성
| 비율 | 참조 | 저장 |
|------|------|------|
| 16:9 | image 1=얼굴, image 2+=아웃룩 단독 | entity_id=char_id, is_primary=0, prompt_used=`[composite:{char}:{outlook}]` |

N개 아웃룩 참조 지원 (옷+모자+무기 등 차후 확장)

## 4. 씬 이미지 참조 매칭

### _resolve_refs_for_prompt

```python
for [[char]+[outlook]] in t2i_prompt:
    composite_key = f"composite:{char_id}:{outlook_id}"

    if composite in scene_ref_image_map:
        → "character in outfit" (1장)
        → _used_ref_ids에 composite_key + char_id + outlook_id 추가
        → continue

    fallback:
        → "character identity" (얼굴) + "outfit appearance" (아웃룩 단독)

if best_prev_bytes:
    → "previous scene for visual continuity"

for prop in visible:
    → "object appearance"
```

### scene_ref_image_map 구성
```
char_id        → face_bytes     (is_primary=1, type=character)
outlook_id     → outfit_bytes   (is_primary=1, type=outlook)
composite:x:y  → composite_bytes (prompt_used LIKE 'composite:%')
```

## 5. _build_final_scene_prompt 라벨 매핑

| 라벨 | 우선순위 | 지시 |
|------|---------|------|
| `"outfit appearance"` | 1 (exact match) | dress in outfit from image N |
| `"character in outfit"` | 2 (contains "outfit") | keep face + use outfit |
| `"character identity"` | 3 (contains "character") | keep face/hair/identity |
| `"object appearance"` | 4 | include object |
| `"previous scene..."` | 5 | maintain visual continuity |

## 6. pipeline_gate

합성 이미지 검증: `composite:` 또는 `outlook_id:` 양쪽 패턴 매칭
```python
or_(
    ImageAsset.prompt_used.like("%composite:%"),
    ImageAsset.prompt_used.like("%outlook_id:%"),
)
```

## 7. DB 키 일관성

visible_entities_json의 entity ID:
```python
# 모든 코드에서 이 패턴 사용
eid = v.get("id") or v.get("entity_id", "")
```

## 8. 이미지 크기

- Gemini 생성: `imageSize: "1K"` (1376×768 또는 1024×1024)
- fal.ai 전송: 4.5MB 초과 시 1536px 리사이즈
- 503/timeout: Gemini 키 로테이션
