Phase I 실행 완료 + 프로세스 재설계 (Stage 2.5 → Stage 5)
Phase I: 전수 정합성 복구 + 넘침 처리 패러다임 전환 (14개 항목) - I-14: SSE 유틸 공통 추출 (src/sse_utils.py 신규, 3개 파일 중복 제거) - I-13: dead code 3건 삭제 (_call_anthropic_direct, _extract_sse_text x2) + import anthropic 제거 - I-1: STEP_B_PROMPT purpose 가이드 미존재 블록 3개 → 실존 블록 교체 - I-2: catalog.yaml not_for 13건 미존재 블록 참조 교체/제거 - I-12: BLOCK_SLOTS 주석 개수 수정 (cards 9, visuals 6, emphasis 10) - I-10: INDEX.md 38개 동기화 (삭제된 8개 블록 행 제거) - I-11: README.md 38개 동기화 (_legacy 제거, 트리/개수 정리) - I-3: PURPOSE_FALLBACK 상수 + purpose 기반 미등록 블록 교체 - I-7: compare-pill-pair 단독 사용 금지 검증 - I-4: 38개 블록 전체에 slot_desc 추가 - I-5: 편집자 프롬프트에 slot_desc 전달 로직 - I-6: 제목 유사도 70% 초과 시 자동 교정 - I-9: 넘침 판단 Kei API 호출 (KEI_OVERFLOW_PROMPT, call_kei_overflow_judgment) - I-8: 대형 콘텐츠 정보 Kei overflow 프롬프트에 포함 프로세스 재설계: - Stage 2.5 제거 → Stage 5에서 Sonnet 감지 + Kei 판단 통합 - _review_balance() 확장: zone 예산 + overflow_detected action 추가 - Stage 5 루프에 Kei 넘침 판단 호출 통합 - _apply_adjustments()에 kei_trim/kei_restructure action 추가 - _build_overflow_context(), _convert_kei_judgment() 헬퍼 함수 추가 - DOWNGRADE_MAP은 Kei API 실패 시 비상용으로만 잔존 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+8
-60
@@ -19,6 +19,7 @@ import httpx
|
||||
|
||||
from src.config import settings
|
||||
from src.design_director import BLOCK_SLOTS
|
||||
from src.sse_utils import stream_sse_tokens
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -92,6 +93,12 @@ async def fill_content(
|
||||
f" 선택 슬롯: {slots.get('optional', [])}"
|
||||
)
|
||||
|
||||
# I-5: 슬롯 의미 설명 전달 (slot_desc가 있으면)
|
||||
slot_desc = slots.get("slot_desc", {})
|
||||
if slot_desc:
|
||||
desc_lines = [f" {k}: {v}" for k, v in slot_desc.items()]
|
||||
req_text += "\n 슬롯 설명:\n" + "\n".join(desc_lines)
|
||||
|
||||
if char_guide:
|
||||
guide_lines = [f" {k}: ~{v}자" for k, v in char_guide.items()]
|
||||
req_text += "\n 글자 수 가이드 (참고, 의미 우선):\n" + "\n".join(guide_lines)
|
||||
@@ -188,7 +195,7 @@ async def _call_kei_editor(prompt: str) -> str | None:
|
||||
logger.warning(f"Kei API (editor) HTTP {response.status_code}")
|
||||
return None
|
||||
|
||||
full_text = await _stream_sse_tokens(response)
|
||||
full_text = await stream_sse_tokens(response)
|
||||
|
||||
if full_text:
|
||||
return full_text
|
||||
@@ -201,65 +208,6 @@ async def _call_kei_editor(prompt: str) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
async def _stream_sse_tokens(response: httpx.Response) -> str:
|
||||
"""SSE 스트리밍 응답에서 토큰을 실시간 수집한다."""
|
||||
tokens: list[str] = []
|
||||
event_type = ""
|
||||
|
||||
async for line in response.aiter_lines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
event_type = ""
|
||||
continue
|
||||
if line.startswith("event:"):
|
||||
event_type = line[6:].strip()
|
||||
elif line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if event_type == "token" and data:
|
||||
try:
|
||||
token = json.loads(data)
|
||||
if isinstance(token, str):
|
||||
tokens.append(token)
|
||||
except json.JSONDecodeError:
|
||||
tokens.append(data)
|
||||
elif event_type == "done":
|
||||
break
|
||||
elif event_type == "error":
|
||||
logger.warning(f"Kei API SSE 에러: {data}")
|
||||
break
|
||||
|
||||
return "".join(tokens)
|
||||
|
||||
|
||||
def _extract_sse_text(raw: str) -> str:
|
||||
"""SSE 응답에서 토큰 텍스트를 수집한다."""
|
||||
import re as _re
|
||||
tokens = []
|
||||
events = _re.split(r'\r?\n\r?\n', raw)
|
||||
for event in events:
|
||||
if not event.strip():
|
||||
continue
|
||||
event_type = ""
|
||||
event_data = ""
|
||||
for line in event.split('\n'):
|
||||
line = line.strip('\r')
|
||||
if line.startswith('event:'):
|
||||
event_type = line[6:].strip()
|
||||
elif line.startswith('data:'):
|
||||
event_data = line[5:].strip()
|
||||
if not event_data:
|
||||
continue
|
||||
if event_type == 'token':
|
||||
try:
|
||||
token = json.loads(event_data)
|
||||
if isinstance(token, str):
|
||||
tokens.append(token)
|
||||
except json.JSONDecodeError:
|
||||
tokens.append(event_data)
|
||||
elif event_type == 'done':
|
||||
break
|
||||
return "".join(tokens)
|
||||
|
||||
|
||||
def _apply_defaults(blocks: list[dict[str, Any]]) -> None:
|
||||
"""실패 시 기본 데이터 적용."""
|
||||
|
||||
Reference in New Issue
Block a user