This release is a pre-release and may not be stable for production use.
ovos-yes-no-plugin
A heuristic yes/no answer classifier for OpenVoiceOS.
Given a question and a spoken or typed response, it returns True (yes), False (no), or None (unclear). It handles common variants (yeah, sure, nah), double negatives (not a lie → yes), and language-specific word lists for 20+ locales.
Role in OVOS
OVOS skills ask yes/no questions through OVOSSkill.ask_yesno() in
ovos-workshop:
# ovos_workshop/skills/ovos.py
def ask_yesno(self, prompt: str, data=None) -> Optional[str]:
resp = self.get_response(dialog=prompt, data=data)
engine = self._get_yesno_engine()
answer = engine.yes_or_no(question=prompt, response=resp, lang=self.lang)
if answer is True:
return "yes"
elif answer is False:
return "no"
else:
return resp # pass-through when answer is ambiguous
_get_yesno_engine() loads the plugin named ovos-yes-no-plugin by
default. This package provides that plugin. The active engine can be overridden
per-skill in settings.json or system-wide in mycroft.conf:
# mycroft.conf
{
"skills": {
"ask_yesno_plugin": "ovos-yes-no-plugin"
}
}
# skill settings.json (overrides the system default for this skill only)
{
"ask_yesno_plugin": "my-custom-yesno-plugin"
}
Install
pip install ovos-yes-no-plugin
Usage
Inside an OVOS skill
class MySkill(OVOSSkill):
def handle_intent(self, message):
answer = self.ask_yesno("confirm.action") # plays TTS, waits for reply
if answer == "yes":
self.speak_dialog("confirmed")
elif answer == "no":
self.speak_dialog("cancelled")
else:
self.speak_dialog("didnt.understand")
ask_yesno returns "yes", "no", or the raw utterance when the engine
returns None.
Direct use
from ovos_yes_no import HeuristicYesNoEngine
engine = HeuristicYesNoEngine()
engine.yes_or_no("Do you want to continue?", "yes", "en-us") # True
engine.yes_or_no("Do you want to continue?", "no way", "en-us") # False
engine.yes_or_no("Do you want to continue?", "beans", "en-us") # None
engine.yes_or_no("Do you want to continue?", "it's not a lie", "en-us") # True (double negative)
engine.yes_or_no("Do you want to continue?", "yes, but actually, no", "en-us") # False (last word wins)
Via ovos-plugin-manager
from ovos_plugin_manager.agents import load_yesno_plugin
cls = load_yesno_plugin("ovos-yes-no-plugin")
engine = cls()
result = engine.yes_or_no("Shall I set a reminder?", "please do", "en-us") # True
Configuration
No mandatory configuration. An optional config dict is accepted by the
constructor. The only supported key is lang, which sets the default language
when yes_or_no is called without an explicit lang argument:
engine = HeuristicYesNoEngine(config={"lang": "de-de"})
Algorithm
Source: HeuristicYesNoEngine.yes_or_no
The engine scans the normalised response against a per-language
locale/<lang>/yesno.json resource file containing four word lists:
| Key | Role |
|---|---|
yes |
Unambiguous affirmatives: yes, yeah, affirmative, ... |
no |
Unambiguous negatives: no, nah, disagree, ... |
neutral_yes |
Soft affirmatives counted only when no no word is present: sure, please, ... |
neutral_no |
Soft negatives counted only when no yes word is present: wrong, mistake, lie, ... |
Decision rules (in order):
- Last word wins. When both a
yesword and anoword appear, the one at the higher character index is taken as the user's final intent. - Double negatives. A
no-category word immediately followed by aneutral_noword (e.g.,not+lie→"not a lie") is interpreted as affirmative. - Neutral words. If neither a
yesnor anoword was found,neutral_yesandneutral_nowords are considered as weak signals. - Default. No recognised word → return
None.
Language matching uses langcodes.tag_distance to find the closest available
locale, so en-AU silently falls back to en-US.
Supported Languages
an, az, ca-ES, cs-CZ, da-DK, de-DE, en-US, es-ES, eu-ES,
fa-IR, fr-FR, hu-HU, it-IT, nl-NL, pl-PL, pt-BR, ru-RU,
sv-SE, tr-TR, uk-UA
Adding a Language
Create ovos_yes_no/locale/<lang-TAG>/yesno.json with the four word lists
described above:
neutral_yes: mild agreement words that are positive but not direct synonyms of "yes" (e.g., French"bien sur", Portuguese"claro").neutral_no: words that imply disapproval indirectly (e.g., French"mensonge", Portuguese"errado").- Double-negative structures vary widely between languages. Test them explicitly.
Limitations
- No sarcasm or idiom detection.
- Vocabulary is limited to the words in the resource files. Unlisted slang is ignored.
- Complex nested negations beyond one level may yield incorrect results.
- Missing or incomplete resource files cause the engine to return
Nonefor that language rather than raising an error.
Related Projects
- OpenVoiceOS/ovos-workshop — the skill base class that calls this plugin through
ask_yesno(). - OpenVoiceOS/ovos-plugin-manager — loads this plugin by name at runtime.
License
Apache 2.0
Metadata
Release files for ovos-yes-no-plugin 0.4.0a1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ovos_yes_no_plugin-0.4.0a1.tar.gz | 19.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ovos_yes_no_plugin-0.4.0a1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.0 kB
Release files / ovos_yes_no_plugin-0.4.0a1.tar.gz
| Download URL | ovos_yes_no_plugin-0.4.0a1.tar.gz |
|---|---|
| Size | 19.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a9e917234b1535c7c1fdfbb8b6ea99729ab49cdbd2288fd9ccdb4214a0acc221
|
|
BLAKE2b-256 checksum How to use checksums |
799cc2c05cbb41e85a9433a156ff139d871c1de8bde1cfd9762bfd94a14a1636
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / ovos_yes_no_plugin-0.4.0a1-py3-none-any.whl
| Download URL | ovos_yes_no_plugin-0.4.0a1-py3-none-any.whl |
|---|---|
| Size | 19.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2262abd98b5b2b6c06bf3cfda28700617420ed6dbbd2c7d7e820871c5b7dc7a0
|
|
BLAKE2b-256 checksum How to use checksums |
918cab1b724dd1c2fe858b408c5eb1417894710d08ad2bb1e4a3faf3fb109916
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|