rhino.py
Go to the documentation of this file.
1 #
2 # Copyright 2018-2022 Picovoice Inc.
3 #
4 # You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
5 # file accompanying this source.
6 #
7 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 # specific language governing permissions and limitations under the License.
10 #
11 
12 import os
13 from collections import namedtuple
14 from ctypes import *
15 from enum import Enum
16 
17 
18 class RhinoError(Exception):
19  pass
20 
21 
23  pass
24 
25 
27  pass
28 
29 
31  pass
32 
33 
35  pass
36 
37 
39  pass
40 
41 
43  pass
44 
45 
47  pass
48 
49 
51  pass
52 
53 
55  pass
56 
57 
59  pass
60 
61 
63  pass
64 
65 
66 class Rhino(object):
67  """
68  Python binding for Rhino Speech-to-Intent engine. It directly infers the user's intent from spoken commands in
69  real-time. Rhino processes incoming audio in consecutive frames and indicates if the inference is finalized. When
70  finalized, the inferred intent can be retrieved as structured data in the form of an intent string and pairs of
71  slots and values. The number of samples per frame can be attained by calling `.frame_length`. The incoming audio
72  needs to have a sample rate equal to `.sample_rate` and be 16-bit linearly-encoded. Rhino operates on single-channel
73  audio.
74  """
75 
76  class PicovoiceStatuses(Enum):
77  SUCCESS = 0
78  OUT_OF_MEMORY = 1
79  IO_ERROR = 2
80  INVALID_ARGUMENT = 3
81  STOP_ITERATION = 4
82  KEY_ERROR = 5
83  INVALID_STATE = 6
84  RUNTIME_ERROR = 7
85  ACTIVATION_ERROR = 8
86  ACTIVATION_LIMIT_REACHED = 9
87  ACTIVATION_THROTTLED = 10
88  ACTIVATION_REFUSED = 11
89 
90  _PICOVOICE_STATUS_TO_EXCEPTION = {
91  PicovoiceStatuses.OUT_OF_MEMORY: RhinoMemoryError,
92  PicovoiceStatuses.IO_ERROR: RhinoIOError,
93  PicovoiceStatuses.INVALID_ARGUMENT: RhinoInvalidArgumentError,
94  PicovoiceStatuses.STOP_ITERATION: RhinoStopIterationError,
95  PicovoiceStatuses.KEY_ERROR: RhinoKeyError,
96  PicovoiceStatuses.INVALID_STATE: RhinoInvalidStateError,
97  PicovoiceStatuses.RUNTIME_ERROR: RhinoRuntimeError,
98  PicovoiceStatuses.ACTIVATION_ERROR: RhinoActivationError,
99  PicovoiceStatuses.ACTIVATION_LIMIT_REACHED: RhinoActivationLimitError,
100  PicovoiceStatuses.ACTIVATION_THROTTLED: RhinoActivationThrottledError,
101  PicovoiceStatuses.ACTIVATION_REFUSED: RhinoActivationRefusedError
102  }
103 
104  Inference = namedtuple('Inference', ['is_understood', 'intent', 'slots'])
105  Inference.__doc__ = """"\
106  Immutable object with `.is_understood`, `.intent` , and `.slots` getters.
107 
108  :param is_understood: Indicates whether the intent was understood by Rhino.
109  :param intent: Name of intent that was inferred
110  :param slots: Dictionary of the slot keys and values extracted from the utterance.
111  """
112 
113  class CRhino(Structure):
114  pass
115 
116  def __init__(self, access_key, library_path, model_path, context_path, sensitivity=0.5, require_endpoint=True):
117  """
118  Constructor.
119 
120  :param access_key: AccessKey obtained from Picovoice Console (https://console.picovoice.ai/).
121  :param library_path: Absolute path to Rhino's dynamic library.
122  :param model_path: Absolute path to file containing model parameters.
123  :param context_path: Absolute path to file containing context parameters. A context represents the set of
124  expressions (spoken commands), intents, and intent arguments (slots) within a domain of interest.
125  :param sensitivity: Inference sensitivity. It should be a number within [0, 1]. A higher sensitivity value
126  results in fewer misses at the cost of (potentially) increasing the erroneous inference rate.
127  :param require_endpoint If set to `False`, Rhino does not require an endpoint (chunk of silence) before
128  finishing inference.
129  """
130 
131  if not access_key:
132  raise ValueError("access_key should be a non-empty string.")
133 
134  if not os.path.exists(library_path):
135  raise IOError("Couldn't find Rhino's dynamic library at '%s'." % library_path)
136 
137  library = cdll.LoadLibrary(library_path)
138 
139  if not os.path.exists(model_path):
140  raise IOError("Couldn't find model file at '%s'." % model_path)
141 
142  if not os.path.exists(context_path):
143  raise IOError("Couldn't find context file at '%s'." % context_path)
144 
145  if not 0 <= sensitivity <= 1:
146  raise ValueError("Sensitivity should be within [0, 1].")
147 
148  init_func = library.pv_rhino_init
149  init_func.argtypes = [
150  c_char_p,
151  c_char_p,
152  c_char_p,
153  c_float,
154  c_bool,
155  POINTER(POINTER(self.CRhino))]
156  init_func.restype = self.PicovoiceStatuses
157 
158  self._handle = POINTER(self.CRhino)()
159 
160  status = init_func(
161  access_key.encode('utf-8'),
162  model_path.encode('utf-8'),
163  context_path.encode('utf-8'),
164  sensitivity,
165  require_endpoint,
166  byref(self._handle))
167  if status is not self.PicovoiceStatuses.SUCCESS:
168  raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
169 
170  self._delete_func = library.pv_rhino_delete
171  self._delete_func.argtypes = [POINTER(self.CRhino)]
172  self._delete_func.restype = None
173 
174  self._process_func = library.pv_rhino_process
175  self._process_func.argtypes = [POINTER(self.CRhino), POINTER(c_short), POINTER(c_bool)]
176  self._process_func.restype = self.PicovoiceStatuses
177 
178  self._is_understood_func = library.pv_rhino_is_understood
179  self._is_understood_func.argtypes = [POINTER(self.CRhino), POINTER(c_bool)]
180  self._is_understood_func.restype = self.PicovoiceStatuses
181 
182  self._get_intent_func = library.pv_rhino_get_intent
183  self._get_intent_func.argtypes = [
184  POINTER(self.CRhino),
185  POINTER(c_char_p),
186  POINTER(c_int),
187  POINTER(POINTER(c_char_p)),
188  POINTER(POINTER(c_char_p))]
189  self._get_intent_func.restype = self.PicovoiceStatuses
190 
191  self._free_slots_and_values_func = library.pv_rhino_free_slots_and_values
192  self._free_slots_and_values_func.argtypes = [POINTER(self.CRhino), POINTER(c_char_p), POINTER(c_char_p)]
194 
195  self._reset_func = library.pv_rhino_reset
196  self._reset_func.argtypes = [POINTER(self.CRhino)]
197  self._reset_func.restype = self.PicovoiceStatuses
198 
199  context_info_func = library.pv_rhino_context_info
200  context_info_func.argtypes = [POINTER(self.CRhino), POINTER(c_char_p)]
201  context_info_func.restype = self.PicovoiceStatuses
202 
203  context_info = c_char_p()
204  status = context_info_func(self._handle, byref(context_info))
205  if status is not self.PicovoiceStatuses.SUCCESS:
206  raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
207 
208  self._context_info = context_info.value.decode('utf-8')
209 
210  version_func = library.pv_rhino_version
211  version_func.argtypes = []
212  version_func.restype = c_char_p
213  self._version = version_func().decode('utf-8')
214 
215  self._frame_length = library.pv_rhino_frame_length()
216 
217  self._sample_rate = library.pv_sample_rate()
218 
219  def delete(self):
220  """Releases resources acquired."""
221 
222  self._delete_func(self._handle)
223 
224  def process(self, pcm):
225  """
226  Processes a frame of audio and emits a flag indicating if the inference is finalized. When finalized,
227  `.get_inference()` should be called to retrieve the intent and slots, if the spoken command is considered valid.
228 
229  :param pcm: A frame of audio samples. The number of samples per frame can be attained by calling
230  `.frame_length`. The incoming audio needs to have a sample rate equal to `.sample_rate` and be 16-bit
231  linearly-encoded. Rhino operates on single-channel audio.
232  :return: Flag indicating if the inference is finalized.
233  """
234 
235  if len(pcm) != self.frame_length:
236  raise ValueError("Invalid frame length. expected %d but received %d" % (self.frame_length, len(pcm)))
237 
238  is_finalized = c_bool()
239  status = self._process_func(self._handle, (c_short * len(pcm))(*pcm), byref(is_finalized))
240  if status is not self.PicovoiceStatuses.SUCCESS:
241  raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
242 
243  return is_finalized.value
244 
245  def get_inference(self):
246  """
247  Gets inference results from Rhino. If the spoken command was understood, it includes the specific intent name
248  that was inferred, and (if applicable) slot keys and specific slot values. Should only be called after the
249  process function returns true, otherwise Rhino has not yet reached an inference conclusion.
250  :return Inference object with `.is_understood`, `.intent` , and `.slots` getters.
251  """
252 
253  is_understood = c_bool()
254  status = self._is_understood_func(self._handle, byref(is_understood))
255  if status is not self.PicovoiceStatuses.SUCCESS:
256  raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
257  is_understood = is_understood.value
258 
259  if is_understood:
260  intent = c_char_p()
261  num_slots = c_int()
262  slot_keys = POINTER(c_char_p)()
263  slot_values = POINTER(c_char_p)()
264  status = self._get_intent_func(
265  self._handle,
266  byref(intent),
267  byref(num_slots),
268  byref(slot_keys),
269  byref(slot_values))
270  if status is not self.PicovoiceStatuses.SUCCESS:
271  raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
272 
273  intent = intent.value.decode('utf-8')
274 
275  slots = dict()
276  for i in range(num_slots.value):
277  slots[slot_keys[i].decode('utf-8')] = slot_values[i].decode('utf-8')
278 
279  status = self._free_slots_and_values_func(self._handle, slot_keys, slot_values)
280  if status is not self.PicovoiceStatuses.SUCCESS:
281  raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
282  else:
283  intent = None
284  slots = dict()
285 
286  status = self._reset_func(self._handle)
287  if status is not self.PicovoiceStatuses.SUCCESS:
288  raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
289 
290  return self.Inference(is_understood=is_understood, intent=intent, slots=slots)
291 
292  @property
293  def context_info(self):
294  """Context information."""
295 
296  return self._context_info
297 
298  @property
299  def version(self):
300  """Version."""
301 
302  return self._version
303 
304  @property
305  def frame_length(self):
306  """Number of audio samples per frame."""
307 
308  return self._frame_length
309 
310  @property
311  def sample_rate(self):
312  """Audio sample rate accepted by Picovoice."""
313 
314  return self._sample_rate
python.rhino.Rhino.CRhino
Definition: rhino.py:113
python.rhino.RhinoActivationRefusedError
Definition: rhino.py:62
python.rhino.Rhino.version
def version(self)
Definition: rhino.py:299
python.rhino.Rhino
Definition: rhino.py:66
python.rhino.RhinoIOError
Definition: rhino.py:26
python.rhino.Rhino.__init__
def __init__(self, access_key, library_path, model_path, context_path, sensitivity=0.5, require_endpoint=True)
Definition: rhino.py:116
python.rhino.RhinoError
Definition: rhino.py:18
python.rhino.Rhino.context_info
def context_info(self)
Definition: rhino.py:293
python.rhino.RhinoKeyError
Definition: rhino.py:38
python.rhino.Rhino.delete
def delete(self)
Definition: rhino.py:219
python.rhino.RhinoActivationThrottledError
Definition: rhino.py:58
python.rhino.Rhino._version
_version
Definition: rhino.py:213
python.rhino.RhinoActivationLimitError
Definition: rhino.py:54
python.rhino.RhinoStopIterationError
Definition: rhino.py:34
python.rhino.Rhino._context_info
_context_info
Definition: rhino.py:208
python.rhino.Rhino._delete_func
_delete_func
Definition: rhino.py:170
python.rhino.RhinoMemoryError
Definition: rhino.py:22
python.rhino.RhinoActivationError
Definition: rhino.py:50
python.rhino.Rhino._is_understood_func
_is_understood_func
Definition: rhino.py:178
python.rhino.Rhino.frame_length
def frame_length(self)
Definition: rhino.py:305
python.rhino.RhinoInvalidStateError
Definition: rhino.py:42
python.rhino.Rhino._process_func
_process_func
Definition: rhino.py:174
python.rhino.Rhino._free_slots_and_values_func
_free_slots_and_values_func
Definition: rhino.py:191
python.rhino.Rhino.PicovoiceStatuses
Definition: rhino.py:76
python.rhino.Rhino.process
def process(self, pcm)
Definition: rhino.py:224
python.rhino.Rhino._reset_func
_reset_func
Definition: rhino.py:195
python.rhino.Rhino._handle
_handle
Definition: rhino.py:158
python.rhino.Rhino.sample_rate
def sample_rate(self)
Definition: rhino.py:311
python.rhino.Rhino._frame_length
_frame_length
Definition: rhino.py:215
python.rhino.Rhino._get_intent_func
_get_intent_func
Definition: rhino.py:182
python.rhino.Rhino._PICOVOICE_STATUS_TO_EXCEPTION
_PICOVOICE_STATUS_TO_EXCEPTION
Definition: rhino.py:90
python.rhino.RhinoInvalidArgumentError
Definition: rhino.py:30
python.rhino.RhinoRuntimeError
Definition: rhino.py:46
python.rhino.Rhino.get_inference
def get_inference(self)
Definition: rhino.py:245
python.rhino.Rhino._sample_rate
_sample_rate
Definition: rhino.py:217
python.rhino.Rhino.Inference
Inference
Definition: rhino.py:104


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:14:50