From 25939b01410e129454d8ffec5b206541c35710ef Mon Sep 17 00:00:00 2001 From: Morten Olsen Date: Fri, 12 Sep 2025 10:59:19 +0200 Subject: [PATCH] init --- .dockerignore | 18 + .gitattributes | 35 ++ .github/release-drafter-config.yml | 48 +++ .github/workflows/auto-labeler.yaml | 21 + .github/workflows/job-draft-release.yaml | 18 + .github/workflows/pipeline-default.yaml | 75 ++++ .u8.json | 4 + Dockerfile | 15 + README.md | 97 +++++ build.sh | 27 ++ docker-compose.yml | 26 ++ model/en_US_glados_medium.json | 502 +++++++++++++++++++++++ model/en_US_glados_medium.onnx | 3 + 13 files changed, 889 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitattributes create mode 100644 .github/release-drafter-config.yml create mode 100644 .github/workflows/auto-labeler.yaml create mode 100644 .github/workflows/job-draft-release.yaml create mode 100644 .github/workflows/pipeline-default.yaml create mode 100644 .u8.json create mode 100644 Dockerfile create mode 100644 README.md create mode 100755 build.sh create mode 100644 docker-compose.yml create mode 100644 model/en_US_glados_medium.json create mode 100644 model/en_US_glados_medium.onnx diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ea9ec8e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +# Git files +.git/ +.gitignore +.gitattributes +.github/ + +# Documentation +README.md + +# Docker files +docker-compose.yml +Dockerfile + +# Development files +*.log +*.tmp +.DS_Store + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a6344aa --- /dev/null +++ b/.gitattributes @@ -0,0 +1,35 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text diff --git a/.github/release-drafter-config.yml b/.github/release-drafter-config.yml new file mode 100644 index 0000000..f72741a --- /dev/null +++ b/.github/release-drafter-config.yml @@ -0,0 +1,48 @@ +name-template: '$RESOLVED_VERSION 🌈' +tag-template: '$RESOLVED_VERSION' +categories: + - title: '🚀 Features' + labels: + - 'feature' + - 'enhancement' + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - title: '🧰 Maintenance' + label: 'chore' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: patch +autolabeler: + - label: 'chore' + files: + - '*.md' + branch: + - '/docs{0,1}\/.+/' + - label: 'bug' + branch: + - '/fix\/.+/' + title: + - '/fix/i' + - label: 'enhancement' + branch: + - '/feature\/.+/' + - '/feat\/.+/' + title: + - '/feat:.+/' +template: | + ## Changes + + $CHANGES diff --git a/.github/workflows/auto-labeler.yaml b/.github/workflows/auto-labeler.yaml new file mode 100644 index 0000000..f134cf8 --- /dev/null +++ b/.github/workflows/auto-labeler.yaml @@ -0,0 +1,21 @@ +name: Auto Labeler +on: + pull_request: + types: [opened, reopened, synchronize] + +permissions: + contents: read + +jobs: + auto-labeler: + permissions: + contents: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v6 + with: + config-name: release-drafter-config.yml + disable-releaser: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/job-draft-release.yaml b/.github/workflows/job-draft-release.yaml new file mode 100644 index 0000000..852935d --- /dev/null +++ b/.github/workflows/job-draft-release.yaml @@ -0,0 +1,18 @@ +name: Draft release +on: + workflow_call: +jobs: + draft-release: + name: Update release drafter + permissions: + contents: write + pull-requests: write + environment: release + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v6 + with: + config-name: release-drafter-config.yml + publish: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pipeline-default.yaml b/.github/workflows/pipeline-default.yaml new file mode 100644 index 0000000..1b5cb57 --- /dev/null +++ b/.github/workflows/pipeline-default.yaml @@ -0,0 +1,75 @@ +name: Build and release + +on: + push: + branches: + - main + pull_request: + types: + - opened + - synchronize + +env: + environment: test + release_channel: latest + DO_NOT_TRACK: "1" + DOCKER_REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +permissions: + contents: write + packages: read + pull-requests: write + id-token: write + actions: read + security-events: write +jobs: + update-release-draft: + if: github.ref == 'refs/heads/main' + uses: ./.github/workflows/job-draft-release.yaml + + release: + permissions: + contents: read + packages: write + attestations: write + id-token: write + pages: write + name: Release + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + needs: update-release-draft + environment: release + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + # - name: Generate artifact attestation + # uses: actions/attest-build-provenance@v2 + # with: + # subject-name: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME}} + # subject-digest: ${{ steps.push.outputs.digest }} + # push-to-registry: true diff --git a/.u8.json b/.u8.json new file mode 100644 index 0000000..8b1f464 --- /dev/null +++ b/.u8.json @@ -0,0 +1,4 @@ +{ + "values": {}, + "entries": [] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..211f0c2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM rhasspy/wyoming-piper + +# Copy custom GLaDOS model directly to the data directory root +# Wyoming Piper looks for voices in the root of the data directory +COPY model/en_US_glados_medium.onnx /usr/share/piper-voices/en_US-glados-medium.onnx +COPY model/en_US_glados_medium.json /usr/share/piper-voices/en_US-glados-medium.onnx.json + +# Set proper permissions +RUN chmod -R 755 /usr/share/piper-voices/ + +# Expose the Wyoming protocol port +EXPOSE 10200 + +# Use the default CMD from the base image +# The base image should handle running the Wyoming Piper server \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fd94213 --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# Piper GLaDOS Medium Voice for Home Assistant + +This container provides a custom GLaDOS voice model for Home Assistant's Wyoming Piper TTS integration. + +## Model Information + +- **Voice**: GLaDOS (from Portal video game series) +- **Language**: English (US) +- **Quality**: Medium +- **Sample Rate**: 22.05 kHz +- **Source**: https://huggingface.co/Stoned-Code/piper-en_US-glados-medium/tree/main + +## Quick Start + +### Build and Run with Docker Compose + +```bash +# Build and start the container +docker-compose up -d + +# Check logs +docker-compose logs -f piper-glados +``` + +### Manual Docker Build + +```bash +# Build the image +docker build -t piper-glados-medium . + +# Run the container +docker run -d \ + --name piper-glados-medium \ + -p 10200:10200 \ + --restart unless-stopped \ + piper-glados-medium +``` + +## Home Assistant Integration + +1. **Add to your Home Assistant configuration.yaml**: + +```yaml +tts: + - platform: wyoming + host: + port: 10200 + name: "Piper GLaDOS" +``` + +2. **Or use Home Assistant UI**: + - Go to Settings → Devices & Services + - Click "Add Integration" + - Search for "Wyoming Protocol" + - Enter the container's IP address and port 10200 + +3. **Test the voice**: + - Go to Developer Tools → Services + - Select `tts.speak` + - Choose entity: `tts.piper_glados` + - Enter test message and target media player + +## Available Voice + +Once integrated, you'll have access to: +- Voice ID: `en_US-glados-medium` +- Language: English (United States) +- Speaker: GLaDOS + +## Container Details + +- **Base Image**: `rhasspy/wyoming-piper` +- **Protocol**: Wyoming (compatible with Home Assistant 2023.5+) +- **Port**: 10200 (Wyoming protocol) +- **Model Path**: `/usr/share/piper-voices/en_US/glados/medium/` + +## Troubleshooting + +### Check if the service is running: +```bash +curl http://localhost:10200/api/voices +``` + +### View container logs: +```bash +docker logs piper-glados-medium +``` + +### Test TTS directly: +```bash +echo "Hello, subject. The tests are now complete." | docker exec -i piper-glados-medium piper --model /usr/share/piper-voices/en_US/glados/medium/en_US-glados-medium.onnx --output-file - | aplay +``` + +## Model Files + +- `model/en_US_glados_medium.onnx` - Neural network model +- `model/en_US_glados_medium.json` - Model configuration and phoneme mappings \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..49f4ecb --- /dev/null +++ b/build.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Build script for Piper GLaDOS container + +set -e + +IMAGE_NAME="piper-glados-medium" +CONTAINER_NAME="piper-glados-medium" + +echo "🏗️ Building Piper GLaDOS container..." +docker build -t "$IMAGE_NAME" . + +echo "🧪 Testing if model files are correctly placed..." +docker run --rm "$IMAGE_NAME" ls -la /usr/share/piper-voices/en_US/glados/medium/ + +echo "🔍 Verifying Piper can load the model..." +docker run --rm "$IMAGE_NAME" piper --model /usr/share/piper-voices/en_US/glados/medium/en_US-glados-medium.onnx --help + +echo "✅ Build completed successfully!" +echo "" +echo "To run the container:" +echo " docker run -d --name $CONTAINER_NAME -p 10200:10200 $IMAGE_NAME" +echo "" +echo "Or use docker-compose:" +echo " docker-compose up -d" +echo "" +echo "Test the voice API at: http://localhost:10200/api/voices" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3e2f6a3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +version: "3.8" + +services: + piper-glados: + build: . + container_name: piper-glados-medium + ports: + - "10200:5000" + environment: + # Wyoming Piper will automatically discover models in /usr/share/piper-voices/ + - PIPER_DEBUG=1 + command: + [ + "--piper", + "/usr/share/piper/piper", + "--voice", + "en_US-glados-medium", + "--data-dir", + "/usr/share/piper-voices", + ] + restart: no + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:10200/api/voices || exit 1"] + interval: 30s + timeout: 10s + retries: 3 diff --git a/model/en_US_glados_medium.json b/model/en_US_glados_medium.json new file mode 100644 index 0000000..00db6fb --- /dev/null +++ b/model/en_US_glados_medium.json @@ -0,0 +1,502 @@ +{ + "audio": { + "sample_rate": 22050, + "quality": "medium" + }, + "espeak": { + "voice": "en-us" + }, + "inference": { + "noise_scale": 0.667, + "length_scale": 1, + "noise_w": 0.8 + }, + "phoneme_type": "espeak", + "phoneme_map": {}, + "phoneme_id_map": { + " ": [ + 3 + ], + "!": [ + 4 + ], + "\"": [ + 150 + ], + "#": [ + 149 + ], + "$": [ + 2 + ], + "'": [ + 5 + ], + "(": [ + 6 + ], + ")": [ + 7 + ], + ",": [ + 8 + ], + "-": [ + 9 + ], + ".": [ + 10 + ], + "0": [ + 130 + ], + "1": [ + 131 + ], + "2": [ + 132 + ], + "3": [ + 133 + ], + "4": [ + 134 + ], + "5": [ + 135 + ], + "6": [ + 136 + ], + "7": [ + 137 + ], + "8": [ + 138 + ], + "9": [ + 139 + ], + ":": [ + 11 + ], + ";": [ + 12 + ], + "?": [ + 13 + ], + "X": [ + 156 + ], + "^": [ + 1 + ], + "_": [ + 0 + ], + "a": [ + 14 + ], + "b": [ + 15 + ], + "c": [ + 16 + ], + "d": [ + 17 + ], + "e": [ + 18 + ], + "f": [ + 19 + ], + "g": [ + 154 + ], + "h": [ + 20 + ], + "i": [ + 21 + ], + "j": [ + 22 + ], + "k": [ + 23 + ], + "l": [ + 24 + ], + "m": [ + 25 + ], + "n": [ + 26 + ], + "o": [ + 27 + ], + "p": [ + 28 + ], + "q": [ + 29 + ], + "r": [ + 30 + ], + "s": [ + 31 + ], + "t": [ + 32 + ], + "u": [ + 33 + ], + "v": [ + 34 + ], + "w": [ + 35 + ], + "x": [ + 36 + ], + "y": [ + 37 + ], + "z": [ + 38 + ], + "æ": [ + 39 + ], + "ç": [ + 40 + ], + "ð": [ + 41 + ], + "ø": [ + 42 + ], + "ħ": [ + 43 + ], + "ŋ": [ + 44 + ], + "œ": [ + 45 + ], + "ǀ": [ + 46 + ], + "ǁ": [ + 47 + ], + "ǂ": [ + 48 + ], + "ǃ": [ + 49 + ], + "ɐ": [ + 50 + ], + "ɑ": [ + 51 + ], + "ɒ": [ + 52 + ], + "ɓ": [ + 53 + ], + "ɔ": [ + 54 + ], + "ɕ": [ + 55 + ], + "ɖ": [ + 56 + ], + "ɗ": [ + 57 + ], + "ɘ": [ + 58 + ], + "ə": [ + 59 + ], + "ɚ": [ + 60 + ], + "ɛ": [ + 61 + ], + "ɜ": [ + 62 + ], + "ɞ": [ + 63 + ], + "ɟ": [ + 64 + ], + "ɠ": [ + 65 + ], + "ɡ": [ + 66 + ], + "ɢ": [ + 67 + ], + "ɣ": [ + 68 + ], + "ɤ": [ + 69 + ], + "ɥ": [ + 70 + ], + "ɦ": [ + 71 + ], + "ɧ": [ + 72 + ], + "ɨ": [ + 73 + ], + "ɪ": [ + 74 + ], + "ɫ": [ + 75 + ], + "ɬ": [ + 76 + ], + "ɭ": [ + 77 + ], + "ɮ": [ + 78 + ], + "ɯ": [ + 79 + ], + "ɰ": [ + 80 + ], + "ɱ": [ + 81 + ], + "ɲ": [ + 82 + ], + "ɳ": [ + 83 + ], + "ɴ": [ + 84 + ], + "ɵ": [ + 85 + ], + "ɶ": [ + 86 + ], + "ɸ": [ + 87 + ], + "ɹ": [ + 88 + ], + "ɺ": [ + 89 + ], + "ɻ": [ + 90 + ], + "ɽ": [ + 91 + ], + "ɾ": [ + 92 + ], + "ʀ": [ + 93 + ], + "ʁ": [ + 94 + ], + "ʂ": [ + 95 + ], + "ʃ": [ + 96 + ], + "ʄ": [ + 97 + ], + "ʈ": [ + 98 + ], + "ʉ": [ + 99 + ], + "ʊ": [ + 100 + ], + "ʋ": [ + 101 + ], + "ʌ": [ + 102 + ], + "ʍ": [ + 103 + ], + "ʎ": [ + 104 + ], + "ʏ": [ + 105 + ], + "ʐ": [ + 106 + ], + "ʑ": [ + 107 + ], + "ʒ": [ + 108 + ], + "ʔ": [ + 109 + ], + "ʕ": [ + 110 + ], + "ʘ": [ + 111 + ], + "ʙ": [ + 112 + ], + "ʛ": [ + 113 + ], + "ʜ": [ + 114 + ], + "ʝ": [ + 115 + ], + "ʟ": [ + 116 + ], + "ʡ": [ + 117 + ], + "ʢ": [ + 118 + ], + "ʦ": [ + 155 + ], + "ʰ": [ + 145 + ], + "ʲ": [ + 119 + ], + "ˈ": [ + 120 + ], + "ˌ": [ + 121 + ], + "ː": [ + 122 + ], + "ˑ": [ + 123 + ], + "˞": [ + 124 + ], + "ˤ": [ + 146 + ], + "̃": [ + 141 + ], + "̧": [ + 140 + ], + "̩": [ + 144 + ], + "̪": [ + 142 + ], + "̯": [ + 143 + ], + "̺": [ + 152 + ], + "̻": [ + 153 + ], + "β": [ + 125 + ], + "ε": [ + 147 + ], + "θ": [ + 126 + ], + "χ": [ + 127 + ], + "ᵻ": [ + 128 + ], + "↑": [ + 151 + ], + "↓": [ + 148 + ], + "ⱱ": [ + 129 + ] + }, + "num_symbols": 256, + "num_speakers": 1, + "speaker_id_map": {}, + "piper_version": "1.0.0", + "language": { + "code": "en_US", + "family": "en", + "region": "US", + "name_native": "English", + "name_english": "English", + "country_english": "United States" + }, + "dataset": "GLaDOS" +} \ No newline at end of file diff --git a/model/en_US_glados_medium.onnx b/model/en_US_glados_medium.onnx new file mode 100644 index 0000000..bcb318b --- /dev/null +++ b/model/en_US_glados_medium.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd1d155f8871452a54fc7db399390691d0252e53a2c84042cd40d33e867890be +size 63516050