fix: relax cv title parsing

Allow lowercase, mixed-case, and numeric experience titles while rejecting label-like lines without colons via a small blocked-label set.
This commit is contained in:
Antoine 2026-05-28 17:28:16 +02:00
parent 19a1731349
commit 49cc4a9959
2 changed files with 57 additions and 3 deletions

View File

@ -35,6 +35,20 @@ EXPERIENCE_TITLE_STOPWORDS = {
"because",
}
EXPERIENCE_TITLE_LABELS = {
"education",
"experience",
"formation",
"languages",
"langues",
"location",
"profile",
"skills",
"compétences",
"competences",
"summary",
}
EXPERIENCE_PROSE_MARKERS = {
"after",
"before",
@ -279,14 +293,18 @@ def _looks_like_experience_title(title: str) -> bool:
return False
first_word = title_words[0]
if len(first_word) < 2 or not first_word[0].isupper():
if len(first_word) < 2:
return False
if first_word.lower() in EXPERIENCE_TITLE_STOPWORDS:
normalized_title = " ".join(title_words).casefold()
if normalized_title in EXPERIENCE_TITLE_LABELS:
return False
if first_word.casefold() in EXPERIENCE_TITLE_STOPWORDS:
return False
return not any(
word.lower() in EXPERIENCE_PROSE_MARKERS for word in title_words if word
word.casefold() in EXPERIENCE_PROSE_MARKERS for word in title_words if word
)

View File

@ -169,6 +169,26 @@ def test_extract_cv_signals_parses_clear_titles_with_french_and_english_connecto
]
def test_extract_cv_signals_accepts_lowercase_mixed_case_and_numeric_titles() -> None:
text = dedent(
"""
Tonio
Location: France
data engineer at Company A
iOS Engineer at Company A
3D Artist at Studio
"""
).strip()
extracted = extract_cv_signals(text)
assert extracted["experience_entries"] == [
{"title": "data engineer", "company": "Company A"},
{"title": "iOS Engineer", "company": "Company A"},
{"title": "3D Artist", "company": "Studio"},
]
def test_extract_cv_signals_ignores_french_prose_continuations() -> None:
text = dedent(
"""
@ -183,6 +203,22 @@ def test_extract_cv_signals_ignores_french_prose_continuations() -> None:
assert extracted["experience_entries"] == []
def test_extract_cv_signals_rejects_label_like_lines_without_colons() -> None:
text = dedent(
"""
Tonio
Location at Paris
Summary at a glance
Profile at LinkedIn
Education at EPITA
"""
).strip()
extracted = extract_cv_signals(text)
assert extracted["experience_entries"] == []
def test_extract_cv_signals_ignores_in_paris_prose_tail() -> None:
text = dedent(
"""