profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/Danesprite/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

dictation-toolbox/dragonfly 217

Speech recognition framework allowing powerful Python-based scripting and extension of Dragon NaturallySpeaking (DNS), Windows Speech Recognition (WSR), Kaldi and CMU Pocket Sphinx

Danesprite/pyjsgf 30

JSpeech Grammar Format (JSGF) compiler, matcher and parser package for Python.

Danesprite/tts-util-app 10

TTS Util — Text-to-speech utility Android app for synthesising text into audible speech

Danesprite/kotlin-opengl-testing 7

Following the Displaying Graphics with OpenGL ES Android developer training class using Kotlin

Danesprite/todoist-org-mode 7

Convert Todoist projects into Org mode files

Danesprite/sphinxwrapper 4

Alternative Python API for recognising speech with CMU Pocket Sphinx

Danesprite/dictation-mode-grammar 3

Dragonfly Dictation Mode Grammar

Danesprite/magneto-host 1

Voice coding host

Danesprite/aenea 0

Client-server library for using voice macros from Dragon NaturallySpeaking and Dragonfly on remote/non-windows hosts.

Danesprite/atom-script 0

:runner: Run ( scripts | selections | source ) in Atom

startedDanesprite/todoist-org-mode

started time in 5 hours

push eventdictation-toolbox/dtactions

Quintijn

commit sha b9082028ccd6d1d23b4ee3cd2a4d7ff3a63dbda3

working on test procedure

view details

push time in 11 hours

push eventdictation-toolbox/dtactions

Quintijn

commit sha 7934bdf5d68ea22791a6ba11e2b512a734d83176

small change

view details

push time in 11 hours

push eventdictation-toolbox/dtactions

Quintijn

commit sha 794fc73a978d122762aec60151cb6a29ac681891

try to implement ! for use_hardware in sendkeys.py

view details

push time in 12 hours

Pull request review commentdictation-toolbox/dragonfly

Change the Choice element class to allow using list/tuple choices

 class Choice(Alternative):                     "previous"      : "pgup",                 }),             ]++        Example using a list:++        .. code:: python++            # Command for recognising and typing nth words, e.g.+            # 'type third'.+            mapping = {+                "type <nth>": Text("%(nth)s"),+            }+            extras = [+                Choice("nth", [+                    "first",+                    "second",+                    "third",+                    "fourth",+                    "fifth",+                    "sixth",+                    "seventh",+                    "eighth",+                    "(last | ninth)",

For this choice, if "last" is spoken, would the returned value be "last | nine" or "last"? I'm not 100% sure offhand, so it would probably be a good idea for the documentation to make it clear. 😃

Danesprite

comment created time in a day

pull request commentdictation-toolbox/dragonfly

Update Kaldi backend

@Danesprite It seems to build and look fine to me. Am I missing something?

daanzu

comment created time in 2 days

pull request commentdictation-toolbox/dragonfly

Talon integration

Here are installation instructions for anyone interested in testing this out:

  1. Install Talon.
  2. Clone dragonfly (or use existing clone): git clone git@github.com:dictation-toolbox/dragonfly.git dragonfly && cd dragonfly
  3. Check out this pull request: git fetch origin pull/326/head:talon && git checkout talon
  4. Pip install your dragonfly clone into Talon's copy of Python, along with any dependencies of your dragonfly grammars:
cd C:\Program Files\Talon
python -m pip install -e c:\path\to\dragonfly\clone
python -m pip install <other modules you need for your grammars>
  1. Copy your dragonfly grammars into your Talon user directory (on Windows: C:\Users\<username>\AppData\Roaming\talon\user). Feel free to nest these in a subdirectory.
  2. Start Talon and check the log for any issues (right-click Talon > Scripting > View Log).
  3. Start using the commands in your Dragonfly grammars! They'll work with any Talon speech backend (Dragon, Conformer, etc).
lunixbochs

comment created time in 2 days

push eventdictation-toolbox/dtactions

Quintijn

commit sha ffa56ead75d99db0b664c621e7cdb6de45446edc

documentation and detail module sendkeys.py

view details

push time in 2 days

push eventdictation-toolbox/dtactions

Quintijn

commit sha 1fcd1a916fba192b40dc355cc68df6aa5ade48b2

unsuccesful try to activate sendkeys.rst documentation

view details

push time in 3 days

push eventdictation-toolbox/dtactions

Quintijn

commit sha 59b33f1b4567028ad53670508efa1ce524fedefb

fix sendkeys, do not use Text, only Key

view details

Quintijn

commit sha b6aed3985a33b3c0040f9a74b655a1aef5aaa346

Merge branch 'makeflitinstall' of https://github.com/dictation-toolbox/dtactions into makeflitinstall

view details

push time in 3 days

startedKeNaCo/auto-changelog

started time in 4 days

issue commentdictation-toolbox/dragonfly

get_current_engine() says Sapi5InProcEngine() even tho I have loaded Kaldi

@Danesprite I think that makes sense and would be a good change. Also, I wonder if there should be a conspicuous warning message or something when this happens, where get_engine is called automatically because a grammar is loaded or whatever? This has definitely occurred other times, and been a bit confusing.

Treshank

comment created time in 4 days

issue closeddictation-toolbox/dragonfly

