Exemple #1
0
    def in_started(self, message: Any, sender: RhasspyActor) -> None:
        """Handle messages in started state."""
        if isinstance(message, RecognizeIntent):
            post_url = urljoin(self.hass_config["url"],
                               "api/conversation/process")

            # Send to Home Assistant
            kwargs = hass_request_kwargs(self.hass_config, self.pem_file)
            kwargs["json"] = {"text": message.text}

            if self.pem_file is not None:
                kwargs["verify"] = self.pem_file

            # POST to /api/conversation/process
            response = requests.post(post_url, **kwargs)
            response.raise_for_status()

            response_json = response.json()

            # Extract speech
            if self.handle_speech:
                speech = pydash.get(response_json, "speech.plain.speech", "")
                if speech:
                    # Forward to TTS system
                    self._logger.debug("Handling speech")
                    self.send(sender, SpeakSentence(speech))

            # Return empty intent since conversation doesn't give it to us
            intent = empty_intent()
            intent["text"] = message.text
            intent["raw_text"] = message.text
            intent["speech_confidence"] = message.confidence
            self.send(message.receiver or sender, IntentRecognized(intent))
Exemple #2
0
    def in_ready(self, message: Any, sender: RhasspyActor) -> None:
        """Handle messages in ready state."""
        if isinstance(message, HandleIntent):
            self.receiver = message.receiver or sender
            intent = message.intent
            try:
                self._logger.debug(self.command)

                # JSON -> STDIN -> STDOUT -> JSON
                json_input = json.dumps(intent).encode()
                output = subprocess.run(
                    self.command,
                    check=True,
                    input=json_input,
                    stdout=subprocess.PIPE).stdout.decode()

                intent = json.loads(output)
                self._logger.debug(intent)

                # Check for speech
                speech = intent.get("speech", {})
                speech_text = speech.get("text", "")
                if speech_text and self.speech_actor:
                    self.send(self.speech_actor, SpeakSentence(speech_text))
            except Exception as e:
                self._logger.exception("in_started")
                intent["error"] = str(e)

            if self.forward_to_hass and self.hass_handler:
                self.transition("forwarding")
                self.send(self.hass_handler, ForwardIntent(intent))
            else:
                # No forwarding
                self.send(self.receiver, IntentHandled(intent))
Exemple #3
0
    def in_ready(self, message: Any, sender: RhasspyActor) -> None:
        """Handle messages in ready state."""
        if isinstance(message, HandleIntent):
            self.receiver = message.receiver or sender
            intent = message.intent
            try:
                # JSON -> Remote -> JSON
                response = requests.post(self.remote_url, json=message.intent)
                response.raise_for_status()

                intent = response.json()
                self._logger.debug(intent)

                # Check for speech
                speech = intent.get("speech", {})
                speech_text = speech.get("text", "")
                if speech_text and self.speech_actor:
                    self.send(self.speech_actor, SpeakSentence(speech_text))
            except Exception as e:
                self._logger.exception("in_started")
                intent["error"] = str(e)

            if self.forward_to_hass and self.hass_handler:
                self.transition("forwarding")
                self.send(self.hass_handler, ForwardIntent(intent))
            else:
                # No forwarding
                self.send(self.receiver, IntentHandled(intent))
Exemple #4
0
    def in_ready(self, message: Any, sender: RhasspyActor) -> None:
        """Handle messages in rady state."""
        if isinstance(message, SpeakSentence):
            self.wav_data = bytes()
            self.receiver = message.receiver or sender
            try:
                voice = message.voice or self.voice
                language_code = message.language or self.language_code
                self.wav_data = self.speak(message.sentence, voice,
                                           language_code)

                if message.play:
                    self.enable_wake = False
                    if self.wake and self.disable_wake:
                        # Disable wake word
                        self.send(self.wake, PauseListeningForWakeWord())
                        self.enable_wake = self.wake_on_start

                    self.transition("speaking")
                    self.send(
                        self.player,
                        PlayWavData(self.wav_data, siteId=message.siteId))
                else:
                    self.transition("ready")
                    self.send(self.receiver, SentenceSpoken(self.wav_data))
            except Exception:
                self._logger.exception("speak")

                # Try fallback system
                try:
                    assert (self.fallback_actor
                            is not None), "No fallback text to speech system"

                    self._logger.debug("Falling back to %s",
                                       self.fallback_actor)
                    self.transition("speaking")
                    self.send(
                        self.fallback_actor,
                        SpeakSentence(
                            message.sentence,
                            play=message.play,
                            voice=message.voice,
                            language=message.language,
                            siteId=message.siteId,
                        ),
                    )
                except Exception:
                    # Give up
                    self.transition("ready")
                    self.send(self.receiver, SentenceSpoken(bytes()))
        elif isinstance(message, Configured):
            # Fallback actor is configured
            pass
