Skip to main content

Moonshine Voice Python Package

A fast, accurate, on-device AI library for building interactive voice applications. Join our Discord to get help and support.

Installation

pip install moonshine-voice

Training a domain adapter is an opt-in extra (pip install 'moonshine-voice[finetune]', also available as [lora]) so the inference install does not pull in PyTorch or Transformers. See Domain Customization.

Quick Start

# Listens to the microphone, logging to the console when there are 
# speech updates.
moonshine-voice mic

Installing the package adds a moonshine-voice command (with a shorter moonshine alias) that groups the built-in tools as subcommands: mic, transcribe, tts, agent, download, g2p, and lora. Run moonshine-voice --help, or moonshine-voice <command> --help for a specific tool. Each subcommand is equivalent to python -m moonshine_voice.<module>, so either invocation style works. The lora subcommand needs the extra above.

Example

"""Transcribes live audio from the default microphone"""
import time
from moonshine_voice import MicTranscriber

# MicTranscriber handles connecting to the microphone, capturing the audio
# data, detecting voice activity, breaking the speech up into segments,
# transcribing it, and calling you back as the results firm up over time.
mic = (
    MicTranscriber()
    .on_text(lambda text: print(f"\r{text}", end="", flush=True))
    .on_line(lambda line: print(f"\r{line.text}"))
)

# Downloads the model files and caches them, so the first call is the slow one.
mic.load()
mic.start()
print("Listening to the microphone, press Ctrl+C to stop...")

while True:
    time.sleep(0.1)

on_text gives you the line as it is being spoken, rewritten as the model changes its mind, and on_line gives you each line once it is final. Configuration is chainable and everything has a working default: language(), model_arch(), device(), update_interval(), and on_progress() for a download bar.

When you need more than the text, such as line ids, speaker spans, or word timings, attach a listener object instead. Both styles can be used together.

from moonshine_voice import MicTranscriber, TranscriptEventListener

class TestListener(TranscriptEventListener):
    def on_line_started(self, event):
        print(f"Line started: {event.line.text}")

    def on_line_text_changed(self, event):
        print(f"Line text changed: {event.line.text}")

    def on_line_completed(self, event):
        print(f"Line completed: {event.line.text}")

mic = MicTranscriber()
mic.add_listener(TestListener())
mic.load()
mic.start()

Other Sources

If you have a different source you're capturing audio from you can supply it directly to a transcriber.

"""Transcribes live audio from an arbitrary audio source."""
from moonshine_voice import (
    Transcriber,
    TranscriptEventListener,
    get_model_for_language,
    load_wav_file,
    get_assets_path,
)
import os
from typing import Iterator, Tuple


def audio_chunk_generator(
    wav_file_path: str, chunk_duration: float = 0.1
) -> Iterator[Tuple[list, int]]:
    """
    Example function that loads a WAV file and yields audio chunks.

    This demonstrates how you can integrate your own proprietary
    audio data capture sources. Replace this function with your own
    implementation that yields (audio_chunk, sample_rate) tuples.

    Args:
        wav_file_path: Path to the WAV file to load
        chunk_duration: Duration of each chunk in seconds

    Yields:
        Tuple of (audio_chunk, sample_rate) where:
        - audio_chunk: List of float audio samples
        - sample_rate: Sample rate in Hz
    """
    audio_data, sample_rate = load_wav_file(wav_file_path)
    chunk_size = int(chunk_duration * sample_rate)

    for i in range(0, len(audio_data), chunk_size):
        chunk = audio_data[i: i + chunk_size]
        yield (chunk, sample_rate)


model_path, model_arch = get_model_for_language("en")

transcriber = Transcriber(
    model_path=model_path, model_arch=model_arch)

stream = transcriber.create_stream(update_interval=0.5)
stream.start()


class TestListener(TranscriptEventListener):
    def on_line_started(self, event):
        print(f"{event.line.start_time:.2f}s: Line started: {event.line.text}")

    def on_line_text_changed(self, event):
        print(
            f"{event.line.start_time:.2f}s: Line text changed: {event.line.text}")

    def on_line_completed(self, event):
        print(f"{event.line.start_time:.2f}s: Line completed: {event.line.text}")