get_current_engine() says Sapi5InProcEngine() even tho I have loaded Kaldi

I'm not sure if this is an issue or I'm making a mistake somewhere, but every time I seem to import Grammar in a file and create functions to load them in the main.py, the engine changes Kaldi to sapi5 and I also get this error that Natlink requires 32bit python. Then no speech is detected at all. However if I create, add and load the grammars directly in main.py it works.

main.py is the same as kaldi_module_loader_plus.py except for the importing loadL1 and unloadL1 and using them when the system is awake and sleeping

I also found this issue occurring when I use Integer or IntegerRef.


# main.py
"""
Command-module loader for Kaldi.

This script is based on 'dfly-loader-wsr.py' written by Christo Butcher and
has been adapted to work with the Kaldi engine instead.

This script can be used to look for Dragonfly command-modules for use with
the Kaldi engine. It scans the directory it's in and loads any ``_*.py`` it
finds.
"""


# TODO Have a simple GUI for pausing, resuming, cancelling and stopping
# recognition, etc

from __future__ import print_function

import logging
import os.path
import sys

import six

from dragonfly import get_engine, get_current_engine
from dragonfly import Grammar, MappingRule, Function, Dictation, FuncContext
from dragonfly.loader import CommandModuleDirectory
from dragonfly.log import setup_log
# from CustomGrammars import l1Grammars
from grammarContoller import loadL1, unloadL1


# --------------------------------------------------------------------------
# Set up basic logging.

if False:
    # Debugging logging for reporting trouble
    logging.basicConfig(level=10)
    logging.getLogger('grammar.decode').setLevel(20)
    logging.getLogger('grammar.begin').setLevel(20)
    logging.getLogger('compound').setLevel(20)
    logging.getLogger('kaldi.compiler').setLevel(10)
else:
    setup_log()


# --------------------------------------------------------------------------
# User notification / rudimentary UI. MODIFY AS DESIRED

# For message in ('sleep', 'wake')
def notify(message):
    if message == 'sleep':
        print("Sleeping...")
        # get_engine().speak("Sleeping")
    elif message == 'wake':
        print("Awake...")
        # get_engine().speak("Awake")


# --------------------------------------------------------------------------
# Sleep/wake grammar. (This can be unused or removed if you don't want it.)

sleeping = False

def load_sleep_wake_grammar(initial_awake):
    sleep_grammar = Grammar("sleep")
    def sleep(force=False):
        global sleeping
        if not sleeping or force:
            sleeping = True
            unloadL1()
            sleep_grammar.set_exclusiveness(True)
        notify('sleep')

    def wake(force=False):
        global sleeping
        if sleeping or force:
            sleeping = False
            loadL1()
            sleep_grammar.set_exclusiveness(False)
        notify('wake')

    class SleepRule(MappingRule):
        mapping = {
            "start listening":  Function(wake) + Function(lambda: get_engine().start_saving_adaptation_state()),
            "stop listening":   Function(lambda: get_engine().stop_saving_adaptation_state()) + Function(sleep),
            "halt listening":   Function(lambda: get_engine().stop_saving_adaptation_state()) + Function(sleep),
        }
    sleep_grammar.add_rule(SleepRule())

    sleep_noise_rule = MappingRule(
        name = "sleep_noise_rule",
        mapping = { "<text>": Function(lambda text: False and print(text)) },
        extras = [ Dictation("text") ],
        context = FuncContext(lambda: sleeping),
    )
    sleep_grammar.add_rule(sleep_noise_rule)

    sleep_grammar.load()

    if initial_awake:
        wake(force=True)
    else:
        sleep(force=True)


# --------------------------------------------------------------------------
# Main event driving loop.

def main():
    logging.basicConfig(level=logging.INFO)

    try:
        path = os.path.dirname(__file__)
    except NameError:
        # The "__file__" name is not always available, for example
        # when this module is run from PythonWin.  In this case we
        # simply use the current working directory.
        path = os.getcwd()
        __file__ = os.path.join(path, "kaldi_module_loader_plus.py")

    # Set any configuration options here as keyword arguments.
    # See Kaldi engine documentation for all available options and more info.
    engine = get_engine('kaldi',
        model_dir='../kaldi_model',  # default model directory
        # vad_aggressiveness=3,  # default aggressiveness of VAD
        # vad_padding_start_ms=150,  # default ms of required silence before VAD
        # vad_padding_end_ms=150,  # default ms of required silence after VAD
        # vad_complex_padding_end_ms=500,  # default ms of required silence after VAD for complex utterances
        # input_device_index=None,  # set to an int to choose a non-default microphone
        lazy_compilation=True,  # set to True to parallelize & speed up loading
        # retain_dir=None,  # set to a writable directory path to retain recognition metadata and/or audio data
        # retain_audio=None,  # set to True to retain speech data wave files in the retain_dir (if set)
    )

    # Call connect() now that the engine configuration is set.
    engine.connect()

    # Load grammars.
    load_sleep_wake_grammar(True)

    directory = CommandModuleDirectory(path, excludes=[__file__])
    directory.load()

    # Define recognition callback functions.
    def on_begin():
        print("Speech start detected.")

    def on_recognition(words):
        message = u"Recognized: %s" % u" ".join(words)

        # This only seems to be an issue with Python 2.7 on Windows.
        if six.PY2:
            encoding = sys.stdout.encoding or "ascii"
            message = message.encode(encoding, errors='replace')
        print(message)

    def on_failure():
        print("Sorry, what was that?")

    # Start the engine's main recognition loop
    engine.prepare_for_recognition()
    try:
        print("Listening...")
        print(get_current_engine())
        engine.do_recognition(on_begin, on_recognition, on_failure)
    except KeyboardInterrupt:
        pass


