diff --git a/custom-skills/46-jamie-journal-editor/code/scripts/journal_validator.py b/custom-skills/46-jamie-journal-editor/code/scripts/journal_validator.py index cab5b25..bbeae2f 100644 --- a/custom-skills/46-jamie-journal-editor/code/scripts/journal_validator.py +++ b/custom-skills/46-jamie-journal-editor/code/scripts/journal_validator.py @@ -388,8 +388,58 @@ class SpellingChecker: class LinkRecommender: """Recommends internal/external links and detects broken or missing ones.""" + PROCEDURE_MAP: Dict[str, Tuple[str, List[str]]] = { + 'double_eyelid': ('쌍꺼풀 수술', ['쌍꺼풀', '매몰법', '절개법', '퀵매몰']), + 'ptosis': ('안검하수 눈매교정', ['안검하수', '눈매교정', '졸린 눈', '눈매 교정']), + 'under_eye_fat': ('눈밑 지방 재배치', ['눈밑 지방', '다크서클', '눈밑지방', '지방 재배치']), + 'dual_epicanthoplasty': ('듀얼 트임', ['듀얼 트임', '앞트임', '뒤트임', '눈꼬리']), + 'forehead_lift': ('내시경 이마거상술', ['이마거상', '이마리프팅', '이마 거상', '이마 리프팅']), + 'brow_lift': ('내시경 눈썹거상술', ['눈썹거상', '눈썹리프팅', '눈썹 거상', '눈썹 리프팅']), + 'sub_brow': ('눈썹밑 피부절개술', ['눈썹밑', '상안검', '눈꺼풀 처짐']), + 'smas_lifting': ('스마스 리프팅', ['스마스', 'SMAS', '안면거상', '페이스리프트']), + 'fat_graft': ('자가지방 이식', ['자가지방', '지방이식', '지방 이식', '지방 생착']), + 'hifu': ('하이푸 리프팅', ['하이푸', 'HIFU', '초음파 리프팅']), + 'cheek_lift': ('앞광대 리프팅', ['앞광대', '팔자 주름', '팔자주름', '광대 리프팅']), + 'endotine': ('엔도타인 고정', ['엔도타인', 'endotine', '3점 고정']), + } + + def _detect_main_topic(self, lines: List[str]) -> Optional[str]: + """Scan first 10 lines to find the main procedure topic.""" + opening_text = '\n'.join(lines[:10]) + for topic_key, (display_name, keywords) in self.PROCEDURE_MAP.items(): + for kw in keywords: + if kw in opening_text: + return topic_key + return None + def check(self, content: str) -> List[ValidationIssue]: - return [] + issues: List[ValidationIssue] = [] + lines = content.split('\n') + + main_topic = self._detect_main_topic(lines) + + for topic_key, (display_name, keywords) in self.PROCEDURE_MAP.items(): + if topic_key == main_topic: + continue + for line_idx, line in enumerate(lines, start=1): + matched_kw = None + for kw in keywords: + if kw in line: + matched_kw = kw + break + if matched_kw: + issues.append(ValidationIssue( + checker='LinkRecommender', + issue_type='internal_link_opportunity', + severity='info', + line_number=line_idx, + matched_text=matched_kw, + message=f'"{matched_kw}" 언급 발견 — "{display_name}" 글로의 내부 링크를 고려하세요.', + suggestion=f'"{display_name}" 시술 페이지로 연결되는 앵커 텍스트 링크를 추가하세요.', + )) + break # one recommendation per topic + + return issues # ---------------------------------------------------------------------------