listener = TestListener()
stream.add_listener(listener)

# Feed audio chunks from the generator into the stream.
wav_file_path = os.path.join(get_assets_path(), "two_cities.wav")
for chunk, sample_rate in audio_chunk_generator(wav_file_path):
    stream.add_audio(chunk, sample_rate)

stream.stop()
stream.close()

Voice Commands

Voice commands go through AgentFlow. Register the phrases you want to listen for and it handles the rest: it downloads the speech recognition, speech synthesis and phrase-matching models, opens the microphone, matches what the user said semantically rather than by exact wording, and runs your handler.

from moonshine_voice import AgentFlow

def lights_on(d):
    print("\n💡 LIGHTS ON!")

def lights_off(d):
    print("\n🌑 LIGHTS OFF!")

runner = (
    AgentFlow()
    .always("turn on the lights", lights_on)
    .always("turn off the lights", lights_off)
)

load() downloads and opens everything it needs, and start_listening() opens the microphone. There's nothing else to construct:

runner.load()
runner.start_listening()
try:
    while True:
        time.sleep(0.1)
except KeyboardInterrupt:
    print("\n\nStopping...", file=sys.stderr)
finally:
    runner.close()

Configuration is chainable, and everything has a working default — language(), voice(), trigger_threshold(), on_heard() / on_said() / on_error() for observing the conversation, and use_mic_transcriber() / use_text_to_speech() when you'd rather supply your own. To drive a runner from text instead of audio, turn the microphone off with microphone(False) and feed it handle_utterance().

For multi-turn conversations — asking a question, confirming an answer, spelling out a password — register a flow with listen_for() instead of a global. See examples/python/agent_flow.py, or run moonshine-voice agent.

Speaking

TextToSpeech follows the same shape: configure it, load() it, then use it.

from moonshine_voice import TextToSpeech

tts = TextToSpeech().language("en_us").voice("kokoro_af_heart")
tts.load()
tts.say("Hello from Moonshine.")
tts.wait()

say() returns immediately and queues the utterance, pre-synthesizing the next one while the current one plays, so consecutive calls run together without a gap. wait() blocks until the queue drains, stop() cancels it, and is_talking() polls. If you would rather have the samples than hear them, use synthesize(). The chainable setters are language(), voice(), output_device(), volume(), models_from(), and on_progress() for a download bar.

To speak in someone else's voice, clone_from() takes a few seconds of them talking, either as a .wav file or as a (pcm, sample_rate) pair.

tts = TextToSpeech().language("en_us").cloning()
tts.load()
tts.clone_from("some-speech.wav")
tts.say("Now I sound like you.")

cloning() fetches ZipVoice and clone ASR during load() so clone_from() only swaps the reference clip. Call it before load(); without it, clone_from() / start_cloning() raise. To capture the reference clip from the microphone instead, start_cloning() hands back a VoiceClone that listens until it has heard enough usable speech.

clone = tts.start_cloning()
clone.on_ready(lambda: print("Got it, you can stop talking."))
clone.from_microphone()
tts.clone_from(clone)

Multiple Languages

The framework currently supports English, Spanish, Mandarin, Japanese, Korean, Vietnamese, Arabic, and Ukrainian. We are working on wider language support, and you can see which are supported in your version by calling supported_languages(). To use a language, request it using get_model_for_language() passing in the two-letter language code. For example get_model_for_language("es") will download the Spanish models and pass the information you need to create Transcriber objects using them.

Documentation

For more information, see the main Moonshine Voice documentation.

License

The code and the models are released under the MIT License by default, in every language and at every size - see the main project repository for details. The only exceptions are the legacy non-streaming models for languages other than English, which stay under the non-commercial Moonshine Community License; that list is enumerated in the project LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

moonshine_voice-0.1.5-py3-none-win_amd64.whl (16.5 MB view details)

Uploaded Python 3Windows x86-64

moonshine_voice-0.1.5-py3-none-manylinux_2_34_x86_64.whl (19.9 MB view details)

Uploaded Python 3manylinux: glibc 2.34+ x86-64

moonshine_voice-0.1.5-py3-none-manylinux_2_34_aarch64.whl (18.6 MB view details)

