How to specify voice-responses in sentence.ini

First of all: BIG THX for this awesome project

How can i specify to overwrite the output-voice-response on a “sentence”-level?

must have: On/Off/Wav-file (for a confirmation ding)
nice2have: Text

somthing like this: sentences.ini

[HassTurnOn]
voice_response = false
Turn on ($lights | $switches){name}

or even this: sentences.ini

[HassTurnOn]
voice_response = Okay
Turn on ($lights | $switches){name} *{{<voice_response>}}*

Im new to rhasspy, maybe a better way would be to have a responses.ini with the same “Keys” as the sentences.ini.
This way one could even build responses like: responses.ini

[HassTurnOn]
Okay, turing on {name}

We don’t have something like this in Rhasspy. It’s the intent handler’s responsibility to end the session by responding to the intent with the right text message. The intent handler can be Home Assistant, a Node-RED flow, your own Python script, …

1 Like

OMG Thank you SOO much, for answering me <3

Yes I’ve read a lot of things for the HomeAssistant-Intents. I think switching from built-in intents to custom once should give me the possibility to solve this problem on the Home-Assistance’s side.

Never the less, i think it would be amazing to at least have the option to skip the response inside Rhasspy. (of course one can just turn of the whole tts)

example:
In sentences like [GetTemperature] or [GetTime] you want to hear the answer.
but in cases of [SetLightToRed] you will get annoyed at some point, hearing “Set {name} color to red”
everytime.
If it is implemented, one could add a trigger-word like “please” to activate the response.
In that way you can have your conversation-feeling if you say “please”, and have your peace if you dont say “please”

The intent handler can be Home Assistant, a Node-RED flow, your own Python script, …

Maybe I can create a small add-on for Rhasspy as python-script.

1 Like

Wow, this community is IMPRESSIVE !!!
Thank you for answering me.

I will test it asap after work today

1 Like

So you mean that instead of an answer you would like to be able to play an audio file?

1 Like

Yes, exactly, but on a per-sentence-level.

