
.. _RefGrammar:

Grammars
****************************************************************************

Dragonfly's core is a language object model containing the following
objects:

 - *Grammars* -- these represent collections of *rules*.
 - *Rules* -- these implement complete or partial voice commands, and
   contain a hierarchy of *elements*.
 - *Elements* -- these form the language building blocks of voice commands,
   and represent literal words, element sequences, references to other
   rules, etc.


To illustrate this language model, we discuss an example grammar which
contains 2 voice commands: **"command one"** and **"(second command |
command two) [test]"**.

 - *Grammar*: container for the two voice commands
    - *Rule*: first voice command rule **"command one"**
       - *Literal element*: element for the literal words **"command one"**.
         This element is the root-element of the first command rule
    - *Rule*: second voice command rule **"(second command | command two) [test]"**
       - *Sequence element*: root-element of the second command rule
          - *Alternative element*: first child element of the sequence
             - *Literal element*: element for the literal words **"second command"**
             - *Literal element*: element for the literal words **"command two"**
          - *Optional element*: second child element of the sequence
             - *Literal element*: element for the literal words **"test"**

All of these different objects are described below and in subsections.


.. _RefGrammarClasses:

Grammar classes
============================================================================

Recognition callbacks
----------------------------------------------------------------------------

The speech recognition engine processes the audio it receives and calls
the following methods of grammar classes to notify them of the results:

 - ``Grammar.process_begin()``: Called when the engine detects the start
   of a phrase, e.g. when the user starts to speak. This method checks
   the grammar's context and activates or deactivates its rules depending
   on whether the context matches.
 - ``Grammar._process_begin()``: Called by ``Grammar.process_begin()``
   allowing derived classes to easily implement custom functionality without
   losing the context matching implemented in ``Grammar.process_begin()``.
 - ``Grammar.process_recognition()``: Called when recognition has completed
   successfully and results are meant for this grammar. If defined, this
   method should return whether to continue rule processing afterwards
   (``True`` or ``False``).
 - ``Grammar.process_recognition_other()``: Called when recognition has
   completed successfully, but the results are not meant for this grammar.
 - ``Grammar.process_recognition_failure()``: Called when recognition was
   not successful, e.g. the microphone picked up background noise.

The last three methods are not defined for the base Grammar class. They
are only called if they are defined for derived classes.


Example Grammar using recognition callbacks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

..  code-block:: python

    from dragonfly import Grammar

    class CallbackGrammar(Grammar):

        def process_recognition(self, words, results):
            print("process_recognition()")
            print(words)
            print(results)

            # Grammar rule processing should continue after this method.
            return True

        def process_recognition_other(self, words, results):
            print("process_recognition_other()")
            print(words)
            print(results)

        def process_recognition_failure(self, results):
            print("process_recognition_failure()")
            print(results)


.. _RefGrammarCallbackResultsTypes:

Recognition callbacks with results objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The last three methods mentioned above can define an optional ``results``
parameter, the value of which differs between each SR engine back-end:

=======================   ===========================================
SR engine back-end        Type of ``results`` objects
=======================   ===========================================
Dragon/Natlink            ``ResObj`` [*]_
Kaldi                     ``Recognition`` [*]_
CMU Pocket Sphinx         ``None``
WSR/SAPI 5                ``ISpeechRecoResultDispatch`` [*]_ [*]_
Text input ("text")       ``None``
=======================   ===========================================

.. [*] See the `natlink.txt`_ file for info on ``ResObj``.
.. [*] See :ref:`Kaldi documentation section <RefKaldiEngineResultsClass>`.
.. [*] See the SAPI 5 documentation on `ISpeechRecoResultDispatch`_
       for how to use it.
.. [*] SAPI 5 does not yield results objects for other grammars, so
       ``process_recognition_other()`` callbacks will return ``None``
       instead.


Grammar class
----------------------------------------------------------------------------

.. autoclass:: dragonfly.grammar.grammar_base.Grammar
   :members:
   :private-members: _process_begin


ConnectionGrammar class
----------------------------------------------------------------------------

.. autoclass:: dragonfly.grammar.grammar_connection.ConnectionGrammar
   :members: application, connection_up, connection_down


.. Links.
.. _natlink.txt: https://github.com/dictation-toolbox/natlink/blob/master/NatlinkSource/natlink.txt
.. _ISpeechRecoResultDispatch: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms722106(v=vs.85)
