# 리팩토링 달성 내용 v2

> Updated: 2026-03-22
> 이전 버전: refactoring-achievement.md (v1, 2026-03-21)

---

## Phase 1: LiteLLM + Opik 통합 (v1에서 완료)

- 전체 LLM 클라이언트를 LiteLLM Router + Opik Cloud로 통합
- PIPELINE_STEPS 19개 등록, prompt_loader 중앙집중화
- 상세 내용은 refactoring-achievement.md 참조

---

## Phase 2: 이미지 파이프라인 구조 변경 (이번 세션)

### 1. 아웃룩 이미지 3단계 분리

**이전**: 얼굴 + 의상 설명 → 합성 이미지 1장 (Gemini가 얼굴 참조로 의상 입힌 전신 생성)

**현재**: 3단계 분리
```
Step 1: 얼굴 참조 이미지 (1:1, 증명사진 스타일)
Step 2: 아웃룩 단독 이미지 (1:1, 투명 마네킹에 의상만)
Step 3: 합성 이미지 = 얼굴 ref + 아웃룩 ref → Gemini가 전신 생성 (16:9)
```

**파일 변경**:
- `prompts/_base/ref_image_prompts/2.202603220100/character_outlook_ref.md` — 의상 단독 프롬프트 (사람 얼굴 없이)
- `prompts/_base/ref_image_prompts/2.202603220100/character_composite_ref.md` — 합성 프롬프트 (얼굴 ref + 아웃룩 ref)
- `image_service.py` — Phase 2 (아웃룩 단독) + Phase 3 (합성) 생성 로직
- `ref_image_pipeline.py` — aspect ratio: character/outlook=1:1, composite/location=16:9

**재사용성**: 같은 아웃룩(예: 서바이벌군복)을 여러 캐릭터가 입을 수 있음 → 아웃룩 이미지 1장으로 여러 합성 생성

### 2. 씬 이미지 참조 매칭 — 합성 우선 + fallback

**`_resolve_refs_for_prompt`** (image_service.py):
```
[[인물]+[아웃룩]] 마커 발견
  → 1순위: composite:{char_id}:{outlook_id} 합성 이미지 ("character in outfit")
  → 2순위: 얼굴 + 아웃룩 단독 분리 첨부 ("character identity" + "outfit appearance")
```

**중복 방지**: `_used_ref_ids`에 composite_key + char_id + outlook_id 모두 등록 → fallback에서 중복 첨부 차단

**이전 씬 참조**: `best_prev_bytes`를 `labeled_refs`에 추가 → 프롬프트에 `"Reference image N: previous scene for visual continuity"` 지시 포함

### 3. `_build_final_scene_prompt` 라벨 처리

| 라벨 | 지시 |
|------|------|
| `"outfit appearance"` | `dress the character in the outfit shown in image N` |
| `"character in outfit"` | `keep face + use outfit from image N` |
| `"character identity"` | `keep face, hair, identity from image N` |
| `"object appearance"` | `include the object shown in image N` |
| `"previous scene..."` | `maintain visual continuity, do NOT copy composition` |

### 4. scene_detail에 해당 씬 요소만 전달

**이전**: `entity_names_block` = 전체 14명 캐릭터 + 8개 배경 + 6개 소품 → GPT가 무관한 인물도 T2I에 추가

**현재**: `_build_scene_entity_block(entities, scene_char_names, scene_text)`
- 인물: `scene_assignments`에서 결정된 캐릭터만
- 배경: 씬 텍스트에 이름이 등장하는 것만
- 소품: 씬 텍스트에 이름이 등장하는 것만
- 명시: "위 목록에 없는 인물, 배경, 물체를 T2I 프롬프트에 절대 추가하지 마세요."

### 5. T2I 변형 표시/편집 (Frontend)

**SceneVariationCard.tsx**:
- 씬 설명 아래에 "T2I 프롬프트 (N개)" 펼침 섹션
- 각 변형: `variant_label + camera_effect` 헤더 + 편집 가능한 텍스트
- 저장 시 `PATCH /stills/{id}/t2i-variation/{index}` API 호출

