study-buddy / app /services /name_signal_extractor.py
GitHub Actions
deploy d092bea3608b7a29952f16357fda39b7a29e399b
2e818da
Raw
History Blame Contribute Delete
1.35 kB
"""Deterministic preferred-name/form-of-address extraction. "I am X" is
deliberately excluded: it matches too many non-name sentences ("I am
confused", "I am working on..."). Patterns use a lookahead rather than an
end-of-string anchor so a name followed by more sentence content ("My name
is Anshuman, and I'm studying robotics") still matches. See
docs/commit-memory-adaptation-architecture.md.
"""
from __future__ import annotations
import re
_NAME_SIGNAL_PATTERNS = (
re.compile(
r"\bmy name is\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)",
re.IGNORECASE,
),
re.compile(
r"\b(?:please\s+)?call me\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)",
re.IGNORECASE,
),
re.compile(
r"\byou can call me\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)",
re.IGNORECASE,
),
re.compile(
r"\bi go by\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)",
re.IGNORECASE,
),
)
def extract_preferred_name(text: str) -> str | None:
for pattern in _NAME_SIGNAL_PATTERNS:
match = pattern.search(text or "")
if not match:
continue
name = re.sub(r"\s+", " ", match.group(1)).strip(" .'-")
if 1 < len(name) <= 80:
return name
return None