1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
"""Intent recognition and handling."""
from dataclasses import asdict, dataclass, field
from typing import Any, Dict, List, Optional
from .event import Event, Eventable
DOMAIN = "intent"
_RECOGNIZE_TYPE = "recognize"
_INTENT_TYPE = "intent"
_NOT_RECOGNIZED_TYPE = "not-recognized"
@dataclass
class Entity:
"""Named entity with a value."""
name: str
value: Optional[Any] = None
@dataclass
class Recognize(Eventable):
"""Request to recognize an event from text."""
text: str
"""Text with intent in natural language."""
context: Optional[Dict[str, Any]] = None
"""Context from previous interactions."""
@staticmethod
def is_type(event_type: str) -> bool:
return event_type == _RECOGNIZE_TYPE
def event(self) -> Event:
data: Dict[str, Any] = {"text": self.text}
if self.context is not None:
data["context"] = self.context
return Event(type=_RECOGNIZE_TYPE, data=data)
@staticmethod
def from_event(event: Event) -> "Recognize":
return Recognize(text=event.data["text"], context=event.data.get("context"))
@dataclass
class Intent(Eventable):
"""Result of successful intent recognition."""
name: str
"""Name of intent."""
entities: List[Entity] = field(default_factory=list)
"""Named entities with values."""
text: Optional[str] = None
"""Human-readable response."""
context: Optional[Dict[str, Any]] = None
"""Context for next interaction."""
@staticmethod
def is_type(event_type: str) -> bool:
return event_type == _INTENT_TYPE
def event(self) -> Event:
data: Dict[str, Any] = {"name": self.name}
if self.entities:
data["entities"] = [asdict(entity) for entity in self.entities]
if self.text is not None:
data["text"] = self.text
if self.context is not None:
data["context"] = self.context
return Event(type=_INTENT_TYPE, data=data)
@staticmethod
def from_dict(data: Dict[str, Any]) -> "Intent":
entity_dicts = data.get("entities")
if entity_dicts:
entities: List[Entity] = [
Entity(**entity_dict) for entity_dict in entity_dicts
]
else:
entities = []
return Intent(
name=data["name"],
entities=entities,
text=data.get("text"),
context=data.get("context"),
)
@staticmethod
def from_event(event: Event) -> "Intent":
return Intent.from_dict(event.data)
def to_rhasspy(self) -> Dict[str, Any]:
return {
"intent": {
"name": self.name,
},
"entities": [
{"entity": entity.name, "value": entity.value}
for entity in self.entities
],
"slots": {entity.name: entity.value for entity in self.entities},
}
@dataclass
class NotRecognized(Eventable):
"""Result of intent recognition failure."""
text: Optional[str] = None
"""Human-readable response."""
context: Optional[Dict[str, Any]] = None
"""Context for next interaction."""
@staticmethod
def is_type(event_type: str) -> bool:
return event_type == _NOT_RECOGNIZED_TYPE
def event(self) -> Event:
data: Dict[str, Any] = {}
if self.text is not None:
data["text"] = self.text
if self.context is not None:
data["context"] = self.context
return Event(type=_NOT_RECOGNIZED_TYPE, data=data)
@staticmethod
def from_event(event: Event) -> "NotRecognized":
return NotRecognized(
text=event.data.get("text"), context=event.data.get("context")
)
|