- Spoken presets: route() now also matches a preset's name as an implicit keyword, so presets with no configured keywords (Nicer email, Calm down, Add emojis) are triggerable by voice — say the name. Explicit keywords still win; names are added to STT hotwords too. Tests added. - General tab: switches moved to the far right of each row with an inline grey description (new _switch_row helper) so each toggle is self-explanatory. - About tab: add "Copyright: 2026 mARTin Bierschenk - Design". - MANUAL + CHANGELOG updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
74 lines
2.3 KiB
Python
74 lines
2.3 KiB
Python
import pytest
|
|
from dataclasses import dataclass
|
|
from blitztext.routing import route, normalize, _strip_span
|
|
|
|
@dataclass
|
|
class DummyPreset:
|
|
name: str
|
|
keywords: list[str]
|
|
|
|
def test_normalize():
|
|
assert normalize("Nicer E-Mail.") == ["nicer", "e", "mail"]
|
|
assert normalize("calm down!") == ["calm", "down"]
|
|
|
|
def test_route_no_presets():
|
|
res = route("Hello world", [])
|
|
assert res.preset_name is None
|
|
assert res.text == "Hello world"
|
|
assert res.keyword is None
|
|
|
|
def test_route_match_start():
|
|
presets = [
|
|
DummyPreset("Email", ["nicer email", "bessere email"]),
|
|
DummyPreset("Calm", ["calm down"]),
|
|
]
|
|
res = route("Nicer e-mail can you send me the report", presets)
|
|
assert res.preset_name == "Email"
|
|
assert res.keyword == "nicer email"
|
|
assert res.position == "start"
|
|
assert res.text == "can you send me the report"
|
|
|
|
def test_route_match_end():
|
|
presets = [
|
|
DummyPreset("Email", ["nicer email"]),
|
|
DummyPreset("Calm", ["calm down"]),
|
|
]
|
|
res = route("Can you send me the report nicer email", presets)
|
|
assert res.preset_name == "Email"
|
|
assert res.keyword == "nicer email"
|
|
assert res.position == "end"
|
|
assert res.text == "Can you send me the report"
|
|
|
|
def test_route_no_match_middle():
|
|
presets = [
|
|
DummyPreset("Email", ["nicer email"]),
|
|
]
|
|
res = route("Can you send me a nicer email please", presets)
|
|
assert res.preset_name is None
|
|
assert res.text == "Can you send me a nicer email please"
|
|
|
|
def test_strip_span():
|
|
# 'nicer e-mail' normalizes to 3 tokens
|
|
res = _strip_span("Nicer e-mail can you send me the report", 3, "start")
|
|
assert res == "can you send me the report"
|
|
|
|
|
|
def test_route_matches_preset_name_without_keywords():
|
|
"""A preset with no keywords is still speakable by its name."""
|
|
presets = [
|
|
DummyPreset("Transcribe", []),
|
|
DummyPreset("Nicer email", []), # no keywords configured
|
|
]
|
|
res = route("nicer email please call me back tomorrow", presets)
|
|
assert res.preset_name == "Nicer email"
|
|
assert res.text == "please call me back tomorrow"
|
|
|
|
|
|
def test_explicit_keyword_still_wins_over_name():
|
|
presets = [
|
|
DummyPreset("Add emojis", ["emoji"]),
|
|
]
|
|
res = route("emoji this is great", presets)
|
|
assert res.preset_name == "Add emojis"
|
|
assert res.text == "this is great"
|