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) 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()
def speak(self, sentence: str) -> bytes: """Get WAV buffer for sentence.""" try: tts_url = urljoin(self.hass_config["url"], "api/tts_get_url") # Send to Home Assistant kwargs = hass_request_kwargs(self.hass_config, self.pem_file) kwargs["json"] = {"platform": self.platform, "message": sentence} if self.pem_file is not None: kwargs["verify"] = self.pem_file # POST to /api/tts_get_url response = requests.post(tts_url, **kwargs) response.raise_for_status() response_json = response.json() self._logger.debug(response_json) # Download MP3 audio_url = response_json["url"] kwargs = hass_request_kwargs(self.hass_config, self.pem_file) if self.pem_file is not None: kwargs["verify"] = self.pem_file # GET audio data response = requests.get(audio_url, **kwargs) response.raise_for_status() audio_bytes = response.content self._logger.debug("Received %s byte(s) of audio data", len(audio_bytes)) # Convert to WAV if audio_url.endswith(".mp3"): lame_command = ["lame", "--decode", "-", "-"] self._logger.debug(lame_command) return subprocess.run(lame_command, input=audio_bytes, check=True, stdout=subprocess.PIPE).stdout # Assume WAV return audio_bytes except Exception: self._logger.exception("speak") return bytes()
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))
def get_problems(self) -> Dict[str, Any]: """Get problems during startup.""" problems: Dict[str, Any] = {} hass_url = self.hass_config["url"] try: url = urljoin(self.hass_config["url"], "/api/") kwargs = hass_request_kwargs(self.hass_config, self.pem_file) requests.get(url, **kwargs) except Exception: problems[ "Can't contact server"] = f"Unable to reach your Home Assistant server at {hass_url}. Is it running?" return problems
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()
def forward_intent(self, event_type: str, slots: Dict[str, Any]): """Forward existing event to Home Assistant.""" # Base URL of Home Assistant server 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()
def get_problems(self) -> Dict[str, Any]: """Get problems at startup.""" problems: Dict[str, Any] = {} if not self.platform: problems[ "Missing platform name"] = "Expected Home Assistant STT platform name in speech_to_text.hass_stt.platform" stt_url = urljoin(self.hass_config["url"], f"api/stt/{self.platform}") try: kwargs = hass_request_kwargs(self.hass_config, self.pem_file) requests.get(stt_url, **kwargs) except Exception: problems[ "Can't contact server"] = f"Unable to reach your Home Assistant STT platform at {stt_url}. Is the platform configured?" return problems
def get_problems(self) -> Dict[str, Any]: """Get problems at startup.""" problems: Dict[str, Any] = {} if not shutil.which("lame"): problems[ "Missing LAME MP3 encoding"] = "LAME MP3 encoder is not installed. Try apt-get install lame" if not self.platform: problems[ "Missing platform name"] = "Expected Home Assistant TTS platform name in text_to_speech.hass_tts.platform" api_url = urljoin(self.hass_config["url"], "api/") try: kwargs = hass_request_kwargs(self.hass_config, self.pem_file) requests.get(api_url, **kwargs) except Exception: problems[ "Can't contact server"] = f"Unable to reach your Home Assistant at {api_url}. Is it running?" return problems
def transcribe_wav(self, wav_data: bytes) -> str: """Get text Home Assistant STT platform.""" try: assert self.platform, "Missing platform name" # Convert WAV to desired format wav_data = maybe_convert_wav( wav_data, rate=self.sample_rate, width=self.bit_rate, channels=self.channels, ) stt_url = urljoin(self.hass_config["url"], f"api/stt/{self.platform}") # Send to Home Assistant kwargs = hass_request_kwargs(self.hass_config, self.pem_file) if self.pem_file is not None: kwargs["verify"] = self.pem_file headers = kwargs.get("headers", {}) headers["X-Speech-Content"] = "; ".join( [ "format=wav", "codec=pcm", f"sample_rate={self.sample_rate}", f"bit_rate={self.bit_rate}", f"channel={self.channels}", f"language={self.language}", ] ) def generate_chunks() -> Iterable[bytes]: with io.BytesIO(wav_data) as wav_buffer: with wave.open(wav_buffer, "rb") as wav_file: # Send empty WAV as initial chunk (header only) with io.BytesIO() as empty_wav_buffer: empty_wav_file: wave.Wave_write = wave.open( empty_wav_buffer, "wb" ) with empty_wav_file: empty_wav_file.setframerate(wav_file.getframerate()) empty_wav_file.setsampwidth(wav_file.getsampwidth()) empty_wav_file.setnchannels(wav_file.getnchannels()) yield empty_wav_buffer.getvalue() # Stream chunks audio_data = wav_file.readframes(wav_file.getnframes()) while audio_data: chunk = audio_data[: self.chunk_size] yield chunk audio_data = audio_data[self.chunk_size :] # POST WAV data to STT response = requests.post(stt_url, data=generate_chunks(), **kwargs) response.raise_for_status() response_json = response.json() self._logger.debug(response_json) assert response_json["result"] == "success" return response_json["text"] except Exception: self._logger.exception("transcribe_wav") return ""