A yes/no answer parser for OpenVoiceOS
Project description
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 — ovos_yes_no/__init__.py:71
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.
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ovos_yes_no_plugin-0.3.0.tar.gz.
File metadata
- Download URL: ovos_yes_no_plugin-0.3.0.tar.gz
- Upload date:
- Size: 18.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f13f40b347fec4fca5ffd9c56bf564dcfa94c26b09545f3f3db0f720c8338c43
|
|
| MD5 |
51fff53b268903869e2e04b79a761547
|
|
| BLAKE2b-256 |
fc7cd115deed612b05d117ed6848e86dfeaf338440dd90e9bdc3082fb570b637
|
File details
Details for the file ovos_yes_no_plugin-0.3.0-py3-none-any.whl.
File metadata
- Download URL: ovos_yes_no_plugin-0.3.0-py3-none-any.whl
- Upload date:
- Size: 18.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36b2330b8c8fe55cc7f2770459b82acda0582542f164fa6eea75340aa0ff02b6
|
|
| MD5 |
f3fa892c3d653d865dd66cf014087a1c
|
|
| BLAKE2b-256 |
583d209cd9813b7b896112751624ecc0df2a29900ee64eb58c211cd98c856011
|