o2o-site-AEO/solution/backend/services/catchphrase_text.py
Mina Choi ef0c44c5f2 [feat] solution/backend: 수집 뒤 콘텐츠 채울 때 캐치프레이즈·순환 문구 생성 — 숙박만
가게별 첫 화면 문구를 만드는 곳이 없어 모든 숙박이 공통 문구 10개를 돌려 썼다.

- COPY 잡에 catchphrase 단계(prepare→generate→save→catchphrase→faq_fill), 숙박이 아니면 건너뜀
- prompts/catchphrase.py·gemini_text.generate_catchphrases: 캐치프레이즈 1 + 일반 20·계절 3×4·월 12·날씨 2×4.
  문구마다 길이·상호명·ground_check(근거 없는 시설·수치) 검사
- fact tagline·catchphrases(lodging 스키마, allow_llm). 순환 문구는 사장님이 줄 단위로 고치게 글로 저장
  (catchphrase_text: `봄 | ` · `9월 | ` · `비 | ` 머리)
- site_payload: narrative.tagline·catchphrases 로 넘기고 이용정보 표(facts)에서는 뺀다
- 빌더 생성 화면 단계 문구, DATA_MODEL·GENERATION_FLOW

테스트 6건 추가. 관련 20개 파일 386 passed · 실패 102건은 main 과 목록이 같다(기존 실패)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:33:17 +09:00

44 lines
1.6 KiB
Python

"""순환 문구를 fact 한 칸에 담는 글 형식 — 사장님이 빌더에서 줄 단위로 고칠 수 있게 JSON 이 아니라 글로 둔다.
한 줄에 한 문구. 앞에 `봄 | ` · `9월 | ` · `비 | ` 를 붙이면 계절·월·날씨 문구, 없으면 일반 문구다.
"""
import re
SEASONS = ("봄", "여름", "가을", "겨울")
WEATHERS = ("맑음", "흐림", "비", "눈")
_MONTH = re.compile(r"^(1[0-2]|[1-9])월$")
def encode(items: list[dict]) -> str:
lines = []
for item in items:
text = str(item.get("text") or "").strip()
if not text:
continue
kind = item.get("kind") or "general"
tag = {"season": item.get("season"), "month": f"{item.get('month')}월", "weather": item.get("weather")}.get(kind)
lines.append(f"{tag} | {text}" if tag else text)
return "\n".join(lines)
def decode(value: str) -> list[dict]:
items: list[dict] = []
for raw in (value or "").splitlines():
line = raw.strip()
if not line:
continue
tag, sep, rest = line.partition("|")
tag, rest = tag.strip(), rest.strip()
if sep and rest:
if tag in SEASONS:
items.append({"text": rest, "kind": "season", "season": tag})
continue
if tag in WEATHERS:
items.append({"text": rest, "kind": "weather", "weather": tag})
continue
if m := _MONTH.match(tag):
items.append({"text": rest, "kind": "month", "month": int(m.group(1))})
continue
items.append({"text": line, "kind": "general"})
return items