if __name__ == "__main__":
    main()
# grammarContoller.py File

from dragonfly import Grammar
from CustomGrammars import l1Grammars


l1_grammar = Grammar('Level 1 Grammar')
l1_grammar.add_rule(l1Grammars.MainGrammarRules())
l1_grammar.add_rule(l1Grammars.FunctionGrammars())

def unloadL1():
    l1_grammar.unload()

def loadL1():
    l1_grammar.load()

closed time in 5 days

Treshank

issue commentdictation-toolbox/dragonfly

get_current_engine() says Sapi5InProcEngine() even tho I have loaded Kaldi

Thanks @daanzu Solved the problem

Treshank

comment created time in 5 days

issue commentdictation-toolbox/dragonfly

get_current_engine() says Sapi5InProcEngine() even tho I have loaded Kaldi

I haven't tested this myself to verify it, but I think your problem may be that you are importing and building the grammars before you have initially called get_engine. What if you move the import line to be after that? By the way, you don't actually need to load and unload your grammars for the wake/sleep: that grammar is specially marked as exclusive, so it should automatically effectively disable all other grammars (that are not also marked as exclusive) whenever it is asleep.

Seems to have solved the problem. I shall test it a little more and close the issue

Treshank

comment created time in 5 days

issue commentdictation-toolbox/dragonfly

get_current_engine() says Sapi5InProcEngine() even tho I have loaded Kaldi

I haven't tested this myself to verify it, but I think your problem may be that you are importing and building the grammars before you have initially called get_engine. What if you move the import line to be after that? By the way, you don't actually need to load and unload your grammars for the wake/sleep: that grammar is specially marked as exclusive, so it should automatically effectively disable all other grammars (that are not also marked as exclusive) whenever it is asleep.

Treshank

comment created time in 5 days

issue openeddictation-toolbox/dragonfly

get_current_engine() says Sapi5InProcEngine() even tho I have loaded Kaldi

I'm not sure if this is an issue or I'm making a mistake somewhere, but every time I seem to import Grammar in a file and create functions to load them in the main.py, the engine changes Kaldi to sapi5 and I also get this error that Natlink requires 32bit python. Then no speech is detected at all. However if I create, add and load the grammars directly in main.py it works.

main.py is the same as kaldi_module_loader_plus.py except for the importing loadL1 and unloadL1 and using them when the system is awake and sleeping

I also found this issue occurring when I use Integer or IntegerRef.


# main.py
"""
Command-module loader for Kaldi.

This script is based on 'dfly-loader-wsr.py' written by Christo Butcher and
has been adapted to work with the Kaldi engine instead.

This script can be used to look for Dragonfly command-modules for use with
the Kaldi engine. It scans the directory it's in and loads any ``_*.py`` it
finds.
"""


# TODO Have a simple GUI for pausing, resuming, cancelling and stopping
# recognition, etc

from __future__ import print_function

import logging
import os.path
import sys

import six

from dragonfly import get_engine, get_current_engine
from dragonfly import Grammar, MappingRule, Function, Dictation, FuncContext
from dragonfly.loader import CommandModuleDirectory
from dragonfly.log import setup_log
# from CustomGrammars import l1Grammars
from grammarContoller import loadL1, unloadL1


# --------------------------------------------------------------------------
# Set up basic logging.

if False:
    # Debugging logging for reporting trouble
    logging.basicConfig(level=10)
    logging.getLogger('grammar.decode').setLevel(20)
    logging.getLogger('grammar.begin').setLevel(20)
    logging.getLogger('compound').setLevel(20)
    logging.getLogger('kaldi.compiler').setLevel(10)
else:
    setup_log()


# --------------------------------------------------------------------------
# User notification / rudimentary UI. MODIFY AS DESIRED

# For message in ('sleep', 'wake')
def notify(message):
    if message == 'sleep':
        print("Sleeping...")
        # get_engine().speak("Sleeping")
    elif message == 'wake':
        print("Awake...")
        # get_engine().speak("Awake")


# --------------------------------------------------------------------------
# Sleep/wake grammar. (This can be unused or removed if you don't want it.)

sleeping = False

def load_sleep_wake_grammar(initial_awake):
    sleep_grammar = Grammar("sleep")
    def sleep(force=False):
        global sleeping
        if not sleeping or force:
            sleeping = True
            unloadL1()
            sleep_grammar.set_exclusiveness(True)
        notify('sleep')

    def wake(force=False):
        global sleeping
        if sleeping or force:
            sleeping = False
            loadL1()
            sleep_grammar.set_exclusiveness(False)
        notify('wake')

    class SleepRule(MappingRule):
        mapping = {
            "start listening":  Function(wake) + Function(lambda: get_engine().start_saving_adaptation_state()),
            "stop listening":   Function(lambda: get_engine().stop_saving_adaptation_state()) + Function(sleep),
            "halt listening":   Function(lambda: get_engine().stop_saving_adaptation_state()) + Function(sleep),
        }
    sleep_grammar.add_rule(SleepRule())

    sleep_noise_rule = MappingRule(
        name = "sleep_noise_rule",
        mapping = { "<text>": Function(lambda text: False and print(text)) },
        extras = [ Dictation("text") ],
        context = FuncContext(lambda: sleeping),
    )
    sleep_grammar.add_rule(sleep_noise_rule)

    sleep_grammar.load()

    if initial_awake:
        wake(force=True)
    else:
        sleep(force=True)


