## 업종 교체 (tour → clinic) PlaceCategory 코드 4번의 의미를 바꾼다. 아직 배포 전이라 데이터 마이그레이션은 없다. - category_schema: tour_activity.json → clinic.json. 체험 스키마(안전 유의사항·우천 시 운영·준비물)를 진료 스키마(진료과목·의료진·상담료·보험 적용·야간/주말진료)로 바꿨다. unit 은 프로그램 → 시술이다(마취 방식·회복 기간·권장 횟수·시술 후 주의사항). - 소개문 계열만 allow_llm 이다. 시술 효과·비용 같은 값은 LLM 이 못 쓴다 — 이 레포의 "검증 전에는 발행 금지" 규칙이 의료 문구에서 특히 중요하다. - jsonld: TouristAttraction → MedicalClinic. 프론트 AeoReadiness 의 같은 표도 맞췄다. - 색 팔레트를 병원 톤(클린 블루·세이지·누드·모노)으로, 아이콘을 Compass → Stethoscope 로. - mock_adapter 목데이터를 시술 기준으로 교체. 스키마에 없는 key 를 쓰면 수집이 죽는다. - site_payload 의 기본 섹션표를 에디터(industryData)와 같게 맞췄다 — test_site_theme 이 이 둘을 대조한다. ## 로그인 관문 되돌리기 (b94daa9·d6a6c8e revert) 두 커밋이 /builder 를 통째로 RequireAuth 뒤로 옮겨 `/` 가 곧바로 로그인 화면이 됐다. `/` 는 자기 화면 없이 /builder 로 넘기기만 하므로, 문 앞 가드는 곧 루트 가드다. 위저드를 열어 두고 에디터 진입에서 한 번 받는969fb67설계로 되돌린다.d6a6c8e가 스스로 "969fb67 과 정면으로 다른 설계"라고 적어 두었다. ## 그 밖 - test_site_theme 의 경로가 solution/front 로 남아 있었다(frontend 개명 누락). - .dockerignore: 이 머신에 buildx 가 없어 레거시 빌더가 돌고, 그러면 nginx/Dockerfile.dockerignore 가 무시된다. 루트 것 하나로 두 이미지를 다 커버한다. 검증: frontend·admin·site lint·build 0. 백엔드 534 passed / 4 failed — 그 4개(test_build_publish 3 · test_snapshot 1)는 이 변경 전부터 실패하던 것이다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xa8ME5FQJy4VA8pPokTo1a
52 lines
2.2 KiB
Python
52 lines
2.2 KiB
Python
"""Prompt contract for image classification and accessible alt text."""
|
|
|
|
from typing import Optional
|
|
|
|
from common.enums import PlaceCategory
|
|
|
|
_LABELS = {
|
|
PlaceCategory.LODGING: ["외관", "침실", "거실", "욕실", "주방", "수영장", "바비큐장", "주차장", "전망", "부대시설"],
|
|
PlaceCategory.CAFE: ["외관", "내부", "좌석", "메뉴", "디저트", "음료", "테라스", "주차장"],
|
|
PlaceCategory.RESTAURANT: ["외관", "내부", "좌석", "메뉴", "음식", "룸", "주차장"],
|
|
PlaceCategory.CLINIC: ["외관", "시설", "장비", "활동", "안전장비", "주차장", "매표소"],
|
|
}
|
|
_DEFAULT_LABELS = ["외관", "내부", "시설", "기타"]
|
|
|
|
RESPONSE_SCHEMA = {
|
|
"type": "object",
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"ref": {"type": "string"},
|
|
"label": {"type": "string"},
|
|
"alt_text": {"type": "string"},
|
|
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
|
|
},
|
|
"required": ["ref", "label", "alt_text", "confidence"],
|
|
},
|
|
}
|
|
},
|
|
"required": ["items"],
|
|
}
|
|
|
|
|
|
def build_prompt(
|
|
category: Optional[PlaceCategory], unit_names: Optional[list[str]], refs: list[str]
|
|
) -> str:
|
|
lines = [
|
|
"소상공인 홈페이지에 사용할 사진을 분류한다.",
|
|
f"사진 {len(refs)}장의 각 [ref]에 대해 아래 값을 만든다.",
|
|
f"- label: {' / '.join(_LABELS.get(category, _DEFAULT_LABELS))} 중 하나",
|
|
"- alt_text: 화면에 보이는 것만 한국어 20~60자로 작성",
|
|
"- confidence: 불명확할수록 0에 가깝게 지정",
|
|
"- 가격·면적·인원·시설을 지어내지 마라.",
|
|
"- '아름다운' 같은 홍보성 또는 평가성 표현을 쓰지 않는다.",
|
|
]
|
|
if unit_names:
|
|
lines.append(f"- 관련된 경우 객실·프로그램 이름을 label에 붙일 수 있다: {', '.join(unit_names)}")
|
|
lines.append(f"모든 ref를 빠짐없이 반환한다: {', '.join(refs)}")
|
|
return "\n".join(lines)
|