Upload staff_service.py
Browse files- src/services/staff_service.py +29 -13
src/services/staff_service.py
CHANGED
|
@@ -123,9 +123,13 @@ def should_attempt_staff_lookup(question: str) -> bool:
|
|
| 123 |
|
| 124 |
def match_staff_name(question: str) -> Optional[Dict]:
|
| 125 |
"""
|
| 126 |
-
Match by name tokens.
|
| 127 |
-
|
| 128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
"""
|
| 130 |
if not should_attempt_staff_lookup(question):
|
| 131 |
return None
|
|
@@ -134,12 +138,27 @@ def match_staff_name(question: str) -> Optional[Dict]:
|
|
| 134 |
if not question_token_set:
|
| 135 |
return None
|
| 136 |
|
| 137 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
for staff in STAFF_DIRECTORY:
|
| 139 |
staff_name_tokens: set[str] = set()
|
| 140 |
for tok in staff.get("tokens", []):
|
| 141 |
staff_name_tokens.update(_normalize(tok))
|
| 142 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
return staff
|
| 144 |
|
| 145 |
# Fuzzy fallback for typos (e.g. "Nikkesh", "Al Harrasi")
|
|
@@ -147,15 +166,12 @@ def match_staff_name(question: str) -> Optional[Dict]:
|
|
| 147 |
|
| 148 |
|
| 149 |
def _fuzzy_staff_match(question: str) -> Optional[Dict]:
|
| 150 |
-
"""
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
| 152 |
all_names = [s["full_name"].lower() for s in STAFF_DIRECTORY]
|
| 153 |
-
matches = difflib.get_close_matches(q_lower, all_names, n=1, cutoff=0.75)
|
| 154 |
-
if matches:
|
| 155 |
-
return next(
|
| 156 |
-
(s for s in STAFF_DIRECTORY if s["full_name"].lower() == matches[0]), None
|
| 157 |
-
)
|
| 158 |
-
# Also try individual tokens for partial names
|
| 159 |
for token in _normalize(question):
|
| 160 |
if len(token) < 4:
|
| 161 |
continue
|
|
|
|
| 123 |
|
| 124 |
def match_staff_name(question: str) -> Optional[Dict]:
|
| 125 |
"""
|
| 126 |
+
Match by name tokens. ALL of a staff member's name tokens must appear
|
| 127 |
+
in the question.
|
| 128 |
+
|
| 129 |
+
Single-token matches are only accepted if the token is distinctive
|
| 130 |
+
(≥6 chars and not a common word). This prevents short or common tokens
|
| 131 |
+
like 'hall', 'rani', 'brian', 'jason' from matching on unrelated queries.
|
| 132 |
+
Multi-token matches (e.g. 'nikesh narayanan', 'rani anand') always accepted.
|
| 133 |
"""
|
| 134 |
if not should_attempt_staff_lookup(question):
|
| 135 |
return None
|
|
|
|
| 138 |
if not question_token_set:
|
| 139 |
return None
|
| 140 |
|
| 141 |
+
# Tokens that are too common/short to be used as sole match criteria
|
| 142 |
+
_WEAK_TOKENS = {
|
| 143 |
+
"hall", "rani", "brian", "alia", "jason", "walter",
|
| 144 |
+
"anand", "fetty",
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
for staff in STAFF_DIRECTORY:
|
| 148 |
staff_name_tokens: set[str] = set()
|
| 149 |
for tok in staff.get("tokens", []):
|
| 150 |
staff_name_tokens.update(_normalize(tok))
|
| 151 |
+
if not staff_name_tokens:
|
| 152 |
+
continue
|
| 153 |
+
if not staff_name_tokens.issubset(question_token_set):
|
| 154 |
+
continue
|
| 155 |
+
# All tokens matched — now check if match is strong enough
|
| 156 |
+
matched = staff_name_tokens & question_token_set
|
| 157 |
+
if len(matched) >= 2:
|
| 158 |
+
return staff
|
| 159 |
+
# Single token match — only accept if distinctive
|
| 160 |
+
sole = next(iter(matched))
|
| 161 |
+
if len(sole) >= 6 and sole not in _WEAK_TOKENS:
|
| 162 |
return staff
|
| 163 |
|
| 164 |
# Fuzzy fallback for typos (e.g. "Nikkesh", "Al Harrasi")
|
|
|
|
| 166 |
|
| 167 |
|
| 168 |
def _fuzzy_staff_match(question: str) -> Optional[Dict]:
|
| 169 |
+
"""
|
| 170 |
+
Fuzzy match individual question tokens against staff full names using difflib.
|
| 171 |
+
Whole-question comparison is skipped — it never matches because a full sentence
|
| 172 |
+
has near-zero similarity to a short name string.
|
| 173 |
+
"""
|
| 174 |
all_names = [s["full_name"].lower() for s in STAFF_DIRECTORY]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
for token in _normalize(question):
|
| 176 |
if len(token) < 4:
|
| 177 |
continue
|