moss-tts-nano-cli 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.
- moss_tts_nano_cli-0.1.0/.github/workflows/publish.yml +40 -0
- moss_tts_nano_cli-0.1.0/.gitignore +10 -0
- moss_tts_nano_cli-0.1.0/.python-version +1 -0
- moss_tts_nano_cli-0.1.0/LICENSE +21 -0
- moss_tts_nano_cli-0.1.0/PKG-INFO +94 -0
- moss_tts_nano_cli-0.1.0/README.md +67 -0
- moss_tts_nano_cli-0.1.0/pyproject.toml +57 -0
- moss_tts_nano_cli-0.1.0/src/moss_tts_nano_cli/__init__.py +5 -0
- moss_tts_nano_cli-0.1.0/src/moss_tts_nano_cli/cache.py +10 -0
- moss_tts_nano_cli-0.1.0/src/moss_tts_nano_cli/cli.py +88 -0
- moss_tts_nano_cli-0.1.0/src/moss_tts_nano_cli/tts.py +62 -0
- moss_tts_nano_cli-0.1.0/tests/test_cli.py +19 -0
- moss_tts_nano_cli-0.1.0/uv.lock +1005 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
id-token: write
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v3
|
|
20
|
+
with:
|
|
21
|
+
version: "0.11.8"
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
|
|
28
|
+
- name: Install build dependencies
|
|
29
|
+
run: uv sync --extra dev
|
|
30
|
+
|
|
31
|
+
- name: Run tests
|
|
32
|
+
run: uv run pytest
|
|
33
|
+
|
|
34
|
+
- name: Build package
|
|
35
|
+
run: uv build
|
|
36
|
+
|
|
37
|
+
- name: Publish to PyPI
|
|
38
|
+
env:
|
|
39
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
40
|
+
run: uv publish
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 moss-tts-nano-cli contributors
|
|
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.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: moss-tts-nano-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: One-command zero-shot voice cloning with MOSS-TTS-Nano via mlx-audio.
|
|
5
|
+
Project-URL: Homepage, https://github.com/vra/moss-tts-nano-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/vra/moss-tts-nano-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/vra/moss-tts-nano-cli/issues
|
|
8
|
+
Author-email: 蔚山 <weishan.wyf@alibaba-inc.com>
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Requires-Dist: click>=8.0.0
|
|
20
|
+
Requires-Dist: mlx-audio>=0.0.1
|
|
21
|
+
Requires-Dist: numpy>=1.26.0
|
|
22
|
+
Requires-Dist: soundfile>=0.12.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.6.0; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# moss-tts-nano-cli
|
|
29
|
+
|
|
30
|
+
One-command zero-shot voice cloning with the [MOSS-TTS-Nano-100M](https://huggingface.co/mlx-community/MOSS-TTS-Nano-100M) model, powered by [mlx-audio](https://github.com/Blaizzy/mlx-audio).
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- **No manual setup**: `uvx moss-tts-nano-cli` installs the environment automatically.
|
|
35
|
+
- **Lazy model download**: the model is fetched from Hugging Face on first use.
|
|
36
|
+
- **Voice cloning**: pass a reference WAV and text to synthesize speech in that voice.
|
|
37
|
+
- **Apple Silicon optimized**: runs on MLX.
|
|
38
|
+
|
|
39
|
+
## Requirements
|
|
40
|
+
|
|
41
|
+
- Python 3.12+
|
|
42
|
+
- macOS with Apple Silicon (MLX backend)
|
|
43
|
+
- [uv](https://docs.astral.sh/uv/) (recommended)
|
|
44
|
+
- FFmpeg (used indirectly by audio tooling)
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv tool install moss-tts-nano-cli
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or run without installing:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uvx --from moss-tts-nano-cli moss-tts-nano --help
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
### Clone a voice
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
moss-tts-nano clone \
|
|
64
|
+
--ref ./my_voice.wav \
|
|
65
|
+
--text "Hello, this is my cloned voice speaking." \
|
|
66
|
+
--out output.wav
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The first run downloads `mlx-community/MOSS-TTS-Nano-100M` and the audio tokenizer into the Hugging Face cache (`~/.cache/huggingface`).
|
|
70
|
+
|
|
71
|
+
### Eagerly download the model
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
moss-tts-nano download
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Show info
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
moss-tts-nano info
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
git clone https://github.com/vra/moss-tts-nano-cli.git
|
|
87
|
+
cd moss-tts-nano-cli
|
|
88
|
+
uv sync --extra dev
|
|
89
|
+
uv run pytest
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# moss-tts-nano-cli
|
|
2
|
+
|
|
3
|
+
One-command zero-shot voice cloning with the [MOSS-TTS-Nano-100M](https://huggingface.co/mlx-community/MOSS-TTS-Nano-100M) model, powered by [mlx-audio](https://github.com/Blaizzy/mlx-audio).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **No manual setup**: `uvx moss-tts-nano-cli` installs the environment automatically.
|
|
8
|
+
- **Lazy model download**: the model is fetched from Hugging Face on first use.
|
|
9
|
+
- **Voice cloning**: pass a reference WAV and text to synthesize speech in that voice.
|
|
10
|
+
- **Apple Silicon optimized**: runs on MLX.
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- Python 3.12+
|
|
15
|
+
- macOS with Apple Silicon (MLX backend)
|
|
16
|
+
- [uv](https://docs.astral.sh/uv/) (recommended)
|
|
17
|
+
- FFmpeg (used indirectly by audio tooling)
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv tool install moss-tts-nano-cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or run without installing:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uvx --from moss-tts-nano-cli moss-tts-nano --help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Clone a voice
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
moss-tts-nano clone \
|
|
37
|
+
--ref ./my_voice.wav \
|
|
38
|
+
--text "Hello, this is my cloned voice speaking." \
|
|
39
|
+
--out output.wav
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The first run downloads `mlx-community/MOSS-TTS-Nano-100M` and the audio tokenizer into the Hugging Face cache (`~/.cache/huggingface`).
|
|
43
|
+
|
|
44
|
+
### Eagerly download the model
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
moss-tts-nano download
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Show info
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
moss-tts-nano info
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/vra/moss-tts-nano-cli.git
|
|
60
|
+
cd moss-tts-nano-cli
|
|
61
|
+
uv sync --extra dev
|
|
62
|
+
uv run pytest
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "moss-tts-nano-cli"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "One-command zero-shot voice cloning with MOSS-TTS-Nano via mlx-audio."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "蔚山", email = "weishan.wyf@alibaba-inc.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Environment :: Console",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Multimedia :: Sound/Audio :: Speech",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"click>=8.0.0",
|
|
22
|
+
"mlx-audio>=0.0.1",
|
|
23
|
+
"numpy>=1.26.0",
|
|
24
|
+
"soundfile>=0.12.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = [
|
|
29
|
+
"pytest>=8.0.0",
|
|
30
|
+
"ruff>=0.6.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
moss-tts-nano = "moss_tts_nano_cli:main"
|
|
35
|
+
moss-tts-nano-cli = "moss_tts_nano_cli:main"
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/vra/moss-tts-nano-cli"
|
|
39
|
+
Repository = "https://github.com/vra/moss-tts-nano-cli"
|
|
40
|
+
Issues = "https://github.com/vra/moss-tts-nano-cli/issues"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["hatchling"]
|
|
44
|
+
build-backend = "hatchling.build"
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.wheel]
|
|
47
|
+
packages = ["src/moss_tts_nano_cli"]
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 100
|
|
51
|
+
target-version = "py312"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = ["E", "F", "I", "W"]
|
|
55
|
+
|
|
56
|
+
[tool.pytest.ini_options]
|
|
57
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Cache and path helpers for the MOSS-TTS-Nano CLI."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
DEFAULT_MODEL_ID = "mlx-community/MOSS-TTS-Nano-100M"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def default_cache_dir() -> Path:
|
|
9
|
+
"""Return the default Hugging Face cache directory used by mlx-audio."""
|
|
10
|
+
return Path.home() / ".cache" / "huggingface"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Command-line interface for MOSS-TTS-Nano."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from moss_tts_nano_cli.cache import DEFAULT_MODEL_ID, default_cache_dir
|
|
8
|
+
from moss_tts_nano_cli.tts import clone_voice, save_audio
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group()
|
|
12
|
+
@click.version_option(version="0.1.0", prog_name="moss-tts-nano")
|
|
13
|
+
def cli():
|
|
14
|
+
"""MOSS-TTS-Nano CLI: zero-shot multilingual voice cloning."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@cli.command()
|
|
18
|
+
@click.option(
|
|
19
|
+
"--ref",
|
|
20
|
+
"ref_path",
|
|
21
|
+
required=True,
|
|
22
|
+
type=click.Path(exists=True, dir_okay=False, path_type=Path),
|
|
23
|
+
help="Path to the reference WAV audio file for voice cloning.",
|
|
24
|
+
)
|
|
25
|
+
@click.option(
|
|
26
|
+
"--text",
|
|
27
|
+
required=True,
|
|
28
|
+
help="Text to synthesize in the cloned voice.",
|
|
29
|
+
)
|
|
30
|
+
@click.option(
|
|
31
|
+
"--out",
|
|
32
|
+
"out_path",
|
|
33
|
+
default="output.wav",
|
|
34
|
+
show_default=True,
|
|
35
|
+
type=click.Path(path_type=Path),
|
|
36
|
+
help="Output WAV file path.",
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--model",
|
|
40
|
+
"model_id",
|
|
41
|
+
default=DEFAULT_MODEL_ID,
|
|
42
|
+
show_default=True,
|
|
43
|
+
help="Hugging Face model id for MOSS-TTS-Nano.",
|
|
44
|
+
)
|
|
45
|
+
@click.option(
|
|
46
|
+
"--quiet",
|
|
47
|
+
is_flag=True,
|
|
48
|
+
help="Suppress progress messages.",
|
|
49
|
+
)
|
|
50
|
+
def clone(ref_path: Path, text: str, out_path: Path, model_id: str, quiet: bool) -> None:
|
|
51
|
+
"""Clone a voice from REF audio and speak TEXT."""
|
|
52
|
+
audio, sample_rate = clone_voice(
|
|
53
|
+
text=text,
|
|
54
|
+
ref_audio_path=ref_path,
|
|
55
|
+
model_id=model_id,
|
|
56
|
+
verbose=not quiet,
|
|
57
|
+
)
|
|
58
|
+
save_audio(out_path, audio, sample_rate)
|
|
59
|
+
click.echo(f"Saved output to {out_path}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@cli.command()
|
|
63
|
+
@click.option(
|
|
64
|
+
"--model",
|
|
65
|
+
"model_id",
|
|
66
|
+
default=DEFAULT_MODEL_ID,
|
|
67
|
+
show_default=True,
|
|
68
|
+
help="Hugging Face model id for MOSS-TTS-Nano.",
|
|
69
|
+
)
|
|
70
|
+
def download(model_id: str) -> None:
|
|
71
|
+
"""Eagerly download the model and audio tokenizer."""
|
|
72
|
+
click.echo(f"Downloading model {model_id!r}...")
|
|
73
|
+
from mlx_audio.tts.utils import load_model
|
|
74
|
+
|
|
75
|
+
load_model(model_id)
|
|
76
|
+
click.echo("Model download complete.")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@cli.command()
|
|
80
|
+
def info() -> None:
|
|
81
|
+
"""Show cache location, default model, and package metadata."""
|
|
82
|
+
click.echo(f"Default model: {DEFAULT_MODEL_ID}")
|
|
83
|
+
click.echo(f"Cache directory: {default_cache_dir()}")
|
|
84
|
+
click.echo("Commands: clone, download, info")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def main() -> None:
|
|
88
|
+
cli()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Text-to-speech inference helpers for MOSS-TTS-Nano."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import soundfile as sf
|
|
7
|
+
from mlx_audio.tts.utils import load_model
|
|
8
|
+
|
|
9
|
+
from moss_tts_nano_cli.cache import DEFAULT_MODEL_ID
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_reference_audio(path: Path) -> tuple[np.ndarray, int]:
|
|
13
|
+
"""Load a reference WAV file and return mono audio + sample rate."""
|
|
14
|
+
audio, sample_rate = sf.read(str(path))
|
|
15
|
+
if audio.ndim > 1:
|
|
16
|
+
audio = audio.mean(axis=1)
|
|
17
|
+
return audio.astype(np.float32), int(sample_rate)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def clone_voice(
|
|
21
|
+
text: str,
|
|
22
|
+
ref_audio_path: Path,
|
|
23
|
+
model_id: str = DEFAULT_MODEL_ID,
|
|
24
|
+
verbose: bool = True,
|
|
25
|
+
):
|
|
26
|
+
"""Generate speech cloned from *ref_audio_path* speaking *text*.
|
|
27
|
+
|
|
28
|
+
Returns the generated waveform as a NumPy array and the model sample rate.
|
|
29
|
+
"""
|
|
30
|
+
ref_audio, ref_sr = load_reference_audio(ref_audio_path)
|
|
31
|
+
if verbose:
|
|
32
|
+
print(f"Loaded reference audio: {ref_audio.shape[0]} samples @ {ref_sr} Hz")
|
|
33
|
+
|
|
34
|
+
if verbose:
|
|
35
|
+
print(f"Loading model {model_id!r}... (first run will download files)")
|
|
36
|
+
model = load_model(model_id)
|
|
37
|
+
if verbose:
|
|
38
|
+
print(f"Model loaded; sample rate = {model.sample_rate} Hz")
|
|
39
|
+
|
|
40
|
+
if verbose:
|
|
41
|
+
print(f"Generating speech for: {text!r}")
|
|
42
|
+
results = list(
|
|
43
|
+
model.generate(
|
|
44
|
+
text=text,
|
|
45
|
+
ref_audio=ref_audio,
|
|
46
|
+
ref_audio_sample_rate=ref_sr,
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
result = results[0]
|
|
50
|
+
audio = np.array(result.audio)
|
|
51
|
+
if verbose:
|
|
52
|
+
print(
|
|
53
|
+
f"Generated {audio.shape[0]} samples "
|
|
54
|
+
f"({result.audio_duration}) @ {result.sample_rate} Hz "
|
|
55
|
+
f"RTF={result.real_time_factor:.3f}"
|
|
56
|
+
)
|
|
57
|
+
return audio, int(result.sample_rate)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def save_audio(path: Path, audio: np.ndarray, sample_rate: int) -> None:
|
|
61
|
+
"""Save a waveform to a WAV file."""
|
|
62
|
+
sf.write(str(path), audio, sample_rate)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Smoke tests for the CLI entry points."""
|
|
2
|
+
|
|
3
|
+
from click.testing import CliRunner
|
|
4
|
+
|
|
5
|
+
from moss_tts_nano_cli.cli import cli
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_info_command():
|
|
9
|
+
runner = CliRunner()
|
|
10
|
+
result = runner.invoke(cli, ["info"])
|
|
11
|
+
assert result.exit_code == 0
|
|
12
|
+
assert "Default model" in result.output
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_clone_requires_ref_and_text():
|
|
16
|
+
runner = CliRunner()
|
|
17
|
+
result = runner.invoke(cli, ["clone"])
|
|
18
|
+
assert result.exit_code != 0
|
|
19
|
+
assert "Missing option" in result.output
|