Exemple #5
0
 async def speak_sentence(
     self,
     sentence: str,
     play: bool = True,
     language: Optional[str] = None,
     voice: Optional[str] = None,
 ) -> SentenceSpoken:
     """Speak an entire sentence using text to speech system."""
     assert self.actor_system is not None
     with self.actor_system.private() as sys:
         result = await sys.async_ask(
             self.dialogue_manager,
             SpeakSentence(sentence,
                           play=play,
                           language=language,
                           voice=voice),
         )
         assert isinstance(result, SentenceSpoken), result
         return result
Exemple #6
0
    def forward_intent(self, intent_name: str, event_type: str, slots: Dict[str, Any]):
        """Forward existing event to Home Assistant."""

        if self.handle_type == HomeAssistantHandleType.INTENT:
            # Call /api/intent/handle
            post_url = urljoin(self.hass_config["url"], "api/intent/handle")

            # Send to Home Assistant
            kwargs = hass_request_kwargs(self.hass_config, self.pem_file)
            kwargs["json"] = {"name": intent_name, "data": slots}

            if self.pem_file is not None:
                kwargs["verify"] = self.pem_file

            response = requests.post(post_url, **kwargs)
            response.raise_for_status()

            intent = response.json()
            self._logger.debug(intent)

            # Check for speech
            speech_text = intent.get("speech", {}).get("plain", {}).get("speech", "")
            if speech_text and self.speech_actor:
                self.send(self.speech_actor, SpeakSentence(speech_text))
        else:
            # Send event
            post_url = urljoin(self.hass_config["url"], "api/events/" + event_type)

            # Send to Home Assistant
            kwargs = hass_request_kwargs(self.hass_config, self.pem_file)
            kwargs["json"] = slots

            if self.pem_file is not None:
                kwargs["verify"] = self.pem_file

            response = requests.post(post_url, **kwargs)
            self._logger.debug("POSTed intent to %s", post_url)

            response.raise_for_status()
Exemple #7
0
    def handle_any(self, message: Any, sender: RhasspyActor) -> None:
        """Handle messages in any state."""
        if isinstance(message, ListenForCommand):
            # Force voice command
            self.handle = message.handle
            self.intent_receiver = message.receiver or sender
            self.listen_timeout_sec = message.timeout
            self.listen_entities = message.entities
            self.transition("awake")
        elif isinstance(message, GetVoiceCommand):
            # Record voice command, but don't do anything with it
            self.send(
                self.command,
                ListenForCommand(message.receiver or sender, timeout=message.timeout),
            )
        elif isinstance(message, TranscribeWav):
            # speech -> text
            self.send(
                self.decoder,
                TranscribeWav(message.wav_data, sender, handle=message.handle),
            )
        elif isinstance(message, RecognizeIntent):
            # text -> intent
            self.send(
                self.recognizer,
                RecognizeIntent(
                    message.text,
                    confidence=message.confidence,
                    receiver=sender,
                    handle=message.handle,
                ),
            )
        elif isinstance(message, HandleIntent):
            # intent -> action
            self.send(self.handler, HandleIntent(message.intent, sender))

            # Forward to MQTT (hermes)
            if self.mqtt is not None:
                self.send(self.mqtt, IntentRecognized(message.intent))
        elif isinstance(message, GetWordPhonemes):
            # eSpeak -> CMU
            self.send(
                self.word_pronouncer, GetWordPhonemes(message.word, receiver=sender)
            )
        elif isinstance(message, SpeakWord):
            # eSpeak -> WAV
            self.send(self.word_pronouncer, SpeakWord(message.word, receiver=sender))
        elif isinstance(message, GetWordPronunciations):
            # word -> [CMU]
            self.send(
                self.word_pronouncer,
                GetWordPronunciations(message.words, n=message.n, receiver=sender),
            )
        elif isinstance(message, SpeakSentence):
            # text -> speech
            self.send(
                self.speech,
                SpeakSentence(
                    message.sentence,
                    receiver=sender,
                    play=message.play,
                    voice=message.voice,
                    language=message.language,
                ),
            )
        elif isinstance(message, TrainProfile):
            # Training
            self.reload_actors_after_training = message.reload_actors
            self.send(self.wake, StopListeningForWakeWord())
            self.training_receiver = message.receiver or sender
            self.transition("training_sentences")
            # self.send(self.sentence_generator, GenerateSentences())
        elif isinstance(message, StartRecordingToBuffer):
            # Record WAV
            self.send(self.recorder, message)
        elif isinstance(message, StopRecordingToBuffer):
            # Stop recording WAV
            self.send(
                self.recorder,
                StopRecordingToBuffer(message.buffer_name, message.receiver or sender),
            )
        elif isinstance(message, StateTransition):
            # Track state of every actor
            self.handle_transition(message, sender)
        elif isinstance(message, GetActorStates):
            self.send(sender, self.actor_states)
        elif isinstance(message, WakeupMessage):
            pass
        elif isinstance(message, WavPlayed):
            pass
        elif isinstance(message, GetProblems):
            # Report problems from child actors
            self.send(sender, Problems(self.problems))
        else:
            self.handle_forward(message, sender)