def in_started(self, message: Any, sender: RhasspyActor) -> None: """Handle messages in started state.""" if isinstance(message, RecognizeIntent): intent = empty_intent() intent["text"] = message.text intent["speech_confidence"] = message.confidence self.send(message.receiver or sender, IntentRecognized(intent))
def in_started(self, message: Any, sender: RhasspyActor) -> None: """Handle messages in started state.""" if isinstance(message, RecognizeIntent): try: self._logger.debug(self.command) # Text -> STDIN -> STDOUT -> JSON output = subprocess.run( self.command, check=True, input=message.text.encode(), stdout=subprocess.PIPE, ).stdout.decode() intent = json.loads(output) except Exception: self._logger.exception("in_started") 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, handle=message.handle), )
def in_loaded(self, message: Any, sender: RhasspyActor) -> None: """Handle messages in loaded state.""" if isinstance(message, RecognizeIntent): try: self.load_graph() # Assume lower case, white-space separated tokens text = message.text tokens = re.split(r"\s+", text) if self.profile.get("intent.fsticuffs.ignore_unknown_words", True): # Filter tokens tokens = [w for w in tokens if w in self.words] recognitions = recognize( tokens, self.graph, fuzzy=self.fuzzy, stop_words=self.stop_words ) assert recognitions, "No intent recognized" # Use first intent recognition = recognitions[0] # Convert to JSON intent = recognition.asdict() except Exception: self._logger.exception("in_loaded") intent = empty_intent() intent["speech_confidence"] = message.confidence self.send( message.receiver or sender, IntentRecognized(intent, handle=message.handle), )
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 recognize(self, text: str) -> Dict[str, Any]: """Use Adapt engine to recognize intent.""" # Get all intents assert self.engine is not None, "Adapt engine not loaded" intents = [ intent for intent in self.engine.determine_intent(text) if intent ] if len(intents) > 0: # Return the best intent only intent = max(intents, key=lambda x: x.get("confidence", 0)) intent_type = intent["intent_type"] entity_prefix = "{0}.".format(intent_type) slots = {} for key, value in intent.items(): if key.startswith(entity_prefix): key = key[len(entity_prefix):] slots[key] = value # Try to match Rasa NLU format for future compatibility return { "text": text, "intent": { "name": intent_type, "confidence": intent.get("confidence", 0), }, "entities": [{ "entity": name, "value": value } for name, value in slots.items()], } return empty_intent()
def recognize(self, text: str) -> Dict[str, Any]: """Find sentence with lowest string-edit distance.""" confidence = 0 if len(text) > 0: assert self.examples is not None, "No examples JSON" choices: Dict[str, Tuple[str, Dict[str, Any]]] = {} with concurrent.futures.ProcessPoolExecutor() as executor: future_to_name = {} for intent_name, intent_examples in self.examples.items(): sentences = [] for example in intent_examples: example_text = example.get("raw_text", example["text"]) logging.debug(example_text) choices[example_text] = (example_text, example) sentences.append(example_text) future = executor.submit(_get_best_fuzzy, text, sentences) future_to_name[future] = intent_name # Process them as they complete best_text = "" best_score = None for future in concurrent.futures.as_completed(future_to_name): intent_name = future_to_name[future] text, score = future.result() if (best_score is None) or (score > best_score): best_text = text best_score = score if best_text in choices: confidence = (best_score / 100) if best_score else 1 if confidence >= self.min_confidence: # (text, intent, slots) best_text, best_intent = choices[best_text] # Update confidence and return example intent best_intent["intent"]["confidence"] = confidence return best_intent self._logger.warning( "Intent did not meet confidence threshold: %s < %s", confidence, self.min_confidence, ) # Empty intent intent = empty_intent() intent["text"] = text intent["intent"]["confidence"] = confidence return intent
def in_started(self, message: Any, sender: RhasspyActor) -> None: """Handle messages in started state.""" if isinstance(message, RecognizeIntent): try: intent = self.recognize(message.text) except Exception: self._logger.exception("in_started") intent = empty_intent() intent["text"] = message.text intent["speech_confidence"] = message.confidence self.send( message.receiver or sender, IntentRecognized(intent, handle=message.handle), )
def recognize_fuzzy(self, text: str, eps: str = "<eps>") -> Dict[str, Any]: """Do fuzzy breadth-first search on FST as graph.""" from rhasspy.train.jsgf2fst import symbols2intent # Assume lower case, white-space separated tokens tokens = re.split(r"\s+", text) if self.profile.get("intent.fsticuffs.ignore_unknown_words", True): # Filter tokens tokens = [w for w in tokens if w in self.words] # Only run search if there are any tokens intents = [] if len(tokens) > 0: intent_symbols_and_costs = FsticuffsRecognizer._get_symbols_and_costs( self.graph, tokens, stop_words=self.stop_words, eps=eps ) for symbols, cost in intent_symbols_and_costs.values(): intent = symbols2intent(symbols, eps=eps) intent["intent"]["confidence"] = (len(tokens) - cost) / len(tokens) intents.append(intent) intents = sorted( intents, key=lambda i: i["intent"]["confidence"], reverse=True ) self._logger.debug("Recognized %s intent(s)", len(intents)) # Use first intent if len(intents) > 0: intent = intents[0] # Add slots intent["slots"] = {} for ev in intent["entities"]: intent["slots"][ev["entity"]] = ev["value"] # Add alternative intents intent["intents"] = [] for other_intent in intents[1:]: intent["intents"].append(other_intent) self._logger.debug(intents) else: intent = empty_intent() intent["text"] = text return intent
def in_started(self, message: Any, sender: RhasspyActor) -> None: """Handle messages in started state.""" if isinstance(message, RecognizeIntent): try: intent = self.recognize(message.text) intent["intent"]["name"] = intent["intent"]["name"] or "" logging.debug(repr(intent)) except Exception: self._logger.exception("in_started") intent = empty_intent() intent["text"] = message.text intent["raw_text"] = message.text self.send( message.receiver or sender, IntentRecognized(intent, handle=message.handle), )
def recognize(self, text: str) -> Dict[str, Any]: """Run intent classifier and then named-entity recognizer.""" # pylint: disable=E0401 from flair.data import Sentence intent = empty_intent() sentence = Sentence(text) assert self.intent_map is not None if self.class_model is not None: self.class_model.predict(sentence) assert len(sentence.labels) > 0, "No intent predicted" label = sentence.labels[0] intent_id = label.value intent["intent"]["confidence"] = label.score else: # Assume first intent intent_id = next(iter(self.intent_map.keys())) intent["intent"]["confidence"] = 1 intent["intent"]["name"] = self.intent_map[intent_id] assert self.ner_models is not None if intent_id in self.ner_models: # Predict entities self.ner_models[intent_id].predict(sentence) ner_dict = sentence.to_dict(tag_type="ner") for named_entity in ner_dict["entities"]: intent["entities"].append({ "entity": named_entity["type"], "value": named_entity["text"], "start": named_entity["start_pos"], "end": named_entity["end_pos"], "confidence": named_entity["confidence"], }) return intent
def in_loaded(self, message: Any, sender: RhasspyActor) -> None: """Handle messages in loaded state.""" if isinstance(message, RecognizeIntent): try: self.load_fst() if self.fuzzy: # Fuzzy search intent = self.recognize_fuzzy(message.text) else: # Strict search intent = self.recognize(message.text) except Exception: self._logger.exception("in_loaded") intent = empty_intent() intent["speech_confidence"] = message.confidence self.send( message.receiver or sender, IntentRecognized(intent, handle=message.handle), )