kokorosay 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.
@@ -0,0 +1,35 @@
1
+ name: Upload Python Package
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*.*.*'
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ # Required for PyPI Trusted Publishing via OIDC token
16
+ id-token: write
17
+
18
+ steps:
19
+ # 1. Check out code
20
+ - uses: actions/checkout@v4
21
+
22
+ # 2. Install and configure uv
23
+ - name: Set up uv
24
+ uses: astral-sh/setup-uv@v8.2.0
25
+ with:
26
+ enable-cache: true
27
+
28
+ # 3. Build release distributions (dist/)
29
+ - name: Build release distributions
30
+ run: uv build
31
+
32
+ # 4. Publish directly to PyPI
33
+ # uv detects GitHub's id-token and handles OIDC exchange with PyPI without API tokens
34
+ - name: Publish to PyPI
35
+ run: uv publish
@@ -0,0 +1,10 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,235 @@
1
+ # AGENTS.md
2
+
3
+ Guidelines for AI agents and contributors working on **kokorosay**, a command-line
4
+ text-to-speech tool built on top of [Kokoro](https://github.com/hexgrad/kokoro).
5
+
6
+ ## Language Policy
7
+
8
+ - **Conversation**: Reply to the user in the same language the user writes in.
9
+ - **Artifacts**: Everything committed to the repository MUST be in English:
10
+ code comments, docstrings, identifiers, log/error messages, CLI help text,
11
+ commit messages, `README.md`, and any other documentation.
12
+
13
+ ## Keeping This Document in Sync
14
+
15
+ - This file is the source of truth for the project's specification.
16
+ - Any code change that adds, removes, or alters behavior covered here (CLI
17
+ arguments, options, subcommands, defaults, exit codes, supported formats,
18
+ module layout, dependencies, tooling, testing requirements, etc.) MUST update
19
+ `AGENTS.md` **in the same change**.
20
+ - A task is not considered done while the code and `AGENTS.md` disagree.
21
+
22
+ ## Tooling
23
+
24
+ | Purpose | Tool |
25
+ | ------------------ | ----------------------------- |
26
+ | Package / env mgmt | [uv](https://docs.astral.sh/uv/) (`uv.lock` is committed) |
27
+ | Lint + format | [ruff](https://docs.astral.sh/ruff/) |
28
+ | Tests | [pytest](https://docs.pytest.org/) |
29
+ | Build backend | hatchling + hatch-vcs (version derived from git tags) |
30
+ | Python | `>=3.14` (see `.python-version`) |
31
+
32
+ Common commands:
33
+
34
+ ```sh
35
+ uv sync # install runtime + dev dependencies
36
+ uv add <pkg> # add a runtime dependency
37
+ uv add --dev <pkg> # add a dev dependency
38
+ uv run ruff check . # lint
39
+ uv run ruff check --fix . # lint with autofix
40
+ uv run ruff format . # format
41
+ uv run pytest # run tests
42
+ uv run kokorosay --help # run the CLI from source
43
+ ```
44
+
45
+ Rules:
46
+
47
+ - Never edit `uv.lock` by hand; always go through `uv add` / `uv remove` / `uv lock`.
48
+ - Do not use `pip install` directly in this project.
49
+ - Code must pass `ruff check` and `ruff format --check` before a task is considered done.
50
+ - All tests must pass before a task is considered done.
51
+
52
+ ## Project Layout (src layout)
53
+
54
+ ```
55
+ kokorosay/
56
+ ├── AGENTS.md
57
+ ├── README.md
58
+ ├── pyproject.toml
59
+ ├── uv.lock
60
+ ├── src/
61
+ │ └── kokorosay/
62
+ │ ├── __init__.py
63
+ │ ├── __main__.py # enables `python -m kokorosay`
64
+ │ ├── cli.py # argument parsing and entry point `main()`
65
+ │ ├── setup_cmd.py # `--setup`: UniDic dictionary download
66
+ │ ├── voices.py # voice catalog, language-code mapping
67
+ │ ├── synth.py # Kokoro pipeline wrapper, segment merging
68
+ │ ├── audio_io.py # writing WAV/MP3, playback
69
+ │ └── py.typed
70
+ └── tests/
71
+ ├── conftest.py # fake kokoro / sounddevice / stdin fixtures
72
+ └── test_*.py
73
+ ```
74
+
75
+ - The console script is registered in `pyproject.toml` as
76
+ `kokorosay = "kokorosay.cli:main"`.
77
+ - Keep modules small and focused; the module list above is a guideline, not a contract.
78
+ - Inside the package, reference sibling modules with **relative imports**
79
+ (e.g. `from .voices import resolve_lang_code`, `from . import audio_io`),
80
+ never `from kokorosay.xxx import ...`. Tests (outside the package) import via
81
+ the absolute package name `kokorosay`.
82
+
83
+ ## CLI Specification
84
+
85
+ ```
86
+ kokorosay INPUT [OUTPUT] [OPTIONS]
87
+ kokorosay --list-voices
88
+ kokorosay --setup
89
+ ```
90
+
91
+ ### `--setup` option
92
+
93
+ `kokorosay --setup` downloads the full UniDic dictionary required by the
94
+ Japanese G2P backend (the `unidic` package is a runtime dependency, but its
95
+ dictionary data must be fetched separately). Implementation sketch:
96
+
97
+ ```python
98
+ import subprocess
99
+ import sys
100
+
101
+ subprocess.check_call([sys.executable, "-m", "unidic", "download"])
102
+ ```
103
+
104
+ - `--setup` is a standalone mode like `--list-voices`: `INPUT` is not required,
105
+ and the program exits after the download.
106
+ - `--setup` cannot be combined with `INPUT`/`OUTPUT` or `--list-voices`; doing
107
+ so is a usage error (exit code `2`).
108
+ - Use `sys.executable` so the download runs in the same environment kokorosay
109
+ is installed in. Do not invoke `python`/`pip` from `PATH`.
110
+ - Progress output from the child process goes straight to the terminal. If the
111
+ child exits non-zero (`CalledProcessError`) or cannot be started, print a
112
+ concise error to stderr and exit with code `1`.
113
+ - Must not import `kokoro` or `torch`.
114
+
115
+ ### Positional arguments
116
+
117
+ | Argument | Description |
118
+ | -------- | ----------- |
119
+ | `INPUT` | Text to synthesize. If it is exactly `-`, read the text from stdin. |
120
+ | `OUTPUT` | Optional output file path. If omitted, the audio is played directly. |
121
+
122
+ ### Options
123
+
124
+ | Option | Default | Description |
125
+ | ------ | ------- | ----------- |
126
+ | `--voice NAME` | `af_heart` | Voice name, e.g. `jf_nezumi`. The language is derived from the **first letter** of the voice name; there is no separate language option. |
127
+ | `--speed FLOAT` | `1.0` | Speech rate multiplier passed to Kokoro. |
128
+ | `--split-pattern REGEX` | `None` | Regex used to split text into segments. When not given, do **not** pass `split_pattern` so Kokoro's own default applies. |
129
+ | `--list-voices` | – | Print all supported voices grouped by language, then exit. `INPUT` is not required in this mode; combining it with `INPUT`/`OUTPUT` is a usage error (exit code `2`). |
130
+ | `--setup` | – | Download the full UniDic dictionary, then exit. `INPUT` is not required in this mode. See [`--setup` option](#--setup-option). |
131
+ | `--version` | – | Print the package version (from git tags via hatch-vcs), then exit. |
132
+
133
+ ### Behavior requirements
134
+
135
+ 1. **Stdin input (`-`)**
136
+ - Read raw bytes from `sys.stdin.buffer` and decode as UTF-8 explicitly
137
+ (use `utf-8-sig` so a leading BOM, common from PowerShell, is stripped).
138
+ - Never rely on the platform default encoding; Windows consoles often use a
139
+ non-UTF-8 code page.
140
+ - Bytes that are not valid UTF-8 are a runtime failure (exit code `1`).
141
+ - Text that is empty or whitespace-only (from `INPUT` or stdin) is a usage
142
+ error (exit code `2`).
143
+ - Text starting with `-` can be passed after `--` (argparse convention).
144
+ 2. **Output file**
145
+ - Only `.mp3` and `.wav` are supported (extension check is case-insensitive).
146
+ Any other extension is a usage error and must be rejected **before** loading
147
+ the model.
148
+ - Files are written with `soundfile` (libsndfile, which supports MP3).
149
+ - Existing files are overwritten without prompting.
150
+ - Missing parent directories are created automatically
151
+ (`Path.parent.mkdir(parents=True, exist_ok=True)`).
152
+ 3. **Segment merging**
153
+ - Kokoro yields one audio chunk per segment. When writing to a file, all chunks
154
+ MUST be concatenated in order and written as a **single** file, regardless of
155
+ whether `--split-pattern` was supplied.
156
+ 4. **Playback (no `OUTPUT`)**
157
+ - Play the synthesized audio on the default output device using
158
+ `sounddevice` (PortAudio).
159
+ - Chunks are played sequentially as they are generated to reduce latency; the
160
+ output stream is opened when the first chunk arrives.
161
+ 5. **Voice → language**
162
+ - `lang_code = voice[0]`, passed to `KPipeline(lang_code=..., repo_id="hexgrad/Kokoro-82M")`
163
+ (passing `repo_id` explicitly suppresses Kokoro's stdout warning).
164
+ - An unknown voice or unsupported language prefix is a usage error with a
165
+ helpful message (suggest `--list-voices`).
166
+ - Other argument validation (`--speed` must be positive, `--split-pattern`
167
+ must be a valid regex) also happens before loading the model and is a usage
168
+ error.
169
+ 6. **Exit codes**
170
+ - `0` success, `1` runtime failure, `2` usage error (argparse convention),
171
+ `130` interrupted with Ctrl+C.
172
+ - Synthesis that produces no audio at all is a runtime failure.
173
+ - Errors go to stderr; stdout is reserved for user-requested output
174
+ (e.g. `--list-voices`). Anything third-party libraries print to stdout
175
+ during synthesis is redirected to stderr, and warnings emitted by `torch`
176
+ are suppressed.
177
+
178
+ ### Kokoro reference
179
+
180
+ - Audio sample rate is **24000 Hz**.
181
+ - Language prefixes:
182
+
183
+ | Prefix | Language |
184
+ | ------ | -------- |
185
+ | `a` | American English |
186
+ | `b` | British English |
187
+ | `e` | Spanish |
188
+ | `f` | French |
189
+ | `h` | Hindi |
190
+ | `i` | Italian |
191
+ | `j` | Japanese |
192
+ | `p` | Brazilian Portuguese |
193
+ | `z` | Mandarin Chinese |
194
+
195
+ - Basic pipeline usage:
196
+
197
+ ```python
198
+ from kokoro import KPipeline
199
+
200
+ pipeline = KPipeline(lang_code="j")
201
+ for graphemes, phonemes, audio in pipeline(text, voice="jf_nezumi", speed=1.0):
202
+ ...
203
+ ```
204
+
205
+ ## Coding Conventions
206
+
207
+ - Target Python 3.14; use modern syntax (type hints everywhere, `pathlib.Path`,
208
+ `from __future__ import annotations` is unnecessary).
209
+ - Public functions have English docstrings.
210
+ - Keep heavy imports (`kokoro`, `torch`) lazy, inside the functions that need them,
211
+ so `--help`, `--list-voices`, `--setup`, and argument validation stay fast.
212
+ - Prefer the standard library (`argparse`) for CLI parsing unless a dependency is
213
+ explicitly approved by the user.
214
+ - Do not add new runtime dependencies without the user's approval.
215
+ - Approved runtime dependencies: `kokoro`, `misaki[en,ja,ko,vi,zh]`, `unidic`
216
+ (Japanese dictionary), `soundfile` (WAV/MP3 writing), `sounddevice`
217
+ (playback). `numpy` comes in transitively and may be used directly.
218
+
219
+ ## Testing
220
+
221
+ - Tests live in `tests/` and use pytest.
222
+ - Unit tests MUST NOT download models or require audio hardware: mock
223
+ `KPipeline` and the playback backend. `tests/conftest.py` provides the
224
+ `fake_kokoro`, `fake_sounddevice`, and `set_stdin` fixtures, which install fake
225
+ `kokoro` / `sounddevice` modules into `sys.modules`.
226
+ - Tests that need the real model or a sound device are marked
227
+ `@pytest.mark.integration` and deselected by default (`addopts` in
228
+ `pyproject.toml`); run them with `uv run pytest -m integration`.
229
+ - Cover at least: argument parsing, stdin UTF-8 decoding (including BOM and
230
+ non-ASCII text), output extension validation, parent directory creation,
231
+ segment concatenation, voice-to-language mapping, `--list-voices` grouping,
232
+ and `--setup` handling (mock `subprocess.check_call`; never actually download
233
+ UniDic in unit tests; verify the command uses `sys.executable`, that a
234
+ failing child results in exit code `1`, and that combining `--setup` with
235
+ `INPUT` or `--list-voices` results in exit code `2`).
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.5
2
+ Name: kokorosay
3
+ Version: 0.1.0
4
+ Summary: A CLI tool for Kokoro
5
+ Project-URL: Homepage, https://github.com/ecator/kokorosay
6
+ Project-URL: Repository, https://github.com/ecator/kokorosay
7
+ Author-email: Martin <qule520@126.com>
8
+ Requires-Python: >=3.14
9
+ Requires-Dist: kokoro>=0.9.4
10
+ Requires-Dist: misaki[en,ja,ko,vi,zh]>=0.9.4
11
+ Requires-Dist: sounddevice>=0.5.6
12
+ Requires-Dist: soundfile>=0.14.0
13
+ Requires-Dist: unidic>=1.1.0
14
+ Description-Content-Type: text/markdown
15
+
16
+ # kokorosay
17
+
18
+ [![PyPI version](https://img.shields.io/pypi/v/kokorosay.svg)](https://pypi.org/project/kokorosay/)
19
+ [![Python versions](https://img.shields.io/pypi/pyversions/kokorosay.svg)](https://pypi.org/project/kokorosay/)
20
+
21
+ `kokorosay` is a fast, lightweight command-line text-to-speech (TTS) tool built on top of [Kokoro](https://github.com/hexgrad/kokoro).
22
+
23
+ Pass text as an argument or pipe it via standard input; `kokorosay` will immediately stream speech through your speakers or export it to high-quality WAV or MP3 audio files.
24
+
25
+ ---
26
+
27
+ ## Features
28
+
29
+ - ⚡ **Fast & Lightweight**: Built on the open-weights 82M parameter Kokoro model (`hexgrad/Kokoro-82M`).
30
+ - 🔊 **Direct Low-Latency Playback**: Streams audio chunks to your default audio device in real time as they are generated.
31
+ - 💾 **WAV & MP3 Export**: Concatenates synthesized chunks into a seamless 24 kHz audio file; parent directories are created automatically.
32
+ - 🌐 **9 Languages & 50+ Voices**: Supports English, Japanese, Mandarin Chinese, Spanish, French, Hindi, Italian, and Brazilian Portuguese.
33
+ - 🔀 **Automatic Language Detection**: The target language is derived directly from the voice name prefix (e.g. `jf_nezumi` &rarr; Japanese, `zf_xiaobei` &rarr; Mandarin, `af_heart` &rarr; American English).
34
+ - 📥 **Pipeline & Stdin Friendly**: Supports `-` as input with explicit UTF-8 and BOM decoding, ideal for shell pipes and automation scripts.
35
+ - 🎛️ **Synthesis Controls**: Easily adjust speech rate multiplier (`--speed`) or provide custom segment-splitting regexes (`--split-pattern`).
36
+ - 🛡️ **Clean CLI & Standard Exit Codes**: Suppresses third-party noise, outputs errors to `stderr`, and adheres to standard exit codes (`0`, `1`, `2`, `130`).
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ `kokorosay` requires **Python 3.14+**.
43
+
44
+ ### Recommended: Using [uv](https://docs.astral.sh/uv/)
45
+
46
+ Install `kokorosay` as a globally isolated command-line tool:
47
+
48
+ ```sh
49
+ uv tool install kokorosay
50
+ ```
51
+
52
+ ### Alternative: Using [pipx](https://github.com/pypa/pipx) or pip
53
+
54
+ ```sh
55
+ # Using pipx
56
+ pipx install kokorosay
57
+
58
+ # Using standard pip (inside an active virtual environment)
59
+ pip install kokorosay
60
+ ```
61
+
62
+ ### System Prerequisites (Linux only)
63
+
64
+ On Windows and macOS, audio dependencies are bundled automatically. On Linux systems, `portaudio` might be needed for direct speaker playback:
65
+
66
+ ```sh
67
+ # Debian / Ubuntu
68
+ sudo apt-get install libportaudio2
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Setup
74
+
75
+ Before first use, run the one-time dictionary setup:
76
+
77
+ ```sh
78
+ kokorosay --setup
79
+ ```
80
+
81
+ - **Japanese UniDic**: `kokorosay --setup` downloads the full UniDic dictionary required for Japanese G2P (grapheme-to-phoneme) processing.
82
+ - **Model weights**: The Kokoro-82M model and voice weights (~330 MB) are automatically fetched from Hugging Face on your first speech synthesis and cached locally for future offline use.
83
+
84
+ ---
85
+
86
+ ## Quick Start & Examples
87
+
88
+ ### 1. Direct Playback
89
+
90
+ Provide text in quotes to play speech instantly through the default audio device:
91
+
92
+ ```sh
93
+ # Play using default voice (af_heart - American English female)
94
+ kokorosay "Hello! Kokorosay brings text to life right from your terminal."
95
+
96
+ # British English voice, slightly faster
97
+ kokorosay "Mind the gap between the train and the platform." --voice bm_george --speed 1.15
98
+ ```
99
+
100
+ ### 2. Exporting to Audio Files (`.wav` / `.mp3`)
101
+
102
+ Specify an output file path as the second positional argument. Only `.mp3` and `.wav` formats are supported (case-insensitive). Missing directories will be created automatically:
103
+
104
+ ```sh
105
+ # Save as MP3
106
+ kokorosay "Speech saved to an MP3 file." output.mp3
107
+
108
+ # Japanese voice saved to a nested directory
109
+ kokorosay "こんにちは、世界。" audio/japanese/hello.wav --voice jf_nezumi
110
+
111
+ # Mandarin Chinese voice
112
+ kokorosay "你好,欢迎使用文本转语音工具。" out/welcome.mp3 --voice zf_xiaobei
113
+ ```
114
+
115
+ ### 3. Piping from Stdin (`-`)
116
+
117
+ Pass `-` as `INPUT` to read text from standard input. `kokorosay` decodes standard input as UTF-8 (and strips PowerShell's UTF-8 BOM if present):
118
+
119
+ ```sh
120
+ # Pipe the output of any command
121
+ fortune | kokorosay -
122
+
123
+ # Read from a file via stdin
124
+ cat story.txt | kokorosay - story.mp3 --voice bf_emma
125
+
126
+ # In PowerShell:
127
+ Get-Content notes.txt -Raw | kokorosay - notes.wav
128
+ ```
129
+
130
+ ### 4. Text Starting with Hyphens (`--`)
131
+
132
+ If your input text begins with a dash or minus sign, use `--` so the argument parser does not interpret it as a flag:
133
+
134
+ ```sh
135
+ kokorosay -- "-5 degrees Celsius outside today."
136
+ ```
137
+
138
+ ---
139
+
140
+ ## CLI Reference
141
+
142
+ ### Synopsis
143
+
144
+ ```sh
145
+ kokorosay INPUT [OUTPUT] [OPTIONS]
146
+ kokorosay --list-voices
147
+ kokorosay --setup
148
+ ```
149
+
150
+ ### Arguments and Options
151
+
152
+ | Argument / Option | Default | Description |
153
+ | ----------------- | ------- | ----------- |
154
+ | `INPUT` | – | Text to synthesize. Use `-` to read UTF-8 text from stdin. |
155
+ | `OUTPUT` | – | Output audio path (`.wav` or `.mp3`). If omitted, audio plays directly. |
156
+ | `--voice NAME` | `af_heart` | Voice identifier (e.g. `jf_nezumi`, `bf_emma`). First letter sets language. |
157
+ | `--speed FLOAT` | `1.0` | Speech rate multiplier (must be a positive number). |
158
+ | `--split-pattern REGEX` | Kokoro default | Regular expression to split input text into segments. |
159
+ | `--list-voices` | – | Print all supported voices grouped by language and exit. |
160
+ | `--setup` | – | Download the UniDic dictionary for Japanese support and exit. |
161
+ | `--version` | – | Show version number and exit. |
162
+ | `-h`, `--help` | – | Show command help and exit. |
163
+
164
+ > **Note:** `--setup` and `--list-voices` are standalone modes. They cannot be combined with positional arguments (`INPUT` / `OUTPUT`) or with each other.
165
+
166
+ ---
167
+
168
+ ## Supported Languages & Voices
169
+
170
+ Kokoro determines the language from the **first letter** of the voice name. The **second letter** indicates voice gender (`f` for female, `m` for male).
171
+
172
+ | Prefix | Language | Example Voices |
173
+ | :---: | --- | --- |
174
+ | `a` | American English | `af_heart` (default), `af_alloy`, `af_bella`, `am_adam`, `am_michael` |
175
+ | `b` | British English | `bf_alice`, `bf_emma`, `bm_daniel`, `bm_george` |
176
+ | `e` | Spanish | `ef_dora`, `em_alex`, `em_santa` |
177
+ | `f` | French | `ff_siwis` |
178
+ | `h` | Hindi | `hf_alpha`, `hf_beta`, `hm_omega`, `hm_psi` |
179
+ | `i` | Italian | `if_sara`, `im_nicola` |
180
+ | `j` | Japanese | `jf_alpha`, `jf_gongitsune`, `jf_nezumi`, `jf_tebukuro`, `jm_kumo` |
181
+ | `p` | Brazilian Portuguese | `pf_dora`, `pm_alex`, `pm_santa` |
182
+ | `z` | Mandarin Chinese | `zf_xiaobei`, `zf_xiaoni`, `zf_xiaoxiao`, `zm_yunjian`, `zm_yunyang` |
183
+
184
+ To view the complete list of available voices grouped by language, run:
185
+
186
+ ```sh
187
+ kokorosay --list-voices
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Exit Codes
193
+
194
+ | Code | Meaning |
195
+ | :---: | --- |
196
+ | `0` | **Success**: Audio played or written successfully, or `--help` / `--list-voices` completed. |
197
+ | `1` | **Runtime Failure**: Network error downloading weights, synthesis failure, missing audio device, or invalid UTF-8 bytes on stdin. |
198
+ | `2` | **Usage Error**: Missing `INPUT`, invalid argument, unknown voice name, unsupported output extension, or empty text. |
199
+ | `130` | **Interrupted**: Execution aborted by `SIGINT` (Ctrl+C). |
200
+
201
+ ---
202
+
203
+ ## Development
204
+
205
+ If you wish to contribute or modify `kokorosay`:
206
+
207
+ ```sh
208
+ # Clone repository
209
+ git clone https://github.com/ecator/kokorosay.git
210
+ cd kokorosay
211
+
212
+ # Install runtime and dev dependencies
213
+ uv sync
214
+
215
+ # Lint and check formatting
216
+ uv run ruff check .
217
+ uv run ruff format --check .
218
+
219
+ # Run unit tests (offline, mocked Kokoro/sounddevice)
220
+ uv run pytest
221
+
222
+ # Run integration tests (requires real model weights & audio device)
223
+ uv run pytest -m integration
224
+ ```
225
+
226
+ See [AGENTS.md](AGENTS.md) for full architecture specifications and coding conventions.
227
+
228
+ ---
229
+
230
+ ## Acknowledgments
231
+
232
+ - [Kokoro](https://github.com/hexgrad/kokoro) for the TTS model.
233
+ - [Misaki](https://github.com/hexgrad/misaki) for G2P text pre-processing.
234
+ - [UniDic](https://github.com/polm/unidic-py) for Japanese morphological analysis.