SSML (Speech Synthesis Markup Language) has a audio tag for this purpose (https://www.w3.org/TR/speech-synthesis/#S3.3.1). So it is possible to use e.g. the sentence

'<audio src="hello_world.wav">hello world</audio>'

which will try to play the audio file and as fallback when the file is not found generate the normal sentence instead.

Rhasspy does not has support for SSML yet, but I am currently working on it :wink:

3 Likes

Welcome, @Blade_John! If you’re using Home Assistant, check out my HA example.

If you use the built-in intents through HA, it will automatically respond with text (which Rhasspy will play through your TTS system). So something like “turn on the kitchen light” will have HA turn the light on and respond “turned on kitchen light”.

You can also write a tiny Bash script to do the response, or configure a Node-RED flow :slight_smile:

1 Like

I recommend using Node-Red but it depends on what you like more of course. I use Node-Red for all HA and rhasspy automations (Node-Red triggers the intended service calls to HA for each intent).

Node-Red also sends my answer to the rhasspy. I will post my example tomorrow, maybe it will be helpful for you.

1 Like

Postet it here: Rhasspy Light and Cover control with Node-RED and HA

1 Like

AMAZING answers!! I was in a lot of forums for different things in my life,
but this one is REALLY impressive!!!

Yes this one is NICE !

This was the root cause of this topic.
The HA-autogenerated-respond was a mix of english and german words, spoken with the eSpeak male voice, resulting in really funny audio-outputs.

I managed it using custom Intents: (for german language).
At the moment i can’t use the speak key in HA, to make rhasspy speak.
I’m using a rest_command service.

configuration.yaml
intent_script:
  GetTemperature:  # Intent type
    action:
      data_template:
        payload: >-
          es sind {{ states("sensor.temperature")|regex_replace(find="\.",
          replace=",", ignorecase=False) }} grad
      service: rest_command.rhasspy_speak
  GetTime:  # Intent type
    action:
      data_template:
        payload: 'es ist {{ now().hour }} uhr {{ now().minute }}'
      service: rest_command.rhasspy_speak

OUTSTANDING! smells like a game-changer.

If anyone is intrested in the german sentences<–>intent for switches & lights in HA:

Expand

sentences.ini

[rhasspYZTurnOnSwitch]
state_on = (ein |  an | einschalten) {state}
\[(kannst | könntest) du] [bitte] [(das | die | den)] ($switches){name} <state_on> [schalten]

[rhasspYZTurnOffSwitch]
state_off = (aus | ausschalten ) {state}
\[(kannst | könntest) du] [bitte] [(das | die | den)] ($switches){name} <state_off> [schalten]

[rhasspYZTurnOnLight]
state_on = (ein |  an | einschalten) {state}
\[(kannst | könntest) du] [bitte] [(das | die | den)] ($lights){name} <state_on> [schalten]

[rhasspYZTurnOffLight]
state_off = (aus | ausschalten ) {state}
\[(kannst | könntest) du] [bitte] [(das | die | den)] ($lights){name} <state_off> [schalten]

[rhasspYZSetLightColor]
\[(kannst | könntest) du] [bitte] [das|die|den] ($lights){name} auf ($colors){color} schalten

[rhasspYZSetLightBrightness]
\[(kannst | könntest) du] [bitte] [das|die|den] ($lights){name} auf (0..100){brightness} Prozent

HA-configuration.yaml:

intent_script:
  rhasspYZTurnOnSwitch:  # Intent type
    action:
      data_template:
        entity_id: >
            switch.{{ name }}
      service_template: >
          switch.turn_on
  rhasspYZTurnOffSwitch:  # Intent type
    action:
      data_template:
        entity_id: >
            switch.{{ name }}
      service_template: >
          switch.turn_off
  rhasspYZTurnOnLight:  # Intent type
    action:
      data_template:
        entity_id: >
            light.{{ name }}
      service_template: >
          light.turn_on
  rhasspYZTurnOffLight:  # Intent type
    action:
      data_template:
        entity_id: >
            light.{{ name }}
      service_template: >
          light.turn_off
          
  rhasspYZSetLightColor:  # Intent type
    action:
      data_template:
        entity_id: >
            light.{{ name }}
        color_name: '{{ color }}'
      service_template: >
          light.turn_on
          
  rhasspYZSetLightBrightness:  # Intent type
    action:
      data_template:
        entity_id: >
            light.{{ name }}
        brightness: '{{ ( brightness * 255 / 100 ) | int }}'
      service_template: >
          light.turn_on

I also tried to merge the 4 intents into 1, but that didn’t work:

Summary
[rhasspYZ]
state_on = (ein |  an | einschalten) {state}
state_off = (aus | ausschalten ) {state}
new_state = <state_on> | <state_off>
\[(kannst | könntest) du] [bitte] [(das | die | den)] ($lights | $switches){name} (<new_state>){state} [schalten]

in the rhasspy log i can see “entity” and “state”, but it is not accessable in HA-templating.

Boom thx for the example. I don’t know why, but im unable to like node-red yet.
Feels like an unneccessary man-in-the-middle. Please don’t get me wrong, the problem is ME, not the world. At the moment it seems, everything can be done within HA (automations, scripts, intents, events). If at some point I can find some real nice benefits, I might fall to dark-side (i mean the red-side)

Nice one, next world opened. thx :slight_smile:

Offtopic: What’s the downside of maryTTS? I tested the online-demo, and it sounds much better than the eSpeak. Maybe perfomance is an issue on a pi 3b+ ?

Thank you for the nice spirit here!!!

Gratefully
Blade

2 Likes

Part of your problem with this sentence is most likely that you got the slot tag behind state_on and state_off and a second time behind them in the actual sentence.

You should try this instead:

fixed sentence
[rhasspYZ]
state_on = (ein |  an | einschalten)
state_off = (aus | ausschalten )
new_state = (<state_on> | <state_off>)
\[(kannst | könntest) du] [bitte] [(das | die | den)] ($lights | $switches){name} (<new_state>){state} [schalten]
the sentences i use for my `ChangeLightState` intent

[ChangeLightState]
light_name = $lampe {name}
light_state = ((ein|an):ein | (aus|ab):aus | heller | dunkler) {state}
[(schalte | schalt)] [(die | das | den)] <light_name> <light_state>
(((deaktiviere):aus)|((aktiviere):ein)) {state} [(die | das | den)] <light_name>
<light_name> ((ausschalten|deaktiviere|abschalten):aus | (einschalten|anschalten|aktiviere):ein {state}

1 Like

Nice works, THANKS

My Light intents are:

[rhasspYZSetLightColor]
\[(kannst | könntest) du] [bitte] [das|die|den] ($lights){name} auf ($colors){color} schalten

[rhasspYZSetLightBrightness]
\[(kannst | könntest) du] [bitte] [das|die|den] ($lights){name} auf (0..100){brightness} Prozent

I’m using automations.yaml to compose my voice responses in Home Assistant. Where I’ve run into a bit of difficulty is obtaining the slots rawValue for any given slot. Below is the example JSON returned from the Rhasspy event where I’d like to obtain the rawValue data for the slot where slotName = “light”. It should be “brass lamp”.

What I have tried is shown here, but alas, neither are working. :frowning:

{{ trigger.event.data._intent.slots["light"].rawValue }}
{{ trigger.event.data._intent.slots.light.rawValue }}

So exactly how should I specify a slot by name?

{
    "event_type": "rhasspy_ChangeLightState",
    "data": {
        "light": "switch.brass_lamp",
        "state": "off",
        "_text": "switch.brass_lamp off",
        "_raw_text": "brass lamp off",
        "_intent": {
            "input": "switch.brass_lamp off",
            "intent": {
                "intentName": "ChangeLightState",
                "confidenceScore": 1
            },
            "siteId": "Listener1",
            "id": null,
            "slots": [
                {
                    "entity": "light",
                    "value": {
                        "kind": "Unknown",
                        "value": "switch.brass_lamp"
                    },
                    "slotName": "light",
                    "rawValue": "brass lamp",
                    "confidence": 1,
                    "range": {
                        "start": 0,
                        "end": 17,
                        "rawStart": 0,
                        "rawEnd": 10
                    }
                },
                {
                    "entity": "state_on_off",
                    "value": {
                        "kind": "Unknown",
                        "value": "off"
                    },
                    "slotName": "state",
                    "rawValue": "off",
                    "confidence": 1,
                    "range": {
                        "start": 18,
                        "end": 21,
                        "rawStart": 11,
                        "rawEnd": 14
                    }
                }
            ],
            "sessionId": "Listener1-porcupine-1ed92005-9da1-433a-8d7d-671cd79390de",
            "customData": null,
            "asrTokens": [
                [
                    {
                        "value": "switch.brass_lamp",
                        "confidence": 1,
                        "rangeStart": 0,
                        "rangeEnd": 17,
                        "time": null
                    },
                    {
                        "value": "off",
                        "confidence": 1,
                        "rangeStart": 18,
                        "rangeEnd": 21,
                        "time": null
                    }
                ]
            ],
            "asrConfidence": null,
            "rawInput": "brass lamp off",
            "wakewordId": "porcupine",
            "lang": null
        }
    },
    "origin": "REMOTE",
    "time_fired": "2020-07-05T18:15:43.376664+00:00",
    "context": {
        "id": "278fc19a54f349f7948dfa12882e2913",
        "parent_id": null,
        "user_id": "26ec3060f78f4880a6a70e903924eb1f"
    }
}

@FredTheFrog Why not using the Snips integration directly?

It is much easier to get all these info.

I’ve never used Snips before! :slight_smile: The good news is, I’ve figured out that because the light is always Slots[0] I can use that notation:
{{ trigger.event.data._intent.slots[0].rawValue }}

@FredTheFrog maybe this will work:
{{ trigger.event.data._intent.slots[0].rawValue }}
This will only work if light is the first slot returned.
slots is an array containing objects.

seems like you already figured it out.

1 Like

Take a look at

It is completely compatible with Rhasspy since Rhasspy 2.5 respect the Hermes protocol.

It greatly simplify the intent handling with Home Assistant.

Hope this helps.

@synesthesiam Maybe a Rhasspy Home Assistant integration based on the Snips one can be proposed to the HA guys…

1 Like

@moqart and @fastjack Thank you both for your very timely and helpful replies. I’ve just placed my first 2.5.0/voltron rhasspy unit into ‘Production’ mode. I had to learn the newer configuration syntax for sentences and slots first. I’m still using HA events to respond using HA automations. Maybe I’ll learn to use Snips/hermes next. :wink:

2 Likes

Proposing that to the HA developers is an EXCELLENT idea. My concern is they might soon deprecate the Snips interface, since Snips went closed-source.