mirror of
https://github.com/TaterTotterson/microWakeWord-Trainer-Nvidia-Docker.git
synced 2026-08-12 16:05:34 -06:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb5033c5fb | ||
|
|
8a8f4a82d9 | ||
|
|
ed120e91ab | ||
|
|
7d8ebd6637 | ||
|
|
874f273d0b | ||
|
|
04249f414d | ||
|
|
6a0d60d569 | ||
|
|
8df17599c2 | ||
|
|
280e8f8de4 | ||
|
|
b582a6cade | ||
|
|
196ab8c0e7 | ||
|
|
134f607bef | ||
|
|
4a9e2f2cde | ||
|
|
7c246856df | ||
|
|
3705dabc09 | ||
|
|
1dcf48209f | ||
|
|
4f44bef8d5 | ||
|
|
98fa879db1 | ||
|
|
dfac549430 | ||
|
|
775a78326b | ||
|
|
429be4cc67 | ||
|
|
2e6179ec32 |
58
.github/workflows/docker-publish.yml
vendored
Normal file
58
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: Publish Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
concurrency:
|
||||
group: docker-publish-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: tatertotterson/microwakeword
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
name: Docker image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=raw,value=latest
|
||||
type=ref,event=tag
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha,scope=mww-trainer-nvidia-docker
|
||||
cache-to: type=gha,mode=max,scope=mww-trainer-nvidia-docker
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
personal_samples/*
|
||||
data/
|
||||
trim_history/
|
||||
.DS_Store
|
||||
40
README.md
40
README.md
@@ -1,9 +1,13 @@
|
||||
<div align="center">
|
||||
<h1>microWakeWord NVIDIA Docker Trainer UI</h1>
|
||||
<img width="800" alt="microWakeWord NVIDIA trainer screenshot" src="https://github.com/user-attachments/assets/694f4cb7-e4d8-4e2b-80ec-b40fb41cbfff" />
|
||||
<a href="https://taterassistant.com">
|
||||
<img src="images/tater-repo-logo.png" alt="microWakeWord Trainer" width="460"/>
|
||||
</a>
|
||||
</div>
|
||||
<h3 align="center">
|
||||
<a href="https://taterassistant.com">taterassistant.com</a>
|
||||
</h3>
|
||||
|
||||
Train custom microWakeWord models in Docker with NVIDIA/CUDA acceleration, generated Piper samples, device-captured samples, reviewed false-wake negatives, live training logs, and ESPHome firmware flashing.
|
||||
Train custom microWakeWord models in Docker with NVIDIA/CUDA acceleration, generated Piper samples, device-captured samples, reviewed false-wake negatives, live training logs, and prebuilt Tater firmware flashing.
|
||||
|
||||
Real samples come from device-captured wake audio, close misses, or manual uploads. Every saved sample is normalized to `16 kHz / mono / 16-bit PCM WAV` before training.
|
||||
|
||||
@@ -15,6 +19,12 @@ Real samples come from device-captured wake audio, close misses, or manual uploa
|
||||
docker pull ghcr.io/tatertotterson/microwakeword:latest
|
||||
```
|
||||
|
||||
Tagged releases also publish matching immutable image tags:
|
||||
|
||||
```bash
|
||||
docker pull ghcr.io/tatertotterson/microwakeword:v5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Run The Container
|
||||
@@ -28,6 +38,8 @@ docker run -d \
|
||||
ghcr.io/tatertotterson/microwakeword:latest
|
||||
```
|
||||
|
||||
Use a version tag such as `ghcr.io/tatertotterson/microwakeword:v5` when you want to pin a known release instead of tracking `latest`.
|
||||
|
||||
The flags:
|
||||
|
||||
- `--gpus all` enables GPU acceleration.
|
||||
@@ -52,14 +64,14 @@ If you change `REC_PORT`, open that port instead and use the same port in the ES
|
||||
- `Trainer` starts a wake-word session, shows positive/negative sample counts, and launches training.
|
||||
- `Captured Audio` reviews clips sent by ESPHome sats, including wake hits, close misses, and false wakes.
|
||||
- `Samples` plays, removes, clears, and manually imports personal or negative samples.
|
||||
- `Firmware` builds the latest `microWakeWords` ESPHome YAMLs from GitHub and flashes VoicePE or Satellite1 over OTA.
|
||||
- `Firmware` pulls verified prebuilt Tater firmware images from GitHub and flashes supported satellites over OTA.
|
||||
- Popup consoles show colorized training and firmware logs while long-running jobs are active.
|
||||
|
||||
---
|
||||
|
||||
## Captured Audio Workflow
|
||||
|
||||
To collect samples from a sat, flash it with the Tater firmware from [TaterTotterson/microWakeWords](https://github.com/TaterTotterson/microWakeWords). The `Firmware` tab can build and flash the VoicePE or Satellite1 YAMLs directly from that repo.
|
||||
To collect samples from a sat, flash it with the Tater firmware from [TaterTotterson/microWakeWords](https://github.com/TaterTotterson/microWakeWords). The `Firmware` tab can pull verified prebuilt OTA images from that repo for fast firmware updates.
|
||||
|
||||
After flashing, the device exposes ESPHome entities for capture setup:
|
||||
|
||||
@@ -173,18 +185,18 @@ After those assets are prepared, later runs reuse the local copies unless the mo
|
||||
|
||||
## Firmware Flashing
|
||||
|
||||
The `Firmware` tab builds and flashes Tater firmware for supported ESPHome sats.
|
||||
The `Firmware` tab flashes prebuilt Tater firmware for supported ESPHome satellites.
|
||||
|
||||
- Downloads the latest firmware YAML templates from `TaterTotterson/microWakeWords` on GitHub.
|
||||
- Lets you choose `VoicePE` or `Satellite1`.
|
||||
- Downloads the latest prebuilt firmware manifest plus OTA and USB factory images from `TaterTotterson/microWakeWords`.
|
||||
- Verifies downloaded images by size and SHA before upload.
|
||||
- Auto-detects ESPHome devices with mDNS when the container is running with host networking.
|
||||
- Allows manual IP or hostname entry if discovery does not find the device.
|
||||
- Saves firmware form values so you do not re-enter sounds and URLs every run.
|
||||
- Lists locally trained wake words from `/data/trained_wake_words/` for easy model selection.
|
||||
- Builds with ESPHome and flashes OTA.
|
||||
- Streams ESPHome output in a colorized firmware console.
|
||||
- Saves the selected OTA target for each firmware family.
|
||||
- Flashes the prebuilt factory image over Browser USB for first installs or recovery when opened in Chrome or Edge.
|
||||
- Lists locally trained wake words from `/data/trained_wake_words/` for live model switching.
|
||||
- Streams download, verification, and OTA upload progress in a colorized firmware console.
|
||||
|
||||
Firmware YAMLs are intentionally pulled from GitHub each time. There is no local fallback path in the trainer UI.
|
||||
You usually only flash for firmware updates. New satellites, or devices older than Tater firmware `3.0.3`, need one USB flash first before OTA updates and live wake-word switching are available.
|
||||
|
||||
---
|
||||
|
||||
@@ -221,7 +233,7 @@ That removes:
|
||||
- cached datasets
|
||||
- training environments
|
||||
- trained models
|
||||
- firmware build caches
|
||||
- downloaded firmware images
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
# System deps
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3.12 python3.12-venv python3.12-dev python3-pip python-is-python3 \
|
||||
git wget curl unzip patch ca-certificates nano less \
|
||||
git wget curl unzip patch ninja-build ca-certificates nano less \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /data
|
||||
|
||||
|
||||
BIN
images/tater-repo-logo.png
Normal file
BIN
images/tater-repo-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 590 KiB |
67
run.sh
67
run.sh
@@ -17,7 +17,6 @@ PIN_FILE="${VENV_DIR}/.pinned_installed"
|
||||
FASTAPI_VERSION="${REC_FASTAPI_VERSION:-0.115.6}"
|
||||
UVICORN_VERSION="${REC_UVICORN_VERSION:-0.30.6}"
|
||||
PY_MULTIPART_VERSION="${REC_PY_MULTIPART_VERSION:-0.0.9}"
|
||||
ESPHOME_VERSION="${REC_ESPHOME_VERSION:-2026.4.0}"
|
||||
|
||||
echo "microWakeWord Trainer UI (Docker)"
|
||||
echo "-> ROOTDIR: ${ROOTDIR}"
|
||||
@@ -26,6 +25,16 @@ echo "-> URL: http://localhost:${PORT}/"
|
||||
|
||||
mkdir -p "${DATA_DIR}"
|
||||
|
||||
install_ui_deps() {
|
||||
${PIP} install \
|
||||
"fastapi==${FASTAPI_VERSION}" \
|
||||
"uvicorn[standard]==${UVICORN_VERSION}" \
|
||||
"python-multipart==${PY_MULTIPART_VERSION}" \
|
||||
"zeroconf>=0.132.2" \
|
||||
"silero-vad>=5.0.0" \
|
||||
"numpy>=1.24.0"
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Trainer UI venv (separate)
|
||||
# -----------------------------
|
||||
@@ -40,32 +49,54 @@ source "${VENV_DIR}/bin/activate"
|
||||
if [[ ! -f "${PIN_FILE}" ]]; then
|
||||
echo "Installing pinned trainer UI deps"
|
||||
${PIP} install -U pip setuptools wheel
|
||||
${PIP} install \
|
||||
"fastapi==${FASTAPI_VERSION}" \
|
||||
"uvicorn[standard]==${UVICORN_VERSION}" \
|
||||
"python-multipart==${PY_MULTIPART_VERSION}" \
|
||||
"esphome==${ESPHOME_VERSION}"
|
||||
install_ui_deps
|
||||
touch "${PIN_FILE}"
|
||||
else
|
||||
echo "Reusing existing trainer UI venv (no upgrades)"
|
||||
if ! "${PY}" - "${ESPHOME_VERSION}" <<'PY' >/dev/null 2>&1
|
||||
import importlib.metadata
|
||||
if ! "${PY}" - "${FASTAPI_VERSION}" "${UVICORN_VERSION}" "${PY_MULTIPART_VERSION}" <<'PY' >/dev/null 2>&1
|
||||
import importlib.metadata as md
|
||||
import sys
|
||||
|
||||
expected = sys.argv[1]
|
||||
installed = importlib.metadata.version("esphome")
|
||||
raise SystemExit(0 if installed == expected else 1)
|
||||
fastapi_version, uvicorn_version, multipart_version = sys.argv[1:4]
|
||||
|
||||
def version_tuple(value):
|
||||
parts = []
|
||||
for token in str(value).replace("-", ".").split("."):
|
||||
if token.isdigit():
|
||||
parts.append(int(token))
|
||||
else:
|
||||
digits = "".join(ch for ch in token if ch.isdigit())
|
||||
if digits:
|
||||
parts.append(int(digits))
|
||||
break
|
||||
return tuple(parts)
|
||||
|
||||
exact = {
|
||||
"fastapi": fastapi_version,
|
||||
"uvicorn": uvicorn_version,
|
||||
"python-multipart": multipart_version,
|
||||
}
|
||||
minimum = {
|
||||
"silero-vad": "5.0.0",
|
||||
"numpy": "1.24.0",
|
||||
"zeroconf": "0.132.2",
|
||||
}
|
||||
present = ("torch",)
|
||||
|
||||
for package, expected in exact.items():
|
||||
if md.version(package) != expected:
|
||||
raise SystemExit(1)
|
||||
for package, minimum_version in minimum.items():
|
||||
if version_tuple(md.version(package)) < version_tuple(minimum_version):
|
||||
raise SystemExit(1)
|
||||
for package in present:
|
||||
md.version(package)
|
||||
PY
|
||||
then
|
||||
echo "Firmware tab dependencies missing or stale; installing ESPHome firmware dependencies"
|
||||
${PIP} install \
|
||||
"fastapi==${FASTAPI_VERSION}" \
|
||||
"uvicorn[standard]==${UVICORN_VERSION}" \
|
||||
"python-multipart==${PY_MULTIPART_VERSION}" \
|
||||
"esphome==${ESPHOME_VERSION}"
|
||||
echo "UI dependencies missing or stale; installing recorder dependencies"
|
||||
install_ui_deps
|
||||
fi
|
||||
fi
|
||||
|
||||
# -----------------------------
|
||||
# Trainer server env
|
||||
# -----------------------------
|
||||
|
||||
1541
static/index.html
1541
static/index.html
File diff suppressed because it is too large
Load Diff
1318
trainer_server.py
1318
trainer_server.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user