From 4bbb16f348f6ae4cb9541930fec2210335ce524e Mon Sep 17 00:00:00 2001 From: ZHIJUN XU <57060481+xzjncu@users.noreply.github.com> Date: Mon, 27 Jul 2026 09:23:11 +0800 Subject: [PATCH] fix: normalize_title retains Unicode alphanumeric chars via NFKC+casefold; add full CJK name equality check for leading author matching - normalize_title(): replace ASCII-only a-z0-9 filter with unicodedata.normalize("NFKC") + character.isalnum() to retain CJK/Unicode characters - _full_leading_author_matches(): add NFKC+casefold full-name equality check before falling back to per-part comparison - _leading_author_status(): add normalized full-name equality as a match condition alongside family-name key comparison Fixes source_pdf_mismatch false negatives for Chinese-titled papers (e.g. same title/author previously scored title_similarity=0.0, leading_author=conflict). --- skills/deeppapernote/scripts/common.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/skills/deeppapernote/scripts/common.py b/skills/deeppapernote/scripts/common.py index e3ecd10..0e73b22 100644 --- a/skills/deeppapernote/scripts/common.py +++ b/skills/deeppapernote/scripts/common.py @@ -135,7 +135,10 @@ def strip_tags(text: str) -> str: def normalize_title(text: str) -> str: - return re.sub(r"[^a-z0-9\s]", "", normalize_whitespace(text).lower()).strip() + normalized = unicodedata.normalize("NFKC", normalize_whitespace(text)).casefold() + return normalize_whitespace("".join( + character for character in normalized if character.isalnum() or character.isspace() + )) LOCAL_PDF_PREFIX_PATTERN = re.compile(r"^(?:[^-]{1,120})\s+-\s+(?:19|20)\d{2}\s+-\s+") @@ -576,6 +579,10 @@ def _full_leading_author_matches( work_authors = _dedupe_string_list(work_record.get("authors", [])) if not source_authors or not work_authors: return False + source_normalized = unicodedata.normalize("NFKC", source_authors[0]).casefold() + work_normalized = unicodedata.normalize("NFKC", work_authors[0]).casefold() + if source_normalized == work_normalized: + return True source_parts = _author_identity_parts(source_authors[0]) work_parts = _author_identity_parts(work_authors[0]) if len(source_parts) < 2 or len(work_parts) < 2: @@ -598,9 +605,11 @@ def _leading_author_status( work_authors = _dedupe_string_list(work_record.get("authors", [])) if not source_authors or not work_authors: return None + source_normalized = unicodedata.normalize("NFKC", source_authors[0]).casefold() + work_normalized = unicodedata.normalize("NFKC", work_authors[0]).casefold() source_key = _author_key(source_authors[0]) work_key = _author_key(work_authors[0]) - status = "match" if source_key and source_key == work_key else "conflict" + status = "match" if source_normalized == work_normalized or (source_key and source_key == work_key) else "conflict" return { "kind": "leading_author", "status": status, @@ -3990,4 +3999,4 @@ def pick_sentences_by_keywords(text: str, keywords: list[str], *, limit: int = 5 picked.append(normalize_whitespace(sentence)) if len(picked) >= limit: break - return picked + return picked \ No newline at end of file