Files
_Geulbeot/04. design_agent/docs/PHASE2-PROCESS.md
kyeongmin 688ddbbb17 04. design_agent 추가 — 콘텐츠 시각 구조화 슬라이드 생성기
5단계 AI 파이프라인:
1. Kei 실장(Opus via Kei API) — 꼭지 추출 + 정보 구조 파악
2. 디자인 팀장 — FAISS 블록 검색 + Opus 추천 + Sonnet 블록 매핑
3. Kei 편집자(Kei API) — 도메인 전문 텍스트 정리
4. 디자인 실무자(Sonnet + Jinja2) — CSS 변수 조정 + HTML 조립
5. 디자인 팀장(Sonnet) — 균형 재검토 (최대 2회 루프)

블록 라이브러리 46개 (6 카테고리) + _legacy 13개
FAISS 블록 검색 (bge-m3, 1024차원)
SVG N개 동적 배치 (cos/sin 좌표 계산)
Pillow 이미지 크기 측정 + base64 인라인
컨테이너 예산 기반 블록 배치 (zone별 높이 px)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:47:13 +09:00

322 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 2 실행 프로세스
## 절대 규칙 (모든 작업에 적용)
```
🔴 단발성/하드코딩 금지 — 모든 구현은 N개, M종류에 범용 동작
🔴 회귀 금지 — Phase 1 확정 구조(catalog 매핑, grid 분리, Kei API 우선) 되돌리지 않음
🔴 Opus→Sonnet 대체 금지 — Kei API가 기본, Sonnet은 fallback만
🔴 "일단 돌아가게" 금지 — 설계대로 구현하거나 설계를 먼저 변경
```
---
## Phase 1 완료 자산
| 항목 | 수량/상태 |
|------|----------|
| 블록 라이브러리 | 46개 (6 카테고리) |
| catalog.yaml | 46개 (when/not_for/slots/height_cost) |
| BLOCK_SLOTS + _apply_defaults | 46개 동기화 |
| SVG premium | venn-diagram 3개 고정 검증 |
| 5단계 파이프라인 | 동작 (BF-4~10 수정) |
| Kei API 연동 | 1단계(실장) + 3단계(편집자) |
| grid 역할 분리 | BF-9 (코드가 grid, Sonnet은 blocks만) |
| catalog→renderer 매핑 | mtime 캐시 (BF-10) |
---
## 실행 순서
```
Phase 2-A (FAISS 블록 검색)
Phase 2-B (SVG N개 자동 배치) ← 2-A와 병렬 가능
Phase 2-D (5단계 재검토 강화) ← 2-A/2-B와 병렬 가능
Phase 2-E (누락 기능: Pillow, details-block)
Phase 2-C (Step A: Opus + FAISS) ← 2-A 완료 필수
```
---
## Phase 2-A: FAISS 블록 검색 인덱스
### 목적
팀장(Step B) 프롬프트에 46개 catalog 전문 대신, FAISS 검색으로 **관련 블록 5~8개만** 전달.
### 수정 파일
| 파일 | 변경 | 신규/수정 |
|------|------|---------|
| `src/block_search.py` | FAISS 인덱스 구축 + 검색 함수 | **신규** |
| `src/design_director.py` | `_load_catalog()` → 검색 결과로 교체 | 수정 (line 294) |
| `data/block_index.faiss` | 인덱스 파일 | **신규** |
| `data/block_metadata.json` | id→블록 매핑 | **신규** |
| `pyproject.toml` | faiss-cpu, sentence-transformers 의존성 | 수정 |
### 기술 상세
```
임베딩 모델: BAAI/bge-m3 (1024차원)
→ Kei persona에서 검증됨 (retriever.py line 49)
→ 한국어 최적화
인덱스 방식: faiss.IndexFlatIP (Inner Product = 코사인 유사도)
→ Kei와 동일 패턴 (retriever.py line 88)
검색 입력: 꼭지별 title + summary + layer + role
검색 출력: 상위 8개 블록 (id + visual + when + not_for + slots)
fallback: FAISS 인덱스 없거나 검색 실패 시 → catalog.yaml 전문 (기존 방식)
```
### 프로세스
```
1. scripts/build_block_index.py 실행 (1회성)
→ catalog.yaml 읽기
→ 각 블록의 (name + visual + when) 임베딩
→ data/block_index.faiss + data/block_metadata.json 생성
2. src/block_search.py
→ 서버 시작 시 인덱스 로드
→ search_blocks(query, top_k=8) → 관련 블록 목록 반환
3. src/design_director.py 수정
→ _load_catalog() 대신 search_blocks() 호출
→ 꼭지별 검색 → 카테고리별 최소 1개 보장 → 프롬프트에 삽입
```
### 충돌 검토
```
design_director.py _load_catalog(): 문자열 반환 → 문자열 반환 (인터페이스 동일) ✅
renderer.py _load_catalog_map(): 별도 함수, 영향 없음 ✅
content_editor.py: BLOCK_SLOTS만 참조, 영향 없음 ✅
pipeline.py: create_layout_concept() 인터페이스 동일 ✅
```
### 점검
- [ ] FAISS 실패 시 catalog 전문 fallback 동작하는가?
- [ ] 검색 결과에 카테고리별 최소 1개 보장되는가?
- [ ] 블록 60개로 늘어나도 인덱스 재구축만으로 동작하는가?
---
## Phase 2-B: SVG N개 자동 배치
### 목적
venn-diagram의 원 3개 고정 → N개(2~7) 자동 배치. cos/sin 수학적 계산.
### 수정 파일
| 파일 | 변경 | 신규/수정 |
|------|------|---------|
| `src/svg_calculator.py` | 좌표 계산 함수 | **신규** |
| `src/renderer.py` | venn-diagram 렌더링 전 좌표 전처리 | 수정 (render_multi_page 내) |
| `templates/blocks/visuals/venn-diagram.html` | 하드코딩 좌표 → 동적 `{{ item.cx }}` | 수정 |
### 기술 상세
```
src/svg_calculator.py:
calc_circle_positions(n, center_x, center_y, radius) → [{cx, cy}, ...]
→ angle = (2π × i / n) - π/2 (12시부터 시계방향)
→ 의존성: Python math (내장)
calc_circle_radius(n) → int
→ n≤3: 120, n≤5: 80, n≤7: 60
→ 하드코딩 아님: base_radius / (1 + (n-3)*0.15) 공식
calc_outer_circle(n) → int
→ 큰 원 반지름도 N에 따라 조정
renderer.py 수정:
render_multi_page() 안에서 block_type == "venn-diagram" 일 때:
1. items = block_data.get("items", [])
2. positions = calc_circle_positions(len(items))
3. for i, item in enumerate(items): item["cx"] = positions[i]["cx"]
4. 나머지는 Jinja2가 처리
venn-diagram.html 수정:
현재: cx="265" (하드코딩)
변경: cx="{{ item.cx }}" (동적)
fallback: items에 cx가 없으면 기존 3개 고정 좌표 사용
```
### 충돌 검토
```
renderer.py: render_multi_page()에 if 분기 추가 — 기존 흐름에 영향 없음 ✅
(venn-diagram 아닌 블록은 그대로 통과)
venn-diagram.html: Phase 1 고정 SVG → 동적으로 변경
→ fallback(cx 없으면 기존 좌표) 필수 ✅
pipeline.py: 변경 없음 ✅
content_editor.py: items[].cx는 renderer에서 추가, 편집자는 모름 ✅
```
### 점검
- [ ] N=2, 3, 4, 5, 6, 7 각각 렌더링 테스트
- [ ] items에 cx/cy가 없을 때 Phase 1 고정 SVG로 fallback
- [ ] 원끼리 겹침 없이 배치되는가? (N=7 특히)
- [ ] 큰 원 안에 모든 작은 원이 들어가는가?
---
## Phase 2-D: 5단계 재검토 강화
### 목적
_review_balance가 실질적으로 동작하도록 강화. shrink/rewrite 구현.
### 수정 파일
| 파일 | 변경 | 신규/수정 |
|------|------|---------|
| `src/pipeline.py` | _review_balance 프롬프트 + _apply_adjustments 3개 action | 수정 |
### 기술 상세
```
_review_balance 개선:
현재: 블록별 데이터 양(글자수)만 전달
변경: 블록별 (area + type + 데이터 양 + height_cost) 전달
+ 전체 zone 예산 대비 사용량
_apply_adjustments 개선:
현재: expand만 동작 (char_guide * 1.5)
변경:
expand: char_guide * 1.5 (현재와 동일)
shrink: char_guide * 0.7 (신규)
rewrite: block["data"] 제거 → fill_content 재호출 시 재작성 (신규)
재조정 루프:
MAX_ADJUSTMENTS = 2 (상수, 하드코딩 아닌 설정값)
for attempt in range(MAX_ADJUSTMENTS): ...
```
### 충돌 검토
```
pipeline.py 내부 함수만 수정 ✅
fill_content 재호출: Kei API 우선 (Phase 1에서 수정됨) ✅
renderer.py: 변경 없음 ✅
```
### 점검
- [ ] expand/shrink/rewrite 3개 action 모두 동작하는가?
- [ ] MAX_ADJUSTMENTS 초과 시 루프 종료되는가?
- [ ] fill_content 재호출이 Kei API를 거치는가? (Sonnet 직접 아닌지)
- [ ] rewrite 후 _apply_defaults로 빈 데이터가 처리되는가?
---
## Phase 2-E: 누락 기능
### E-1: Pillow 이미지 크기
| 파일 | 변경 |
|------|------|
| `src/design_director.py` | create_layout_concept() 내 이미지 크기 확인 |
```
수정 위치: topics 순회할 때 content_type=="image" 확인
→ Pillow Image.open().size로 width, height 읽기
→ topic에 image_width, image_height, image_ratio 추가
→ Step B 프롬프트에 이미지 크기 정보 포함
→ 팀장이 가로형→image-full, 세로형→image-side-text 판단 가능
fallback: 이미지 파일 없으면 → 기본 비율 1.5 (가로형 가정)
⚠️ 이것은 하드코딩이 아닌 "정보 부재 시 안전한 기본값"
```
### E-2: details-block 연결
| 파일 | 변경 |
|------|------|
| `src/design_director.py` | detail_target 꼭지를 "생략" → "details-block 배치"로 |
| `src/content_editor.py` | detail_target 꼭지에 summary + detail 두 버전 작성 |
```
현재: design_director.py에서 detail_target 꼭지를 "생략 (미구현)"으로 처리
변경: detail_target 꼭지를 details-block으로 body/sidebar에 배치
→ 편집자가 summary(3줄) + detail(전체) 작성
→ renderer가 <details>/<summary>로 조립
```
### 점검
- [ ] 이미지 없는 콘텐츠에서 Pillow 에러 안 나는가?
- [ ] detail_target 꼭지가 details-block으로 렌더링되는가?
- [ ] <details> 접기/펼치기가 브라우저에서 동작하는가?
- [ ] 인쇄 시 자동 펼침 JavaScript가 동작하는가?
---
## Phase 2-C: Step A Opus+FAISS
### 목적
규칙 4줄 → Opus가 FAISS 검색으로 구조/블록 선정 + 배치/크기 결정.
### 수정 파일
| 파일 | 변경 | 신규/수정 |
|------|------|---------|
| `src/design_director.py` | select_preset() 유지 + _opus_block_selection() 추가 | 수정 |
### 기술 상세
```
현재 흐름:
Step A: select_preset() → 규칙 기반 (코드)
Step B: Sonnet → 블록 매핑
Phase 2 흐름:
Step A-1: select_preset() → 프리셋 선택 (유지, 안정적)
Step A-2: _opus_block_selection() → Kei API(Opus)로 블록 후보 선정
입력: 꼭지 분석 + FAISS 검색 결과
출력: 각 꼭지에 추천 블록 + 배치 방향 + 크기 가이드
Step B: Sonnet → Opus 추천 기반으로 최종 매핑 + 글자수 가이드
핵심: Opus 호출은 반드시 Kei API 경유
→ kei_client.py의 _call_kei_api() 패턴 재사용
→ anthropic.AsyncAnthropic 직접 호출 절대 금지
```
### 의존성
```
Phase 2-A 완료 필수 (FAISS 인덱스 + search_blocks 함수)
Kei API(localhost:8000) 안정 동작 필요
```
### 충돌 검토
```
select_preset(): 유지 (삭제하지 않음) ✅
create_layout_concept(): Step A-2 결과를 Step B에 전달하는 구조 추가
→ 기존 인터페이스(return {"title": ..., "pages": [...]}) 동일 ✅
pipeline.py: create_layout_concept() 호출 방식 동일 ✅
```
### 점검
- [ ] Opus 호출이 Kei API를 거치는가? (`grep "AsyncAnthropic" → fallback만`)
- [ ] Kei API 실패 시 현재 방식(규칙+Sonnet)으로 fallback
- [ ] FAISS 검색 결과가 Opus에게 전달되는가?
- [ ] select_preset()이 삭제되지 않았는가? (안정적 규칙은 유지)
---
## 산출물 체크리스트
### 코드 파일
```
신규:
src/block_search.py ← 2-A
src/svg_calculator.py ← 2-B
scripts/build_block_index.py ← 2-A
data/block_index.faiss ← 2-A
data/block_metadata.json ← 2-A
수정:
src/design_director.py ← 2-A, 2-C, 2-E
src/renderer.py ← 2-B
src/pipeline.py ← 2-D, 2-E
templates/blocks/visuals/venn-diagram.html ← 2-B
pyproject.toml ← 2-A (의존성)
```
### 문서
```
docs/PHASE2-PLAN.md ← 완료
docs/PHASE2-PROCESS.md ← 이 파일
docs/PHASE2-TECH-REVIEW.md ← 완료
PLAN.md ← Phase 2 태스크 추가 필요
PROGRESS.md ← Phase 2 진행 상황 추적
```