Uploaded Python 3manylinux: glibc 2.34+ ARM64

moonshine_voice-0.1.5-py3-none-manylinux_2_31_aarch64.whl (18.5 MB view details)

Uploaded Python 3manylinux: glibc 2.31+ ARM64

moonshine_voice-0.1.5-py3-none-macosx_15_0_arm64.whl (18.6 MB view details)

Uploaded Python 3macOS 15.0+ ARM64

File details

Details for the file moonshine_voice-0.1.5-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for moonshine_voice-0.1.5-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 7fc9a84e827360ddb85c2735f44a1502c5575c27dcb476a2555646cd20a70e9d
MD5 d7b56d9c617622ced6ccf687a11eae31
BLAKE2b-256 ea05ad3457baa56170a13829c98327598a4d99d6cd4bdff8ae59df4c47ebdd11

See more details on using hashes here.

File details

Details for the file moonshine_voice-0.1.5-py3-none-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for moonshine_voice-0.1.5-py3-none-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 1ed9e0ccf94be4845d69e7fa862dcf4c8b5801a758796966494c694f48184496
MD5 0fe859f886fe46c528e2fd8e3a394230
BLAKE2b-256 a99d228f738b48e0e7cc1de97c3f842b5470c6a3c5f7a0bffbf13c3d00eefb87

See more details on using hashes here.

File details

Details for the file moonshine_voice-0.1.5-py3-none-manylinux_2_34_aarch64.whl.

File metadata

File hashes

Hashes for moonshine_voice-0.1.5-py3-none-manylinux_2_34_aarch64.whl
Algorithm Hash digest
SHA256 fd9fa38ab58c6a8e64eb43b81b0f491138159c7ce45584bb0736ed7efa539766
MD5 964af46c59c5eb4953e0318caa5c0947
BLAKE2b-256 56b3ca8c6f3eb47498208e92094d68e3dc2a0ce50213fdf980e212f293872455

See more details on using hashes here.

File details

Details for the file moonshine_voice-0.1.5-py3-none-manylinux_2_31_aarch64.whl.

File metadata

File hashes

Hashes for moonshine_voice-0.1.5-py3-none-manylinux_2_31_aarch64.whl
Algorithm Hash digest
SHA256 605300afe33eb7920301e73f11e0ea7493770eb655f389ba65be4aa1db8dedd6
MD5 7bcfbf6158277c124c328bf2b7a4491d
BLAKE2b-256 231ccb821747b2a7b40216dd576a62d1ebc77d04fab97064efc97fa460f137ed

See more details on using hashes here.

File details

Details for the file moonshine_voice-0.1.5-py3-none-macosx_15_0_arm64.whl.

File metadata

File hashes

Hashes for moonshine_voice-0.1.5-py3-none-macosx_15_0_arm64.whl
Algorithm Hash digest
SHA256 9866b1956d12fff11923ad42f1140bcb314bf05bf8d8576fb7b3aa819ec40e51
MD5 ee08c85a8399a832a079e778bc8bfac0
BLAKE2b-256 862a9eca2f000e4990315d18aa360c6eb679417b29252e6307c273bcbef38461

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.5 This release

5 files

0.1.3

5 files

0.1.2

5 files

0.1.1

5 files

0.1.0

5 files

0.0.73

5 files

0.0.71

5 files

0.0.69

5 files

0.0.68

5 files

0.0.67

3 files

0.0.66

4 files

0.0.65

5 files

0.0.64

2 files

0.0.63

5 files

0.0.62

5 files

0.0.60

1 file

0.0.59

5 files

0.0.58

3 files

0.0.57

1 file

0.0.55

2 files

0.0.54

3 files

0.0.52

5 files

0.0.49

5 files

0.0.48

5 files

0.0.45

5 files

0.0.44

7 files

0.0.43

5 files

0.0.42

4 files

0.0.41

3 files

0.0.38

3 files

0.0.37

4 files

0.0.36

3 files

0.0.35

2 files

0.0.33

1 file

0.0.30

3 files

0.0.29

5 files

0.0.28

3 files

0.0.5

1 file

0.0.4

5 files

0.0.3

1 file

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page