hatsuon 0.1.0__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.
- hatsuon-0.1.0/.gitignore +19 -0
- hatsuon-0.1.0/DATA_SOURCES.md +18 -0
- hatsuon-0.1.0/LICENSE +21 -0
- hatsuon-0.1.0/PKG-INFO +121 -0
- hatsuon-0.1.0/README.md +81 -0
- hatsuon-0.1.0/docs/SPEC.md +867 -0
- hatsuon-0.1.0/pyproject.toml +57 -0
- hatsuon-0.1.0/src/hatsuon/__init__.py +8 -0
- hatsuon-0.1.0/src/hatsuon/acoustic.py +114 -0
- hatsuon-0.1.0/src/hatsuon/align.py +217 -0
- hatsuon-0.1.0/src/hatsuon/api.py +45 -0
- hatsuon-0.1.0/src/hatsuon/audio.py +147 -0
- hatsuon-0.1.0/src/hatsuon/calibration/__init__.py +43 -0
- hatsuon-0.1.0/src/hatsuon/calibration/default.json +409 -0
- hatsuon-0.1.0/src/hatsuon/errors.py +17 -0
- hatsuon-0.1.0/src/hatsuon/export.py +94 -0
- hatsuon-0.1.0/src/hatsuon/frontend/__init__.py +1 -0
- hatsuon-0.1.0/src/hatsuon/frontend/analyze.py +239 -0
- hatsuon-0.1.0/src/hatsuon/frontend/morae.py +183 -0
- hatsuon-0.1.0/src/hatsuon/frontend/pitch_pattern.py +60 -0
- hatsuon-0.1.0/src/hatsuon/gop.py +50 -0
- hatsuon-0.1.0/src/hatsuon/pipeline.py +358 -0
- hatsuon-0.1.0/src/hatsuon/pitch.py +131 -0
- hatsuon-0.1.0/src/hatsuon/targets.py +68 -0
- hatsuon-0.1.0/src/hatsuon/timing.py +58 -0
- hatsuon-0.1.0/src/hatsuon/types.py +93 -0
- hatsuon-0.1.0/tests/test_align.py +96 -0
- hatsuon-0.1.0/tests/test_analyze.py +122 -0
- hatsuon-0.1.0/tests/test_audio.py +84 -0
- hatsuon-0.1.0/tests/test_calibration.py +36 -0
- hatsuon-0.1.0/tests/test_judges.py +58 -0
- hatsuon-0.1.0/tests/test_morae.py +44 -0
- hatsuon-0.1.0/tests/test_phonemes.py +53 -0
- hatsuon-0.1.0/tests/test_pipeline.py +53 -0
- hatsuon-0.1.0/tests/test_pitch_pattern.py +50 -0
- hatsuon-0.1.0/tests/test_smoke.py +6 -0
- hatsuon-0.1.0/tests/test_targets.py +55 -0
- hatsuon-0.1.0/tools/calibrate.py +398 -0
- hatsuon-0.1.0/tools/eval_accent.py +149 -0
- hatsuon-0.1.0/tools/fetch_data.sh +51 -0
hatsuon-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.venv/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.ruff_cache/
|
|
9
|
+
|
|
10
|
+
# Never commit audio or downloaded corpora (licences forbid redistribution)
|
|
11
|
+
data/
|
|
12
|
+
*.wav
|
|
13
|
+
*.flac
|
|
14
|
+
*.mp3
|
|
15
|
+
*.m4a
|
|
16
|
+
*.onnx
|
|
17
|
+
|
|
18
|
+
# Claude
|
|
19
|
+
CLAUDE.md
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Data sources
|
|
2
|
+
|
|
3
|
+
Corpora used for calibration and evaluation (SPEC Appendix B). Nothing listed here
|
|
4
|
+
is redistributed by this repository: audio lives in the git-ignored `data/`
|
|
5
|
+
directory and is fetched by `tools/fetch_data.sh`. Licence summaries are
|
|
6
|
+
paraphrases for planning, not legal advice — re-read the official page before use.
|
|
7
|
+
|
|
8
|
+
| Source | Official page | Licence (summary) | Read on | Used for |
|
|
9
|
+
|---|---|---|---|---|
|
|
10
|
+
| JSUT v1.1 | https://sites.google.com/site/shinnosuketakamichi/publication/jsut | Text CC BY-SA 4.0. Audio: academic / non-commercial research (incl. inside companies) / personal use; no redistribution (small excerpts allowed); commercial use by contacting the authors. | 2026-11-04 | F0 and duration sanity checks, local regression fixtures |
|
|
11
|
+
| JVS v1 | https://sites.google.com/site/shinnosuketakamichi/research-topics/jvs_corpus | Tags CC BY-SA 4.0. Audio: same terms as JSUT (non-commercial research, no redistribution). | 2026-11-04 | Per-phone GOP calibration, duration norms, native false-alarm rate |
|
|
12
|
+
| jsut-label | https://github.com/sarulab-speech/jsut-label | CC BY-SA 4.0 | 2026-11-04 | Ground-truth accent nucleus for basic5000 (front-end accent accuracy) |
|
|
13
|
+
|
|
14
|
+
## Models
|
|
15
|
+
|
|
16
|
+
| Model | Page | Licence | Read on | Notes |
|
|
17
|
+
|---|---|---|---|---|
|
|
18
|
+
| japanese-hubert-base-phoneme-ctc-v4 | https://huggingface.co/prj-beatrice/japanese-hubert-base-phoneme-ctc-v4 | Apache-2.0 | 2026-11-04 | Fine-tuned from rinna/japanese-hubert-base on ReazonSpeech (CDLA-Sharing-1.0, Art. 30-4 restricted — see SPEC B.2). Not redistributed; users export it locally with `hatsuon-export`. |
|
hatsuon-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Công Anh Dũng
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
hatsuon-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: hatsuon
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Japanese pronunciation scoring: mora-level accuracy, special morae and pitch accent.
|
|
5
|
+
Author: Công Anh Dũng
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: gop,japanese,mora,pitch-accent,pronunciation,speech
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: Education
|
|
12
|
+
Classifier: Natural Language :: Japanese
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: numpy>=1.24
|
|
18
|
+
Provides-Extra: all
|
|
19
|
+
Requires-Dist: librosa>=0.10; extra == 'all'
|
|
20
|
+
Requires-Dist: onnxruntime>=1.17; extra == 'all'
|
|
21
|
+
Requires-Dist: pyopenjtalk>=0.3; extra == 'all'
|
|
22
|
+
Requires-Dist: soundfile>=0.12; extra == 'all'
|
|
23
|
+
Provides-Extra: audio
|
|
24
|
+
Requires-Dist: librosa>=0.10; extra == 'audio'
|
|
25
|
+
Requires-Dist: soundfile>=0.12; extra == 'audio'
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
30
|
+
Requires-Dist: twine>=5; extra == 'dev'
|
|
31
|
+
Provides-Extra: export
|
|
32
|
+
Requires-Dist: onnx>=1.15; extra == 'export'
|
|
33
|
+
Requires-Dist: torch>=2.2; extra == 'export'
|
|
34
|
+
Requires-Dist: transformers>=4.40; extra == 'export'
|
|
35
|
+
Provides-Extra: frontend
|
|
36
|
+
Requires-Dist: pyopenjtalk>=0.3; extra == 'frontend'
|
|
37
|
+
Provides-Extra: onnx
|
|
38
|
+
Requires-Dist: onnxruntime>=1.17; extra == 'onnx'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# hatsuon
|
|
42
|
+
|
|
43
|
+
Japanese pronunciation scoring for read-aloud speech, on the CPU. It scores
|
|
44
|
+
accuracy per mora, the special morae (っ, ん, long vowels) and Tokyo pitch accent.
|
|
45
|
+
|
|
46
|
+
> Status: **alpha (0.1)**. Thresholds were tuned on native speech only (JSUT/JVS),
|
|
47
|
+
> and no L2 learner data has been used yet. Treat the scores as feedback, not as a
|
|
48
|
+
> grade. Design and tuning records: [docs/SPEC.md](docs/SPEC.md) and
|
|
49
|
+
> [`calibration/default.json`](src/hatsuon/calibration/default.json).
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install "hatsuon[all]"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The acoustic model is **not** shipped in the package. Convert it once on your
|
|
58
|
+
machine. This step needs PyTorch and transformers only for the conversion itself:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install "hatsuon[export]"
|
|
62
|
+
hatsuon-export # writes ~/.cache/hatsuon/models/... (ONNX, int8)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`hatsuon-export --out DIR` writes the model elsewhere; set `HATSUON_MODEL_DIR=DIR`
|
|
66
|
+
to use it. `--no-quantize` keeps FP32 weights.
|
|
67
|
+
|
|
68
|
+
## Use
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import hatsuon
|
|
72
|
+
|
|
73
|
+
r = hatsuon.score("learner.wav", "東京に行きます。")
|
|
74
|
+
print(r.overall, r.accuracy, r.completeness, r.pitch, r.timing, r.confidence)
|
|
75
|
+
for w in r.words:
|
|
76
|
+
print(w.surface, w.reading, w.score, w.accent.value)
|
|
77
|
+
for m in w.morae:
|
|
78
|
+
print(" ", m.kana, m.status.value, round(m.score), m.duration, m.pitch_status)
|
|
79
|
+
print([x.value for x in r.warnings])
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- `audio` can be a path, encoded bytes, or a `(samples, sample_rate)` tuple.
|
|
83
|
+
- Ambiguous readings: `reading="きょう"` (whole text) or `reading={"今日": "きょう"}`.
|
|
84
|
+
- Accent overrides: `accent={"箸": 1}` (0 = heiban, n = fall after mora n).
|
|
85
|
+
- `pitch=False` or `timing=False` skips those stages.
|
|
86
|
+
- `debug=True` attaches F0, the free decode and per-phone GOP to `r.debug`.
|
|
87
|
+
- Soft problems such as `no_speech`, `content_mismatch` or `pitch_unreliable`
|
|
88
|
+
come back in `r.warnings` and lower `r.confidence`.
|
|
89
|
+
- Hard errors raise `hatsuon.AudioError` or `hatsuon.TextError`.
|
|
90
|
+
|
|
91
|
+
## Known limitations (0.1)
|
|
92
|
+
|
|
93
|
+
- **Native-only calibration.** We have not yet measured mispronunciation recall
|
|
94
|
+
on learners. On 20 held-out JVS speakers, 0.6% of correct native morae fall
|
|
95
|
+
below the `mispronounced` threshold. Synthetic one-mora substitutions (the
|
|
96
|
+
text is changed, the audio is not) are caught 94% of the time: 98% for
|
|
97
|
+
consonants and 91% for vowels. Real learner errors are subtler than these.
|
|
98
|
+
- **Pitch accent:**
|
|
99
|
+
- Native speakers often place the F0 peak one mora late, so a fall up to one
|
|
100
|
+
mora after the nucleus is accepted. As a result, a learner who puts the
|
|
101
|
+
nucleus one mora too late is not caught.
|
|
102
|
+
- About 9% of native heiban phrases are flagged with a false fall.
|
|
103
|
+
- **Readings come from OpenJTalk.** When it misreads a word (proper nouns,
|
|
104
|
+
命 → イノチ when the speaker says めい), a correct reading shows up as
|
|
105
|
+
`deleted` morae. Pass `reading={"命": "めい"}` in those cases.
|
|
106
|
+
- Read speech only. Not for spontaneous speech or singing.
|
|
107
|
+
|
|
108
|
+
## Development
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pip install -e ".[all,dev]"
|
|
112
|
+
pytest && ruff check .
|
|
113
|
+
bash tools/fetch_data.sh # JSUT, JVS, jsut-label into data/ (see DATA_SOURCES.md)
|
|
114
|
+
python tools/eval_accent.py --n 300 # pitch-accent accuracy on JSUT
|
|
115
|
+
python tools/calibrate.py collect && python tools/calibrate.py fit --write
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT. Corpora and the acoustic model have their own licences and are never
|
|
121
|
+
redistributed. See [DATA_SOURCES.md](DATA_SOURCES.md).
|
hatsuon-0.1.0/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# hatsuon
|
|
2
|
+
|
|
3
|
+
Japanese pronunciation scoring for read-aloud speech, on the CPU. It scores
|
|
4
|
+
accuracy per mora, the special morae (っ, ん, long vowels) and Tokyo pitch accent.
|
|
5
|
+
|
|
6
|
+
> Status: **alpha (0.1)**. Thresholds were tuned on native speech only (JSUT/JVS),
|
|
7
|
+
> and no L2 learner data has been used yet. Treat the scores as feedback, not as a
|
|
8
|
+
> grade. Design and tuning records: [docs/SPEC.md](docs/SPEC.md) and
|
|
9
|
+
> [`calibration/default.json`](src/hatsuon/calibration/default.json).
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install "hatsuon[all]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The acoustic model is **not** shipped in the package. Convert it once on your
|
|
18
|
+
machine. This step needs PyTorch and transformers only for the conversion itself:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install "hatsuon[export]"
|
|
22
|
+
hatsuon-export # writes ~/.cache/hatsuon/models/... (ONNX, int8)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`hatsuon-export --out DIR` writes the model elsewhere; set `HATSUON_MODEL_DIR=DIR`
|
|
26
|
+
to use it. `--no-quantize` keeps FP32 weights.
|
|
27
|
+
|
|
28
|
+
## Use
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import hatsuon
|
|
32
|
+
|
|
33
|
+
r = hatsuon.score("learner.wav", "東京に行きます。")
|
|
34
|
+
print(r.overall, r.accuracy, r.completeness, r.pitch, r.timing, r.confidence)
|
|
35
|
+
for w in r.words:
|
|
36
|
+
print(w.surface, w.reading, w.score, w.accent.value)
|
|
37
|
+
for m in w.morae:
|
|
38
|
+
print(" ", m.kana, m.status.value, round(m.score), m.duration, m.pitch_status)
|
|
39
|
+
print([x.value for x in r.warnings])
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- `audio` can be a path, encoded bytes, or a `(samples, sample_rate)` tuple.
|
|
43
|
+
- Ambiguous readings: `reading="きょう"` (whole text) or `reading={"今日": "きょう"}`.
|
|
44
|
+
- Accent overrides: `accent={"箸": 1}` (0 = heiban, n = fall after mora n).
|
|
45
|
+
- `pitch=False` or `timing=False` skips those stages.
|
|
46
|
+
- `debug=True` attaches F0, the free decode and per-phone GOP to `r.debug`.
|
|
47
|
+
- Soft problems such as `no_speech`, `content_mismatch` or `pitch_unreliable`
|
|
48
|
+
come back in `r.warnings` and lower `r.confidence`.
|
|
49
|
+
- Hard errors raise `hatsuon.AudioError` or `hatsuon.TextError`.
|
|
50
|
+
|
|
51
|
+
## Known limitations (0.1)
|
|
52
|
+
|
|
53
|
+
- **Native-only calibration.** We have not yet measured mispronunciation recall
|
|
54
|
+
on learners. On 20 held-out JVS speakers, 0.6% of correct native morae fall
|
|
55
|
+
below the `mispronounced` threshold. Synthetic one-mora substitutions (the
|
|
56
|
+
text is changed, the audio is not) are caught 94% of the time: 98% for
|
|
57
|
+
consonants and 91% for vowels. Real learner errors are subtler than these.
|
|
58
|
+
- **Pitch accent:**
|
|
59
|
+
- Native speakers often place the F0 peak one mora late, so a fall up to one
|
|
60
|
+
mora after the nucleus is accepted. As a result, a learner who puts the
|
|
61
|
+
nucleus one mora too late is not caught.
|
|
62
|
+
- About 9% of native heiban phrases are flagged with a false fall.
|
|
63
|
+
- **Readings come from OpenJTalk.** When it misreads a word (proper nouns,
|
|
64
|
+
命 → イノチ when the speaker says めい), a correct reading shows up as
|
|
65
|
+
`deleted` morae. Pass `reading={"命": "めい"}` in those cases.
|
|
66
|
+
- Read speech only. Not for spontaneous speech or singing.
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install -e ".[all,dev]"
|
|
72
|
+
pytest && ruff check .
|
|
73
|
+
bash tools/fetch_data.sh # JSUT, JVS, jsut-label into data/ (see DATA_SOURCES.md)
|
|
74
|
+
python tools/eval_accent.py --n 300 # pitch-accent accuracy on JSUT
|
|
75
|
+
python tools/calibrate.py collect && python tools/calibrate.py fit --write
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT. Corpora and the acoustic model have their own licences and are never
|
|
81
|
+
redistributed. See [DATA_SOURCES.md](DATA_SOURCES.md).
|