# BestWebby Academy narration: notices

The narration in this folder is synthetic speech, generated from the lesson
scripts in `apps/marketing/components/academy/lessons/` by
`apps/marketing/scripts/academy-narrate.mjs`, on our own machines. No script
text is sent to an outside service.

## Voice

- Voice: `en_US-ljspeech-high` (US English, female, single speaker)
- Model card: https://huggingface.co/rhasspy/piper-voices/blob/main/en/en_US/ljspeech/high/MODEL_CARD
- Model card, as read on 2026-10-23:
  - Dataset: LJ Speech, https://keithito.com/LJ-Speech-Dataset/ , licence: public domain
  - Training: trained from scratch (not fine-tuned from another voice) by Bryce Beattie,
    https://brycebeattie.com/files/tts/ , where the model itself is listed as "License: public domain"
- Model file: `en_US-ljspeech-high.onnx`, SHA-256 `5d4f08ba6a2a48c44592eed3ce56bf85e9de3dd4e20df90541ae68a8310c029a`
- Commercial use: allowed. Both the training data and the trained model are in the public domain.

Voices that were checked and NOT used, because their model cards point to a
licence that does not clearly allow commercial use, or say they were fine-tuned
from a voice that has one:
`en_US-lessac-*` (Blizzard 2013 licence), `en_US-hfc_female-medium` (CC BY-NC-SA 4.0),
`en_US-amy-medium` and the British-English "jenny_dioco" voice (both fine-tuned from lessac).

## Software

- Piper text-to-speech, release 2023.11.14-2, https://github.com/rhasspy/piper (MIT licence).
  Piper uses espeak-ng (GPL-3.0) to turn text into phonemes while the audio is
  generated. Neither program is shipped with the site; only the audio is.
- ffmpeg encodes each chapter twice, loudness-normalised and mono: AAC at 48 kbps (.m4a) and Opus at 40 kbps (.ogg, for browsers without AAC). Speaking rate: Piper `--length_scale 0.92` (recorded in the timing file).

## Regenerating

Run on the Claude host or vm-devops, never on the production VM:

    node apps/marketing/scripts/academy-narrate.mjs --lesson module-1 \
      --piper /path/to/piper/piper --model /path/to/en_US-ljspeech-high.onnx

The script rewrites the audio and `lessons/<lesson>.timing.json`. The lesson
test fails when a caption has changed but its audio has not been regenerated.
Using a different voice means checking its model card first and updating this
notice in the same commit.
