scriptconv 0.0.4a2__tar.gz → 0.0.4a4__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.
- {scriptconv-0.0.4a2/scriptconv.egg-info → scriptconv-0.0.4a4}/PKG-INFO +51 -22
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/README.md +43 -21
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/pyproject.toml +3 -1
- scriptconv-0.0.4a4/scriptconv/diacritics.py +153 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/base.py +102 -2
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/registry.py +4 -1
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/version.py +1 -1
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4/scriptconv.egg-info}/PKG-INFO +51 -22
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv.egg-info/SOURCES.txt +2 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv.egg-info/requires.txt +9 -0
- scriptconv-0.0.4a4/tests/test_diacritics_graph.py +104 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_phonemizers_base.py +82 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/LICENSE +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/requirements.txt +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/__main__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/cangjie.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/conventions.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/data/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/data/cangjie5_tc.tsv.gz +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/graph.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/notation.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/bw2ipa.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/hangul2ipa.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/aspiration.csv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/assimilation.csv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/double_coda.csv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/hanja.tsv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/ipa.csv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/neutralization.csv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/tensification.csv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/yale.csv +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/codeswitch.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/diacritize.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/dialectal.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/english_g2p.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/espeak.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/frontend.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/levantine_g2p.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/normalize.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/phoneme_inventory.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/zh_num.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/kog2p/LICENSE.md +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/kog2p/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/kog2p/rulebook.txt +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/LICENSE.md +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/buck/__init__.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/buck/phonetise_buckwalter.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/buck/symbols.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/buck/tokenization.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/num2words.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/unicode_symbol2label.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/ar.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/en.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/enums.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/eu.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/fa.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/gl.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/he.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/ja.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/ko.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/mul.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/mwl.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/o2ipa.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/pt.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/shami.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/vi.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/zh.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/py.typed +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/readings.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/scripts.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/translit.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv.egg-info/dependency_links.txt +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv.egg-info/top_level.txt +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/setup.cfg +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_arpa_stress.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_cangjie.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_cli.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_conventions.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_errors_policy.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_examples.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_graph.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_notation.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_phonemizers_cjk_ar.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_readings.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_readings_zh.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_scripts.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_scripts_stressonnx_compat.py +0 -0
- {scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/tests/test_translit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scriptconv
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4a4
|
|
4
4
|
Summary: Zero-dependency script & phoneme-notation core — ISO-15924 detection & metadata, IPA↔ARPABET/X-SAMPA/Lexique/Kirshenbaum/Cotovía/RFE, Buckwalter↔Arabic, Hangul→jamo, kana
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://github.com/TigreGotico/scriptconv
|
|
@@ -78,6 +78,12 @@ Requires-Dist: viphoneme; extra == "vi"
|
|
|
78
78
|
Provides-Extra: tashkeel
|
|
79
79
|
Requires-Dist: scriptconv[phonemizers]; extra == "tashkeel"
|
|
80
80
|
Requires-Dist: text2tashkeel; extra == "tashkeel"
|
|
81
|
+
Provides-Extra: stress
|
|
82
|
+
Requires-Dist: scriptconv[phonemizers]; extra == "stress"
|
|
83
|
+
Requires-Dist: stressonnx>=0.0.2; extra == "stress"
|
|
84
|
+
Provides-Extra: pt
|
|
85
|
+
Requires-Dist: scriptconv[phonemizers]; extra == "pt"
|
|
86
|
+
Requires-Dist: bifonia>=0.1.1; extra == "pt"
|
|
81
87
|
Provides-Extra: ja-phonemizers
|
|
82
88
|
Requires-Dist: scriptconv[phonemizers]; extra == "ja-phonemizers"
|
|
83
89
|
Requires-Dist: pyopenjtalk; extra == "ja-phonemizers"
|
|
@@ -115,6 +121,7 @@ Requires-Dist: quebra-frases; extra == "test"
|
|
|
115
121
|
Requires-Dist: langcodes; extra == "test"
|
|
116
122
|
Requires-Dist: regex; extra == "test"
|
|
117
123
|
Requires-Dist: ovos-number-parser; extra == "test"
|
|
124
|
+
Requires-Dist: bifonia>=0.1.1; extra == "test"
|
|
118
125
|
Dynamic: license-file
|
|
119
126
|
|
|
120
127
|
<div align="center">
|
|
@@ -369,6 +376,38 @@ Two design points worth knowing:
|
|
|
369
376
|
local `model=` path; resolving and caching model files is the caller's
|
|
370
377
|
concern.
|
|
371
378
|
|
|
379
|
+
**Pre-G2P disambiguation.** `add_diacritics(text, lang, model=None)` restores
|
|
380
|
+
information ordinary orthography omits but a G2P needs, before phonemization:
|
|
381
|
+
Hebrew niqqud (phonikud), Arabic tashkeel (text2tashkeel), word stress across
|
|
382
|
+
26 stressonnx language tags — East Slavic, Bulgarian/Macedonian/Slovene,
|
|
383
|
+
Latvian, Armenian, Georgian, and Turkic/Caucasian languages (`scriptconv[stress]`),
|
|
384
|
+
and European-Portuguese heterophonic-homograph sense diacritics (bifonia —
|
|
385
|
+
`scriptconv[pt]`, never applied to `pt-BR`, whose vowel system differs):
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
from scriptconv.phonemizers import GraphemePhonemizer
|
|
389
|
+
|
|
390
|
+
p = GraphemePhonemizer()
|
|
391
|
+
p.add_diacritics("Tenho muita sede hoje.", "pt") # 'Tenho muita sêde hoje.' (thirst)
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Diacritization also joins the graph, like phonemization, via
|
|
395
|
+
`scriptconv.diacritics.register` — a `text -> text-diacritized` edge, opt-in,
|
|
396
|
+
with `text -> ipa` routing unchanged:
|
|
397
|
+
|
|
398
|
+
```python
|
|
399
|
+
from scriptconv import diacritics
|
|
400
|
+
g = DEFAULT_GRAPH.extend(diacritics.register).extend(phonemizers.register)
|
|
401
|
+
g.convert("Tenho muita sede hoje.", "text", "text-diacritized", lang="pt")
|
|
402
|
+
# 'Tenho muita sêde hoje.'
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Stress is unwritten or under-marked in all 26 covered languages; East Slavic
|
|
406
|
+
is the clearest case, where unstressed vowels also reduce (e.g. Russian
|
|
407
|
+
о→[ɐ]/[ə]), so a missing mark corrupts more than prosody there. stressonnx is
|
|
408
|
+
optional (not yet on PyPI) and emits the standard combining acute (U+0301)
|
|
409
|
+
after the stressed vowel.
|
|
410
|
+
|
|
372
411
|
Details: [docs/phonemizers.md](docs/phonemizers.md).
|
|
373
412
|
|
|
374
413
|
## Fidelity guarantees
|
|
@@ -412,6 +451,8 @@ The core installs with zero dependencies. Capabilities opt in:
|
|
|
412
451
|
| `espeak`, `gruut`, `goruut`, `epitran`, `transphone`, `misaki`, `byt5` | Multilingual phonemizer backends |
|
|
413
452
|
| `en-phonemizers`, `ja-phonemizers`, `zh-phonemizers`, `ko`, `ar-phonemizers`, `eu`, `pt-phonemizers`, `gl`, `he`, `fa`, `vi`, `mwl`, `shami`, `o2i` | Per-language phonemizer backends |
|
|
414
453
|
| `tashkeel` | Arabic diacritization for the phonemizer pipeline (text2tashkeel) |
|
|
454
|
+
| `stress` | Word-stress restoration for 26 stressonnx language tags — East Slavic, Bulgarian/Macedonian/Slovene, Latvian, Armenian, Georgian, Turkic/Caucasian — for the phonemizer pipeline (stressonnx; not yet on PyPI) |
|
|
455
|
+
| `pt` | European-Portuguese heterophonic-homograph sense diacritics for the phonemizer pipeline (bifonia) |
|
|
415
456
|
|
|
416
457
|
## Licensing
|
|
417
458
|
|
|
@@ -433,29 +474,17 @@ build on it:
|
|
|
433
474
|
text-to-speech; consumes scriptconv for scripts, notation, conventions and
|
|
434
475
|
the whole phonemizer layer.
|
|
435
476
|
- [orthography2ipa](https://github.com/TigreGotico/orthography2ipa) —
|
|
436
|
-
data-driven orthography→IPA engine; the usual per-language phonemizer
|
|
437
|
-
|
|
438
|
-
- [
|
|
439
|
-
|
|
477
|
+
data-driven orthography→IPA engine; the usual per-language phonemizer default.
|
|
478
|
+
- [arbtok](https://github.com/TigreGotico/arbtok) — Arabic phonemizer (dialect-aware).
|
|
479
|
+
- [euskaphone](https://github.com/TigreGotico/euskaphone) — Basque phonemizer (dialect-aware).
|
|
480
|
+
- [tugaphone](https://github.com/TigreGotico/tugaphone) — Portuguese phonemizer (dialect-aware).
|
|
481
|
+
- [mwl_phonemizer](https://github.com/TigreGotico/mwl_phonemizer) — Mirandese phonemizer.
|
|
482
|
+
- [g2p_barranquenho](https://github.com/TigreGotico/g2p_barranquenho) — Barranquenho phonemizer.
|
|
483
|
+
- [pycotovia](https://github.com/TigreGotico/pycotovia) — Pure-Python phonemizer port
|
|
484
|
+
of the Cotovía Galician TTS engine, whose notation scriptconv transcodes.
|
|
440
485
|
- [espyak](https://github.com/TigreGotico/espyak) — pure-Python port of
|
|
441
486
|
espeak-ng's G2P; the espeak fallback when the binary is absent.
|
|
442
|
-
|
|
443
|
-
phonemizer (dialect-aware).
|
|
444
|
-
- [tugaphone](https://github.com/TigreGotico/tugaphone) — European
|
|
445
|
-
Portuguese phonemizer.
|
|
446
|
-
- [mwl_phonemizer](https://github.com/TigreGotico/mwl_phonemizer) —
|
|
447
|
-
Mirandese phonemizer.
|
|
448
|
-
- [g2p_barranquenho](https://github.com/TigreGotico/g2p_barranquenho) —
|
|
449
|
-
Barranquenho phonemizer.
|
|
450
|
-
- [pycotovia](https://github.com/TigreGotico/pycotovia) — Python bindings
|
|
451
|
-
for the Cotovía Galician TTS engine, whose notation scriptconv transcodes.
|
|
452
|
-
- [stressonnx](https://github.com/TigreGotico/stressonnx) — East Slavic
|
|
453
|
-
stress annotation; shares scriptconv's script tags.
|
|
454
|
-
- [text2tashkeel](https://github.com/TigreGotico/text2tashkeel) — Arabic
|
|
455
|
-
diacritization models (the prediction side of the `tashkeel` convention).
|
|
456
|
-
- [text2nikkud](https://github.com/TigreGotico/text2nikkud) — Hebrew
|
|
457
|
-
niqqud restoration (the prediction side of the `niqqud` convention).
|
|
458
|
-
|
|
487
|
+
|
|
459
488
|
## Development
|
|
460
489
|
|
|
461
490
|
```bash
|
|
@@ -250,6 +250,38 @@ Two design points worth knowing:
|
|
|
250
250
|
local `model=` path; resolving and caching model files is the caller's
|
|
251
251
|
concern.
|
|
252
252
|
|
|
253
|
+
**Pre-G2P disambiguation.** `add_diacritics(text, lang, model=None)` restores
|
|
254
|
+
information ordinary orthography omits but a G2P needs, before phonemization:
|
|
255
|
+
Hebrew niqqud (phonikud), Arabic tashkeel (text2tashkeel), word stress across
|
|
256
|
+
26 stressonnx language tags — East Slavic, Bulgarian/Macedonian/Slovene,
|
|
257
|
+
Latvian, Armenian, Georgian, and Turkic/Caucasian languages (`scriptconv[stress]`),
|
|
258
|
+
and European-Portuguese heterophonic-homograph sense diacritics (bifonia —
|
|
259
|
+
`scriptconv[pt]`, never applied to `pt-BR`, whose vowel system differs):
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
from scriptconv.phonemizers import GraphemePhonemizer
|
|
263
|
+
|
|
264
|
+
p = GraphemePhonemizer()
|
|
265
|
+
p.add_diacritics("Tenho muita sede hoje.", "pt") # 'Tenho muita sêde hoje.' (thirst)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Diacritization also joins the graph, like phonemization, via
|
|
269
|
+
`scriptconv.diacritics.register` — a `text -> text-diacritized` edge, opt-in,
|
|
270
|
+
with `text -> ipa` routing unchanged:
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
from scriptconv import diacritics
|
|
274
|
+
g = DEFAULT_GRAPH.extend(diacritics.register).extend(phonemizers.register)
|
|
275
|
+
g.convert("Tenho muita sede hoje.", "text", "text-diacritized", lang="pt")
|
|
276
|
+
# 'Tenho muita sêde hoje.'
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Stress is unwritten or under-marked in all 26 covered languages; East Slavic
|
|
280
|
+
is the clearest case, where unstressed vowels also reduce (e.g. Russian
|
|
281
|
+
о→[ɐ]/[ə]), so a missing mark corrupts more than prosody there. stressonnx is
|
|
282
|
+
optional (not yet on PyPI) and emits the standard combining acute (U+0301)
|
|
283
|
+
after the stressed vowel.
|
|
284
|
+
|
|
253
285
|
Details: [docs/phonemizers.md](docs/phonemizers.md).
|
|
254
286
|
|
|
255
287
|
## Fidelity guarantees
|
|
@@ -293,6 +325,8 @@ The core installs with zero dependencies. Capabilities opt in:
|
|
|
293
325
|
| `espeak`, `gruut`, `goruut`, `epitran`, `transphone`, `misaki`, `byt5` | Multilingual phonemizer backends |
|
|
294
326
|
| `en-phonemizers`, `ja-phonemizers`, `zh-phonemizers`, `ko`, `ar-phonemizers`, `eu`, `pt-phonemizers`, `gl`, `he`, `fa`, `vi`, `mwl`, `shami`, `o2i` | Per-language phonemizer backends |
|
|
295
327
|
| `tashkeel` | Arabic diacritization for the phonemizer pipeline (text2tashkeel) |
|
|
328
|
+
| `stress` | Word-stress restoration for 26 stressonnx language tags — East Slavic, Bulgarian/Macedonian/Slovene, Latvian, Armenian, Georgian, Turkic/Caucasian — for the phonemizer pipeline (stressonnx; not yet on PyPI) |
|
|
329
|
+
| `pt` | European-Portuguese heterophonic-homograph sense diacritics for the phonemizer pipeline (bifonia) |
|
|
296
330
|
|
|
297
331
|
## Licensing
|
|
298
332
|
|
|
@@ -314,29 +348,17 @@ build on it:
|
|
|
314
348
|
text-to-speech; consumes scriptconv for scripts, notation, conventions and
|
|
315
349
|
the whole phonemizer layer.
|
|
316
350
|
- [orthography2ipa](https://github.com/TigreGotico/orthography2ipa) —
|
|
317
|
-
data-driven orthography→IPA engine; the usual per-language phonemizer
|
|
318
|
-
|
|
319
|
-
- [
|
|
320
|
-
|
|
351
|
+
data-driven orthography→IPA engine; the usual per-language phonemizer default.
|
|
352
|
+
- [arbtok](https://github.com/TigreGotico/arbtok) — Arabic phonemizer (dialect-aware).
|
|
353
|
+
- [euskaphone](https://github.com/TigreGotico/euskaphone) — Basque phonemizer (dialect-aware).
|
|
354
|
+
- [tugaphone](https://github.com/TigreGotico/tugaphone) — Portuguese phonemizer (dialect-aware).
|
|
355
|
+
- [mwl_phonemizer](https://github.com/TigreGotico/mwl_phonemizer) — Mirandese phonemizer.
|
|
356
|
+
- [g2p_barranquenho](https://github.com/TigreGotico/g2p_barranquenho) — Barranquenho phonemizer.
|
|
357
|
+
- [pycotovia](https://github.com/TigreGotico/pycotovia) — Pure-Python phonemizer port
|
|
358
|
+
of the Cotovía Galician TTS engine, whose notation scriptconv transcodes.
|
|
321
359
|
- [espyak](https://github.com/TigreGotico/espyak) — pure-Python port of
|
|
322
360
|
espeak-ng's G2P; the espeak fallback when the binary is absent.
|
|
323
|
-
|
|
324
|
-
phonemizer (dialect-aware).
|
|
325
|
-
- [tugaphone](https://github.com/TigreGotico/tugaphone) — European
|
|
326
|
-
Portuguese phonemizer.
|
|
327
|
-
- [mwl_phonemizer](https://github.com/TigreGotico/mwl_phonemizer) —
|
|
328
|
-
Mirandese phonemizer.
|
|
329
|
-
- [g2p_barranquenho](https://github.com/TigreGotico/g2p_barranquenho) —
|
|
330
|
-
Barranquenho phonemizer.
|
|
331
|
-
- [pycotovia](https://github.com/TigreGotico/pycotovia) — Python bindings
|
|
332
|
-
for the Cotovía Galician TTS engine, whose notation scriptconv transcodes.
|
|
333
|
-
- [stressonnx](https://github.com/TigreGotico/stressonnx) — East Slavic
|
|
334
|
-
stress annotation; shares scriptconv's script tags.
|
|
335
|
-
- [text2tashkeel](https://github.com/TigreGotico/text2tashkeel) — Arabic
|
|
336
|
-
diacritization models (the prediction side of the `tashkeel` convention).
|
|
337
|
-
- [text2nikkud](https://github.com/TigreGotico/text2nikkud) — Hebrew
|
|
338
|
-
niqqud restoration (the prediction side of the `niqqud` convention).
|
|
339
|
-
|
|
361
|
+
|
|
340
362
|
## Development
|
|
341
363
|
|
|
342
364
|
```bash
|
|
@@ -53,13 +53,15 @@ he = ["scriptconv[phonemizers]", "phonikud-onnx"]
|
|
|
53
53
|
fa = ["scriptconv[phonemizers]", "persian_phonemizer"]
|
|
54
54
|
vi = ["scriptconv[phonemizers]", "viphoneme"]
|
|
55
55
|
tashkeel = ["scriptconv[phonemizers]", "text2tashkeel"]
|
|
56
|
+
stress = ["scriptconv[phonemizers]", "stressonnx>=0.0.2"]
|
|
57
|
+
pt = ["scriptconv[phonemizers]", "bifonia>=0.1.1"]
|
|
56
58
|
ja-phonemizers = ["scriptconv[phonemizers]", "pyopenjtalk", "cutlet", "pykakasi>=2.3,<3"]
|
|
57
59
|
ko = ["scriptconv[phonemizers]", "g2pk", "regex"]
|
|
58
60
|
zh-phonemizers = ["scriptconv[phonemizers]", "jieba", "pypinyin>=0.50,<1", "xpinyin", "g2pM", "pinyin_to_ipa"]
|
|
59
61
|
en-phonemizers = ["scriptconv[phonemizers]", "g2p_en", "openphonemizer", "deep-phonemizer"]
|
|
60
62
|
ar-phonemizers = ["scriptconv[phonemizers]", "arbtok", "ovos-number-parser"]
|
|
61
63
|
shami = ["scriptconv[phonemizers]", "regex"]
|
|
62
|
-
test = ["pytest", "pytest-timeout", "pykakasi>=2.3,<3", "pypinyin>=0.50,<1", "quebra-frases", "langcodes", "regex", "ovos-number-parser"]
|
|
64
|
+
test = ["pytest", "pytest-timeout", "pykakasi>=2.3,<3", "pypinyin>=0.50,<1", "quebra-frases", "langcodes", "regex", "ovos-number-parser", "bifonia>=0.1.1"]
|
|
63
65
|
|
|
64
66
|
[project.urls]
|
|
65
67
|
Homepage = "https://github.com/TigreGotico/scriptconv"
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Diacritization as a graph extension — parallel to :mod:`scriptconv.phonemizers`.
|
|
2
|
+
|
|
3
|
+
Diacritization (Arabic tashkeel, Hebrew niqqud, East-Slavic/Turkic/Caucasian
|
|
4
|
+
word stress, European-Portuguese homograph sense marks) is, architecturally,
|
|
5
|
+
just another transform between text representations: it maps the ``"text"``
|
|
6
|
+
node to a lang-contextual ``"text-diacritized"`` node. Like
|
|
7
|
+
:func:`scriptconv.phonemizers.register` it is opt-in — ``DEFAULT_GRAPH`` stays
|
|
8
|
+
free of it until a caller extends a graph::
|
|
9
|
+
|
|
10
|
+
from scriptconv.graph import DEFAULT_GRAPH
|
|
11
|
+
from scriptconv import diacritics, phonemizers
|
|
12
|
+
g = DEFAULT_GRAPH.extend(diacritics.register).extend(phonemizers.register)
|
|
13
|
+
|
|
14
|
+
g.convert("замок стоит на горе", "text", "text-diacritized", lang="ru")
|
|
15
|
+
# 'за́мок сто́ит на горе́' — just the diacritized text
|
|
16
|
+
|
|
17
|
+
g.convert("Tenho muita sede hoje.", "text", "text-diacritized", lang="pt")
|
|
18
|
+
# 'Tenho muita sêde hoje.'
|
|
19
|
+
|
|
20
|
+
Routing ``"text" -> "ipa"`` still takes the direct phonemization edge by
|
|
21
|
+
default: the diacritization edge is model-based (``lossless=False``), so it
|
|
22
|
+
never out-prices a direct phonemization, and enabling this extension does not
|
|
23
|
+
silently change phonemization output. The diacritized route is taken only
|
|
24
|
+
when a caller asks for ``"text-diacritized"`` explicitly.
|
|
25
|
+
|
|
26
|
+
A future per-engine *stance* would push this further into topology rather than
|
|
27
|
+
a flag: an engine that *requires* vocalized input would carry only a
|
|
28
|
+
``"text-diacritized" -> "ipa"`` edge (forcing the detour), one that *forbids*
|
|
29
|
+
diacritics would carry only ``"text" -> "ipa"`` (making the detour
|
|
30
|
+
unroutable), and a tolerant engine (e.g. arbtok, which self-vocalizes) carries
|
|
31
|
+
both. The strip direction (``"text-diacritized" -> "text"``) is registered too, but
|
|
32
|
+
gated to languages whose marks are removable *overlay* diacritics —
|
|
33
|
+
Arabic/Hebrew vocalization and East-Slavic/Turkic/Caucasian stress. Strip
|
|
34
|
+
removes only the specific overlay codepoints each backend adds (combining
|
|
35
|
+
acute/grave for stress, tashkeel for Arabic, niqqud for Hebrew) — never a
|
|
36
|
+
blanket combining-mark filter — so precomposed native letters survive
|
|
37
|
+
(Cyrillic й/ё, Latvian macrons, Azerbaijani ç/ö, Arabic hamza carriers أ إ آ ؤ
|
|
38
|
+
ئ). The gate uses exact primary-subtag matching, so Aragonese (``arg``),
|
|
39
|
+
Herero (``her``), Mapudungun (``arn``) etc. are never misread as Arabic/Hebrew.
|
|
40
|
+
Languages whose diacritics are native orthography (European Portuguese, via
|
|
41
|
+
bifonia) refuse the strip with :class:`ValueError` instead of silently
|
|
42
|
+
corrupting the spelling (``café`` must never become ``cafe``). This split
|
|
43
|
+
tracks which backend/model produced the marks: overlay backends (phonikud,
|
|
44
|
+
tashkeel, stressonnx) are strippable; spelling-integral backends (bifonia) are
|
|
45
|
+
not.
|
|
46
|
+
"""
|
|
47
|
+
from scriptconv.graph import Edge
|
|
48
|
+
from scriptconv.phonemizers.base import STRESS_LANGS, _primary_subtag
|
|
49
|
+
|
|
50
|
+
#: The lang-contextual node produced by diacritization. Like ``"text"`` it is
|
|
51
|
+
#: meaningful only with ``lang=`` context and exists only in opted-in graphs.
|
|
52
|
+
DIACRITIZED = "text-diacritized"
|
|
53
|
+
|
|
54
|
+
_DEFAULT_PHONEMIZER = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _get_phonemizer(phonikud_model=None):
|
|
58
|
+
global _DEFAULT_PHONEMIZER
|
|
59
|
+
if phonikud_model:
|
|
60
|
+
from scriptconv.phonemizers.base import GraphemePhonemizer
|
|
61
|
+
return GraphemePhonemizer(phonikud_model=phonikud_model)
|
|
62
|
+
if _DEFAULT_PHONEMIZER is None:
|
|
63
|
+
from scriptconv.phonemizers.base import GraphemePhonemizer
|
|
64
|
+
_DEFAULT_PHONEMIZER = GraphemePhonemizer()
|
|
65
|
+
return _DEFAULT_PHONEMIZER
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def diacritize(text: str, lang: str = "und", model=None, **context) -> str:
|
|
69
|
+
"""Add pronunciation-disambiguating diacritics to *text* for *lang*.
|
|
70
|
+
|
|
71
|
+
Thin wrapper over :meth:`BasePhonemizer.add_diacritics` — the single
|
|
72
|
+
dispatch (he→phonikud, ar→tashkeel, ru/uk/be/…→stressonnx, pt→bifonia).
|
|
73
|
+
Reuses a cached default phonemizer so repeated calls don't reload models; a
|
|
74
|
+
per-call Hebrew ``phonikud_model`` path (via context) builds a fresh one.
|
|
75
|
+
"""
|
|
76
|
+
return _get_phonemizer(context.get("phonikud_model")).add_diacritics(text, lang, model)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# Combining marks each diacritization backend overlays onto the bare text.
|
|
80
|
+
# Strip removes ONLY these codepoints — never a blanket combining-mark filter,
|
|
81
|
+
# which (via NFD) would decompose and destroy precomposed native letters:
|
|
82
|
+
# Cyrillic й/ё, Latvian ī, Azerbaijani ç/ö, and Arabic hamza carriers أ إ آ ؤ ئ.
|
|
83
|
+
_STRESS_MARKS = frozenset({0x0300, 0x0301}) # combining grave / acute
|
|
84
|
+
_ARABIC_MARKS = frozenset(range(0x064B, 0x0660)) | frozenset({0x0670}) # tashkeel + dagger alef
|
|
85
|
+
_HEBREW_MARKS = (frozenset(range(0x05B0, 0x05BE))
|
|
86
|
+
| frozenset({0x05BF, 0x05C1, 0x05C2, 0x05C4, 0x05C5, 0x05C7})) # niqqud
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _overlay_marks(lang: str) -> "frozenset | None":
|
|
90
|
+
"""The overlay codepoints for *lang*'s diacritization backend, or None.
|
|
91
|
+
|
|
92
|
+
Uses exact primary-subtag matching (never ``startswith``) so Aragonese
|
|
93
|
+
(``arg``), Herero (``her``), Mapudungun (``arn``) etc. are NOT misread as
|
|
94
|
+
Arabic/Hebrew and stripped.
|
|
95
|
+
"""
|
|
96
|
+
p = _primary_subtag(lang)
|
|
97
|
+
if p in STRESS_LANGS:
|
|
98
|
+
return _STRESS_MARKS
|
|
99
|
+
if p == "ar":
|
|
100
|
+
return _ARABIC_MARKS
|
|
101
|
+
if p == "he":
|
|
102
|
+
return _HEBREW_MARKS
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _supports_strip(lang: str) -> bool:
|
|
107
|
+
"""True for languages whose diacritics are removable overlays (stress marks,
|
|
108
|
+
Arabic tashkeel, Hebrew niqqud) rather than native orthography."""
|
|
109
|
+
return _overlay_marks(lang) is not None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def strip_diacritics(text: str, lang: str = "und", **_) -> str:
|
|
113
|
+
"""Remove the overlay diacritics *lang*'s backend adds, recovering the bare
|
|
114
|
+
text WITHOUT touching native letters.
|
|
115
|
+
|
|
116
|
+
Removes only the specific overlay codepoints (combining acute/grave for
|
|
117
|
+
stress, tashkeel for Arabic, niqqud for Hebrew) — precomposed native
|
|
118
|
+
letters (Cyrillic й/ё, Latvian ī, Azerbaijani ç, Arabic hamza carriers) are
|
|
119
|
+
left intact. Raises :class:`ValueError` for languages whose diacritics are
|
|
120
|
+
part of the native orthography (e.g. European Portuguese), where any removal
|
|
121
|
+
would corrupt the spelling.
|
|
122
|
+
"""
|
|
123
|
+
marks = _overlay_marks(lang)
|
|
124
|
+
if marks is None:
|
|
125
|
+
raise ValueError(
|
|
126
|
+
f"cannot strip diacritics for lang={lang!r}: its diacritics are "
|
|
127
|
+
"part of the native orthography, so removal would corrupt the "
|
|
128
|
+
"spelling. strip is defined only for overlay diacritics "
|
|
129
|
+
"(Arabic/Hebrew vocalization, East-Slavic/Turkic stress).")
|
|
130
|
+
return "".join(c for c in text if ord(c) not in marks)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def register(graph) -> None:
|
|
134
|
+
"""Opt-in graph integration: add the diacritize/strip edge pair.
|
|
135
|
+
|
|
136
|
+
``text -> text-diacritized`` is model-based (``lossless=False``), so a
|
|
137
|
+
direct ``text -> ipa`` phonemization always out-prices the detour —
|
|
138
|
+
enabling this extension is safe and non-invasive. Pair with
|
|
139
|
+
:func:`scriptconv.phonemizers.register` to make
|
|
140
|
+
``"text-diacritized" -> "ipa"`` reachable.
|
|
141
|
+
|
|
142
|
+
``text-diacritized -> text`` (:func:`strip_diacritics`) is lossless and
|
|
143
|
+
cheap, but gated: it raises for languages whose diacritics are native
|
|
144
|
+
orthography rather than removable overlays.
|
|
145
|
+
"""
|
|
146
|
+
graph.register(
|
|
147
|
+
Edge("text", DIACRITIZED,
|
|
148
|
+
lambda text, lang="und", model=None, **c: diacritize(text, lang, model, **c),
|
|
149
|
+
lossless=False))
|
|
150
|
+
graph.register(
|
|
151
|
+
Edge(DIACRITIZED, "text",
|
|
152
|
+
lambda text, lang="und", **_: strip_diacritics(text, lang),
|
|
153
|
+
lossless=True))
|
|
@@ -34,6 +34,45 @@ RawPhonemizedChunks = List[Tuple[str, str, bool]]
|
|
|
34
34
|
|
|
35
35
|
PhonemizedChunks = list[list[str]]
|
|
36
36
|
|
|
37
|
+
# Across East Slavic, Bulgarian/Macedonian/Slovene, Latvian, Armenian,
|
|
38
|
+
# Georgian, and several Turkic/Caucasian languages, lexical word stress is
|
|
39
|
+
# free (not fixed to a syllable) and ordinary orthography leaves it unwritten
|
|
40
|
+
# or under-marked. The clearest case is East Slavic: stress is also mobile
|
|
41
|
+
# (it shifts between forms of the same word) and unstressed vowels *reduce*
|
|
42
|
+
# — Russian unstressed "о" surfaces as [ɐ] or [ə] depending on distance from
|
|
43
|
+
# the stress, not [o] — so a wrong or missing mark there corrupts the vowel
|
|
44
|
+
# quality of the whole word, not just its prosody. Other families in this set
|
|
45
|
+
# don't necessarily reduce vowels, but still need the mark for correct stress
|
|
46
|
+
# placement and prosody. stressonnx restores it as a combining acute (U+0301)
|
|
47
|
+
# after the stressed vowel, covering 26 BCP-47 tags across these families
|
|
48
|
+
# (24 primary subtags; Azerbaijani and Uzbek each have Cyrillic/Latin script
|
|
49
|
+
# variants routed by the full tag).
|
|
50
|
+
STRESS_LANGS = {
|
|
51
|
+
"az", "ba", "be", "bg", "cv", "hy", "ka", "kbd", "kjh", "kk", "ky", "lv",
|
|
52
|
+
"mdf", "mk", "myv", "ru", "sah", "sl", "tg", "tt", "udm", "uk", "uz", "xal",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _primary_subtag(lang: str) -> str:
|
|
57
|
+
"""Lowercase, ``_``→``-`` normalized primary language subtag.
|
|
58
|
+
|
|
59
|
+
Used for exact-match routing (``STRESS_LANGS`` membership) rather than
|
|
60
|
+
``str.startswith``, so e.g. Berber (``ber``) never false-matches
|
|
61
|
+
Belarusian (``be``).
|
|
62
|
+
"""
|
|
63
|
+
return lang.lower().replace("_", "-").split("-")[0]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _is_european_portuguese(lang: str) -> bool:
|
|
67
|
+
"""True for European Portuguese (``pt`` or a ``pt-PT`` region tag).
|
|
68
|
+
|
|
69
|
+
False for Brazilian Portuguese (``pt-BR``) and everything else — the two
|
|
70
|
+
varieties' vowel systems differ, and bifonia's open/closed diacritics are
|
|
71
|
+
only valid for European Portuguese phonology.
|
|
72
|
+
"""
|
|
73
|
+
norm = lang.lower().replace("_", "-")
|
|
74
|
+
return norm == "pt" or norm == "pt-pt"
|
|
75
|
+
|
|
37
76
|
|
|
38
77
|
class BasePhonemizer(metaclass=abc.ABCMeta):
|
|
39
78
|
def __init__(self, alphabet: Alphabet = Alphabet.UNICODE,
|
|
@@ -94,6 +133,41 @@ class BasePhonemizer(metaclass=abc.ABCMeta):
|
|
|
94
133
|
self._tashkeel[model] = Diacritizer(model)
|
|
95
134
|
return self._tashkeel[model]
|
|
96
135
|
|
|
136
|
+
def _stress(self, text: str, lang: str, model: Optional[str] = None) -> str:
|
|
137
|
+
"""Word-stress restoration via stressonnx, for the 26 language tags
|
|
138
|
+
it covers (see ``STRESS_LANGS``) — East Slavic, Bulgarian/Macedonian/
|
|
139
|
+
Slovene, Latvian, Armenian, Georgian, and Turkic/Caucasian languages.
|
|
140
|
+
|
|
141
|
+
stressonnx is not on PyPI yet; install straight from source. Install
|
|
142
|
+
with ``pip install scriptconv[stress]`` (or ``pip install
|
|
143
|
+
stressonnx``)."""
|
|
144
|
+
try:
|
|
145
|
+
from stressonnx import stress
|
|
146
|
+
except ImportError as e:
|
|
147
|
+
raise ImportError(
|
|
148
|
+
"stress restoration requires the stressonnx package: "
|
|
149
|
+
"pip install scriptconv[stress] (or pip install stressonnx)"
|
|
150
|
+
) from e
|
|
151
|
+
return stress(text, lang, model=model)
|
|
152
|
+
|
|
153
|
+
def _sense_diacritics_pt(self, text: str) -> str:
|
|
154
|
+
"""European-Portuguese heterophonic-homograph sense diacritics via bifonia.
|
|
155
|
+
|
|
156
|
+
Rewrites homographs whose pronunciation depends on meaning (e.g.
|
|
157
|
+
"sede" thirst/closed vs. seat/open) with an explicit open/closed
|
|
158
|
+
vowel diacritic. These are ordinary Portuguese orthographic marks,
|
|
159
|
+
chosen so any downstream G2P — rule-based, neural, or espeak —
|
|
160
|
+
reads them correctly. Install with ``pip install scriptconv[pt]``
|
|
161
|
+
(or ``pip install bifonia``)."""
|
|
162
|
+
try:
|
|
163
|
+
from bifonia import add_extra_diacritics
|
|
164
|
+
except ImportError as e:
|
|
165
|
+
raise ImportError(
|
|
166
|
+
"European-Portuguese sense diacritics require the bifonia package: "
|
|
167
|
+
"pip install scriptconv[pt] (or pip install bifonia)"
|
|
168
|
+
) from e
|
|
169
|
+
return add_extra_diacritics(text)
|
|
170
|
+
|
|
97
171
|
@abc.abstractmethod
|
|
98
172
|
def phonemize_string(self, text: str, lang: str) -> str:
|
|
99
173
|
raise NotImplementedError
|
|
@@ -103,10 +177,36 @@ class BasePhonemizer(metaclass=abc.ABCMeta):
|
|
|
103
177
|
|
|
104
178
|
def add_diacritics(self, text: str, lang: str,
|
|
105
179
|
model: Optional[str] = None) -> str:
|
|
106
|
-
|
|
180
|
+
"""Disambiguate pronunciation before G2P by adding diacritics.
|
|
181
|
+
|
|
182
|
+
Four backends, each restoring information ordinary orthography
|
|
183
|
+
omits but downstream G2P needs:
|
|
184
|
+
|
|
185
|
+
- Hebrew (``he``) — niqqud via phonikud (``phonikud_model=``).
|
|
186
|
+
- Arabic (``ar``) — tashkeel via text2tashkeel (``[tashkeel]``).
|
|
187
|
+
- East Slavic, Bulgarian/Macedonian/Slovene, Latvian, Armenian,
|
|
188
|
+
Georgian, and Turkic/Caucasian languages (``STRESS_LANGS``, 26
|
|
189
|
+
stressonnx tags) — word stress via stressonnx (``[stress]``);
|
|
190
|
+
stress is unwritten or under-marked in these languages, and in
|
|
191
|
+
East Slavic unstressed vowels also reduce, so a missing mark can
|
|
192
|
+
corrupt more than prosody.
|
|
193
|
+
- European Portuguese (``pt``/``pt-PT``, never ``pt-BR``) —
|
|
194
|
+
heterophonic-homograph sense diacritics via bifonia (``[pt]``);
|
|
195
|
+
ordinary Portuguese orthographic marks that any downstream G2P
|
|
196
|
+
reads correctly.
|
|
197
|
+
|
|
198
|
+
Unrecognized languages are returned unchanged. Each backend raises
|
|
199
|
+
``ImportError`` naming its extra when the optional dependency is
|
|
200
|
+
missing — scriptconv never installs anything on the caller's behalf.
|
|
201
|
+
"""
|
|
202
|
+
if _primary_subtag(lang) == "he":
|
|
107
203
|
return self.phonikud.add_diacritics(text)
|
|
108
|
-
elif lang
|
|
204
|
+
elif _primary_subtag(lang) == "ar":
|
|
109
205
|
return self.tashkeel(model).diacritize(text)
|
|
206
|
+
elif _primary_subtag(lang) in STRESS_LANGS:
|
|
207
|
+
return self._stress(text, lang, model)
|
|
208
|
+
elif _is_european_portuguese(lang):
|
|
209
|
+
return self._sense_diacritics_pt(text)
|
|
110
210
|
return text
|
|
111
211
|
|
|
112
212
|
def phonemize(self, text: str, lang: str) -> PhonemizedChunks:
|
|
@@ -219,7 +219,9 @@ def register(graph) -> None:
|
|
|
219
219
|
routing context, and present only in graphs that opted in (the
|
|
220
220
|
:data:`scriptconv.graph.DEFAULT_GRAPH` stays orthography-only by
|
|
221
221
|
design) — and one dispatching ``text -> ipa`` edge that resolves the
|
|
222
|
-
per-language default (honouring an ``override=`` context key).
|
|
222
|
+
per-language default (honouring an ``override=`` context key). It also
|
|
223
|
+
accepts already-diacritized input via a ``"text-diacritized" -> "ipa"``
|
|
224
|
+
edge (the same phonemization; pair with :func:`scriptconv.diacritics.register`).
|
|
223
225
|
|
|
224
226
|
Usage::
|
|
225
227
|
|
|
@@ -236,3 +238,4 @@ def register(graph) -> None:
|
|
|
236
238
|
override).phonemize_string(text, lang)
|
|
237
239
|
|
|
238
240
|
graph.register(Edge("text", "ipa", _text_to_ipa, lossless=False))
|
|
241
|
+
graph.register(Edge("text-diacritized", "ipa", _text_to_ipa, lossless=False))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scriptconv
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4a4
|
|
4
4
|
Summary: Zero-dependency script & phoneme-notation core — ISO-15924 detection & metadata, IPA↔ARPABET/X-SAMPA/Lexique/Kirshenbaum/Cotovía/RFE, Buckwalter↔Arabic, Hangul→jamo, kana
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://github.com/TigreGotico/scriptconv
|
|
@@ -78,6 +78,12 @@ Requires-Dist: viphoneme; extra == "vi"
|
|
|
78
78
|
Provides-Extra: tashkeel
|
|
79
79
|
Requires-Dist: scriptconv[phonemizers]; extra == "tashkeel"
|
|
80
80
|
Requires-Dist: text2tashkeel; extra == "tashkeel"
|
|
81
|
+
Provides-Extra: stress
|
|
82
|
+
Requires-Dist: scriptconv[phonemizers]; extra == "stress"
|
|
83
|
+
Requires-Dist: stressonnx>=0.0.2; extra == "stress"
|
|
84
|
+
Provides-Extra: pt
|
|
85
|
+
Requires-Dist: scriptconv[phonemizers]; extra == "pt"
|
|
86
|
+
Requires-Dist: bifonia>=0.1.1; extra == "pt"
|
|
81
87
|
Provides-Extra: ja-phonemizers
|
|
82
88
|
Requires-Dist: scriptconv[phonemizers]; extra == "ja-phonemizers"
|
|
83
89
|
Requires-Dist: pyopenjtalk; extra == "ja-phonemizers"
|
|
@@ -115,6 +121,7 @@ Requires-Dist: quebra-frases; extra == "test"
|
|
|
115
121
|
Requires-Dist: langcodes; extra == "test"
|
|
116
122
|
Requires-Dist: regex; extra == "test"
|
|
117
123
|
Requires-Dist: ovos-number-parser; extra == "test"
|
|
124
|
+
Requires-Dist: bifonia>=0.1.1; extra == "test"
|
|
118
125
|
Dynamic: license-file
|
|
119
126
|
|
|
120
127
|
<div align="center">
|
|
@@ -369,6 +376,38 @@ Two design points worth knowing:
|
|
|
369
376
|
local `model=` path; resolving and caching model files is the caller's
|
|
370
377
|
concern.
|
|
371
378
|
|
|
379
|
+
**Pre-G2P disambiguation.** `add_diacritics(text, lang, model=None)` restores
|
|
380
|
+
information ordinary orthography omits but a G2P needs, before phonemization:
|
|
381
|
+
Hebrew niqqud (phonikud), Arabic tashkeel (text2tashkeel), word stress across
|
|
382
|
+
26 stressonnx language tags — East Slavic, Bulgarian/Macedonian/Slovene,
|
|
383
|
+
Latvian, Armenian, Georgian, and Turkic/Caucasian languages (`scriptconv[stress]`),
|
|
384
|
+
and European-Portuguese heterophonic-homograph sense diacritics (bifonia —
|
|
385
|
+
`scriptconv[pt]`, never applied to `pt-BR`, whose vowel system differs):
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
from scriptconv.phonemizers import GraphemePhonemizer
|
|
389
|
+
|
|
390
|
+
p = GraphemePhonemizer()
|
|
391
|
+
p.add_diacritics("Tenho muita sede hoje.", "pt") # 'Tenho muita sêde hoje.' (thirst)
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Diacritization also joins the graph, like phonemization, via
|
|
395
|
+
`scriptconv.diacritics.register` — a `text -> text-diacritized` edge, opt-in,
|
|
396
|
+
with `text -> ipa` routing unchanged:
|
|
397
|
+
|
|
398
|
+
```python
|
|
399
|
+
from scriptconv import diacritics
|
|
400
|
+
g = DEFAULT_GRAPH.extend(diacritics.register).extend(phonemizers.register)
|
|
401
|
+
g.convert("Tenho muita sede hoje.", "text", "text-diacritized", lang="pt")
|
|
402
|
+
# 'Tenho muita sêde hoje.'
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Stress is unwritten or under-marked in all 26 covered languages; East Slavic
|
|
406
|
+
is the clearest case, where unstressed vowels also reduce (e.g. Russian
|
|
407
|
+
о→[ɐ]/[ə]), so a missing mark corrupts more than prosody there. stressonnx is
|
|
408
|
+
optional (not yet on PyPI) and emits the standard combining acute (U+0301)
|
|
409
|
+
after the stressed vowel.
|
|
410
|
+
|
|
372
411
|
Details: [docs/phonemizers.md](docs/phonemizers.md).
|
|
373
412
|
|
|
374
413
|
## Fidelity guarantees
|
|
@@ -412,6 +451,8 @@ The core installs with zero dependencies. Capabilities opt in:
|
|
|
412
451
|
| `espeak`, `gruut`, `goruut`, `epitran`, `transphone`, `misaki`, `byt5` | Multilingual phonemizer backends |
|
|
413
452
|
| `en-phonemizers`, `ja-phonemizers`, `zh-phonemizers`, `ko`, `ar-phonemizers`, `eu`, `pt-phonemizers`, `gl`, `he`, `fa`, `vi`, `mwl`, `shami`, `o2i` | Per-language phonemizer backends |
|
|
414
453
|
| `tashkeel` | Arabic diacritization for the phonemizer pipeline (text2tashkeel) |
|
|
454
|
+
| `stress` | Word-stress restoration for 26 stressonnx language tags — East Slavic, Bulgarian/Macedonian/Slovene, Latvian, Armenian, Georgian, Turkic/Caucasian — for the phonemizer pipeline (stressonnx; not yet on PyPI) |
|
|
455
|
+
| `pt` | European-Portuguese heterophonic-homograph sense diacritics for the phonemizer pipeline (bifonia) |
|
|
415
456
|
|
|
416
457
|
## Licensing
|
|
417
458
|
|
|
@@ -433,29 +474,17 @@ build on it:
|
|
|
433
474
|
text-to-speech; consumes scriptconv for scripts, notation, conventions and
|
|
434
475
|
the whole phonemizer layer.
|
|
435
476
|
- [orthography2ipa](https://github.com/TigreGotico/orthography2ipa) —
|
|
436
|
-
data-driven orthography→IPA engine; the usual per-language phonemizer
|
|
437
|
-
|
|
438
|
-
- [
|
|
439
|
-
|
|
477
|
+
data-driven orthography→IPA engine; the usual per-language phonemizer default.
|
|
478
|
+
- [arbtok](https://github.com/TigreGotico/arbtok) — Arabic phonemizer (dialect-aware).
|
|
479
|
+
- [euskaphone](https://github.com/TigreGotico/euskaphone) — Basque phonemizer (dialect-aware).
|
|
480
|
+
- [tugaphone](https://github.com/TigreGotico/tugaphone) — Portuguese phonemizer (dialect-aware).
|
|
481
|
+
- [mwl_phonemizer](https://github.com/TigreGotico/mwl_phonemizer) — Mirandese phonemizer.
|
|
482
|
+
- [g2p_barranquenho](https://github.com/TigreGotico/g2p_barranquenho) — Barranquenho phonemizer.
|
|
483
|
+
- [pycotovia](https://github.com/TigreGotico/pycotovia) — Pure-Python phonemizer port
|
|
484
|
+
of the Cotovía Galician TTS engine, whose notation scriptconv transcodes.
|
|
440
485
|
- [espyak](https://github.com/TigreGotico/espyak) — pure-Python port of
|
|
441
486
|
espeak-ng's G2P; the espeak fallback when the binary is absent.
|
|
442
|
-
|
|
443
|
-
phonemizer (dialect-aware).
|
|
444
|
-
- [tugaphone](https://github.com/TigreGotico/tugaphone) — European
|
|
445
|
-
Portuguese phonemizer.
|
|
446
|
-
- [mwl_phonemizer](https://github.com/TigreGotico/mwl_phonemizer) —
|
|
447
|
-
Mirandese phonemizer.
|
|
448
|
-
- [g2p_barranquenho](https://github.com/TigreGotico/g2p_barranquenho) —
|
|
449
|
-
Barranquenho phonemizer.
|
|
450
|
-
- [pycotovia](https://github.com/TigreGotico/pycotovia) — Python bindings
|
|
451
|
-
for the Cotovía Galician TTS engine, whose notation scriptconv transcodes.
|
|
452
|
-
- [stressonnx](https://github.com/TigreGotico/stressonnx) — East Slavic
|
|
453
|
-
stress annotation; shares scriptconv's script tags.
|
|
454
|
-
- [text2tashkeel](https://github.com/TigreGotico/text2tashkeel) — Arabic
|
|
455
|
-
diacritization models (the prediction side of the `tashkeel` convention).
|
|
456
|
-
- [text2nikkud](https://github.com/TigreGotico/text2nikkud) — Hebrew
|
|
457
|
-
niqqud restoration (the prediction side of the `niqqud` convention).
|
|
458
|
-
|
|
487
|
+
|
|
459
488
|
## Development
|
|
460
489
|
|
|
461
490
|
```bash
|
|
@@ -6,6 +6,7 @@ scriptconv/__init__.py
|
|
|
6
6
|
scriptconv/__main__.py
|
|
7
7
|
scriptconv/cangjie.py
|
|
8
8
|
scriptconv/conventions.py
|
|
9
|
+
scriptconv/diacritics.py
|
|
9
10
|
scriptconv/graph.py
|
|
10
11
|
scriptconv/notation.py
|
|
11
12
|
scriptconv/py.typed
|
|
@@ -77,6 +78,7 @@ tests/test_arpa_stress.py
|
|
|
77
78
|
tests/test_cangjie.py
|
|
78
79
|
tests/test_cli.py
|
|
79
80
|
tests/test_conventions.py
|
|
81
|
+
tests/test_diacritics_graph.py
|
|
80
82
|
tests/test_errors_policy.py
|
|
81
83
|
tests/test_examples.py
|
|
82
84
|
tests/test_graph.py
|
|
@@ -78,6 +78,10 @@ orthography2ipa
|
|
|
78
78
|
quebra-frases
|
|
79
79
|
langcodes
|
|
80
80
|
|
|
81
|
+
[pt]
|
|
82
|
+
scriptconv[phonemizers]
|
|
83
|
+
bifonia>=0.1.1
|
|
84
|
+
|
|
81
85
|
[pt-phonemizers]
|
|
82
86
|
scriptconv[phonemizers]
|
|
83
87
|
tugaphone
|
|
@@ -87,6 +91,10 @@ g2p_barranquenho
|
|
|
87
91
|
scriptconv[phonemizers]
|
|
88
92
|
regex
|
|
89
93
|
|
|
94
|
+
[stress]
|
|
95
|
+
scriptconv[phonemizers]
|
|
96
|
+
stressonnx>=0.0.2
|
|
97
|
+
|
|
90
98
|
[tashkeel]
|
|
91
99
|
scriptconv[phonemizers]
|
|
92
100
|
text2tashkeel
|
|
@@ -100,6 +108,7 @@ quebra-frases
|
|
|
100
108
|
langcodes
|
|
101
109
|
regex
|
|
102
110
|
ovos-number-parser
|
|
111
|
+
bifonia>=0.1.1
|
|
103
112
|
|
|
104
113
|
[transphone]
|
|
105
114
|
scriptconv[phonemizers]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import types
|
|
3
|
+
import unittest
|
|
4
|
+
from unittest import mock
|
|
5
|
+
|
|
6
|
+
from scriptconv.graph import DEFAULT_GRAPH
|
|
7
|
+
from scriptconv import diacritics, phonemizers
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestDiacriticsGraphExtension(unittest.TestCase):
|
|
11
|
+
def setUp(self):
|
|
12
|
+
self.graph = DEFAULT_GRAPH.extend(diacritics.register).extend(phonemizers.register)
|
|
13
|
+
|
|
14
|
+
def test_default_graph_has_no_diacritized_node(self):
|
|
15
|
+
self.assertFalse(DEFAULT_GRAPH.can_convert("text", "text-diacritized"))
|
|
16
|
+
|
|
17
|
+
def test_extend_adds_diacritized_node(self):
|
|
18
|
+
self.assertTrue(self.graph.can_convert("text", "text-diacritized"))
|
|
19
|
+
self.assertTrue(self.graph.can_convert("text-diacritized", "ipa"))
|
|
20
|
+
|
|
21
|
+
def test_text_to_ipa_prefers_direct_route(self):
|
|
22
|
+
route = self.graph.route("text", "ipa")
|
|
23
|
+
self.assertEqual(len(route), 1)
|
|
24
|
+
edge = route[0]
|
|
25
|
+
self.assertEqual(edge.src, "text")
|
|
26
|
+
self.assertEqual(edge.dst, "ipa")
|
|
27
|
+
|
|
28
|
+
def test_portuguese_diacritization_via_graph(self):
|
|
29
|
+
out = self.graph.convert("Tenho muita sede hoje.", "text",
|
|
30
|
+
"text-diacritized", lang="pt")
|
|
31
|
+
self.assertEqual(out, "Tenho muita sêde hoje.")
|
|
32
|
+
out2 = self.graph.convert("A sede da empresa fica em Lisboa.", "text",
|
|
33
|
+
"text-diacritized", lang="pt")
|
|
34
|
+
self.assertEqual(out2, "A séde da empresa fica em Lisboa.")
|
|
35
|
+
|
|
36
|
+
def test_slavic_diacritization_routes_to_stressonnx_stub(self):
|
|
37
|
+
calls = []
|
|
38
|
+
mod = types.ModuleType("stressonnx")
|
|
39
|
+
|
|
40
|
+
def stress(text, lang, model=None):
|
|
41
|
+
calls.append((text, lang, model))
|
|
42
|
+
return "STRESSED"
|
|
43
|
+
|
|
44
|
+
mod.stress = stress
|
|
45
|
+
with mock.patch.dict(sys.modules, {"stressonnx": mod}):
|
|
46
|
+
out = self.graph.convert("замок стоит", "text",
|
|
47
|
+
"text-diacritized", lang="ru")
|
|
48
|
+
self.assertEqual(out, "STRESSED")
|
|
49
|
+
self.assertEqual(calls, [("замок стоит", "ru", None)])
|
|
50
|
+
|
|
51
|
+
def test_strip_recovers_bare_russian(self):
|
|
52
|
+
out = self.graph.convert("за́мок", "text-diacritized", "text", lang="ru")
|
|
53
|
+
self.assertEqual(out, "замок")
|
|
54
|
+
|
|
55
|
+
def test_strip_recovers_bare_arabic(self):
|
|
56
|
+
vocalized = "مُحَمَّد"
|
|
57
|
+
bare = "".join(c for c in vocalized if not (0x064B <= ord(c) <= 0x065F
|
|
58
|
+
or ord(c) == 0x0670))
|
|
59
|
+
out = self.graph.convert(vocalized, "text-diacritized", "text", lang="ar")
|
|
60
|
+
self.assertEqual(out, bare)
|
|
61
|
+
self.assertEqual(out, "محمد")
|
|
62
|
+
|
|
63
|
+
def test_strip_refused_for_portuguese(self):
|
|
64
|
+
with self.assertRaises(ValueError) as ctx:
|
|
65
|
+
self.graph.convert("sêde", "text-diacritized", "text", lang="pt")
|
|
66
|
+
self.assertIn("native orthography", str(ctx.exception))
|
|
67
|
+
|
|
68
|
+
def test_strip_edge_does_not_change_text_to_ipa_route(self):
|
|
69
|
+
route = self.graph.route("text", "ipa")
|
|
70
|
+
self.assertEqual(len(route), 1)
|
|
71
|
+
edge = route[0]
|
|
72
|
+
self.assertEqual(edge.src, "text")
|
|
73
|
+
self.assertEqual(edge.dst, "ipa")
|
|
74
|
+
|
|
75
|
+
def test_strip_preserves_cyrillic_native_letters(self):
|
|
76
|
+
out = self.graph.convert("мой родно́й край", "text-diacritized",
|
|
77
|
+
"text", lang="ru")
|
|
78
|
+
self.assertEqual(out, "мой родной край")
|
|
79
|
+
out2 = self.graph.convert("ёлка", "text-diacritized", "text", lang="ru")
|
|
80
|
+
self.assertEqual(out2, "ёлка")
|
|
81
|
+
|
|
82
|
+
def test_strip_preserves_latin_stress_lang_diacritics(self):
|
|
83
|
+
# native macron (ī) plus an added combining acute overlay
|
|
84
|
+
out = self.graph.convert("Rī́ga", "text-diacritized", "text",
|
|
85
|
+
lang="lv")
|
|
86
|
+
self.assertEqual(out, "Rīga")
|
|
87
|
+
out2 = self.graph.convert("Rīga", "text-diacritized", "text", lang="lv")
|
|
88
|
+
self.assertEqual(out2, "Rīga")
|
|
89
|
+
|
|
90
|
+
def test_strip_preserves_arabic_hamza(self):
|
|
91
|
+
out = self.graph.convert("أَحْمَد", "text-diacritized", "text", lang="ar")
|
|
92
|
+
self.assertEqual(out, "أحمد")
|
|
93
|
+
|
|
94
|
+
def test_strip_refuses_aragonese(self):
|
|
95
|
+
with self.assertRaises(ValueError):
|
|
96
|
+
self.graph.convert("Cristián", "text-diacritized", "text", lang="arg")
|
|
97
|
+
|
|
98
|
+
def test_add_diacritics_does_not_misroute_herero(self):
|
|
99
|
+
from scriptconv.phonemizers.base import GraphemePhonemizer
|
|
100
|
+
self.assertEqual(GraphemePhonemizer().add_diacritics("teste", "her"), "teste")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
unittest.main()
|
|
@@ -221,3 +221,85 @@ class TestModelForwarding(unittest.TestCase):
|
|
|
221
221
|
def test_model_none_forwards_nothing(self):
|
|
222
222
|
g = get_phonemizer(Phonemizer.GRAPHEMES, model=None)
|
|
223
223
|
self.assertIsInstance(g, GraphemePhonemizer)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class TestEuropeanPortugueseSenseDiacritics(unittest.TestCase):
|
|
227
|
+
"""Real bifonia — it is on PyPI, so this exercises the actual backend."""
|
|
228
|
+
|
|
229
|
+
def test_thirst_sense_gets_closed_vowel(self):
|
|
230
|
+
out = GraphemePhonemizer().add_diacritics(
|
|
231
|
+
"Tenho muita sede hoje.", "pt")
|
|
232
|
+
self.assertEqual(out, "Tenho muita sêde hoje.")
|
|
233
|
+
|
|
234
|
+
def test_seat_sense_gets_open_vowel(self):
|
|
235
|
+
out = GraphemePhonemizer().add_diacritics(
|
|
236
|
+
"A sede da empresa fica em Lisboa.", "pt")
|
|
237
|
+
self.assertEqual(out, "A séde da empresa fica em Lisboa.")
|
|
238
|
+
|
|
239
|
+
def test_no_homograph_unchanged(self):
|
|
240
|
+
text = "O cão correu no jardim."
|
|
241
|
+
self.assertEqual(GraphemePhonemizer().add_diacritics(text, "pt"), text)
|
|
242
|
+
|
|
243
|
+
def test_brazilian_portuguese_excluded(self):
|
|
244
|
+
text = "Tenho muita sede hoje."
|
|
245
|
+
self.assertEqual(GraphemePhonemizer().add_diacritics(text, "pt-BR"), text)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class TestEastSlavicStressRouting(unittest.TestCase):
|
|
249
|
+
"""stressonnx is not yet on PyPI — routing is verified against a stub."""
|
|
250
|
+
|
|
251
|
+
def _stub(self, calls):
|
|
252
|
+
import types
|
|
253
|
+
mod = types.ModuleType("stressonnx")
|
|
254
|
+
|
|
255
|
+
def stress(text, lang, model=None):
|
|
256
|
+
calls.append((text, lang, model))
|
|
257
|
+
return "STRESSED"
|
|
258
|
+
|
|
259
|
+
mod.stress = stress
|
|
260
|
+
return mod
|
|
261
|
+
|
|
262
|
+
def test_russian_routes_to_stress_backend(self):
|
|
263
|
+
import sys
|
|
264
|
+
from unittest import mock
|
|
265
|
+
calls = []
|
|
266
|
+
with mock.patch.dict(sys.modules, {"stressonnx": self._stub(calls)}):
|
|
267
|
+
out = GraphemePhonemizer().add_diacritics(
|
|
268
|
+
"замок стоит", "ru", model="silero")
|
|
269
|
+
self.assertEqual(out, "STRESSED")
|
|
270
|
+
self.assertEqual(calls, [("замок стоит", "ru", "silero")])
|
|
271
|
+
|
|
272
|
+
def test_ukrainian_and_belarusian_route_too(self):
|
|
273
|
+
import sys
|
|
274
|
+
from unittest import mock
|
|
275
|
+
for lang in ("uk", "be"):
|
|
276
|
+
calls = []
|
|
277
|
+
with mock.patch.dict(sys.modules, {"stressonnx": self._stub(calls)}):
|
|
278
|
+
GraphemePhonemizer().add_diacritics("текст", lang, model="ruaccent")
|
|
279
|
+
self.assertEqual(calls, [("текст", lang, "ruaccent")], lang)
|
|
280
|
+
|
|
281
|
+
def test_additional_stressonnx_languages_route_too(self):
|
|
282
|
+
import sys
|
|
283
|
+
from unittest import mock
|
|
284
|
+
for lang in ("kk", "hy", "az-Latn"):
|
|
285
|
+
calls = []
|
|
286
|
+
with mock.patch.dict(sys.modules, {"stressonnx": self._stub(calls)}):
|
|
287
|
+
GraphemePhonemizer().add_diacritics("text", lang, model="simple")
|
|
288
|
+
self.assertEqual(calls, [("text", lang, "simple")], lang)
|
|
289
|
+
|
|
290
|
+
def test_berber_does_not_false_match_belarusian(self):
|
|
291
|
+
import sys
|
|
292
|
+
from unittest import mock
|
|
293
|
+
calls = []
|
|
294
|
+
with mock.patch.dict(sys.modules, {"stressonnx": self._stub(calls)}):
|
|
295
|
+
out = GraphemePhonemizer().add_diacritics("azul", "ber")
|
|
296
|
+
self.assertEqual(out, "azul")
|
|
297
|
+
self.assertEqual(calls, [])
|
|
298
|
+
|
|
299
|
+
def test_missing_stressonnx_raises_named_importerror(self):
|
|
300
|
+
import sys
|
|
301
|
+
from unittest import mock
|
|
302
|
+
with mock.patch.dict(sys.modules, {"stressonnx": None}):
|
|
303
|
+
with self.assertRaises(ImportError) as ctx:
|
|
304
|
+
GraphemePhonemizer().add_diacritics("замок", "ru")
|
|
305
|
+
self.assertIn("stressonnx", str(ctx.exception))
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/hanja.tsv
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/ipa.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/ko_tables/yale.csv
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/__init__.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/codeswitch.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/diacritize.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/dialectal.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/english_g2p.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/espeak.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/frontend.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/levantine_g2p.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_thirdparty/shami/normalize.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/kog2p/__init__.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/kog2p/rulebook.txt
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/LICENSE.md
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/__init__.py
RENAMED
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/buck/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/buck/symbols.py
RENAMED
|
File without changes
|
|
File without changes
|
{scriptconv-0.0.4a2 → scriptconv-0.0.4a4}/scriptconv/phonemizers/_vendored/mantoq/num2words.py
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|