Constrain automatic aliases and cache terminology matchers

This commit is contained in:
Kai Tan
2026-10-08 09:21:47 +08:00
parent 2c3feb37c9
commit 4f124a0335
4 changed files with 34 additions and 8 deletions
+19 -8
View File
@@ -4,13 +4,19 @@ import json
import re
import copy
from pathlib import Path
from functools import lru_cache
from src.common.utils import setup_logger
logger = setup_logger('glossary')
COMMON_ALIASES = {'who', 'us', 'it', 'he', 'she', 'we', 'you', 'they', 'me', 'them',
'our', 'my', 'the', 'a', 'an', 'in', 'on', 'at', 'to', 'of', 'or',
'dad', 'father', 'mother', 'mom', 'son', 'brother', 'sister',
'family', 'face', 'carry'}
'family', 'face', 'carry', 'arm',
'january', 'february', 'march', 'april', 'may', 'june', 'july',
'august', 'september', 'october', 'november', 'december',
'chinese', 'japanese', 'korean', 'russian', 'english', 'french',
'german', 'british', 'american', 'indian', 'african', 'asian',
'european', 'turkish', 'italian'}
def sanitize_automatic_terms(terms, ambiguous_aliases):
@@ -23,6 +29,11 @@ def sanitize_automatic_terms(terms, ambiguous_aliases):
keep = []
for alias in term.get('aliases', []):
unsafe = alias.casefold() in COMMON_ALIASES or re.fullmatch(r'[a-z]+', alias)
if re.fullmatch(r'[A-Za-z][A-Za-z.-]*', alias) and alias != term['source']:
acronym = bool(re.fullmatch(r'[A-Z][A-Z.-]+', alias))
nickname = 'nickname' in term.get('notes', '').casefold() and alias in term.get('notes', '')
if not acronym and not nickname:
unsafe = True
# A surname shared implicitly by another full name is ambiguous,
# even when the model did not explicitly propose it as an alias.
for other in terms:
@@ -48,13 +59,18 @@ def source_digest(entries):
def matches(source, text):
return alias_pattern(source).search(text) is not None
@lru_cache(maxsize=8192)
def alias_pattern(source):
# Word boundaries for Latin aliases prevent Son matching Sony / grandson.
escaped = re.escape(source)
if source and source[0].isascii() and source[0].isalnum():
escaped = r'(?<!\w)' + escaped
if source and source[-1].isascii() and source[-1].isalnum():
escaped += r'(?!\w)'
return re.search(escaped, text, matching_flags(source)) is not None
return re.compile(escaped, matching_flags(source))
def matching_flags(alias):
@@ -94,12 +110,7 @@ class BookGlossary:
excluded = [m.span() for context in term.get('exclude_contexts', [])
for m in re.finditer(re.escape(context), text, re.IGNORECASE)]
for alias in [term['source']] + term.get('aliases', []):
pattern = re.escape(alias)
if alias[0].isascii() and alias[0].isalnum():
pattern = r'(?<!\w)' + pattern
if alias[-1].isascii() and alias[-1].isalnum():
pattern += r'(?!\w)'
for match in re.finditer(pattern, text, matching_flags(alias)):
for match in alias_pattern(alias).finditer(text):
start, end = match.span()
if any(start < right and end > left for left, right in excluded):
continue