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:
parent
19a1731349
commit
49cc4a9959
@ -35,6 +35,20 @@ EXPERIENCE_TITLE_STOPWORDS = {
|
|||||||
"because",
|
"because",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPERIENCE_TITLE_LABELS = {
|
||||||
|
"education",
|
||||||
|
"experience",
|
||||||
|
"formation",
|
||||||
|
"languages",
|
||||||
|
"langues",
|
||||||
|
"location",
|
||||||
|
"profile",
|
||||||
|
"skills",
|
||||||
|
"compétences",
|
||||||
|
"competences",
|
||||||
|
"summary",
|
||||||
|
}
|
||||||
|
|
||||||
EXPERIENCE_PROSE_MARKERS = {
|
EXPERIENCE_PROSE_MARKERS = {
|
||||||
"after",
|
"after",
|
||||||
"before",
|
"before",
|
||||||
@ -279,14 +293,18 @@ def _looks_like_experience_title(title: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
first_word = title_words[0]
|
first_word = title_words[0]
|
||||||
if len(first_word) < 2 or not first_word[0].isupper():
|
if len(first_word) < 2:
|
||||||
return False
|
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 False
|
||||||
|
|
||||||
return not any(
|
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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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:
|
def test_extract_cv_signals_ignores_french_prose_continuations() -> None:
|
||||||
text = dedent(
|
text = dedent(
|
||||||
"""
|
"""
|
||||||
@ -183,6 +203,22 @@ def test_extract_cv_signals_ignores_french_prose_continuations() -> None:
|
|||||||
assert extracted["experience_entries"] == []
|
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:
|
def test_extract_cv_signals_ignores_in_paris_prose_tail() -> None:
|
||||||
text = dedent(
|
text = dedent(
|
||||||
"""
|
"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user