Quick Start

August 1, 2026 · View on GitHub

This guide takes you from zero to a working intent parser in five minutes.


1. Install

pip install palavreado

2. Keyword intent (required slots only)

Register vocabulary words for each slot, build an intent, and match utterances.

from palavreado import IntentContainer, IntentCreator

container = IntentContainer()

intent = (
    IntentCreator("lights_off")
    .require("off",   ["off", "disable", "shutdown"])
    .require("light", ["light", "lights", "lamp"])
)
container.add_intent(intent)

result = container.calc_intent("turn off the lights")
print(result["name"])               # lights_off
print(result["conf"])               # 0.9438
print(result["keywords"])           # {'off': ['off'], 'light': ['light']}
print(result["utterance_remainder"]) # 'turn the'

An intent only fires when every required slot has at least one matching keyword in the utterance. Unmatched required slots cause the intent to be skipped entirely.


3. Optional slots

Optional slots contribute to confidence when present but do not gate the intent.

intent = (
    IntentCreator("lights_off")
    .require("off",   ["off", "disable"])
    .require("light", ["light", "lights"])
    .optionally("room", ["kitchen", "bedroom", "bathroom"])
)
container.add_intent(intent)

result = container.calc_intent("turn off the bedroom lights")
print(result["keywords"]["room"])   # ['bedroom']
print(result["conf"])               # higher than without room match

4. Bracket/pipe expansion

All sample strings support (a|b) alternation and [optional] syntax, which are expanded at registration time.

IntentCreator("lights_on") \
    .require("action", ["(turn|switch|flick) on"]) \
    .require("light",  ["(the |)(lights|light|lamp)"])

(turn|switch|flick) on expands to ["turn on", "switch on", "flick on"] before any matching occurs. [word] is equivalent to (word|).


5. Autoregex: entity extraction via simplematch patterns

simplematch {entity} patterns are compiled to regular expressions automatically. Matched capture groups are returned as slot values.

intent = (
    IntentCreator("buy")
    .require_autoregex("item", ["buy {item}", "purchase {item}", "get {item}"])
)
container.add_intent(intent)

result = container.calc_intent("buy some milk")
print(result["keywords"]["item"])   # ['some milk']

The {item} placeholder captures everything that fills that position in the pattern.


6. Raw regex slots

When simplematch is not expressive enough, supply raw regex strings directly. Named groups become slot values.

rx = r'\b(at|in|for) (?P<Location>.*)'
intent = (
    IntentCreator("time_in_location")
    .require_regex("Location", rx)
    .require("time", ["time", "what time"])
)
container.add_intent(intent)

result = container.calc_intent("what time is it in London")
print(result["keywords"]["Location"])   # ['London']

7. Calling calc_intent

calc_intent always returns a dict. When nothing matches, name is None and conf is 0.

result = container.calc_intent("some random utterance")
if result["name"]:
    skill_handler(result)
else:
    fallback_handler(result["utterance"])

To see every intent that scored above zero (not just the best):

for result in container.calc_intents("turn off the lights"):
    print(result["name"], result["conf"])

8. Removing an intent

Registering the same intent name twice raises RuntimeError. Remove the old registration first.

container.remove_intent("lights_off")   # silent no-op if not present
container.add_intent(new_intent)

Result dict fields

FieldTypeDescription
namestr | NoneMatched intent name, or None
conffloatConfidence in [0.0, 1.0], 4 decimal places
keywordsdict[str, list[str]]Matched values keyed by slot name
utterancestrNormalised query
utterance_remainderstrPortion of the utterance not consumed by any slot

← Installation · Home · Intent API →