Spaces:
Build error
Build error
File size: 5,261 Bytes
0827183 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from typing import List, Union
from recognizers_number import NumberModel, NumberRecognizer, OrdinalModel
from recognizers_text import Culture
from .choice import Choice
from .find import Find
from .find_choices_options import FindChoicesOptions
from .found_choice import FoundChoice
from .model_result import ModelResult
class ChoiceRecognizers:
"""Contains methods for matching user input against a list of choices."""
@staticmethod
def recognize_choices(
utterance: str,
choices: List[Union[str, Choice]],
options: FindChoicesOptions = None,
) -> List[ModelResult]:
"""
Matches user input against a list of choices.
This is layered above the `Find.find_choices()` function, and adds logic to let the user specify
their choice by index (they can say "one" to pick `choice[0]`) or ordinal position
(they can say "the second one" to pick `choice[1]`.)
The user's utterance is recognized in the following order:
- By name using `find_choices()`
- By 1's based ordinal position.
- By 1's based index position.
Parameters:
-----------
utterance: The input.
choices: The list of choices.
options: (Optional) Options to control the recognition strategy.
Returns:
--------
A list of found choices, sorted by most relevant first.
"""
if utterance is None:
utterance = ""
# Normalize list of choices
choices_list = [
Choice(value=choice) if isinstance(choice, str) else choice
for choice in choices
]
# Try finding choices by text search first
# - We only want to use a single strategy for returning results to avoid issues where utterances
# like the "the third one" or "the red one" or "the first division book" would miss-recognize as
# a numerical index or ordinal as well.
locale = options.locale if (options and options.locale) else Culture.English
matched = Find.find_choices(utterance, choices_list, options)
if not matched:
matches = []
if not options or options.recognize_ordinals:
# Next try finding by ordinal
matches = ChoiceRecognizers._recognize_ordinal(utterance, locale)
for match in matches:
ChoiceRecognizers._match_choice_by_index(
choices_list, matched, match
)
if not matches and (not options or options.recognize_numbers):
# Then try by numerical index
matches = ChoiceRecognizers._recognize_number(utterance, locale)
for match in matches:
ChoiceRecognizers._match_choice_by_index(
choices_list, matched, match
)
# Sort any found matches by their position within the utterance.
# - The results from find_choices() are already properly sorted so we just need this
# for ordinal & numerical lookups.
matched = sorted(matched, key=lambda model_result: model_result.start)
return matched
@staticmethod
def _recognize_ordinal(utterance: str, culture: str) -> List[ModelResult]:
model: OrdinalModel = NumberRecognizer(culture).get_ordinal_model(culture)
return list(
map(ChoiceRecognizers._found_choice_constructor, model.parse(utterance))
)
@staticmethod
def _match_choice_by_index(
choices: List[Choice], matched: List[ModelResult], match: ModelResult
):
try:
index: int = int(match.resolution.value) - 1
if 0 <= index < len(choices):
choice = choices[index]
matched.append(
ModelResult(
start=match.start,
end=match.end,
type_name="choice",
text=match.text,
resolution=FoundChoice(
value=choice.value, index=index, score=1.0
),
)
)
except:
# noop here, as in dotnet/node repos
pass
@staticmethod
def _recognize_number(utterance: str, culture: str) -> List[ModelResult]:
model: NumberModel = NumberRecognizer(culture).get_number_model(culture)
return list(
map(ChoiceRecognizers._found_choice_constructor, model.parse(utterance))
)
@staticmethod
def _found_choice_constructor(value_model: ModelResult) -> ModelResult:
return ModelResult(
start=value_model.start,
end=value_model.end,
type_name="choice",
text=value_model.text,
resolution=FoundChoice(
value=value_model.resolution["value"], index=0, score=1.0
),
)
|