Resolve one topic phrase to one or more matching stored profile keys.
(
profile: Dict[str, Any],
topic_text: str,
*,
include_semantic_family: bool = False,
)
| 501 | |
| 502 | |
| 503 | def find_related_profile_topic_keys( |
| 504 | profile: Dict[str, Any], |
| 505 | topic_text: str, |
| 506 | *, |
| 507 | include_semantic_family: bool = False, |
| 508 | ) -> List[str]: |
| 509 | """Resolve one topic phrase to one or more matching stored profile keys.""" |
| 510 | target = normalize_topic_token(topic_text) |
| 511 | if not target: |
| 512 | return [] |
| 513 | |
| 514 | keys: List[str] = [] |
| 515 | for container_name in ("core_directions", "topic_weights"): |
| 516 | container = profile.get(container_name, {}) or {} |
| 517 | for key in container.keys(): |
| 518 | if key not in keys: |
| 519 | keys.append(key) |
| 520 | |
| 521 | exact_matches: List[str] = [] |
| 522 | partial_matches: List[tuple[int, str]] = [] |
| 523 | for key in keys: |
| 524 | alias_norms = [ |
| 525 | normalize_topic_token(alias) |
| 526 | for alias in iter_topic_aliases(key) |
| 527 | if normalize_topic_token(alias) |
| 528 | ] |
| 529 | if target in alias_norms: |
| 530 | if key not in exact_matches: |
| 531 | exact_matches.append(key) |
| 532 | continue |
| 533 | |
| 534 | for alias_norm in alias_norms: |
| 535 | if target in alias_norm or alias_norm in target: |
| 536 | partial_matches.append((abs(len(alias_norm) - len(target)), key)) |
| 537 | break |
| 538 | |
| 539 | semantic_matches: List[str] = [] |
| 540 | if include_semantic_family: |
| 541 | family_name = resolve_semantic_topic_family(topic_text) |
| 542 | if family_name: |
| 543 | member_tokens = { |
| 544 | normalize_topic_token(member) |
| 545 | for member in SEMANTIC_TOPIC_FAMILIES[family_name].get("members", set()) |
| 546 | } |
| 547 | for key in keys: |
| 548 | if normalize_topic_token(key) in member_tokens and key not in semantic_matches: |
| 549 | semantic_matches.append(key) |
| 550 | |
| 551 | ordered_matches: List[str] = [] |
| 552 | for key in exact_matches + semantic_matches: |
| 553 | if key not in ordered_matches: |
| 554 | ordered_matches.append(key) |
| 555 | |
| 556 | if ordered_matches: |
| 557 | return ordered_matches |
| 558 | |
| 559 | partial_matches.sort(key=lambda item: item[0]) |
| 560 | for _, key in partial_matches: |
no test coverage detected