# --------------------------------------------------------------------------
# Main event driving loop.

def main():
    logging.basicConfig(level=logging.INFO)

    try:
        path = os.path.dirname(__file__)
    except NameError:
        # The "__file__" name is not always available, for example
        # when this module is run from PythonWin.  In this case we
        # simply use the current working directory.
        path = os.getcwd()
        __file__ = os.path.join(path, "kaldi_module_loader_plus.py")

    # Set any configuration options here as keyword arguments.
    # See Kaldi engine documentation for all available options and more info.
    engine = get_engine('kaldi',
        model_dir='../kaldi_model',  # default model directory
        # vad_aggressiveness=3,  # default aggressiveness of VAD
        # vad_padding_start_ms=150,  # default ms of required silence before VAD
        # vad_padding_end_ms=150,  # default ms of required silence after VAD
        # vad_complex_padding_end_ms=500,  # default ms of required silence after VAD for complex utterances
        # input_device_index=None,  # set to an int to choose a non-default microphone
        lazy_compilation=True,  # set to True to parallelize & speed up loading
        # retain_dir=None,  # set to a writable directory path to retain recognition metadata and/or audio data
        # retain_audio=None,  # set to True to retain speech data wave files in the retain_dir (if set)
    )

    # Call connect() now that the engine configuration is set.
    engine.connect()

    # Load grammars.
    load_sleep_wake_grammar(True)

    directory = CommandModuleDirectory(path, excludes=[__file__])
    directory.load()

    # Define recognition callback functions.
    def on_begin():
        print("Speech start detected.")

    def on_recognition(words):
        message = u"Recognized: %s" % u" ".join(words)

        # This only seems to be an issue with Python 2.7 on Windows.
        if six.PY2:
            encoding = sys.stdout.encoding or "ascii"
            message = message.encode(encoding, errors='replace')
        print(message)

    def on_failure():
        print("Sorry, what was that?")

    # Start the engine's main recognition loop
    engine.prepare_for_recognition()
    try:
        print("Listening...")
        print(get_current_engine())
        engine.do_recognition(on_begin, on_recognition, on_failure)
    except KeyboardInterrupt:
        pass


if __name__ == "__main__":
    main()
# grammarContoller.py File

from dragonfly import Grammar
from CustomGrammars import l1Grammars


l1_grammar = Grammar('Level 1 Grammar')
l1_grammar.add_rule(l1Grammars.MainGrammarRules())
l1_grammar.add_rule(l1Grammars.FunctionGrammars())

def unloadL1():
    l1_grammar.unload()

def loadL1():
    l1_grammar.load()

created time in 5 days

pull request commentdictation-toolbox/dragonfly

Talon integration

Does dragonfly normally allow two grammars to have the same name?

Sorry, bad test case. If I change the second name, it does work properly. But there is a bug to report -- it just takes a more complicated example to demonstrate:

from dragonfly import (
    Dictation,
    Grammar,
    IntegerRef,
    Key,
    MappingRule,
    Text,
)

class CommandRule(MappingRule):
    mapping = {
        "hello world [<n>]": Text("This is working!"),
    }
    extras = [IntegerRef("n", 1, 10, default=1)]

grammar = Grammar("DragonflyTest")
grammar.add_rule(CommandRule())
grammar.load()


class SecondCommandRule(MappingRule):
    mapping = {
        "goodbye world [<n>]": Text("This is also working!"),
    }
    extras = [IntegerRef("n", 1, 10, default=1)]

second_grammar = Grammar("DragonflyTest2")
second_grammar.add_rule(SecondCommandRule())
second_grammar.load()

Note multiple conditions for this repro to work (I tested without each of these):

  1. IntegerRef must be added and used in the grammars.
  2. Two grammars using IntegerRef must be present.

Fails like so:

2021-04-11 18:03:01 ERROR defer_load() failed
   18:                                                                      threading.py:912* # loader thread
   17:                                                                      threading.py:954* 
   16:                                                                      threading.py:892* 
   15:                                                           app\resources\loader.py:715| 
   14:                                                           app\resources\loader.py:693| 
   13:                                                           app\resources\loader.py:235| 
   12:                                                  user\dragonfly\dragonfly_test.py:29 | second_grammar.load()
   11:         c:\users\james\projects\talon_dragonfly\dragonfly\grammar\grammar_base.py:451| lst._update()
   10: c:\users\james\projects\talon_dragonfly\dragonfly\engines\backend_talon\engine.py:67 | self._grammar_wrappers[grammar.name] =..
    9: c:\users\james\projects\talon_dragonfly\dragonfly\engines\backend_talon\engine.py:82 | return wrapper
    8:                                                   talon\experimental\dragonfly.py:87 | 
    7:                                                         talon\scripting\module.py:80 | 
    6:                                                           talon\scripting\rctx.py:42 | 
    5:                                                           talon\scripting\rctx.py:96 | # [stack splice]
    4:                                                           talon\scripting\rctx.py:59 | 
    3:                                                                          <string>:1  | 
    2:                                                         talon\scripting\module.py:82 | 
    1:                                                       talon\scripting\registry.py:188| 
