mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Prefer shorter keys for intent matching (#43672)
When using fuzzy matching to match entity names for intents, whichever entity is first is preferred in the case of equal matches. This leads to situations where entities with similar names (such as entities named for their area and then specific area location) may be used when the whole area is wanted. I ran into this with the my Phillips Hue lights. I have each individual light named such that its room is the first part of the name, and its location within the room after. So my living room has: Living Room West Living Room Northwest Living Room North Living Room Northeast I then have a group for the whole room: Living Room Because the group is the last of the entities, trying to adjust the whole room only activates one light, because all of the lights match equally well. By preferring the shortest of equal matches, we prefer keys that have the least amount of extra information, causing "Living Room" to match the group instead of an individual light.
This commit is contained in:
parent
3841f0e42d
commit
1433cdaa12
@ -169,10 +169,13 @@ def _fuzzymatch(name: str, items: Iterable[T], key: Callable[[T], str]) -> Optio
|
||||
for idx, item in enumerate(items):
|
||||
match = regex.search(key(item))
|
||||
if match:
|
||||
# Add index so we pick first match in case same group and start
|
||||
matches.append((len(match.group()), match.start(), idx, item))
|
||||
# Add key length so we prefer shorter keys with the same group and start.
|
||||
# Add index so we pick first match in case same group, start, and key length.
|
||||
matches.append(
|
||||
(len(match.group()), match.start(), len(key(item)), idx, item)
|
||||
)
|
||||
|
||||
return sorted(matches)[0][3] if matches else None
|
||||
return sorted(matches)[0][4] if matches else None
|
||||
|
||||
|
||||
class ServiceIntentHandler(IntentHandler):
|
||||
|
@ -38,3 +38,21 @@ def test_async_validate_slots():
|
||||
handler1.async_validate_slots(
|
||||
{"name": {"value": "kitchen"}, "probability": {"value": "0.5"}}
|
||||
)
|
||||
|
||||
|
||||
def test_fuzzy_match():
|
||||
"""Test _fuzzymatch."""
|
||||
state1 = State("light.living_room_northwest", "off")
|
||||
state2 = State("light.living_room_north", "off")
|
||||
state3 = State("light.living_room_northeast", "off")
|
||||
state4 = State("light.living_room_west", "off")
|
||||
state5 = State("light.living_room", "off")
|
||||
states = [state1, state2, state3, state4, state5]
|
||||
|
||||
state = intent._fuzzymatch("Living Room", states, lambda state: state.name)
|
||||
assert state == state5
|
||||
|
||||
state = intent._fuzzymatch(
|
||||
"Living Room Northwest", states, lambda state: state.name
|
||||
)
|
||||
assert state == state1
|
||||
|
Loading…
x
Reference in New Issue
Block a user