Using rhasspynlu and fuzzywuzzy

Hi all,

I’m currently working on a voice-assistant for doing control/command in an offline context.
I firstly wrote my own command-interpreter but it was too restrictive given the speech-to-text results.

I just discovered rhasspy few day ago and I realize that the rhasspynlu package is what I’d need for my project as I lack knowledge for writing an acceptable intent-detection.

My question is, if it’s possible to use rhasspynlu package independently from the whole rhasspy environment ? Knowing that my project is already written in python with MQTT features as well.
Is it enough ?

Secondly, I’m also interested in the fuzzy matching features. Previously I used a c library (used for TRE python package) for doing fuzzy matching.
Is there a recommended way to integrate rhasspy-fuzzywuzzy inside rhasspynlu ? Or should it be used separatly ?

Thanks for your feedback.

Best Regards,

Z.

Hi @zyend, welcome :slight_smile:

rhasspy-nlu can definitely be used independently. The project home page has some Python examples. Note that the rhasspy-nlu project doesn’t have any MQTT stuff in it; all of that is contained in rhasspy-nlu-hermes.

The rhasspy-fuzzywuzzy project uses @maxbachmann’s rapidfuzz under the hood, but provides an interface like rhasspy-nlu. So you would use rhasspy-fuzzywuzzy in place of rhasspy-nlu. Both projects can be trained on the same sentences.ini files, and produce the same Recognition Python objects.

Best of luck!

Hello @synesthesiam

Thank you so much for your quick feedback. :+1:
I will dive into fuzzywhuzzy asap.
I was currently tuning a sample “sentences.ini” to test rhasspynlu. It is definitly what I was looking for :
However, without using the whole rhasspy system, is it possible to manage slot files ?
Reading the docs, it says slots shall be places in a profile directory.
Is there a location where rhasspynlu could find them anyway ?

Kind Regards.

The intents_to_graph function in rhasspy-nlu takes a replacements argument. You can load a directory of slot files with get_slot_replacements, passing the result to intents_to_graph:

from pathlib import Path

import rhasspynlu

# Load and parse
intents = rhasspynlu.parse_ini(
"""
[LightOn]
turn on [the] ($light){name}
"""
)

# Assume /path/to/slots/light exists with:
# living room lamp
# kitchen light
replacements = rhasspynlu.get_slot_replacements(
    intents, slot_dirs=[Path("/path/to/slots")]
)

graph = rhasspynlu.intents_to_graph(intents, replacements=replacements)

print(rhasspynlu.recognize("turn on the living room lamp", graph))

Hello @synesthesiam,

I have tried to use rhasspy-fuzzywuzzy in place of rhasspy-nlu.
I have tuned my sentences.ini with rhasspy-nlu, but I"d need to make further “fuzzy” tests.
As you’ve suggested, I plan to use rhasspy-fuzzywuzzy package.

In my sample code, instead of calling

rhasspynlu.recognize(line, graph)

I’d need to use:

rhasspyfuzzywuzzy.recognize(line, graph)

However, there’s a missing and mandatory parameter in recognize, it’s the example path.
What is it actually ? What should be found in this path ?

Is it documented somewhere ?

Thks !

examples_path is the filesystem path to an SQLite database generated during the training process. It maps the words of each possible sentence to a path through the rhasspynlu intent graph (which has the intent/slot info).

Ok !
So it means that even if I plan to use rhasspynlu or rhasspyfuzzywuzzy separately, I’d still need to have a complete system on a dev machine to train the whole things ?

Please forget my previous post.
I just found out how to execute the train method after getting the intent graph. Everything works as expected.
Thnks !

1 Like

I’ve a question…one year later please.
Using the train method of rhasspyfuzzywuzzy, is it possible to use slot_programs without the whole rhasspy system ?

Cheers.

You should be able to. If you use the rhasspy-nlu command-line interface with --write-json to generate a JSON graph file, you can then use this as the --intent-graph in the rhasspy-fuzzywuzzy command-line interface.

Thanks for your feedback.

But how could it be embedded in my code ? My current program does the following:
Is there something’s missing ?


if __name__ == "__main__":

    intents = rhasspynlu.parse_ini(open(SENTENCE_INI, "r").read())

    replacements = rhasspynlu.get_slot_replacements(intents, slots_dirs=[Path(SLOTS_DIR)], slot_programs_dirs = [Path(SLOT_PROGRAMS_DIR)]) 

    graph = rhasspynlu.intents_to_graph(intents, replacements=replacements)

    print("Training...")
    examples = rfw.train(graph)
    print("Done.")

    if examples:
    # Write examples to SQLite database
        conn = sqlite3.connect(EXAMPLES_DIR)
        c = conn.cursor()
        c.execute("""DROP TABLE IF EXISTS intents""")
        c.execute("""CREATE TABLE intents (sentence text, path text)""")

        for _, sentences in examples.items():
            for sentence, path in sentences.items():
                c.execute(
                    "INSERT INTO intents VALUES (?, ?)",
                    (sentence, json.dumps(path, ensure_ascii=False)),
                )

        conn.commit()
        conn.close()



    for line in sys.stdin: 

        if line.rstrip() in ('q', '*'): 
            break
        #res = rhasspynlu.recognize(line, graph) 
        res = rfw.recognize(line, graph, EXAMPLES_DIR) 
        print("*" * 80) 

        for rec in res:
            print("nb entities: ", len(rec.entities))
            print("~~~~~~~~~~")
            print(rec.asdict())
    
    sys.exit(0)

Knowing that as I input:

set volume twenty

it does not convert twenty to 20.In my sentence.ini I have:

[SetMonitorCommand]
set volume (0..100){value}

I do believe I missed something :frowning:

Cheers.

Z.