abstractvoice 0.6.1__py3-none-any.whl → 0.6.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
abstractvoice/__init__.py CHANGED
@@ -29,5 +29,5 @@ warnings.filterwarnings(
29
29
  # Import the main class for public API
30
30
  from .voice_manager import VoiceManager
31
31
 
32
- __version__ = "0.6.1"
32
+ __version__ = "0.6.2"
33
33
  __all__ = ["VoiceManager"]
@@ -19,6 +19,7 @@ import threading
19
19
  import time
20
20
  import requests
21
21
  from abstractvoice import VoiceManager
22
+ from abstractvoice.text_sanitize import sanitize_markdown_for_speech
22
23
 
23
24
 
24
25
  # ANSI color codes
@@ -1563,6 +1564,10 @@ class VoiceREPL(cmd.Cmd):
1563
1564
  if not self.voice_manager:
1564
1565
  return
1565
1566
 
1567
+ # LLM output often contains Markdown. Strip the most common formatting
1568
+ # tokens so TTS stays natural (do not change what is printed).
1569
+ speak_text = sanitize_markdown_for_speech(text)
1570
+
1566
1571
  is_clone = bool(self.current_tts_voice)
1567
1572
  if not is_clone:
1568
1573
  # Offline-first: Piper voices must be explicitly cached. Provide a clear
@@ -1583,7 +1588,7 @@ class VoiceREPL(cmd.Cmd):
1583
1588
  try:
1584
1589
  if is_clone:
1585
1590
  ind.start()
1586
- self.voice_manager.speak(text, voice=self.current_tts_voice)
1591
+ self.voice_manager.speak(speak_text, voice=self.current_tts_voice)
1587
1592
 
1588
1593
  if not is_clone:
1589
1594
  return
@@ -0,0 +1,33 @@
1
+ """Lightweight text sanitizers for better speech UX.
2
+
3
+ Design goals:
4
+ - No heavy dependencies (regex only).
5
+ - Deterministic and conservative (only strip the most common Markdown syntax).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import re
11
+
12
+
13
+ _MD_HEADER_RE = re.compile(r"(?m)^[ \t]*#{1,5}(?!#)[ \t]*(\S.*)$")
14
+ _MD_BOLD_RE = re.compile(r"\*\*([^*\n]+?)\*\*")
15
+ # Avoid matching "**bold**" as italic. The bold pass runs first, but keep this safe.
16
+ _MD_ITALIC_RE = re.compile(r"(?<!\*)\*([^*\n]+?)\*(?!\*)")
17
+
18
+
19
+ def sanitize_markdown_for_speech(text: str) -> str:
20
+ """Remove common Markdown syntax that sounds bad in TTS.
21
+
22
+ Intentionally minimal:
23
+ - Strip ATX headers at the start of a line: "#", "##", ... "#####"
24
+ - Strip emphasis markers: "**bold**" and "*italic*"
25
+ """
26
+ if not text:
27
+ return ""
28
+
29
+ out = str(text)
30
+ out = _MD_HEADER_RE.sub(r"\1", out)
31
+ out = _MD_BOLD_RE.sub(r"\1", out)
32
+ out = _MD_ITALIC_RE.sub(r"\1", out)
33
+ return out
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: abstractvoice
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: A modular Python library for voice interactions with AI systems
5
5
  Author-email: Laurent-Philippe Albou <contact@abstractcore.ai>
6
6
  License-Expression: MIT
@@ -1,10 +1,11 @@
1
- abstractvoice/__init__.py,sha256=Ce_KZwKQ_4G-elHU6G8cqmPMUKSih9NP0tEjDK7JHR4,817
1
+ abstractvoice/__init__.py,sha256=lR9Enlcyz-n1wcDq3vO2WpeujVAMOP3LzVAtZFr9wA8,817
2
2
  abstractvoice/__main__.py,sha256=EVhZgFwWHBaeRcz1cVoILCzibCyxpD9V9nCOQiO1yUU,8357
3
3
  abstractvoice/artifacts.py,sha256=jHcOK6q4barEh92og1oy52b5p4IqC9AwyKbZzFIitww,5750
4
4
  abstractvoice/dependency_check.py,sha256=3iz5-bwCQOJvh1jeC9NO8mmlKjuN5LKZ7ZKVy7zcjQw,10002
5
5
  abstractvoice/prefetch.py,sha256=XciaG-OPuOLbAbVauyWJdcVh2oDHuyBMJ9a9bht0kwA,2939
6
6
  abstractvoice/recognition.py,sha256=xkCjKGKIfHKLuvM-rcdVVfVzZqhcVUv1sqABnZokgJU,27623
7
7
  abstractvoice/stop_phrase.py,sha256=PLUkL2uM6n0J--uFs_O_VeIWN6k2-jNhVlmKBol02ys,3382
8
+ abstractvoice/text_sanitize.py,sha256=9dt_NiwTYWjUOSaVK19Pr9a_HDWOovURQLpevQjgF1A,964
8
9
  abstractvoice/voice_manager.py,sha256=6M1yT9etb6TQWoAmgqhfGWSex7Blg2bzlLTJZTytL7s,234
9
10
  abstractvoice/adapters/__init__.py,sha256=PRhDqLA6cj_fEYMkp54PJ5xrAiEt2oEvE5yVK1MKbP4,452
10
11
  abstractvoice/adapters/base.py,sha256=GXmBcwvrVpCCIsNcnClMdvn--ngxMZxp0zjfFvVHYd4,6212
@@ -25,7 +26,7 @@ abstractvoice/compute/device.py,sha256=IM4hf45RRs8u-ZJI81PSX5i_vI9YJosvuy-XqCImn
25
26
  abstractvoice/config/__init__.py,sha256=VK2uK7bMbFDL6-WlZV-FXmKO1Ii-ezbwYN-rHo2lUTQ,54
26
27
  abstractvoice/config/voice_catalog.py,sha256=py5D2qO4tL_PezEtDRyS48BzkA6MiX_l06BsE-Xa5NA,496
27
28
  abstractvoice/examples/__init__.py,sha256=94vpKJDlfOrEBIUETg-57Q5Z7fYDidg6v4UzV7V_lZA,60
28
- abstractvoice/examples/cli_repl.py,sha256=dO7aauMB4mJ0_RZTqVKSzJp0L5oR0Id_cO7zKbWoftk,128469
29
+ abstractvoice/examples/cli_repl.py,sha256=VEyJvaqGdithxpjwqM8gOS2DuwPp28oIKMuzEPKTSq4,128751
29
30
  abstractvoice/examples/voice_cli.py,sha256=jJ27H7VtwFTktEixxt4Ne_u5vwcZoTiL7oninqCmjio,11068
30
31
  abstractvoice/examples/web_api.py,sha256=0g5LKJpl7fZepPQJL25AcdaevV-xv34VqqyWGYYchPk,6376
31
32
  abstractvoice/integrations/__init__.py,sha256=NsLg9ewvcXwBP118n0BDg4ye5KMWdcsHxikhkfaIs5s,61
@@ -44,9 +45,9 @@ abstractvoice/vm/core.py,sha256=UL4dFxnggn7ueEmECGS1vRpW7qZMB2FcZjrn3OWXwgU,5305
44
45
  abstractvoice/vm/manager.py,sha256=4yZI-LdBUP3LriEyY3kV3dKF25AO8r-JAR3YV-YLmWY,4158
45
46
  abstractvoice/vm/stt_mixin.py,sha256=5VZ7lVwsy1yGt0UVA4Ixfvyp-1pHqAQJjv0QmQXAedo,5932
46
47
  abstractvoice/vm/tts_mixin.py,sha256=GvPC73YjfkkoA6rYrHYqf_FhbzRMuZVbzQ88QubjDQs,22525
47
- abstractvoice-0.6.1.dist-info/licenses/LICENSE,sha256=TiDPM5WcFRQPoC5e46jGMeMppZ-eu0eFx_HytjE49bk,1105
48
- abstractvoice-0.6.1.dist-info/METADATA,sha256=y_oRXVn3EynZkyHmz2w3wmhqHtEHb9SZ4BjF1-OP6M0,7213
49
- abstractvoice-0.6.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
50
- abstractvoice-0.6.1.dist-info/entry_points.txt,sha256=PT4IchtBfcgcjlhbX_84WKyCpe-HWzjpNgJ24Kordco,234
51
- abstractvoice-0.6.1.dist-info/top_level.txt,sha256=a1qyxqgF1O8cJtPKpcJuImGZ_uXqPNghbLZ9gp-UiOo,14
52
- abstractvoice-0.6.1.dist-info/RECORD,,
48
+ abstractvoice-0.6.2.dist-info/licenses/LICENSE,sha256=TiDPM5WcFRQPoC5e46jGMeMppZ-eu0eFx_HytjE49bk,1105
49
+ abstractvoice-0.6.2.dist-info/METADATA,sha256=mDZobk4G5Bd9FzINxFmxHU9ciCu0Os8vMaLJ06bUOZc,7213
50
+ abstractvoice-0.6.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
51
+ abstractvoice-0.6.2.dist-info/entry_points.txt,sha256=PT4IchtBfcgcjlhbX_84WKyCpe-HWzjpNgJ24Kordco,234
52
+ abstractvoice-0.6.2.dist-info/top_level.txt,sha256=a1qyxqgF1O8cJtPKpcJuImGZ_uXqPNghbLZ9gp-UiOo,14
53
+ abstractvoice-0.6.2.dist-info/RECORD,,