intents icon indicating copy to clipboard operation
intents copied to clipboard

We should prioritize intent matching in specific contexts over generic ones

Open tetele opened this issue 1 year ago • 11 comments

Probably the most common phrase for turning off a light in Romanian is "inchide [light]". The most common phrase for closing a door/window is "inchide [opening]".

Notice that the verb is the same ("inchide") in Romanian, although in English the 2 are totally different.

As a consequence, a test written for the sentence "inchide " matches the homeassistant_HassTurnOff intent, even when that specific entity name is a cover, which is more specific.

A working example (only relevant parts selected): sentences/ro/_common.yaml

expansion_rules:
  area: "{area} [(zona | zonă | regiune)]"
  name: "({name}[ul] | {name})"
  din: "(din | (î|i)n | pentru | [de] la)"
  opreste: "(stop | opre(ș|s)te | (î|i)nchide | stinge | dezactiveaz(ă|a))"
  inchide: "((î|i)nchide | coboar(ă|a))"

sentences/ro/cover_HassCloseCover.yaml

intents:
  HassCloseCover:
    data:
      - sentences:
          - "<inchide> <name>"
          - "<inchide> <name> [<din>] <area>"

sentences/ro/homeassistant_HassTurnOff.yaml

intents:
  HassTurnOff:
    data:
      - sentences:
          - "<opreste> <name>"

tests/ro/_fixtures.yaml

entities:
  - name: fereastra din stanga
    id: cover.bedroom_window_left
    device_class: window
    area: bedroom

tests/ro/cover_HassCloseCover.yaml

tests:
  - sentences:
      - "inchide fereastra din stanga"
    intent:
      name: HassCloseCover
      slots:
        name: cover.bedroom_window_left

The test result:

FAILED tests/test_language_sentences.py::test_cover_HassCloseCover[ro] - AssertionError: For 'inchide fereastra din stanga' expected intent HassCloseCover, got HassTurnOff

tetele avatar Jan 10 '23 08:01 tetele

Then we should have: expansion_rules: area: "{area} [(zona | zonă | regiune)]" name: "({name}[ul] | {name})" din: "(din | (î|i)n | pentru | [de] la)" opreste: "(stop | opre(ș|s)te | stinge | dezactiveaz(ă|a))" inchide: "((î|i)nchide | coboar(ă|a))"

and then we can clearly use them. As example "inchide" make more sense to blinds, doors and covers them to lights ?

rechin304 avatar Jan 10 '23 09:01 rechin304

True, but we can't control how people are going to ask for certain actions to happen. And to be fair, mostly everyone says "inchide lumina" when trying to turn off the light.

If it comes to that, I'm more willing to sacrifice "inchide usa" in favor of "inchide lumina", as fewer people have door shutting devices than those who have smart lights.

tetele avatar Jan 10 '23 09:01 tetele

I think then they need to use proper "aprinde / stinge" for lights.

rechin304 avatar Jan 10 '23 09:01 rechin304

This image might answer a lot better than I ever could.

Sure, you can force users to say "aprinde/stinge" instead of their usual "deschide/inchide". Dictionaries recommend it. But if you want to provide a good experience, you need to allow them to (also) use the colloquial wording they are accustomed to.

Plus, @synesthesiam said he may have a fix based on more/less context when defining the intent sentences. Let's see if that works and we'll figure out a workaround afterwards, if necessary.

tetele avatar Jan 10 '23 09:01 tetele

ok, good point.

rechin304 avatar Jan 10 '23 09:01 rechin304

Jut did a test on current voice assistant and asking to "open light name" did not worked the same for "turn on gate name". So also looks that even in EN is strict usage. But as you mention let's see latter.

rechin304 avatar Jan 10 '23 09:01 rechin304

It doesn't make sense in English to "open a light". You turn it on. You open a gate, which you can't turn on. It's different in Romanian.

"A inchide" literally means "to shut [an opening]", but also "to darken [a color, the sky]" https://dexonline.ro/definitie/%C3%AEnchidere.

tetele avatar Jan 10 '23 09:01 tetele

So that was my point that "inchide" should not be used for lights ;)

rechin304 avatar Jan 10 '23 10:01 rechin304

I agree with @tetele. Home Assistant should simply work. If Romanian people usually say "inchide lumina" to turn off a light, this case of use should be supported, no matter if the verb is the same as the one used to close doors.

davefx avatar Jan 10 '23 12:01 davefx

I can see in #416 that this same case happens in Simplified Chinese, where the same verb is used to turn on a light and to open a curtain.

Also in #416, @synesthesiam said that he is working on the ability to restrict an intent match to a specific domain, so the test entities will have their domain with them... Not sure if this has progressed or not.

davefx avatar Jan 10 '23 12:01 davefx

hm... for me, this looks like a design flaw...

I think - it would be more suitable to use the device / domain to define the possible actions and then, you could use what ever you want to activate the corresponding action.

For example - if I have a garage door and a light, the devices define the possible actions. Now, I could combine an intent like "get rid of..." either to "close", "shut down", "delete" - or whatever I want it to be.

The device / domain will then link to the required action:

"Get rid of the waste" -> deleting the trash on my computer "Get rid of the living room light" -> shut down the light in the living room "Get rid of the Garage door" -> is closing the garage door.

The user should be able to define ANYTHING he wants for an action, not only "most common" spoken terms etc.

Hope, my thoughts are somehow clear and understandable... :)

ChristophCaina avatar Jan 11 '23 13:01 ChristophCaina

I'm working on a PR for this now. In short, you use requires_context in the cover intent to only match on a specific domain. Then, excludes_context in the generic turn on/off intent to skip matches with that domain.

Why are both needed? For matching speed. Intents are not ordered before matching, and the first match is always returned. So both intents need to be aware of the constraints.

When the PR lands, the changes needed in sentences/ro/cover_HassCloseCover.yaml are:

intents:
  HassCloseCover:
    data:
      - sentences:
          - "<inchide> <name>"
          - "<inchide> <name> [<din>] <area>"
        requires_context:
          domain: cover

and in sentences/ro/homeassistant_HassTurnOff.yaml:

intents:
  HassTurnOff:
    data:
      - sentences:
          - "<opreste> <name>"
        excludes_context:
          domain: cover

Note that domain can be a list as well.

synesthesiam avatar Jan 11 '23 20:01 synesthesiam

Not sure if you've thought about this in advance, but it might help to "require context" with any value for certain slots.

For example a certain sentence should signal an intent only if an area is provided, explicitly or implicitly. Or if a certain entity name exists. Etc.

For example

intents:
  HassCloseCover:
    data:
      - sentences:
          - "turn off {name} [from] {area}"
        requires_context:
          area: *
          domain: cover

That could cover the inferred context I was talking about elsewhere.

tetele avatar Jan 11 '23 20:01 tetele

I'm working on a PR for this now. In short, you use requires_context in the cover intent to only match on a specific domain. Then, excludes_context in the generic turn on/off intent to skip matches with that domain.

That is great!

spuljko avatar Jan 12 '23 10:01 spuljko

PR is merged :slightly_smiling_face:

synesthesiam avatar Jan 12 '23 15:01 synesthesiam