From 77d2f0f5c68a928b227c2218aa93bd72e1b0e3c9 Mon Sep 17 00:00:00 2001 From: Antoine Date: Thu, 28 May 2026 17:05:17 +0200 Subject: [PATCH] fix: tighten french cv heuristics Reject au sein prose continuations and recognize dotted MSc/BSc degree variants in education parsing. --- src/job_research/profile/cv_extractor.py | 5 +++- tests/profile/test_cv_extractor.py | 36 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/job_research/profile/cv_extractor.py b/src/job_research/profile/cv_extractor.py index 089ce65..9a0ec88 100644 --- a/src/job_research/profile/cv_extractor.py +++ b/src/job_research/profile/cv_extractor.py @@ -223,7 +223,7 @@ def _parse_education_entry(line: str) -> dict[str, str] | None: def _looks_like_education_credential(text: str) -> bool: - lowered = text.lower() + lowered = text.lower().replace(".", "") return any( re.search(rf"\b{re.escape(keyword)}\b", lowered) for keyword in EDUCATION_TITLE_KEYWORDS @@ -236,6 +236,9 @@ def _looks_like_institution(text: str) -> bool: def _parse_experience_entry(line: str) -> dict[str, str] | None: + if " au sein " in line.lower(): + return None + for connector in EXPERIENCE_LINE_CONNECTORS: if line.count(connector) != 1: continue diff --git a/tests/profile/test_cv_extractor.py b/tests/profile/test_cv_extractor.py index 279e4d1..c88cb6d 100644 --- a/tests/profile/test_cv_extractor.py +++ b/tests/profile/test_cv_extractor.py @@ -125,6 +125,20 @@ def test_extract_cv_signals_parses_french_experience_connectors() -> None: ] +def test_extract_cv_signals_ignores_french_prose_continuations() -> None: + text = dedent( + """ + Tonio + Location: France + Ingénieur au sein de BNP Paribas + """ + ).strip() + + extracted = extract_cv_signals(text) + + assert extracted["experience_entries"] == [] + + def test_extract_cv_signals_ignores_in_paris_prose_tail() -> None: text = dedent( """ @@ -189,6 +203,28 @@ def test_extract_cv_signals_extracts_common_french_education_entries() -> None: ] +def test_extract_cv_signals_extracts_dotted_degree_variants() -> None: + text = dedent( + """ + Tonio + Location: France + Education: + M.Sc. in Data Engineering at EPITA + B.Sc. in Computer Science at University X + """ + ).strip() + + extracted = extract_cv_signals(text) + + assert extracted["education_entries"] == [ + {"credential": "M.Sc. in Data Engineering", "institution": "EPITA"}, + { + "credential": "B.Sc. in Computer Science", + "institution": "University X", + }, + ] + + def test_extract_cv_signals_ignores_before_moving_prose_tail() -> None: text = dedent( """