From 311adaf06cc5d0a8005c31dff8b5952c5a40ad96 Mon Sep 17 00:00:00 2001 From: Andrew Yim Date: Sun, 29 Mar 2026 07:28:49 +0900 Subject: [PATCH] feat(jamie-journal): implement SpellingChecker (built-in medical dict + optional hanspell) --- .../code/scripts/journal_validator.py | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) 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 6c1e101..cab5b25 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 @@ -307,8 +307,82 @@ class ComplianceChecker: class SpellingChecker: """Checks for common spelling/terminology issues in medical/beauty content.""" + # Format: wrong_term -> (correct_term, category) + MEDICAL_DICT: Dict[str, Tuple[str, str]] = { + '쌍커풀': ('쌍꺼풀', '눈 성형'), + '쌍거풀': ('쌍꺼풀', '눈 성형'), + '안겸하수': ('안검하수', '눈 성형'), + '눈꺼플': ('눈꺼풀', '눈 성형'), + '눈커풀': ('눈꺼풀', '눈 성형'), + '네시경': ('내시경', '이마 성형'), + '거상 술': ('거상술', '이마 성형'), + '앤도타인': ('엔도타인', '이마 성형'), + '봉합 사': ('봉합사', '이마 성형'), + '히알루론 산': ('히알루론산', '필러'), + '히알류론산': ('히알루론산', '필러'), + '지방 이식': ('지방이식', '동안 성형'), + '눈밑지방': ('눈밑 지방', '눈 성형'), + '다크 서클': ('다크서클', '눈 성형'), + '팔자주름': ('팔자 주름', '동안 성형'), + '절게법': ('절개법', '눈 성형'), + '매몰 법': ('매몰법', '눈 성형'), + '눈썹밑절개': ('눈썹밑 절개', '이마 성형'), + } + def check(self, content: str) -> List[ValidationIssue]: - return [] + issues: List[ValidationIssue] = [] + lines = content.split('\n') + + # Tier 1: built-in medical dictionary scan + for line_idx, line in enumerate(lines, start=1): + for wrong, (correct, category) in self.MEDICAL_DICT.items(): + if wrong == correct: + continue + if wrong in line: + issues.append(ValidationIssue( + checker='SpellingChecker', + issue_type='medical_misspelling', + severity='medium', + line_number=line_idx, + matched_text=wrong, + message=f'[{category}] 잘못된 표기: "{wrong}" → "{correct}"', + suggestion=f'"{wrong}"을 "{correct}"로 수정하세요.', + )) + + # Tier 2: optional py-hanspell + try: + from hanspell import spell_checker # type: ignore + for line_idx, line in enumerate(lines, start=1): + stripped = line.strip() + # Skip code blocks, short lines, headings + if stripped.startswith('```') or stripped.startswith('#') or len(stripped) < 5: + continue + try: + result = spell_checker.check(stripped) + if result.checked != stripped: + issues.append(ValidationIssue( + checker='SpellingChecker', + issue_type='hanspell_correction', + severity='medium', + line_number=line_idx, + matched_text=stripped[:80], + message=f'맞춤법 교정 제안: {result.result}', + suggestion=result.checked[:200], + )) + except Exception: + pass # Network or parse error — skip this line + except ImportError: + issues.append(ValidationIssue( + checker='SpellingChecker', + issue_type='hanspell_unavailable', + severity='info', + line_number=0, + matched_text='', + message='py-hanspell이 설치되어 있지 않아 맞춤법 자동 검사를 건너뜁니다.', + suggestion='pip install py-hanspell 을 실행하면 한국어 맞춤법 자동 검사가 활성화됩니다.', + )) + + return issues class LinkRecommender: