mirror of https://github.com/coqui-ai/TTS.git
refactor(espeak_wrapper): fix ruff lint suggestions
This commit is contained in:
parent
7b2289a454
commit
962f9bbbcf
|
@ -1,7 +1,9 @@
|
||||||
|
"""Wrapper to call the espeak/espeak-ng phonemizer."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Dict, List
|
from typing import Optional
|
||||||
|
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
|
|
||||||
|
@ -11,7 +13,7 @@ from TTS.tts.utils.text.punctuation import Punctuation
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def is_tool(name):
|
def _is_tool(name) -> bool:
|
||||||
from shutil import which
|
from shutil import which
|
||||||
|
|
||||||
return which(name) is not None
|
return which(name) is not None
|
||||||
|
@ -22,23 +24,25 @@ def is_tool(name):
|
||||||
espeak_version_pattern = re.compile(r"text-to-speech:\s(?P<version>\d+\.\d+(\.\d+)?)")
|
espeak_version_pattern = re.compile(r"text-to-speech:\s(?P<version>\d+\.\d+(\.\d+)?)")
|
||||||
|
|
||||||
|
|
||||||
def get_espeak_version():
|
def get_espeak_version() -> str:
|
||||||
|
"""Return version of the `espeak` binary."""
|
||||||
output = subprocess.getoutput("espeak --version")
|
output = subprocess.getoutput("espeak --version")
|
||||||
match = espeak_version_pattern.search(output)
|
match = espeak_version_pattern.search(output)
|
||||||
|
|
||||||
return match.group("version")
|
return match.group("version")
|
||||||
|
|
||||||
|
|
||||||
def get_espeakng_version():
|
def get_espeakng_version() -> str:
|
||||||
|
"""Return version of the `espeak-ng` binary."""
|
||||||
output = subprocess.getoutput("espeak-ng --version")
|
output = subprocess.getoutput("espeak-ng --version")
|
||||||
return output.split()[3]
|
return output.split()[3]
|
||||||
|
|
||||||
|
|
||||||
# priority: espeakng > espeak
|
# priority: espeakng > espeak
|
||||||
if is_tool("espeak-ng"):
|
if _is_tool("espeak-ng"):
|
||||||
_DEF_ESPEAK_LIB = "espeak-ng"
|
_DEF_ESPEAK_LIB = "espeak-ng"
|
||||||
_DEF_ESPEAK_VER = get_espeakng_version()
|
_DEF_ESPEAK_VER = get_espeakng_version()
|
||||||
elif is_tool("espeak"):
|
elif _is_tool("espeak"):
|
||||||
_DEF_ESPEAK_LIB = "espeak"
|
_DEF_ESPEAK_LIB = "espeak"
|
||||||
_DEF_ESPEAK_VER = get_espeak_version()
|
_DEF_ESPEAK_VER = get_espeak_version()
|
||||||
else:
|
else:
|
||||||
|
@ -46,7 +50,7 @@ else:
|
||||||
_DEF_ESPEAK_VER = None
|
_DEF_ESPEAK_VER = None
|
||||||
|
|
||||||
|
|
||||||
def _espeak_exe(espeak_lib: str, args: List, sync=False) -> List[str]:
|
def _espeak_exe(espeak_lib: str, args: list, *, sync: bool = False) -> list[bytes]:
|
||||||
"""Run espeak with the given arguments."""
|
"""Run espeak with the given arguments."""
|
||||||
cmd = [
|
cmd = [
|
||||||
espeak_lib,
|
espeak_lib,
|
||||||
|
@ -73,9 +77,7 @@ def _espeak_exe(espeak_lib: str, args: List, sync=False) -> List[str]:
|
||||||
if p.stdin:
|
if p.stdin:
|
||||||
p.stdin.close()
|
p.stdin.close()
|
||||||
return res
|
return res
|
||||||
res2 = []
|
res2 = list(res)
|
||||||
for line in res:
|
|
||||||
res2.append(line)
|
|
||||||
p.stdout.close()
|
p.stdout.close()
|
||||||
if p.stderr:
|
if p.stderr:
|
||||||
p.stderr.close()
|
p.stderr.close()
|
||||||
|
@ -86,7 +88,7 @@ def _espeak_exe(espeak_lib: str, args: List, sync=False) -> List[str]:
|
||||||
|
|
||||||
|
|
||||||
class ESpeak(BasePhonemizer):
|
class ESpeak(BasePhonemizer):
|
||||||
"""ESpeak wrapper calling `espeak` or `espeak-ng` from the command-line the perform G2P
|
"""Wrapper calling `espeak` or `espeak-ng` from the command-line to perform G2P.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
language (str):
|
language (str):
|
||||||
|
@ -111,13 +113,17 @@ class ESpeak(BasePhonemizer):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_ESPEAK_LIB = _DEF_ESPEAK_LIB
|
def __init__(
|
||||||
_ESPEAK_VER = _DEF_ESPEAK_VER
|
self,
|
||||||
|
language: str,
|
||||||
def __init__(self, language: str, backend=None, punctuations=Punctuation.default_puncs(), keep_puncs=True):
|
backend: Optional[str] = None,
|
||||||
if self._ESPEAK_LIB is None:
|
punctuations: str = Punctuation.default_puncs(),
|
||||||
raise Exception(" [!] No espeak backend found. Install espeak-ng or espeak to your system.")
|
keep_puncs: bool = True,
|
||||||
self.backend = self._ESPEAK_LIB
|
):
|
||||||
|
if _DEF_ESPEAK_LIB is None:
|
||||||
|
msg = "[!] No espeak backend found. Install espeak-ng or espeak to your system."
|
||||||
|
raise FileNotFoundError(msg)
|
||||||
|
self.backend = _DEF_ESPEAK_LIB
|
||||||
|
|
||||||
# band-aid for backwards compatibility
|
# band-aid for backwards compatibility
|
||||||
if language == "en":
|
if language == "en":
|
||||||
|
@ -130,35 +136,37 @@ class ESpeak(BasePhonemizer):
|
||||||
self.backend = backend
|
self.backend = backend
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def backend(self):
|
def backend(self) -> str:
|
||||||
return self._ESPEAK_LIB
|
return self._ESPEAK_LIB
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def backend_version(self):
|
def backend_version(self) -> str:
|
||||||
return self._ESPEAK_VER
|
return self._ESPEAK_VER
|
||||||
|
|
||||||
@backend.setter
|
@backend.setter
|
||||||
def backend(self, backend):
|
def backend(self, backend: str) -> None:
|
||||||
if backend not in ["espeak", "espeak-ng"]:
|
if backend not in ["espeak", "espeak-ng"]:
|
||||||
raise Exception("Unknown backend: %s" % backend)
|
msg = f"Unknown backend: {backend}"
|
||||||
|
raise ValueError(msg)
|
||||||
self._ESPEAK_LIB = backend
|
self._ESPEAK_LIB = backend
|
||||||
self._ESPEAK_VER = get_espeakng_version() if backend == "espeak-ng" else get_espeak_version()
|
self._ESPEAK_VER = get_espeakng_version() if backend == "espeak-ng" else get_espeak_version()
|
||||||
|
|
||||||
def auto_set_espeak_lib(self) -> None:
|
def auto_set_espeak_lib(self) -> None:
|
||||||
if is_tool("espeak-ng"):
|
if _is_tool("espeak-ng"):
|
||||||
self._ESPEAK_LIB = "espeak-ng"
|
self._ESPEAK_LIB = "espeak-ng"
|
||||||
self._ESPEAK_VER = get_espeakng_version()
|
self._ESPEAK_VER = get_espeakng_version()
|
||||||
elif is_tool("espeak"):
|
elif _is_tool("espeak"):
|
||||||
self._ESPEAK_LIB = "espeak"
|
self._ESPEAK_LIB = "espeak"
|
||||||
self._ESPEAK_VER = get_espeak_version()
|
self._ESPEAK_VER = get_espeak_version()
|
||||||
else:
|
else:
|
||||||
raise Exception("Cannot set backend automatically. espeak-ng or espeak not found")
|
msg = "Cannot set backend automatically. espeak-ng or espeak not found"
|
||||||
|
raise FileNotFoundError(msg)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def name():
|
def name() -> str:
|
||||||
return "espeak"
|
return "espeak"
|
||||||
|
|
||||||
def phonemize_espeak(self, text: str, separator: str = "|", tie=False) -> str:
|
def phonemize_espeak(self, text: str, separator: str = "|", *, tie: bool = False) -> str:
|
||||||
"""Convert input text to phonemes.
|
"""Convert input text to phonemes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -193,7 +201,7 @@ class ESpeak(BasePhonemizer):
|
||||||
args.append(text)
|
args.append(text)
|
||||||
# compute phonemes
|
# compute phonemes
|
||||||
phonemes = ""
|
phonemes = ""
|
||||||
for line in _espeak_exe(self._ESPEAK_LIB, args, sync=True):
|
for line in _espeak_exe(self.backend, args, sync=True):
|
||||||
logger.debug("line: %s", repr(line))
|
logger.debug("line: %s", repr(line))
|
||||||
ph_decoded = line.decode("utf8").strip()
|
ph_decoded = line.decode("utf8").strip()
|
||||||
# espeak:
|
# espeak:
|
||||||
|
@ -210,11 +218,11 @@ class ESpeak(BasePhonemizer):
|
||||||
phonemes += ph_decoded.strip()
|
phonemes += ph_decoded.strip()
|
||||||
return phonemes.replace("_", separator)
|
return phonemes.replace("_", separator)
|
||||||
|
|
||||||
def _phonemize(self, text, separator=None):
|
def _phonemize(self, text: str, separator: str = "") -> str:
|
||||||
return self.phonemize_espeak(text, separator, tie=False)
|
return self.phonemize_espeak(text, separator, tie=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def supported_languages() -> Dict:
|
def supported_languages() -> dict[str, str]:
|
||||||
"""Get a dictionary of supported languages.
|
"""Get a dictionary of supported languages.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -224,8 +232,7 @@ class ESpeak(BasePhonemizer):
|
||||||
return {}
|
return {}
|
||||||
args = ["--voices"]
|
args = ["--voices"]
|
||||||
langs = {}
|
langs = {}
|
||||||
count = 0
|
for count, line in enumerate(_espeak_exe(_DEF_ESPEAK_LIB, args, sync=True)):
|
||||||
for line in _espeak_exe(_DEF_ESPEAK_LIB, args, sync=True):
|
|
||||||
line = line.decode("utf8").strip()
|
line = line.decode("utf8").strip()
|
||||||
if count > 0:
|
if count > 0:
|
||||||
cols = line.split()
|
cols = line.split()
|
||||||
|
@ -233,7 +240,6 @@ class ESpeak(BasePhonemizer):
|
||||||
lang_name = cols[3]
|
lang_name = cols[3]
|
||||||
langs[lang_code] = lang_name
|
langs[lang_code] = lang_name
|
||||||
logger.debug("line: %s", repr(line))
|
logger.debug("line: %s", repr(line))
|
||||||
count += 1
|
|
||||||
return langs
|
return langs
|
||||||
|
|
||||||
def version(self) -> str:
|
def version(self) -> str:
|
||||||
|
@ -242,16 +248,12 @@ class ESpeak(BasePhonemizer):
|
||||||
Returns:
|
Returns:
|
||||||
str: Version of the used backend.
|
str: Version of the used backend.
|
||||||
"""
|
"""
|
||||||
args = ["--version"]
|
return self.backend_version
|
||||||
for line in _espeak_exe(self.backend, args, sync=True):
|
|
||||||
version = line.decode("utf8").strip().split()[2]
|
|
||||||
logger.debug("line: %s", repr(line))
|
|
||||||
return version
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_available(cls):
|
def is_available(cls) -> bool:
|
||||||
"""Return true if ESpeak is available else false"""
|
"""Return true if ESpeak is available else false."""
|
||||||
return is_tool("espeak") or is_tool("espeak-ng")
|
return _is_tool("espeak") or _is_tool("espeak-ng")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -8,6 +8,7 @@ requires = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
|
target-version = "py39"
|
||||||
line-length = 120
|
line-length = 120
|
||||||
lint.extend-select = [
|
lint.extend-select = [
|
||||||
"B033", # duplicate-value
|
"B033", # duplicate-value
|
||||||
|
|
Loading…
Reference in New Issue