talon.scripting.types.DuplicateError: user.dragonfly.dragonfly_test
2021-04-11 18:03:01    IO root (ERROR): defer_load() failed
   18:                                                                      threading.py:912* # loader thread
   17:                                                                      threading.py:954* 
   16:                                                                      threading.py:892* 
   15:                                                           app\resources\loader.py:715| 
   14:                                                           app\resources\loader.py:693| 
   13:                                                           app\resources\loader.py:235| 
   12:                                                  user\dragonfly\dragonfly_test.py:29 | second_grammar.load()
   11:         c:\users\james\projects\talon_dragonfly\dragonfly\grammar\grammar_base.py:451| lst._update()
   10: c:\users\james\projects\talon_dragonfly\dragonfly\engines\backend_talon\engine.py:67 | self._grammar_wrappers[grammar.name] =..
    9: c:\users\james\projects\talon_dragonfly\dragonfly\engines\backend_talon\engine.py:82 | return wrapper
    8:                                                   talon\experimental\dragonfly.py:87 | 
    7:                                                         talon\scripting\module.py:80 | 
    6:                                                           talon\scripting\rctx.py:42 | 
    5:                                                           talon\scripting\rctx.py:96 | # [stack splice]
    4:                                                           talon\scripting\rctx.py:59 | 
    3:                                                                          <string>:1  | 
    2:                                                         talon\scripting\module.py:82 | 
    1:                                                       talon\scripting\registry.py:188| 
talon.scripting.types.DuplicateError: user.dragonfly.dragonfly_test
2021-04-11 18:03:02 WARNING rule referenced but not declared: user.dragonfly_DragonflyTest2__IntegerRef_36
2021-04-11 18:03:02    IO root (WARNING): rule referenced but not declared: user.dragonfly_DragonflyTest2__IntegerRef_36
2021-04-11 18:03:02 WARNING rule referenced but not declared: user.dragonfly_DragonflyTest2__IntegerRef_36
2021-04-11 18:03:02    IO root (WARNING): rule referenced but not declared: user.dragonfly_DragonflyTest2__IntegerRef_36
lunixbochs

comment created time in 8 days

pull request commentdictation-toolbox/dragonfly

Talon integration

Does dragonfly normally allow two grammars to have the same name?

lunixbochs

comment created time in 8 days

pull request commentdictation-toolbox/dragonfly

Talon integration

Also, regarding scipy: I'm currently using scikit-image which pulls this in. I am mostly just using this for Otsu thresholding. The way the code is structured, thresholding can be applied independently of the OCR backend, but in practice it is not needed for WinRT (just Tesseract). OpenCV also supports Otsu thresholding although it does not support adaptive Otsu thresholding out of the box, which I use in my "quality" presets for constructing a Tesseract reader. So basically, I could probably make it an optional dependency but it would be a minor pain to structure and I probably won't get to it right away. How do you feel about the other dependencies:

        "numpy",
        "pillow",
        "rapidfuzz",
lunixbochs

comment created time in 8 days

pull request commentdictation-toolbox/dragonfly

Talon integration

Here's a simple example that demonstrates multiple grammars in one file not working:

from dragonfly import (
    Dictation,
    Grammar,
    IntegerRef,
    Key,
    MappingRule,
    Text,
)

class CommandRule(MappingRule):
    mapping = {
        "hello world": Text("This is working!"),
    }

grammar = Grammar("DragonflyTest")
grammar.add_rule(CommandRule())
grammar.load()


class SecondCommandRule(MappingRule):
    mapping = {
        "goodbye world": Text("This is also working!"),
    }

second_grammar = Grammar("DragonflyTest")
second_grammar.add_rule(SecondCommandRule())
second_grammar.load()

Fails with:

2021-04-11 13:04:58 ERROR defer_load() failed
   23:                                                                      threading.py:912* # cron thread
   22:                                                                      threading.py:954* 
   21:                                                                      threading.py:892* 
   20:                                                                     talon\cron.py:123| 
   19:                                                                     talon\cron.py:83 | 
   18:                                                                       talon\fs.py:54 | 
   17:                                                                       talon\fs.py:47 | 
   16:                                                           talon\scripting\rctx.py:225| # 'fs' main:on_change()
   15:                                                           app\resources\loader.py:669| 
   14:                                                           app\resources\loader.py:621| 
   13:                                                           app\resources\loader.py:235| 
   12:                                                  user\dragonfly\dragonfly_test.py:27 | second_grammar.load()
   11:         c:\users\james\projects\talon_dragonfly\dragonfly\grammar\grammar_base.py:451| lst._update()
   10: c:\users\james\projects\talon_dragonfly\dragonfly\engines\backend_talon\engine.py:67 | self._grammar_wrappers[grammar.name] =..
    9: c:\users\james\projects\talon_dragonfly\dragonfly\engines\backend_talon\engine.py:82 | return wrapper
    8:                                                   talon\experimental\dragonfly.py:87 | 
    7:                                                        talon\scripting\context.py:282| 
    6:                                                           talon\scripting\rctx.py:42 | 
    5:                                                           talon\scripting\rctx.py:96 | # [stack splice]
    4:                                                           talon\scripting\rctx.py:59 | 
    3:                                                                          <string>:1  | 
    2:                                                        talon\scripting\context.py:290| 
    1:                                                       talon\scripting\registry.py:267| 
