feat(jamie-journal): implement SpellingChecker (built-in medical dict + optional hanspell)
This commit is contained in:
@@ -307,8 +307,82 @@ class ComplianceChecker:
|
|||||||
class SpellingChecker:
|
class SpellingChecker:
|
||||||
"""Checks for common spelling/terminology issues in medical/beauty content."""
|
"""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]:
|
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:
|
class LinkRecommender:
|
||||||
|
|||||||
Reference in New Issue
Block a user