wyoming-piper 1.5.3__tar.gz → 1.6.3__tar.gz
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.
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/PKG-INFO +5 -3
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/pyproject.toml +5 -3
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/tests/test_piper.py +1 -0
- wyoming_piper-1.6.3/tests/test_sentence_boundary.py +61 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/__init__.py +1 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/__main__.py +14 -6
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/download.py +9 -7
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/handler.py +66 -8
- wyoming_piper-1.6.3/wyoming_piper/sentence_boundary.py +58 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/voices.json +180 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper.egg-info/PKG-INFO +5 -3
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper.egg-info/SOURCES.txt +2 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper.egg-info/requires.txt +2 -1
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/LICENSE.md +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/README.md +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/setup.cfg +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/const.py +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/file_hash.py +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper/process.py +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper.egg-info/dependency_links.txt +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper.egg-info/entry_points.txt +0 -0
- {wyoming_piper-1.5.3 → wyoming_piper-1.6.3}/wyoming_piper.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wyoming-piper
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.3
|
|
4
4
|
Summary: Wyoming Server for Piper
|
|
5
5
|
Author-email: Michael Hansen <mike@rhasspy.org>
|
|
6
6
|
License: MIT
|
|
@@ -14,10 +14,12 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: >=3.8
|
|
18
19
|
Description-Content-Type: text/markdown
|
|
19
20
|
License-File: LICENSE.md
|
|
20
|
-
Requires-Dist: wyoming
|
|
21
|
+
Requires-Dist: wyoming<1.8,>=1.7.2
|
|
22
|
+
Requires-Dist: regex==2024.11.6
|
|
21
23
|
Provides-Extra: dev
|
|
22
24
|
Requires-Dist: black==22.12.0; extra == "dev"
|
|
23
25
|
Requires-Dist: flake8==6.0.0; extra == "dev"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "wyoming-piper"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.6.3"
|
|
4
4
|
description = "Wyoming Server for Piper"
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.8
|
|
6
|
+
requires-python = ">=3.8"
|
|
7
7
|
license = {text = "MIT"}
|
|
8
8
|
authors = [
|
|
9
9
|
{name = "Michael Hansen", email = "mike@rhasspy.org"}
|
|
@@ -18,9 +18,11 @@ classifiers = [
|
|
|
18
18
|
"Programming Language :: Python :: 3.10",
|
|
19
19
|
"Programming Language :: Python :: 3.11",
|
|
20
20
|
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
21
22
|
]
|
|
22
23
|
dependencies = [
|
|
23
|
-
"wyoming>=1.
|
|
24
|
+
"wyoming>=1.7.2,<1.8",
|
|
25
|
+
"regex==2024.11.6",
|
|
24
26
|
]
|
|
25
27
|
|
|
26
28
|
[project.urls]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Tests for sentence boundary detection."""
|
|
2
|
+
|
|
3
|
+
from wyoming_piper.sentence_boundary import SentenceBoundaryDetector, remove_asterisks
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_one_chunk() -> None:
|
|
7
|
+
sbd = SentenceBoundaryDetector()
|
|
8
|
+
assert not list(sbd.add_chunk("Test chunk"))
|
|
9
|
+
assert sbd.finish() == "Test chunk"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_one_chunk_with_punctuation() -> None:
|
|
13
|
+
sbd = SentenceBoundaryDetector()
|
|
14
|
+
assert list(sbd.add_chunk("Test chunk 1. Test chunk 2")) == ["Test chunk 1."]
|
|
15
|
+
assert sbd.finish() == "Test chunk 2"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_multiple_chunks() -> None:
|
|
19
|
+
sbd = SentenceBoundaryDetector()
|
|
20
|
+
assert not list(sbd.add_chunk("Test chunk"))
|
|
21
|
+
assert list(sbd.add_chunk(" 1. Test chunk")) == ["Test chunk 1."]
|
|
22
|
+
assert not list(sbd.add_chunk(" 2."))
|
|
23
|
+
assert sbd.finish() == "Test chunk 2."
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_numbered_lists() -> None:
|
|
27
|
+
sbd = SentenceBoundaryDetector()
|
|
28
|
+
sentences = list(
|
|
29
|
+
sbd.add_chunk(
|
|
30
|
+
"Final Fantasy VII features several key characters who drive the narrative: "
|
|
31
|
+
"1. **Cloud Strife** - The protagonist, an ex-SOLDIER mercenary and a skilled fighter. "
|
|
32
|
+
"2. **Aerith Gainsborough (Aeris)** - A kindhearted flower seller with spiritual powers and deep connections to the planet's ecosystem. "
|
|
33
|
+
"3. **Barret Wallace** - A leader of eco-terrorists called AVALANCHE, fighting against Shinra Corporation's exploitation of the planet. "
|
|
34
|
+
"4. **Tifa Lockhart** - Cloud's childhood friend who runs a bar in Sector 7 and helps him recover from past trauma. "
|
|
35
|
+
"5. **Sephiroth** - The main antagonist, an ex-SOLDIER with god-like abilities, seeking to control or destroy the planet. "
|
|
36
|
+
"6. **Red XIII (aka Red 13)** - A member of a catlike race called Cetra, searching for answers about his heritage and destiny. "
|
|
37
|
+
"7. **Vincent Valentine** - A brooding former Turk who lives in isolation from guilt over past failures but aids Cloud's party with his powerful abilities. "
|
|
38
|
+
"8. **Cid Highwind** - The pilot of the rocket plane Highwind and a skilled engineer working on various airship projects. 9. "
|
|
39
|
+
"**Shinra Employees (JENOVA Project)** - Characters like Professor Hojo, President Shinra, and Reno who play crucial roles in the plot's development. "
|
|
40
|
+
"Each character brings unique skills and perspectives to the story, contributing to its rich narrative and gameplay dynamics."
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
assert len(sentences) == 9
|
|
44
|
+
assert sbd.finish().startswith("Each character")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_remove_word_asterisks() -> None:
|
|
48
|
+
sbd = SentenceBoundaryDetector()
|
|
49
|
+
assert list(
|
|
50
|
+
sbd.add_chunk(
|
|
51
|
+
"**Test** sentence with *emphasized* words! Another *** sentence."
|
|
52
|
+
)
|
|
53
|
+
) == ["Test sentence with emphasized words!"]
|
|
54
|
+
assert sbd.finish() == "Another *** sentence."
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_remove_line_asterisks() -> None:
|
|
58
|
+
assert (
|
|
59
|
+
remove_asterisks("* Test item 1.\n\n** Test item 2\n * Test item 3.")
|
|
60
|
+
== " Test item 1.\n\n Test item 2\n Test item 3."
|
|
61
|
+
)
|
|
@@ -60,6 +60,11 @@ async def main() -> None:
|
|
|
60
60
|
default=1,
|
|
61
61
|
help="Maximum number of piper process to run simultaneously (default: 1)",
|
|
62
62
|
)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--streaming",
|
|
65
|
+
action="store_true",
|
|
66
|
+
help="Enable audio streaming on sentence boundaries",
|
|
67
|
+
)
|
|
63
68
|
#
|
|
64
69
|
parser.add_argument(
|
|
65
70
|
"--update-voices",
|
|
@@ -113,12 +118,14 @@ async def main() -> None:
|
|
|
113
118
|
voice_info.get("espeak", {}).get("voice", voice_name.split("_")[0]),
|
|
114
119
|
)
|
|
115
120
|
],
|
|
116
|
-
speakers=
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
speakers=(
|
|
122
|
+
[
|
|
123
|
+
TtsVoiceSpeaker(name=speaker_name)
|
|
124
|
+
for speaker_name in voice_info["speaker_id_map"]
|
|
125
|
+
]
|
|
126
|
+
if voice_info.get("speaker_id_map")
|
|
127
|
+
else None
|
|
128
|
+
),
|
|
122
129
|
)
|
|
123
130
|
for voice_name, voice_info in voices_info.items()
|
|
124
131
|
if not voice_info.get("_is_alias", False)
|
|
@@ -180,6 +187,7 @@ async def main() -> None:
|
|
|
180
187
|
installed=True,
|
|
181
188
|
voices=sorted(voices, key=lambda v: v.name),
|
|
182
189
|
version=__version__,
|
|
190
|
+
supports_synthesize_streaming=args.streaming,
|
|
183
191
|
)
|
|
184
192
|
],
|
|
185
193
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Utility for downloading Piper voices."""
|
|
2
|
+
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
4
5
|
import shutil
|
|
@@ -10,7 +11,7 @@ from urllib.request import urlopen
|
|
|
10
11
|
|
|
11
12
|
from .file_hash import get_file_hash
|
|
12
13
|
|
|
13
|
-
URL_FORMAT = "https://huggingface.co/rhasspy/piper-voices/resolve/
|
|
14
|
+
URL_FORMAT = "https://huggingface.co/rhasspy/piper-voices/resolve/main/{file}"
|
|
14
15
|
|
|
15
16
|
_DIR = Path(__file__).parent
|
|
16
17
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -47,20 +48,21 @@ def get_voices(
|
|
|
47
48
|
except Exception:
|
|
48
49
|
_LOGGER.exception("Failed to update voices list")
|
|
49
50
|
|
|
51
|
+
voices_embedded = _DIR / "voices.json"
|
|
52
|
+
_LOGGER.debug("Loading %s", voices_embedded)
|
|
53
|
+
with open(voices_embedded, "r", encoding="utf-8") as voices_file:
|
|
54
|
+
voices = json.load(voices_file)
|
|
55
|
+
|
|
50
56
|
# Prefer downloaded file to embedded
|
|
51
57
|
if voices_download.exists():
|
|
52
58
|
try:
|
|
53
59
|
_LOGGER.debug("Loading %s", voices_download)
|
|
54
60
|
with open(voices_download, "r", encoding="utf-8") as voices_file:
|
|
55
|
-
|
|
61
|
+
voices.update(json.load(voices_file))
|
|
56
62
|
except Exception:
|
|
57
63
|
_LOGGER.exception("Failed to load %s", voices_download)
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
voices_embedded = _DIR / "voices.json"
|
|
61
|
-
_LOGGER.debug("Loading %s", voices_embedded)
|
|
62
|
-
with open(voices_embedded, "r", encoding="utf-8") as voices_file:
|
|
63
|
-
return json.load(voices_file)
|
|
65
|
+
return voices
|
|
64
66
|
|
|
65
67
|
|
|
66
68
|
def ensure_voice_exists(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Event handler for clients of the server."""
|
|
2
|
+
|
|
2
3
|
import argparse
|
|
3
4
|
import json
|
|
4
5
|
import logging
|
|
@@ -12,9 +13,16 @@ from wyoming.error import Error
|
|
|
12
13
|
from wyoming.event import Event
|
|
13
14
|
from wyoming.info import Describe, Info
|
|
14
15
|
from wyoming.server import AsyncEventHandler
|
|
15
|
-
from wyoming.tts import
|
|
16
|
+
from wyoming.tts import (
|
|
17
|
+
Synthesize,
|
|
18
|
+
SynthesizeChunk,
|
|
19
|
+
SynthesizeStart,
|
|
20
|
+
SynthesizeStop,
|
|
21
|
+
SynthesizeStopped,
|
|
22
|
+
)
|
|
16
23
|
|
|
17
24
|
from .process import PiperProcessManager
|
|
25
|
+
from .sentence_boundary import SentenceBoundaryDetector, remove_asterisks
|
|
18
26
|
|
|
19
27
|
_LOGGER = logging.getLogger(__name__)
|
|
20
28
|
|
|
@@ -33,6 +41,9 @@ class PiperEventHandler(AsyncEventHandler):
|
|
|
33
41
|
self.cli_args = cli_args
|
|
34
42
|
self.wyoming_info_event = wyoming_info.event()
|
|
35
43
|
self.process_manager = process_manager
|
|
44
|
+
self.sbd = SentenceBoundaryDetector()
|
|
45
|
+
self.is_streaming: Optional[bool] = None
|
|
46
|
+
self._synthesize: Optional[Synthesize] = None
|
|
36
47
|
|
|
37
48
|
async def handle_event(self, event: Event) -> bool:
|
|
38
49
|
if Describe.is_type(event.type):
|
|
@@ -40,20 +51,67 @@ class PiperEventHandler(AsyncEventHandler):
|
|
|
40
51
|
_LOGGER.debug("Sent info")
|
|
41
52
|
return True
|
|
42
53
|
|
|
43
|
-
if not Synthesize.is_type(event.type):
|
|
44
|
-
_LOGGER.warning("Unexpected event: %s", event)
|
|
45
|
-
return True
|
|
46
|
-
|
|
47
54
|
try:
|
|
48
|
-
|
|
55
|
+
if Synthesize.is_type(event.type):
|
|
56
|
+
if self.is_streaming:
|
|
57
|
+
# Ignore since this is only sent for compatibility reasons.
|
|
58
|
+
# For streaming, we expect:
|
|
59
|
+
# [synthesize-start] -> [synthesize-chunk]+ -> [synthesize]? -> [synthesize-stop]
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
# Sent outside a stream, so we must process it
|
|
63
|
+
synthesize = Synthesize.from_event(event)
|
|
64
|
+
synthesize.text = remove_asterisks(synthesize.text)
|
|
65
|
+
return await self._handle_synthesize(synthesize)
|
|
66
|
+
|
|
67
|
+
if not self.cli_args.streaming:
|
|
68
|
+
# Streaming is not enabled
|
|
69
|
+
return True
|
|
70
|
+
|
|
71
|
+
if SynthesizeStart.is_type(event.type):
|
|
72
|
+
# Start of a stream
|
|
73
|
+
stream_start = SynthesizeStart.from_event(event)
|
|
74
|
+
self.is_streaming = True
|
|
75
|
+
self.sbd = SentenceBoundaryDetector()
|
|
76
|
+
self._synthesize = Synthesize(text="", voice=stream_start.voice)
|
|
77
|
+
_LOGGER.debug("Text stream started: voice=%s", stream_start.voice)
|
|
78
|
+
return True
|
|
79
|
+
|
|
80
|
+
if SynthesizeChunk.is_type(event.type):
|
|
81
|
+
assert self._synthesize is not None
|
|
82
|
+
stream_chunk = SynthesizeChunk.from_event(event)
|
|
83
|
+
for sentence in self.sbd.add_chunk(stream_chunk.text):
|
|
84
|
+
_LOGGER.debug("Synthesizing stream sentence: %s", sentence)
|
|
85
|
+
self._synthesize.text = sentence
|
|
86
|
+
await self._handle_synthesize(self._synthesize)
|
|
87
|
+
|
|
88
|
+
return True
|
|
89
|
+
|
|
90
|
+
if SynthesizeStop.is_type(event.type):
|
|
91
|
+
assert self._synthesize is not None
|
|
92
|
+
self._synthesize.text = self.sbd.finish()
|
|
93
|
+
if self._synthesize.text:
|
|
94
|
+
# Final audio chunk(s)
|
|
95
|
+
await self._handle_synthesize(self._synthesize)
|
|
96
|
+
|
|
97
|
+
# End of audio
|
|
98
|
+
await self.write_event(SynthesizeStopped().event())
|
|
99
|
+
|
|
100
|
+
_LOGGER.debug("Text stream stopped")
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
if not Synthesize.is_type(event.type):
|
|
104
|
+
return True
|
|
105
|
+
|
|
106
|
+
synthesize = Synthesize.from_event(event)
|
|
107
|
+
return await self._handle_synthesize(synthesize)
|
|
49
108
|
except Exception as err:
|
|
50
109
|
await self.write_event(
|
|
51
110
|
Error(text=str(err), code=err.__class__.__name__).event()
|
|
52
111
|
)
|
|
53
112
|
raise err
|
|
54
113
|
|
|
55
|
-
async def
|
|
56
|
-
synthesize = Synthesize.from_event(event)
|
|
114
|
+
async def _handle_synthesize(self, synthesize: Synthesize) -> bool:
|
|
57
115
|
_LOGGER.debug(synthesize)
|
|
58
116
|
|
|
59
117
|
raw_text = synthesize.text
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Guess the sentence boundaries in text."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
|
|
5
|
+
import regex as re
|
|
6
|
+
|
|
7
|
+
SENTENCE_END = r"[.!?…]|[。!?]|[؟]|[।॥]"
|
|
8
|
+
ABBREVIATION_RE = re.compile(r"\b\p{L}{1,3}\.$", re.UNICODE)
|
|
9
|
+
|
|
10
|
+
SENTENCE_BOUNDARY_RE = re.compile(
|
|
11
|
+
rf"(.*?(?:{SENTENCE_END}+))(?=\s+[\p{{Lu}}\p{{Lt}}\p{{Lo}}]|(?:\s+\d+\.\s+))",
|
|
12
|
+
re.DOTALL,
|
|
13
|
+
)
|
|
14
|
+
WORD_ASTERISKS = re.compile(r"\*+([^\*]+)\*+")
|
|
15
|
+
LINE_ASTERICKS = re.compile(r"(?<=^|\n)\s*\*+")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SentenceBoundaryDetector:
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
self.remaining_text = ""
|
|
21
|
+
self.current_sentence = ""
|
|
22
|
+
|
|
23
|
+
def add_chunk(self, chunk: str) -> Iterable[str]:
|
|
24
|
+
self.remaining_text += chunk
|
|
25
|
+
while self.remaining_text:
|
|
26
|
+
match = SENTENCE_BOUNDARY_RE.search(self.remaining_text)
|
|
27
|
+
if not match:
|
|
28
|
+
break
|
|
29
|
+
|
|
30
|
+
match_text = match.group(0)
|
|
31
|
+
|
|
32
|
+
if not self.current_sentence:
|
|
33
|
+
self.current_sentence = match_text
|
|
34
|
+
elif ABBREVIATION_RE.search(self.current_sentence[-5:]):
|
|
35
|
+
self.current_sentence += match_text
|
|
36
|
+
else:
|
|
37
|
+
yield remove_asterisks(self.current_sentence.strip())
|
|
38
|
+
self.current_sentence = match_text
|
|
39
|
+
|
|
40
|
+
if not ABBREVIATION_RE.search(self.current_sentence[-5:]):
|
|
41
|
+
yield remove_asterisks(self.current_sentence.strip())
|
|
42
|
+
self.current_sentence = ""
|
|
43
|
+
|
|
44
|
+
self.remaining_text = self.remaining_text[match.end() :]
|
|
45
|
+
|
|
46
|
+
def finish(self) -> str:
|
|
47
|
+
text = (self.current_sentence + self.remaining_text).strip()
|
|
48
|
+
self.remaining_text = ""
|
|
49
|
+
self.current_sentence = ""
|
|
50
|
+
|
|
51
|
+
return remove_asterisks(text)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def remove_asterisks(text: str) -> str:
|
|
55
|
+
"""Remove *asterisks* surrounding **words**"""
|
|
56
|
+
text = WORD_ASTERISKS.sub(r"\1", text)
|
|
57
|
+
text = LINE_ASTERICKS.sub("", text)
|
|
58
|
+
return text
|
|
@@ -4013,6 +4013,36 @@
|
|
|
4013
4013
|
},
|
|
4014
4014
|
"aliases": []
|
|
4015
4015
|
},
|
|
4016
|
+
"es_AR-daniela-high": {
|
|
4017
|
+
"key": "es_AR-daniela-high",
|
|
4018
|
+
"name": "daniela",
|
|
4019
|
+
"language": {
|
|
4020
|
+
"code": "es_AR",
|
|
4021
|
+
"family": "es",
|
|
4022
|
+
"region": "AR",
|
|
4023
|
+
"name_native": "Español",
|
|
4024
|
+
"name_english": "Spanish",
|
|
4025
|
+
"country_english": "Argentina"
|
|
4026
|
+
},
|
|
4027
|
+
"quality": "high",
|
|
4028
|
+
"num_speakers": 1,
|
|
4029
|
+
"speaker_id_map": {},
|
|
4030
|
+
"files": {
|
|
4031
|
+
"es/es_AR/daniela/high/es_AR-daniela-high.onnx": {
|
|
4032
|
+
"size_bytes": 114199011,
|
|
4033
|
+
"md5_digest": "e373fb657c93877dbc438badeadff4cb"
|
|
4034
|
+
},
|
|
4035
|
+
"es/es_AR/daniela/high/es_AR-daniela-high.onnx.json": {
|
|
4036
|
+
"size_bytes": 7248,
|
|
4037
|
+
"md5_digest": "b68d699a1779d98ee94c0cd9a08ba95b"
|
|
4038
|
+
},
|
|
4039
|
+
"es/es_AR/daniela/high/MODEL_CARD": {
|
|
4040
|
+
"size_bytes": 353,
|
|
4041
|
+
"md5_digest": "d940f7c6667a11ea165ff83ef7a86669"
|
|
4042
|
+
}
|
|
4043
|
+
},
|
|
4044
|
+
"aliases": []
|
|
4045
|
+
},
|
|
4016
4046
|
"es_ES-carlfm-x_low": {
|
|
4017
4047
|
"key": "es_ES-carlfm-x_low",
|
|
4018
4048
|
"name": "carlfm",
|
|
@@ -4791,6 +4821,66 @@
|
|
|
4791
4821
|
},
|
|
4792
4822
|
"aliases": []
|
|
4793
4823
|
},
|
|
4824
|
+
"hi_IN-pratham-medium": {
|
|
4825
|
+
"key": "hi_IN-pratham-medium",
|
|
4826
|
+
"name": "pratham",
|
|
4827
|
+
"language": {
|
|
4828
|
+
"code": "hi_IN",
|
|
4829
|
+
"family": "hi",
|
|
4830
|
+
"region": "IN",
|
|
4831
|
+
"name_native": "हिन्दी",
|
|
4832
|
+
"name_english": "Hindi",
|
|
4833
|
+
"country_english": "India"
|
|
4834
|
+
},
|
|
4835
|
+
"quality": "medium",
|
|
4836
|
+
"num_speakers": 1,
|
|
4837
|
+
"speaker_id_map": {},
|
|
4838
|
+
"files": {
|
|
4839
|
+
"hi/hi_IN/pratham/medium/hi_IN-pratham-medium.onnx": {
|
|
4840
|
+
"size_bytes": 63516050,
|
|
4841
|
+
"md5_digest": "f1e5a629a9e533a7155910530109eb86"
|
|
4842
|
+
},
|
|
4843
|
+
"hi/hi_IN/pratham/medium/hi_IN-pratham-medium.onnx.json": {
|
|
4844
|
+
"size_bytes": 4970,
|
|
4845
|
+
"md5_digest": "ab655cdad90f1939f00d1b3aaf440e99"
|
|
4846
|
+
},
|
|
4847
|
+
"hi/hi_IN/pratham/medium/MODEL_CARD": {
|
|
4848
|
+
"size_bytes": 304,
|
|
4849
|
+
"md5_digest": "eccc77c3d857a883e85c52cb17653c1f"
|
|
4850
|
+
}
|
|
4851
|
+
},
|
|
4852
|
+
"aliases": []
|
|
4853
|
+
},
|
|
4854
|
+
"hi_IN-priyamvada-medium": {
|
|
4855
|
+
"key": "hi_IN-priyamvada-medium",
|
|
4856
|
+
"name": "priyamvada",
|
|
4857
|
+
"language": {
|
|
4858
|
+
"code": "hi_IN",
|
|
4859
|
+
"family": "hi",
|
|
4860
|
+
"region": "IN",
|
|
4861
|
+
"name_native": "हिन्दी",
|
|
4862
|
+
"name_english": "Hindi",
|
|
4863
|
+
"country_english": "India"
|
|
4864
|
+
},
|
|
4865
|
+
"quality": "medium",
|
|
4866
|
+
"num_speakers": 1,
|
|
4867
|
+
"speaker_id_map": {},
|
|
4868
|
+
"files": {
|
|
4869
|
+
"hi/hi_IN/priyamvada/medium/hi_IN-priyamvada-medium.onnx": {
|
|
4870
|
+
"size_bytes": 63516050,
|
|
4871
|
+
"md5_digest": "7d5e20c2d1e72de8ed772f222e679626"
|
|
4872
|
+
},
|
|
4873
|
+
"hi/hi_IN/priyamvada/medium/hi_IN-priyamvada-medium.onnx.json": {
|
|
4874
|
+
"size_bytes": 4973,
|
|
4875
|
+
"md5_digest": "599ca4dc5d421a9c66692433f618e080"
|
|
4876
|
+
},
|
|
4877
|
+
"hi/hi_IN/priyamvada/medium/MODEL_CARD": {
|
|
4878
|
+
"size_bytes": 307,
|
|
4879
|
+
"md5_digest": "e2b745cf97087be0a97c7f10215bfa70"
|
|
4880
|
+
}
|
|
4881
|
+
},
|
|
4882
|
+
"aliases": []
|
|
4883
|
+
},
|
|
4794
4884
|
"hu_HU-anna-medium": {
|
|
4795
4885
|
"key": "hu_HU-anna-medium",
|
|
4796
4886
|
"name": "anna",
|
|
@@ -5264,6 +5354,96 @@
|
|
|
5264
5354
|
},
|
|
5265
5355
|
"aliases": []
|
|
5266
5356
|
},
|
|
5357
|
+
"ml_IN-arjun-medium": {
|
|
5358
|
+
"key": "ml_IN-arjun-medium",
|
|
5359
|
+
"name": "arjun",
|
|
5360
|
+
"language": {
|
|
5361
|
+
"code": "ml_IN",
|
|
5362
|
+
"family": "ml",
|
|
5363
|
+
"region": "IN",
|
|
5364
|
+
"name_native": "മലയാളം",
|
|
5365
|
+
"name_english": "Malayalam",
|
|
5366
|
+
"country_english": "India"
|
|
5367
|
+
},
|
|
5368
|
+
"quality": "medium",
|
|
5369
|
+
"num_speakers": 1,
|
|
5370
|
+
"speaker_id_map": {},
|
|
5371
|
+
"files": {
|
|
5372
|
+
"ml/ml_IN/arjun/medium/ml_IN-arjun-medium.onnx": {
|
|
5373
|
+
"size_bytes": 62950044,
|
|
5374
|
+
"md5_digest": "4f20109c108aa80f46df85ab9cda5daa"
|
|
5375
|
+
},
|
|
5376
|
+
"ml/ml_IN/arjun/medium/ml_IN-arjun-medium.onnx.json": {
|
|
5377
|
+
"size_bytes": 5044,
|
|
5378
|
+
"md5_digest": "18454efcad5bb889ee4cb1cb035993f5"
|
|
5379
|
+
},
|
|
5380
|
+
"ml/ml_IN/arjun/medium/MODEL_CARD": {
|
|
5381
|
+
"size_bytes": 308,
|
|
5382
|
+
"md5_digest": "eb0037396b93f38ffbc093dba42cf8be"
|
|
5383
|
+
}
|
|
5384
|
+
},
|
|
5385
|
+
"aliases": []
|
|
5386
|
+
},
|
|
5387
|
+
"ml_IN-meera-medium": {
|
|
5388
|
+
"key": "ml_IN-meera-medium",
|
|
5389
|
+
"name": "meera",
|
|
5390
|
+
"language": {
|
|
5391
|
+
"code": "ml_IN",
|
|
5392
|
+
"family": "ml",
|
|
5393
|
+
"region": "IN",
|
|
5394
|
+
"name_native": "മലയാളം",
|
|
5395
|
+
"name_english": "Malayalam",
|
|
5396
|
+
"country_english": "India"
|
|
5397
|
+
},
|
|
5398
|
+
"quality": "medium",
|
|
5399
|
+
"num_speakers": 1,
|
|
5400
|
+
"speaker_id_map": {},
|
|
5401
|
+
"files": {
|
|
5402
|
+
"ml/ml_IN/meera/medium/ml_IN-meera-medium.onnx": {
|
|
5403
|
+
"size_bytes": 62950044,
|
|
5404
|
+
"md5_digest": "3eb7b05d25c1551f7a7cec1e1c153b1f"
|
|
5405
|
+
},
|
|
5406
|
+
"ml/ml_IN/meera/medium/ml_IN-meera-medium.onnx.json": {
|
|
5407
|
+
"size_bytes": 5045,
|
|
5408
|
+
"md5_digest": "64c2eee28c62e3a072ccc2ea3d812748"
|
|
5409
|
+
},
|
|
5410
|
+
"ml/ml_IN/meera/medium/MODEL_CARD": {
|
|
5411
|
+
"size_bytes": 308,
|
|
5412
|
+
"md5_digest": "626a0c1d744d0ce6ffca95665c526939"
|
|
5413
|
+
}
|
|
5414
|
+
},
|
|
5415
|
+
"aliases": []
|
|
5416
|
+
},
|
|
5417
|
+
"ne_NP-chitwan-medium": {
|
|
5418
|
+
"key": "ne_NP-chitwan-medium",
|
|
5419
|
+
"name": "chitwan",
|
|
5420
|
+
"language": {
|
|
5421
|
+
"code": "ne_NP",
|
|
5422
|
+
"family": "ne",
|
|
5423
|
+
"region": "NP",
|
|
5424
|
+
"name_native": "नेपाली",
|
|
5425
|
+
"name_english": "Nepali",
|
|
5426
|
+
"country_english": "Nepal"
|
|
5427
|
+
},
|
|
5428
|
+
"quality": "medium",
|
|
5429
|
+
"num_speakers": 1,
|
|
5430
|
+
"speaker_id_map": {},
|
|
5431
|
+
"files": {
|
|
5432
|
+
"ne/ne_NP/chitwan/medium/ne_NP-chitwan-medium.onnx": {
|
|
5433
|
+
"size_bytes": 62950044,
|
|
5434
|
+
"md5_digest": "74cdb5b32816c366af74b55ed7494e25"
|
|
5435
|
+
},
|
|
5436
|
+
"ne/ne_NP/chitwan/medium/ne_NP-chitwan-medium.onnx.json": {
|
|
5437
|
+
"size_bytes": 5043,
|
|
5438
|
+
"md5_digest": "7ddc520e24a862016f6d22cde4b70ac1"
|
|
5439
|
+
},
|
|
5440
|
+
"ne/ne_NP/chitwan/medium/MODEL_CARD": {
|
|
5441
|
+
"size_bytes": 275,
|
|
5442
|
+
"md5_digest": "dcd35df097f84ace498d7afeb5b1a29c"
|
|
5443
|
+
}
|
|
5444
|
+
},
|
|
5445
|
+
"aliases": []
|
|
5446
|
+
},
|
|
5267
5447
|
"ne_NP-google-medium": {
|
|
5268
5448
|
"key": "ne_NP-google-medium",
|
|
5269
5449
|
"name": "google",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wyoming-piper
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.3
|
|
4
4
|
Summary: Wyoming Server for Piper
|
|
5
5
|
Author-email: Michael Hansen <mike@rhasspy.org>
|
|
6
6
|
License: MIT
|
|
@@ -14,10 +14,12 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: >=3.8
|
|
18
19
|
Description-Content-Type: text/markdown
|
|
19
20
|
License-File: LICENSE.md
|
|
20
|
-
Requires-Dist: wyoming
|
|
21
|
+
Requires-Dist: wyoming<1.8,>=1.7.2
|
|
22
|
+
Requires-Dist: regex==2024.11.6
|
|
21
23
|
Provides-Extra: dev
|
|
22
24
|
Requires-Dist: black==22.12.0; extra == "dev"
|
|
23
25
|
Requires-Dist: flake8==6.0.0; extra == "dev"
|
|
@@ -3,6 +3,7 @@ README.md
|
|
|
3
3
|
pyproject.toml
|
|
4
4
|
setup.cfg
|
|
5
5
|
tests/test_piper.py
|
|
6
|
+
tests/test_sentence_boundary.py
|
|
6
7
|
wyoming_piper/__init__.py
|
|
7
8
|
wyoming_piper/__main__.py
|
|
8
9
|
wyoming_piper/const.py
|
|
@@ -10,6 +11,7 @@ wyoming_piper/download.py
|
|
|
10
11
|
wyoming_piper/file_hash.py
|
|
11
12
|
wyoming_piper/handler.py
|
|
12
13
|
wyoming_piper/process.py
|
|
14
|
+
wyoming_piper/sentence_boundary.py
|
|
13
15
|
wyoming_piper/voices.json
|
|
14
16
|
wyoming_piper.egg-info/PKG-INFO
|
|
15
17
|
wyoming_piper.egg-info/SOURCES.txt
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|