talon.scripting.types.DuplicateError: user.dragonfly.dragonfly_test.DragonflyTest
lunixbochs

comment created time in 8 days

Pull request review commentdictation-toolbox/dragonfly

Talon integration

+#+# This file is part of Dragonfly.+# (c) Copyright 2007, 2008 by Christo Butcher+# Licensed under the LGPL.+#+#   Dragonfly is free software: you can redistribute it and/or modify it+#   under the terms of the GNU Lesser General Public License as published+#   by the Free Software Foundation, either version 3 of the License, or+#   (at your option) any later version.+#+#   Dragonfly is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+#   Lesser General Public License for more details.+#+#   You should have received a copy of the GNU Lesser General Public+#   License along with Dragonfly.  If not, see+#   <http://www.gnu.org/licenses/>.+#++# pylint: disable=E0401+from talon import ui++from .base_monitor import BaseMonitor+from .rectangle import Rectangle+++#===========================================================================+# Monitor class for storing info about a single display monitor.++class TalonMonitor(BaseMonitor):+    """+    The monitor class used under Talon.+    """++    @classmethod+    def get_all_monitors(cls):+        monitors = []+        for screen in ui.screens():+            rectangle = Rectangle(screen.x, screen.y, screen.width, screen.height)+            monitors.append(cls.get_monitor(screen, rectangle))

Sounds good.

lunixbochs

comment created time in 8 days

Pull request review commentdictation-toolbox/dragonfly

Talon integration

+#+# This file is part of Dragonfly.+# (c) Copyright 2007, 2008 by Christo Butcher+# Licensed under the LGPL.+#+#   Dragonfly is free software: you can redistribute it and/or modify it+#   under the terms of the GNU Lesser General Public License as published+#   by the Free Software Foundation, either version 3 of the License, or+#   (at your option) any later version.+#+#   Dragonfly is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+#   Lesser General Public License for more details.+#+#   You should have received a copy of the GNU Lesser General Public+#   License along with Dragonfly.  If not, see+#   <http://www.gnu.org/licenses/>.+#++from talon import ctrl++from ._base import BaseButtonEvent, MoveEvent+++#---------------------------------------------------------------------------+# Functions and event delegate for getting and setting the cursor position.++def get_cursor_position():+    ctrl.mouse_pos()+++def set_cursor_position(x, y):+    ctrl.mouse_move(x, y)+    return True+++class MoveEventDelegate(object):+    @classmethod+    def get_position(cls):+        return get_cursor_position()++    @classmethod+    def set_position(cls, x, y):+        return set_cursor_position(x, y)+++# Set MoveEvent's delegate. This allows us to set platform-specific+# functions for getting and setting the cursor position without having+# to do a lot of sub-classing for no good reason.+MoveEvent.delegate = MoveEventDelegate()++#---------------------------------------------------------------------------+# Pynput mouse button and wheel up/down flags.+++_buttons = {+    'left': 0,+    'right': 1,+    'middle': 2,+    'four': 3,+    'five': 4,+}+def get_button(name):+    return buttons.get(name, None)+++PLATFORM_BUTTON_FLAGS = {+    # ((button, event_type), down)+    # The inner pair is used here and below to be compatible with the+    # original Windows flags.+    "left":   (((0, 0), 1),  # down+               ((0, 0), 0)),  # up+    "right":  (((1, 0), 1),+               ((2, 0), 0)),+    "middle": (((2, 0), 1),+               ((2, 0), 0)),++    # We call these "four" and "five" because Windows calls them that.+    # These buttons typically behave as browser back and forward media keys.+    "four": (((3, 0), 1),+             ((3, 0), 0)),+    "five": (((4, 0), 1),+             ((4, 0), 0)),+}++PLATFORM_WHEEL_FLAGS = {+    # ((button, event_type), scroll_count)+    "wheelup": (('up', 1), 3),+    "stepup": (('up', 1), 1),+    "wheeldown": (('down', 1), 3),+    "stepdown": (('down', 1), 1),+    "wheelright": (('right', 1), 3),+    "stepright": (('right', 1), 1),+    "wheelleft": (('left', 1), 3),+    "stepleft": (('left', 1), 1),+}+++#---------------------------------------------------------------------------+# event classes.+++class ButtonEvent(BaseButtonEvent):++    def execute(self, window):+        for ((button, event_type), flag) in self._flags:+            # Check if the button is unknown.+            if button is None:+                event_type_s = "button" if event_type == 0 else "scroll"+                raise ValueError("Unsupported %s event" % event_type_s)++            if event_type == 0:  # Button press event+                ctrl.mouse_click(button, down=flag)

Not urgent to get this working on my machine, but I'll note that the latest published beta (talon-windows-108-0.1.5-51-g3121.exe) still has this bug.

lunixbochs

comment created time in 8 days

pull request commentdictation-toolbox/dragonfly

