Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "python-voiceio"
version = "0.3.1"
version = "0.3.2"
description = "Speak → text, locally, instantly."
readme = "README.md"
license = "MIT"
Expand Down
4 changes: 2 additions & 2 deletions tests/test_tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def test_player_empty_audio():

def test_tts_config_defaults():
cfg = TTSConfig()
assert cfg.enabled is False
assert cfg.enabled is True
assert cfg.engine == "auto"
assert cfg.hotkey == "ctrl+alt+s"
assert cfg.voice == ""
Expand All @@ -155,4 +155,4 @@ def test_tts_config_in_main_config():
cfg = Config()
assert hasattr(cfg, "tts")
assert isinstance(cfg.tts, TTSConfig)
assert cfg.tts.enabled is False
assert cfg.tts.enabled is True
2 changes: 1 addition & 1 deletion voiceio/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.3.1"
__version__ = "0.3.2"
2 changes: 1 addition & 1 deletion voiceio/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class AutocorrectConfig:

@dataclass
class TTSConfig:
enabled: bool = False
enabled: bool = True
engine: str = "auto" # "auto" | "piper" | "espeak" | "edge-tts"
hotkey: str = "ctrl+alt+s" # "s" for speak
voice: str = "" # empty = engine default
Expand Down
9 changes: 9 additions & 0 deletions voiceio/numbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def convert_numbers(text: str, language: str = "en") -> str:
# Collect consecutive number words
if _is_number_word(low) and low != "a" and low != "and":
num_words = []
last_category = None # "ones", "tens", "scale"
j = i
while j < len(words):
w = words[j].lower().rstrip(".,;:?!")
Expand All @@ -153,6 +154,7 @@ def convert_numbers(text: str, language: str = "en") -> str:
# "a" at start: only if followed by scale word
if j + 1 < len(words) and words[j + 1].lower().rstrip(".,;:?!") in _SCALES:
num_words.append(w)
last_category = "ones"
j += 1
continue
break
Expand All @@ -163,7 +165,14 @@ def convert_numbers(text: str, language: str = "en") -> str:
j += 1
continue
break
# Two consecutive ones-words = separate numbers
# e.g. "one two three" should NOT become 6
# But "twenty three", "one hundred", "thirteen thousand" are valid
cat = "scale" if w in _SCALES else ("tens" if w in _TENS else "ones")
if cat == "ones" and last_category == "ones":
break
num_words.append(w)
last_category = cat
j += 1
else:
break
Expand Down
15 changes: 14 additions & 1 deletion voiceio/tts/edge_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,25 @@ class EdgeEngine:
def probe(self) -> ProbeResult:
try:
import edge_tts # noqa: F401
return ProbeResult(ok=True)
except ImportError:
return ProbeResult(
ok=False, reason="edge-tts not installed",
fix_hint="pip install edge-tts",
)
try:
import soundfile # noqa: F401
return ProbeResult(ok=True)
except ImportError:
pass
try:
import pydub # noqa: F401
return ProbeResult(ok=True)
except ImportError:
return ProbeResult(
ok=False,
reason="edge-tts needs soundfile or pydub to decode audio",
fix_hint="pip install soundfile",
)

def synthesize(self, text: str, voice: str, speed: float) -> tuple[np.ndarray, int]:
import asyncio
Expand Down
5 changes: 3 additions & 2 deletions voiceio/tts/piper_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ def __init__(self, model: str = ""):
def probe(self) -> ProbeResult:
try:
import piper # noqa: F401
from piper.download import ensure_voice_exists, get_voices # noqa: F401
return ProbeResult(ok=True)
except ImportError:
except ImportError as e:
return ProbeResult(
ok=False, reason="piper-tts not installed",
ok=False, reason=f"piper-tts not fully installed: {e}",
fix_hint="pip install piper-tts",
)

Expand Down
Loading