diff --git a/solution/backend/services/site_payload.py b/solution/backend/services/site_payload.py index e51d959..367bbdf 100644 --- a/solution/backend/services/site_payload.py +++ b/solution/backend/services/site_payload.py @@ -163,6 +163,21 @@ _DEFAULT_THEME = { # ── 값 변환 헬퍼 ────────────────────────────────────────────────────────── +def _first_sentence(text: str) -> str: + """첫 문장. 마침표가 없으면 통째로 돌려준다. + + ★ 왜 필요한가: 히어로 아래 한 줄과 meta description 이 같은 값을 쓴다. 둘 다 **한 문장** + 자리라, 문단이 들어가면 히어로는 세 줄로 부풀고 검색 결과에서는 뒤가 잘린다. + ★ 마침표 뒤에 공백이 없어도 자른다("…입니다.일본식" 같은 생성물이 실제로 온다). + 다만 숫자 사이의 점(1.5km)은 자르지 않는다 — 뒤가 숫자면 문장 끝이 아니다. + """ + import re as _re + + match = _re.search(r"[.!?](?![0-9])", text or "") + return text[: match.end()].strip() if match else (text or "").strip() + + + def _get(row, key, default=None): """ORM 행이든 dict 든 같은 방식으로 읽는다(테스트가 가짜 행을 넣기 쉬우라고).""" if isinstance(row, dict): @@ -805,8 +820,12 @@ def to_site_payload(place, snapshot: dict, site, version, links) -> dict: paragraphs = [p.strip() for p in intro.split("\n") if p.strip()] if intro else [] narrative = { "about": paragraphs, - # 요약은 첫 문단을 그대로 쓴다(요약문을 새로 생성하지 않는다). - "summary": paragraphs[0] if paragraphs else None, + # ★ 요약은 **첫 문장**이다. 문단이 아니다. + # 계약이 "요약 한 문장"이라 적어 뒀는데(shared/site-payload.ts) 첫 문단을 통째로 + # 넣고 있었다. 그 값은 두 곳으로 나간다 — 히어로 아래 한 줄과 meta description. + # 문단이 들어가면 히어로가 세 문장을 이고 서고(실측 2026-09-10), meta description 은 + # 검색 결과에서 잘린다. 문장을 새로 생성하지는 않는다 — 있는 글의 첫 문장을 뗄 뿐이다. + "summary": _first_sentence(paragraphs[0]) if paragraphs else None, } theme_spec = _DEFAULT_THEME.get(category) or _DEFAULT_THEME[PlaceCategory.LODGING.value]