scriptconv-copyleft 0.1.0a1__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.
- scriptconv_copyleft/__init__.py +6 -0
- scriptconv_copyleft/phonemizers/__init__.py +7 -0
- scriptconv_copyleft/phonemizers/_vendored/__init__.py +8 -0
- scriptconv_copyleft/phonemizers/_vendored/kog2p/COPYING +674 -0
- scriptconv_copyleft/phonemizers/_vendored/kog2p/LICENSE.md +5 -0
- scriptconv_copyleft/phonemizers/_vendored/kog2p/__init__.py +393 -0
- scriptconv_copyleft/phonemizers/_vendored/kog2p/rulebook.txt +212 -0
- scriptconv_copyleft/phonemizers/eu.py +112 -0
- scriptconv_copyleft/phonemizers/fa.py +44 -0
- scriptconv_copyleft/phonemizers/gl.py +81 -0
- scriptconv_copyleft/phonemizers/ja.py +47 -0
- scriptconv_copyleft/phonemizers/ko.py +102 -0
- scriptconv_copyleft/phonemizers/mul.py +1157 -0
- scriptconv_copyleft/readings.py +99 -0
- scriptconv_copyleft/version.py +8 -0
- scriptconv_copyleft-0.1.0a1.dist-info/METADATA +123 -0
- scriptconv_copyleft-0.1.0a1.dist-info/RECORD +22 -0
- scriptconv_copyleft-0.1.0a1.dist-info/WHEEL +5 -0
- scriptconv_copyleft-0.1.0a1.dist-info/licenses/LICENSE +202 -0
- scriptconv_copyleft-0.1.0a1.dist-info/licenses/scriptconv_copyleft/phonemizers/_vendored/kog2p/COPYING +674 -0
- scriptconv_copyleft-0.1.0a1.dist-info/licenses/scriptconv_copyleft/phonemizers/_vendored/kog2p/LICENSE.md +5 -0
- scriptconv_copyleft-0.1.0a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from scriptconv.phonemizers.base import BasePhonemizer
|
|
4
|
+
from scriptconv.phonemizers.enums import Alphabet
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# AhoTTS engine variant, selected per-voice via ``phonemizer_model`` in the
|
|
8
|
+
# voice config. Each maps to an ``ahotts_g2p.phonemize`` call.
|
|
9
|
+
ENGINES = {
|
|
10
|
+
"classic": {"version": "classic"}, # original AhoTTS engine (HiTZ VITS voices)
|
|
11
|
+
"modern": {"version": "modern"}, # StyleTTS-era build (HiTZ/StyleTTS2-eu)
|
|
12
|
+
"northern": {"dialect": "northern"}, # Northern (Iparralde / Iparrahotsa) dialect
|
|
13
|
+
}
|
|
14
|
+
DEFAULT_ENGINE = "modern"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AhoTTSPhonemizer(BasePhonemizer):
|
|
18
|
+
"""
|
|
19
|
+
AhoTTS phonemizer backed by ``ahotts-g2p``, a pure-Python port of the
|
|
20
|
+
AhoTTS engine (no C build, no runtime dependencies).
|
|
21
|
+
|
|
22
|
+
Covers the two AhoTTS-frontend languages: Basque (``eu``) and Spanish
|
|
23
|
+
(``es``). The target language is taken from the per-call ``lang`` argument
|
|
24
|
+
(so the same phonemizer instance serves both); ``ahotts_g2p.phonemize``
|
|
25
|
+
dispatches on it.
|
|
26
|
+
|
|
27
|
+
The engine variant is chosen per-voice with ``phonemizer_model`` in the
|
|
28
|
+
voice config (passed to the constructor as ``engine``):
|
|
29
|
+
|
|
30
|
+
* ``classic`` -- the original AhoTTS engine; the HiTZ VITS voices (eu+es).
|
|
31
|
+
* ``modern`` -- the StyleTTS-era build; HiTZ/StyleTTS2-eu. The default.
|
|
32
|
+
* ``northern`` -- the Northern (Iparralde / Iparrahotsa) Basque dialect:
|
|
33
|
+
pronounced /h/, French vowels (ü -> /y/), uvular /ʁ/, a remapped
|
|
34
|
+
sibilant system. Basque only.
|
|
35
|
+
|
|
36
|
+
``ahotts_g2p.phonemize`` already returns the collapsed single-char training
|
|
37
|
+
string, so no further token folding is needed. It is imported lazily so
|
|
38
|
+
importing ``scriptconv`` does not hard-require it.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
engine_distribution = "ahotts_g2p"
|
|
42
|
+
|
|
43
|
+
SUPPORTED_LANGS = ["eu-ES", "es-ES"]
|
|
44
|
+
|
|
45
|
+
def __init__(self, engine: Optional[str] = None,
|
|
46
|
+
alphabet: Alphabet = Alphabet.IPA):
|
|
47
|
+
"""
|
|
48
|
+
Args:
|
|
49
|
+
engine (Optional[str]): AhoTTS variant -- ``"classic"``, ``"modern"``
|
|
50
|
+
or ``"northern"`` (from the voice's ``phonemizer_model``).
|
|
51
|
+
Defaults to ``"modern"``.
|
|
52
|
+
alphabet (Alphabet): Accepted for signature parity; AhoTTS always
|
|
53
|
+
produces IPA-derived single-char tokens.
|
|
54
|
+
"""
|
|
55
|
+
engine = (engine or DEFAULT_ENGINE).lower()
|
|
56
|
+
if engine not in ENGINES:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
f"unknown AhoTTS engine {engine!r} "
|
|
59
|
+
f"(supported: {', '.join(ENGINES)})"
|
|
60
|
+
)
|
|
61
|
+
self.engine = engine
|
|
62
|
+
self._phonemize = None
|
|
63
|
+
super().__init__(alphabet)
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def phonemize_fn(self):
|
|
67
|
+
"""Lazily import and cache ``ahotts_g2p.phonemize``."""
|
|
68
|
+
if self._phonemize is None:
|
|
69
|
+
try:
|
|
70
|
+
from ahotts_g2p import phonemize
|
|
71
|
+
except ImportError as e:
|
|
72
|
+
raise ImportError(
|
|
73
|
+
"ahotts-g2p is required for the AhoTTS Basque phonemizer. "
|
|
74
|
+
"Install it with 'pip install ahotts-g2p' "
|
|
75
|
+
"(or 'pip install scriptconv[eu]')."
|
|
76
|
+
) from e
|
|
77
|
+
self._phonemize = phonemize
|
|
78
|
+
return self._phonemize
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def get_lang(cls, target_lang: str) -> str:
|
|
82
|
+
"""
|
|
83
|
+
Validate and return the closest supported language code (eu or es).
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
ValueError: If the language code is unsupported.
|
|
87
|
+
"""
|
|
88
|
+
return cls.match_lang(target_lang, cls.SUPPORTED_LANGS)
|
|
89
|
+
|
|
90
|
+
def phonemize_string(self, text: str, lang: str) -> str:
|
|
91
|
+
"""
|
|
92
|
+
Convert Basque or Spanish text into the AhoTTS single-char IPA training
|
|
93
|
+
string.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
text (str): The input text to phonemize.
|
|
97
|
+
lang (str): The language code (``eu`` or ``es``). The ``northern``
|
|
98
|
+
dialect engine is Basque-only; combining it with ``es`` raises.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
str: Space-separated single-char phoneme tokens.
|
|
102
|
+
"""
|
|
103
|
+
g2p_lang = self.get_lang(lang).split("-")[0]
|
|
104
|
+
kwargs = dict(ENGINES[self.engine])
|
|
105
|
+
if g2p_lang != "eu" and "dialect" in kwargs:
|
|
106
|
+
raise ValueError(
|
|
107
|
+
f"the {self.engine!r} AhoTTS engine (dialect) is Basque-only; "
|
|
108
|
+
f"it cannot phonemize lang={lang!r}"
|
|
109
|
+
)
|
|
110
|
+
return self.phonemize_fn(text, lang=g2p_lang, **kwargs)
|
|
111
|
+
|
|
112
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from scriptconv.phonemizers.base import BasePhonemizer
|
|
2
|
+
from scriptconv.phonemizers.enums import Alphabet
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PersianPhonemizer(BasePhonemizer):
|
|
6
|
+
"""https://github.com/de-mh/persian_phonemizer"""
|
|
7
|
+
|
|
8
|
+
engine_distribution = "persian_phonemizer"
|
|
9
|
+
def __init__(self, alphabet=Alphabet.IPA):
|
|
10
|
+
try:
|
|
11
|
+
from persian_phonemizer import Phonemizer
|
|
12
|
+
except ImportError as e:
|
|
13
|
+
raise ImportError(
|
|
14
|
+
"persian_phonemizer is required for the Persian phonemizer. "
|
|
15
|
+
"Install it with 'pip install persian_phonemizer' "
|
|
16
|
+
"(or 'pip install scriptconv[fa]')."
|
|
17
|
+
) from e
|
|
18
|
+
assert alphabet in [Alphabet.ERAAB, Alphabet.IPA]
|
|
19
|
+
output_format = "IPA" if alphabet == Alphabet.IPA else 'eraab'
|
|
20
|
+
self.g2p = Phonemizer(output_format)
|
|
21
|
+
super().__init__(alphabet)
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def get_lang(cls, target_lang: str) -> str:
|
|
25
|
+
"""
|
|
26
|
+
Validates and returns the closest supported language code.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
target_lang (str): The language code to validate.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
str: The validated language code.
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
ValueError: If the language code is unsupported.
|
|
36
|
+
"""
|
|
37
|
+
# this check is here only to throw an exception if invalid language is provided
|
|
38
|
+
return cls.match_lang(target_lang, ["fa"])
|
|
39
|
+
|
|
40
|
+
def phonemize_string(self, text: str, lang: str = "fa") -> str:
|
|
41
|
+
"""
|
|
42
|
+
"""
|
|
43
|
+
lang = self.get_lang(lang)
|
|
44
|
+
return self.g2p.phonemize(text)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from scriptconv.phonemizers.base import BasePhonemizer
|
|
4
|
+
from scriptconv.phonemizers.enums import Alphabet
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CotoviaPhonemizer(BasePhonemizer):
|
|
8
|
+
"""
|
|
9
|
+
Galician phonemizer backed by pycotovia — a pure-Python port of the Cotovia
|
|
10
|
+
G2P engine that has verified parity with the original C binary.
|
|
11
|
+
|
|
12
|
+
Output alphabets:
|
|
13
|
+
- ``Alphabet.COTOVIA`` (default) — raw Cotovia phoneme notation (e.g.
|
|
14
|
+
``"Este e uN ..."``), the binary-parity-tested native phoneset
|
|
15
|
+
- ``Alphabet.IPA`` — IPA string produced by pycotovia's ``cotovia_to_ipa``
|
|
16
|
+
|
|
17
|
+
Voices trained on Cotovia-alphabet output continue to receive the same
|
|
18
|
+
notation strings as before because pycotovia is binary-parity-tested
|
|
19
|
+
(see pycotovia/docs/parity.md).
|
|
20
|
+
|
|
21
|
+
``pycotovia`` is an optional dependency (the ``gl`` extra); it is imported
|
|
22
|
+
lazily so that ``import scriptconv.phonemizers`` works without it installed.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
engine_distribution = "pycotovia"
|
|
26
|
+
|
|
27
|
+
def __init__(self, alphabet: Alphabet = Alphabet.COTOVIA,
|
|
28
|
+
model: Optional[str] = None):
|
|
29
|
+
"""
|
|
30
|
+
Args:
|
|
31
|
+
alphabet (Alphabet): ``COTOVIA`` (raw notation, the default) or
|
|
32
|
+
``IPA``.
|
|
33
|
+
model (Optional[str]): phonemizer variant, from the voice's
|
|
34
|
+
``phonemizer_model``. ``"stress"`` emits the cotovia notation
|
|
35
|
+
with the stressed vowel marked by a trailing ``^`` (e.g.
|
|
36
|
+
``"o^la"``) and multi-char phonemes preserved -- matching the
|
|
37
|
+
AhoTTS Cotovia front-end the HiTZ gl VITS voices were trained on,
|
|
38
|
+
whose tokenizer gives stressed vowels their own ids. The default
|
|
39
|
+
(``None``) is the original stressless transcription used by the
|
|
40
|
+
proxectonos gl voices.
|
|
41
|
+
"""
|
|
42
|
+
self._engine: Optional[Any] = None
|
|
43
|
+
self.model = (model or "").lower() or None
|
|
44
|
+
super().__init__(alphabet)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def engine(self) -> Any:
|
|
48
|
+
if self._engine is None:
|
|
49
|
+
try:
|
|
50
|
+
from pycotovia import Phonemizer as _PycotoviaPhonemizer
|
|
51
|
+
except ImportError as e:
|
|
52
|
+
raise ImportError(
|
|
53
|
+
"pycotovia is required for the Galician (Cotovia) phonemizer. "
|
|
54
|
+
"Install it with 'pip install pycotovia' or 'pip install scriptconv[gl]'."
|
|
55
|
+
) from e
|
|
56
|
+
self._engine = _PycotoviaPhonemizer()
|
|
57
|
+
return self._engine
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def get_lang(cls, target_lang: str) -> str:
|
|
61
|
+
return cls.match_lang(target_lang, ["gl-ES"])
|
|
62
|
+
|
|
63
|
+
def phonemize_string(self, text: str, lang: str) -> str:
|
|
64
|
+
self.get_lang(lang)
|
|
65
|
+
if self.model == "stress":
|
|
66
|
+
# tra=2 -> stressed vowel followed by '^'. The trailing space the
|
|
67
|
+
# engine appends per word is kept (word separator); the tokenizer
|
|
68
|
+
# folds 'V^' and multi-char phonemes (tS, rr, ...) back into single
|
|
69
|
+
# tokens via the voice's phoneme_id_map compound keys.
|
|
70
|
+
return self.engine.phonemize(text, tra=2)
|
|
71
|
+
cotovia_output = self.engine.phonemize(text)
|
|
72
|
+
if self.alphabet == Alphabet.IPA:
|
|
73
|
+
try:
|
|
74
|
+
from pycotovia import cotovia_to_ipa as _cotovia_to_ipa
|
|
75
|
+
except ImportError as e:
|
|
76
|
+
raise ImportError(
|
|
77
|
+
"pycotovia is required for the Galician (Cotovia) phonemizer. "
|
|
78
|
+
"Install it with 'pip install pycotovia' or 'pip install scriptconv[gl]'."
|
|
79
|
+
) from e
|
|
80
|
+
return _cotovia_to_ipa(cotovia_output)
|
|
81
|
+
return cotovia_output
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from scriptconv.phonemizers.base import BasePhonemizer, _check_alphabet
|
|
2
|
+
from scriptconv.phonemizers.enums import Alphabet
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PyKakasiPhonemizer(BasePhonemizer):
|
|
6
|
+
engine_distribution = "pykakasi"
|
|
7
|
+
|
|
8
|
+
def __init__(self, alphabet=Alphabet.HEPBURN):
|
|
9
|
+
_check_alphabet(self, alphabet,
|
|
10
|
+
[Alphabet.HEPBURN, Alphabet.KANA, Alphabet.HIRA])
|
|
11
|
+
# kana, hira, hepburn
|
|
12
|
+
try:
|
|
13
|
+
import pykakasi
|
|
14
|
+
except ImportError as e:
|
|
15
|
+
raise ImportError(
|
|
16
|
+
"pykakasi is required for the PyKakasi phonemizer. "
|
|
17
|
+
"Install it with 'pip install pykakasi' "
|
|
18
|
+
"(or 'pip install scriptconv[ja-phonemizers]')."
|
|
19
|
+
) from e
|
|
20
|
+
self.g2p = pykakasi.kakasi()
|
|
21
|
+
super().__init__(alphabet)
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def get_lang(cls, target_lang: str) -> str:
|
|
25
|
+
"""
|
|
26
|
+
Validates and returns the closest supported language code.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
target_lang (str): The language code to validate.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
str: The validated language code.
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
ValueError: If the language code is unsupported.
|
|
36
|
+
"""
|
|
37
|
+
# this check is here only to throw an exception if invalid language is provided
|
|
38
|
+
return cls.match_lang(target_lang, ["ja"])
|
|
39
|
+
|
|
40
|
+
def phonemize_string(self, text: str, lang: str = "ja") -> str:
|
|
41
|
+
"""
|
|
42
|
+
"""
|
|
43
|
+
lang = self.get_lang(lang)
|
|
44
|
+
return " ".join([
|
|
45
|
+
a[self.alphabet] for a in
|
|
46
|
+
self.g2p.convert(text)
|
|
47
|
+
])
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from importlib import metadata
|
|
5
|
+
from typing import Tuple
|
|
6
|
+
|
|
7
|
+
from scriptconv.phonemizers.base import BasePhonemizer, _check_alphabet
|
|
8
|
+
from scriptconv.phonemizers._thirdparty.hangul2ipa import hangul2ipa
|
|
9
|
+
from scriptconv.phonemizers.enums import Alphabet
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class G2PKPhonemizer(BasePhonemizer):
|
|
13
|
+
engine_distribution = "g2pk"
|
|
14
|
+
|
|
15
|
+
def __init__(self, descriptive=True, group_vowels=True, to_syl=True,
|
|
16
|
+
alphabet=Alphabet.IPA):
|
|
17
|
+
_check_alphabet(self, alphabet, [Alphabet.IPA, Alphabet.HANGUL])
|
|
18
|
+
try:
|
|
19
|
+
from g2pk import G2p
|
|
20
|
+
except ImportError as e:
|
|
21
|
+
if sys.version_info >= (3, 13):
|
|
22
|
+
raise ImportError(
|
|
23
|
+
"g2pk is required for the G2PK phonemizer. Its dependency "
|
|
24
|
+
"python-mecab-ko has wheels up to CPython 3.12 only, so on "
|
|
25
|
+
"Python 3.13 and later pip builds it from source. Install "
|
|
26
|
+
"MeCab-ko first, so that mecab-config is on PATH, then run "
|
|
27
|
+
"'pip install g2pk'."
|
|
28
|
+
) from e
|
|
29
|
+
raise ImportError(
|
|
30
|
+
"g2pk is required for the G2PK phonemizer. "
|
|
31
|
+
"Install it with 'pip install g2pk' "
|
|
32
|
+
"(or 'pip install scriptconv[ko]')."
|
|
33
|
+
) from e
|
|
34
|
+
self.g2p = G2p()
|
|
35
|
+
self.descriptive = descriptive
|
|
36
|
+
self.group_vowels = group_vowels
|
|
37
|
+
self.to_syl = to_syl
|
|
38
|
+
super().__init__(alphabet)
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def get_lang(cls, target_lang: str) -> str:
|
|
42
|
+
"""
|
|
43
|
+
Validates and returns the closest supported language code.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
target_lang (str): The language code to validate.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
str: The validated language code.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ValueError: If the language code is unsupported.
|
|
53
|
+
"""
|
|
54
|
+
# this check is here only to throw an exception if invalid language is provided
|
|
55
|
+
return cls.match_lang(target_lang, ["ko"])
|
|
56
|
+
|
|
57
|
+
def phonemize_string(self, text: str, lang: str = "ko") -> str:
|
|
58
|
+
"""
|
|
59
|
+
"""
|
|
60
|
+
lang = self.get_lang(lang)
|
|
61
|
+
p = self.g2p(text, descriptive=self.descriptive,
|
|
62
|
+
group_vowels=self.group_vowels,
|
|
63
|
+
to_syl=self.to_syl)
|
|
64
|
+
if self.alphabet == Alphabet.IPA:
|
|
65
|
+
return hangul2ipa(p)
|
|
66
|
+
return p
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class KoG2PPhonemizer(BasePhonemizer):
|
|
70
|
+
"""Korean phonemizer wrapping an external ``kog2p`` distribution.
|
|
71
|
+
|
|
72
|
+
Uses an externally-installed ``kog2p`` when present, otherwise the
|
|
73
|
+
quarantined vendored copy under ``_vendored/kog2p`` — GPL-3.0 under its
|
|
74
|
+
own license, NOT this library's Apache-2.0. Never selected
|
|
75
|
+
automatically; :class:`G2PKPhonemizer` is the unencumbered default.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(self, alphabet: Alphabet = Alphabet.IPA):
|
|
79
|
+
super().__init__(alphabet)
|
|
80
|
+
try:
|
|
81
|
+
# an externally-installed kog2p distribution wins
|
|
82
|
+
from kog2p import runKoG2P
|
|
83
|
+
except ImportError:
|
|
84
|
+
# quarantined vendored copy, GPL-3.0 under its own license
|
|
85
|
+
# (see _vendored/kog2p/LICENSE.md); explicit opt-in by
|
|
86
|
+
# requesting this phonemizer
|
|
87
|
+
from scriptconv_copyleft.phonemizers._vendored.kog2p import runKoG2P
|
|
88
|
+
self.g2p = runKoG2P
|
|
89
|
+
|
|
90
|
+
def _engine_release(self) -> Tuple[str, str]:
|
|
91
|
+
"""An installed ``kog2p`` runs in place of the vendored copy."""
|
|
92
|
+
if self.g2p.__module__.startswith("scriptconv_copyleft."):
|
|
93
|
+
return super()._engine_release()
|
|
94
|
+
return "kog2p", metadata.version("kog2p")
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def get_lang(cls, target_lang: str) -> str:
|
|
98
|
+
return cls.match_lang(target_lang, ["ko"])
|
|
99
|
+
|
|
100
|
+
def phonemize_string(self, text: str, lang: str) -> str:
|
|
101
|
+
# contract: the installed module's runKoG2P(text) -> phoneme string
|
|
102
|
+
return self.g2p(text)
|