NU-KIOSK-API / backend /tools /faculty_profile.py
Monish BV
Add kiosk-api: stripped backend for speech integration
c2b7a7b
"""Helper functions for faculty record lookups used by multiple blueprints."""
from __future__ import annotations
import difflib
from typing import Any, Dict, List, Optional, Tuple
from ..data.utils import canonicalize_name, generate_name_variants
from .base import AnalysisContext
def _lookup_record(context: AnalysisContext, target_name: str) -> Tuple[Any, List[str], Optional[Dict[str, Any]]]:
"""Return the faculty record matching ``target_name`` and any lookup notes."""
notes: List[str] = []
dataset = context.catalog.get("faculty")
record = dataset.get_by_key(target_name)
if record is None:
target_canonical = canonicalize_name(target_name)
for row in dataset.records:
if canonicalize_name(row.get("Name", "")) == target_canonical:
record = row
break
if record is None:
candidates = [row.get("Name", "") for row in dataset.records if row.get("Name")]
closest = difflib.get_close_matches(target_name, candidates, n=1, cutoff=0.6)
if closest:
record = dataset.get_by_key(closest[0])
notes.append(f"Showing results for '{closest[0]}' (closest match).")
# Fallback: some names appear only in office-assignment CSVs (e.g., "Bain,Connor").
# Try to match those assignee names back into the faculty roster using
# common name permutations.
office_row: Optional[Dict[str, Any]] = None
if record is None:
offices = context.catalog.try_get("faculty_offices")
if offices:
for row in offices.records:
assignee = row.get("Assignee Name") or row.get("Assignee") or row.get("Name")
if not assignee:
continue
# If the assignee directly matches the target name (or its variants),
# prefer returning the matched faculty roster row when available; if
# no roster row matches, keep the office row as a fallback to emit
# office/location facts.
matched = False
for variant in generate_name_variants(assignee):
# If the variant matches the requested target, consider it a hit.
if canonicalize_name(variant) == canonicalize_name(target_name):
candidate = dataset.get_by_key(variant)
if candidate is not None:
record = candidate
notes.append(f"Matched '{assignee}' from faculty offices to roster entry '{candidate.get('Name')}'.")
matched = True
break
# remember office row as fallback if no roster entry exists
office_row = row
matched = True
break
if matched:
break
return record, notes, office_row