### 6. 엔티티 썸네일 행 (Frontend)

**SceneVariationCard.tsx**:
- `resolved_entities`에서 composite(인물+아웃룩 합성이미지) 1개 항목으로 표시
- 소품/배경은 개별 썸네일
- (+) 추가 피커: `available_outfits` 기반, 아웃룩 단독 이미지 있는 것만
- (✕) 제거 기능

### 7. Outlook Extraction 프롬프트 v4

**몽타주/교차편집 규칙 강화**:
- 다른 장소 인물이 번갈아 보이는 몽타주 → 각 인물은 자기 물리적 위치 씬에만 배정
- 소울라이드 원격 접속 → 현장에 조종자 배정 금지
- "(괄호)" 표기 → 괄호 안 인물은 원격 조종자

**모델 변경**: Gemini Pro → **GPT-5.5** (outlook_extraction)

### 8. DB 동기화 (`_sync_analysis_to_db`)

StepRunner 체크포인트 → DB 동기화:
- EntityCanon + EntityEpisodeLink (인물/배경/소품/아웃룩)
- SceneStill (씬 설명 + 의존성 + T2I 변형)
- CharacterOutlook 매핑
- episode.status → "analyzed"
- visible_entities_json에 entity_id 자동 추가

### 9. Gemini 이미지 키 풀 강화

`gemini_image_client.py`:
- 429 + **503** + **timeout** 시 키 로테이션 추가
- 이전: 429에서만 키 교체

### 10. 이미지 크기

`gemini_image_client.py`:
- `imageSize: "2K"` → `"1K"` (2752x1536 → 1376x768)
- fal.ai 전송 시 5MB 초과 → 1536px 리사이즈 fallback

---

## 변경 파일 목록

### Backend
| 파일 | 변경 내용 |
|------|----------|
| `llm_client.py` | PIPELINE_STEPS 19→20개 (outlook_merge 추가), call_structured에 max_tokens, outlook_extraction→gpt |
| `image_service.py` | 아웃룩 단독/합성 3단계, _resolve_refs 합성 우선, 이전 씬 ref, 씬별 요소 필터, fal.ai 리사이즈 |
| `ref_image_pipeline.py` | composite 타입 추가, aspect ratio 정리, regeneration aspect 일관성 |
| `gemini_image_client.py` | 503/timeout 키 로테이션, imageSize 1K |
| `entities.py` | resolved_entities 합성 이미지 중심, available_outfits, T2I variation PATCH API, 이름 기반 매칭 |
| `image_steps.py` | _sync_analysis_to_db (EntityEpisodeLink for outlook), _get_system_actor_id, _mark_composite_done |
| `scene_extractor_v2.py` | _build_scene_entity_block (씬별 요소만), dead code 제거 |
| `analysis_steps.py` | ProjectSummaryStep, OutlookDedupStep 구현 |
| `step_runner.py` | traceback 로깅 |

### Frontend
| 파일 | 변경 내용 |
|------|----------|
| `SceneVariationCard.tsx` | T2I 변형 표시/편집, 엔티티 썸네일 행 (합성 이미지 중심), 2-step 추가 피커 |
| `EpisodeDetail.tsx` | availableOutfits, handleSaveT2iVariation, fetchStills 응답 구조 변경 |
| `ImageGalleryModal.tsx` | 엔티티 표시 섹션 제거 (씬 카드로 이동) |

### Prompts
| 파일 | 내용 |
|------|------|
| `ref_image_prompts/2.202603220100/character_outlook_ref.md` | 의상 단독 (마네킹, 얼굴 없이) |
| `ref_image_prompts/2.202603220100/character_composite_ref.md` | 합성 (얼굴 ref + 아웃룩 ref → 전신) |
| `outlook_extractor/4.202603220800/extract_prompt.md` | 몽타주/소울라이드/교차편집 규칙 강화 |
