Skip to content

hello_world.py

New to the Python Session API? Start with the Python tab in Your first program, then return here for the complete sample.

This example loads a phrase-spotter model, runs it across a sample WAV file in pull mode, and prints each spotted phrase as it arrives.

Instructions

  1. Set up the sample project environment:

    cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.2/sample/python
    uv venv
    uv sync
    
  2. Run the sample:

    uv run src/hello_world.py
    

    The sample prints the SDK version, model and audio file paths, then one line per ^result event.

Code

Available in this TrulyNatural SDK installation at ~/Sensory/TrulyNaturalSDK/7.8.0-pre.2/sample/python/src/hello_world.py

hello_world.py

"""Hello world for the TrulyNatural SDK Python binding.

Loads a phrase-spotter model and runs it across a sample WAV file,
printing each spotted phrase as it arrives.

Modelled on ``tests/test_snsr.py::test_Session_run_spotter`` from the
``snsr`` binding test suite, trimmed to the minimum needed to
demonstrate the public API.

Usage::

    uv run src/hello_world.py [--sdk-root PATH]

The default ``--sdk-root`` is the SDK install directory containing
this sample (``<sdk-root>/sample/python/`` -> ``<sdk-root>``).
"""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

import snsr


MODEL = "spot-voicegenie-enUS-6.5.1-m.snsr"
AUDIO = "voice-genie-set-cruise-control.wav"


def default_sdk_root() -> Path:
    # <sdk-root>/sample/python/src/hello_world.py
    #   parents[0] = src/
    #   parents[1] = python/
    #   parents[2] = sample/
    #   parents[3] = <sdk-root>
    return Path(__file__).resolve().parents[3]


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    parser.add_argument(
        "--sdk-root",
        type=Path,
        default=default_sdk_root(),
        help="TrulyNatural SDK install root (default: auto-detect)",
    )
    return parser.parse_args(argv)


def run_spotter(model_path: Path, audio_path: Path) -> int:
    """Run the spotter on ``audio_path`` and print one line per result.

    Returns the number of result events received.
    """
    count = 0

    def on_result(s: snsr.Session, _key: bytes) -> None:
        nonlocal count
        count += 1
        text = s.get_string(snsr.RES_TEXT)
        begin_ms = s.get_int(snsr.RES_BEGIN_MS)
        end_ms = s.get_double(snsr.RES_END_MS)
        score = s.get_double(snsr.RES_SCORE)
        print(f"  spotted {text!r}: {begin_ms:>5} ms - {end_ms:>7.1f} ms (score {score:.4f})")

    print(f"snsr {snsr.VERSION}")
    print(f"  model: {model_path}")
    print(f"  audio: {audio_path}")
    print()

    with snsr.Session(str(model_path)) as s:
        s.require(snsr.TASK_TYPE, snsr.PHRASESPOT)
        s.set_handler(snsr.RESULT_EVENT, on_result)
        s.set_stream(snsr.SOURCE_AUDIO_PCM, str(audio_path))
        s.run()

    print()
    print(f"done: {count} result event(s)")
    return count


def main(argv: list[str] | None = None) -> int:
    args = parse_args(argv)
    sdk_root: Path = args.sdk_root.resolve()

    model_path = sdk_root / "model" / MODEL
    audio_path = sdk_root / "data" / "audio" / AUDIO

    for label, path in (("model", model_path), ("audio", audio_path)):
        if not path.is_file():
            print(f"error: {label} not found: {path}", file=sys.stderr)
            print(f"hint: pass --sdk-root pointing at a TrulyNatural SDK install", file=sys.stderr)
            return 2

    run_spotter(model_path, audio_path)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())