Talon integration

Cool, can you come up with a repro for grammars not working so I can work on it?

For scipy, is it possible for you to remove that as a dependency? We do have opencv and numpy available in Talon at the moment.

The python executable in the Talon directory is pure cpython, but the python running inside Talon is not exactly. Complex dependencies like scipy will work best if I ship them with Talon (they won't import on Mac otherwise, for example). I'm not currently shipping scipy because it's a bit heavy.

lunixbochs

comment created time in 9 days

Pull request review commentdictation-toolbox/dragonfly

Talon integration

+#+# This file is part of Dragonfly.+# (c) Copyright 2007, 2008 by Christo Butcher+# Licensed under the LGPL.+#+#   Dragonfly is free software: you can redistribute it and/or modify it+#   under the terms of the GNU Lesser General Public License as published+#   by the Free Software Foundation, either version 3 of the License, or+#   (at your option) any later version.+#+#   Dragonfly is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+#   Lesser General Public License for more details.+#+#   You should have received a copy of the GNU Lesser General Public+#   License along with Dragonfly.  If not, see+#   <http://www.gnu.org/licenses/>.+#++# pylint: disable=E0401+from talon import ui++from .base_monitor import BaseMonitor+from .rectangle import Rectangle+++#===========================================================================+# Monitor class for storing info about a single display monitor.++class TalonMonitor(BaseMonitor):+    """+    The monitor class used under Talon.+    """++    @classmethod+    def get_all_monitors(cls):+        monitors = []+        for screen in ui.screens():+            rectangle = Rectangle(screen.x, screen.y, screen.width, screen.height)+            monitors.append(cls.get_monitor(screen, rectangle))

I would probably just use id(screen) there

lunixbochs

comment created time in 9 days

Pull request review commentdictation-toolbox/dragonfly

Talon integration

+#+# This file is part of Dragonfly.+# (c) Copyright 2007, 2008 by Christo Butcher+# Licensed under the LGPL.+#+#   Dragonfly is free software: you can redistribute it and/or modify it+#   under the terms of the GNU Lesser General Public License as published+#   by the Free Software Foundation, either version 3 of the License, or+#   (at your option) any later version.+#+#   Dragonfly is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+#   Lesser General Public License for more details.+#+#   You should have received a copy of the GNU Lesser General Public+#   License along with Dragonfly.  If not, see+#   <http://www.gnu.org/licenses/>.+#++from talon import ctrl++from ._base import BaseButtonEvent, MoveEvent+++#---------------------------------------------------------------------------+# Functions and event delegate for getting and setting the cursor position.++def get_cursor_position():+    ctrl.mouse_pos()+++def set_cursor_position(x, y):+    ctrl.mouse_move(x, y)+    return True+++class MoveEventDelegate(object):+    @classmethod+    def get_position(cls):+        return get_cursor_position()++    @classmethod+    def set_position(cls, x, y):+        return set_cursor_position(x, y)+++# Set MoveEvent's delegate. This allows us to set platform-specific+# functions for getting and setting the cursor position without having+# to do a lot of sub-classing for no good reason.+MoveEvent.delegate = MoveEventDelegate()++#---------------------------------------------------------------------------+# Pynput mouse button and wheel up/down flags.+++_buttons = {+    'left': 0,+    'right': 1,+    'middle': 2,+    'four': 3,+    'five': 4,+}+def get_button(name):+    return buttons.get(name, None)+++PLATFORM_BUTTON_FLAGS = {+    # ((button, event_type), down)+    # The inner pair is used here and below to be compatible with the+    # original Windows flags.+    "left":   (((0, 0), 1),  # down+               ((0, 0), 0)),  # up+    "right":  (((1, 0), 1),+               ((2, 0), 0)),+    "middle": (((2, 0), 1),+               ((2, 0), 0)),++    # We call these "four" and "five" because Windows calls them that.+    # These buttons typically behave as browser back and forward media keys.+    "four": (((3, 0), 1),+             ((3, 0), 0)),+    "five": (((4, 0), 1),+             ((4, 0), 0)),+}++PLATFORM_WHEEL_FLAGS = {+    # ((button, event_type), scroll_count)+    "wheelup": (('up', 1), 3),+    "stepup": (('up', 1), 1),+    "wheeldown": (('down', 1), 3),+    "stepdown": (('down', 1), 1),+    "wheelright": (('right', 1), 3),+    "stepright": (('right', 1), 1),+    "wheelleft": (('left', 1), 3),+    "stepleft": (('left', 1), 1),+}+++#---------------------------------------------------------------------------+# event classes.+++class ButtonEvent(BaseButtonEvent):++    def execute(self, window):+        for ((button, event_type), flag) in self._flags:+            # Check if the button is unknown.+            if button is None:+                event_type_s = "button" if event_type == 0 else "scroll"+                raise ValueError("Unsupported %s event" % event_type_s)++            if event_type == 0:  # Button press event+                ctrl.mouse_click(button, down=flag)

That's an unrelated bug in Talon on Windows. The fix is already in beta and will be released as part of v0.2. As a workaround, you should be able to do:

if flag: ctrl.mouse_click(button, down=True)
else: ctrl.mouse_click(button, up=True)
lunixbochs

comment created time in 9 days

Pull request review commentdictation-toolbox/dragonfly

Talon integration

+#+# This file is part of Dragonfly.+# (c) Copyright 2007, 2008 by Christo Butcher+# Licensed under the LGPL.+#+#   Dragonfly is free software: you can redistribute it and/or modify it+#   under the terms of the GNU Lesser General Public License as published+#   by the Free Software Foundation, either version 3 of the License, or+#   (at your option) any later version.+#+#   Dragonfly is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+#   Lesser General Public License for more details.+#+#   You should have received a copy of the GNU Lesser General Public+#   License along with Dragonfly.  If not, see+#   <http://www.gnu.org/licenses/>.+#++from talon import ctrl++from ._base import BaseButtonEvent, MoveEvent+++#---------------------------------------------------------------------------+# Functions and event delegate for getting and setting the cursor position.++def get_cursor_position():+    ctrl.mouse_pos()+++def set_cursor_position(x, y):+    ctrl.mouse_move(x, y)+    return True+++class MoveEventDelegate(object):+    @classmethod+    def get_position(cls):+        return get_cursor_position()++    @classmethod+    def set_position(cls, x, y):+        return set_cursor_position(x, y)+++# Set MoveEvent's delegate. This allows us to set platform-specific+# functions for getting and setting the cursor position without having+# to do a lot of sub-classing for no good reason.+MoveEvent.delegate = MoveEventDelegate()++#---------------------------------------------------------------------------+# Pynput mouse button and wheel up/down flags.+++_buttons = {+    'left': 0,+    'right': 1,+    'middle': 2,+    'four': 3,+    'five': 4,+}+def get_button(name):+    return buttons.get(name, None)+++PLATFORM_BUTTON_FLAGS = {+    # ((button, event_type), down)+    # The inner pair is used here and below to be compatible with the+    # original Windows flags.+    "left":   (((0, 0), 1),  # down+               ((0, 0), 0)),  # up+    "right":  (((1, 0), 1),+               ((2, 0), 0)),+    "middle": (((2, 0), 1),+               ((2, 0), 0)),++    # We call these "four" and "five" because Windows calls them that.+    # These buttons typically behave as browser back and forward media keys.+    "four": (((3, 0), 1),+             ((3, 0), 0)),+    "five": (((4, 0), 1),+             ((4, 0), 0)),+}++PLATFORM_WHEEL_FLAGS = {+    # ((button, event_type), scroll_count)+    "wheelup": (('up', 1), 3),+    "stepup": (('up', 1), 1),+    "wheeldown": (('down', 1), 3),+    "stepdown": (('down', 1), 1),+    "wheelright": (('right', 1), 3),+    "stepright": (('right', 1), 1),+    "wheelleft": (('left', 1), 3),+    "stepleft": (('left', 1), 1),+}+++#---------------------------------------------------------------------------+# event classes.+++class ButtonEvent(BaseButtonEvent):++    def execute(self, window):+        for ((button, event_type), flag) in self._flags:+            # Check if the button is unknown.+            if button is None:+                event_type_s = "button" if event_type == 0 else "scroll"+                raise ValueError("Unsupported %s event" % event_type_s)++            if event_type == 0:  # Button press event+                ctrl.mouse_click(button, down=flag)

There appears to be a bug somewhere here such that Mouse("left").execute() clicks down but doesn't release the click (the expected behavior without an "up" or "down" qualifier).

lunixbochs

comment created time in 9 days

Pull request review commentdictation-toolbox/dragonfly

Talon integration

+#+# This file is part of Dragonfly.+# (c) Copyright 2007, 2008 by Christo Butcher+# Licensed under the LGPL.+#+#   Dragonfly is free software: you can redistribute it and/or modify it+#   under the terms of the GNU Lesser General Public License as published+#   by the Free Software Foundation, either version 3 of the License, or+#   (at your option) any later version.+#+#   Dragonfly is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+#   Lesser General Public License for more details.+#+#   You should have received a copy of the GNU Lesser General Public+#   License along with Dragonfly.  If not, see+#   <http://www.gnu.org/licenses/>.+#++# pylint: disable=E0401+from talon import ui++from .base_monitor import BaseMonitor+from .rectangle import Rectangle+++#===========================================================================+# Monitor class for storing info about a single display monitor.++class TalonMonitor(BaseMonitor):+    """+    The monitor class used under Talon.+    """++    @classmethod+    def get_all_monitors(cls):+        monitors = []+        for screen in ui.screens():+            rectangle = Rectangle(screen.x, screen.y, screen.width, screen.height)+            monitors.append(cls.get_monitor(screen, rectangle))

This throws an error that screen is unhashable. You need to pass in a unique integer here (I got it working with hash(screen.name) but there are probably better choices).

lunixbochs

comment created time in 9 days

issue commentDanesprite/tts-util-app

Problem of system language

Sorry, I forgot this account.

It is Android 10. German voice is installed.

GrimPixel2

comment created time in 11 days

pull request commentdictation-toolbox/dragonfly

Update Kaldi backend

Yes, I think this should be ready for merging now, as far as I know, unless any other testers pipe up.

Re: testing with audio. True, for this, slowing of the processing down to real time is the code path that requires extra logic. The Kaldi backend supports both methods.

Re: custom words. They should be added automatically with estimated pronunciations. Is this not working for you?

daanzu

comment created time in 13 days