violawake 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- violawake-0.1.0/.dockerignore +41 -0
- violawake-0.1.0/.github/workflows/ci.yml +204 -0
- violawake-0.1.0/.github/workflows/console-ci.yml +124 -0
- violawake-0.1.0/.github/workflows/model-verify.yml +89 -0
- violawake-0.1.0/.github/workflows/release.yml +179 -0
- violawake-0.1.0/.gitignore +111 -0
- violawake-0.1.0/.pre-commit-config.yaml +17 -0
- violawake-0.1.0/CHANGELOG.md +43 -0
- violawake-0.1.0/CONTRIBUTING.md +185 -0
- violawake-0.1.0/LICENSE +161 -0
- violawake-0.1.0/PKG-INFO +644 -0
- violawake-0.1.0/README.md +389 -0
- violawake-0.1.0/RELEASE_NOTES.md +36 -0
- violawake-0.1.0/SECURITY.md +13 -0
- violawake-0.1.0/docs/ARCHITECTURE.md +594 -0
- violawake-0.1.0/docs/PRD.md +331 -0
- violawake-0.1.0/docs/PRE_LAUNCH_CHECKLIST.md +159 -0
- violawake-0.1.0/docs/REGISTRY.md +73 -0
- violawake-0.1.0/docs/ROADMAP_10_OF_10.md +539 -0
- violawake-0.1.0/docs/S1.3_REQUIREMENTS_SYNTHESIS.md +102 -0
- violawake-0.1.0/docs/TEST_STRATEGY.md +341 -0
- violawake-0.1.0/docs/adr/ADR-001-onnx-runtime.md +149 -0
- violawake-0.1.0/docs/adr/ADR-002-oww-feature-extractor.md +156 -0
- violawake-0.1.0/docs/adr/ADR-003-python-first.md +146 -0
- violawake-0.1.0/docs/adr/ADR-004-open-core.md +182 -0
- violawake-0.1.0/docs/adr/ADR-005-packaging.md +229 -0
- violawake-0.1.0/docs/api/README.md +40 -0
- violawake-0.1.0/examples/.gitkeep +1 -0
- violawake-0.1.0/examples/async_detection.py +38 -0
- violawake-0.1.0/examples/basic_detection.py +29 -0
- violawake-0.1.0/examples/streaming_eval.py +16 -0
- violawake-0.1.0/pyproject.toml +257 -0
- violawake-0.1.0/python +0 -0
- violawake-0.1.0/src/violawake/__init__.py +4 -0
- violawake-0.1.0/src/violawake_sdk/__init__.py +143 -0
- violawake-0.1.0/src/violawake_sdk/_constants.py +178 -0
- violawake-0.1.0/src/violawake_sdk/_exceptions.py +40 -0
- violawake-0.1.0/src/violawake_sdk/async_detector.py +145 -0
- violawake-0.1.0/src/violawake_sdk/audio.py +334 -0
- violawake-0.1.0/src/violawake_sdk/audio_source.py +452 -0
- violawake-0.1.0/src/violawake_sdk/backends/__init__.py +99 -0
- violawake-0.1.0/src/violawake_sdk/backends/base.py +129 -0
- violawake-0.1.0/src/violawake_sdk/backends/onnx_backend.py +101 -0
- violawake-0.1.0/src/violawake_sdk/backends/tflite_backend.py +467 -0
- violawake-0.1.0/src/violawake_sdk/cli/__init__.py +7 -0
- violawake-0.1.0/src/violawake_sdk/cli/download.py +6 -0
- violawake-0.1.0/src/violawake_sdk/cli/evaluate.py +6 -0
- violawake-0.1.0/src/violawake_sdk/cli/train.py +63 -0
- violawake-0.1.0/src/violawake_sdk/confidence.py +135 -0
- violawake-0.1.0/src/violawake_sdk/ensemble.py +230 -0
- violawake-0.1.0/src/violawake_sdk/models.py +592 -0
- violawake-0.1.0/src/violawake_sdk/noise_profiler.py +202 -0
- violawake-0.1.0/src/violawake_sdk/oww_backbone.py +272 -0
- violawake-0.1.0/src/violawake_sdk/pipeline.py +410 -0
- violawake-0.1.0/src/violawake_sdk/power_manager.py +262 -0
- violawake-0.1.0/src/violawake_sdk/py.typed +0 -0
- violawake-0.1.0/src/violawake_sdk/security/__init__.py +32 -0
- violawake-0.1.0/src/violawake_sdk/security/cert_pinning.py +792 -0
- violawake-0.1.0/src/violawake_sdk/speaker.py +399 -0
- violawake-0.1.0/src/violawake_sdk/stt.py +307 -0
- violawake-0.1.0/src/violawake_sdk/stt_engine.py +132 -0
- violawake-0.1.0/src/violawake_sdk/training/__init__.py +1 -0
- violawake-0.1.0/src/violawake_sdk/training/augment.py +621 -0
- violawake-0.1.0/src/violawake_sdk/training/evaluate.py +686 -0
- violawake-0.1.0/src/violawake_sdk/training/losses.py +102 -0
- violawake-0.1.0/src/violawake_sdk/training/temporal_model.py +302 -0
- violawake-0.1.0/src/violawake_sdk/training/weight_averaging.py +279 -0
- violawake-0.1.0/src/violawake_sdk/tts.py +307 -0
- violawake-0.1.0/src/violawake_sdk/tts_engine.py +21 -0
- violawake-0.1.0/src/violawake_sdk/vad.py +378 -0
- violawake-0.1.0/src/violawake_sdk/vad_engine.py +9 -0
- violawake-0.1.0/src/violawake_sdk/wake_detector.py +1156 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Git
|
|
2
|
+
.git
|
|
3
|
+
.gitignore
|
|
4
|
+
|
|
5
|
+
# Node (frontend builds have their own Dockerfile)
|
|
6
|
+
console/frontend/node_modules
|
|
7
|
+
console/frontend/dist
|
|
8
|
+
|
|
9
|
+
# Python caches
|
|
10
|
+
__pycache__
|
|
11
|
+
*.pyc
|
|
12
|
+
*.pyo
|
|
13
|
+
.pytest_cache
|
|
14
|
+
.ruff_cache
|
|
15
|
+
.coverage
|
|
16
|
+
.benchmarks
|
|
17
|
+
*.egg-info
|
|
18
|
+
|
|
19
|
+
# IDE / editor
|
|
20
|
+
.vscode
|
|
21
|
+
.idea
|
|
22
|
+
*.swp
|
|
23
|
+
|
|
24
|
+
# Environment and secrets
|
|
25
|
+
.env
|
|
26
|
+
.env.*
|
|
27
|
+
!.env.example
|
|
28
|
+
|
|
29
|
+
# Docs and non-runtime files
|
|
30
|
+
docs/
|
|
31
|
+
*.md
|
|
32
|
+
LICENSE
|
|
33
|
+
CLAUDE.md
|
|
34
|
+
|
|
35
|
+
# Test data (large)
|
|
36
|
+
data/
|
|
37
|
+
models/*.onnx
|
|
38
|
+
|
|
39
|
+
# OS
|
|
40
|
+
Thumbs.db
|
|
41
|
+
.DS_Store
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main, develop]
|
|
6
|
+
tags:
|
|
7
|
+
- "v*.*.*"
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [master, main]
|
|
10
|
+
schedule:
|
|
11
|
+
- cron: "0 2 * * *" # 2am UTC nightly
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ci-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
env:
|
|
18
|
+
PYTHON_DEFAULT: "3.11"
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
# Job 1: Lint (ruff + mypy)
|
|
22
|
+
lint:
|
|
23
|
+
name: Lint
|
|
24
|
+
runs-on: ubuntu-22.04
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- name: Set up Python
|
|
29
|
+
uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ env.PYTHON_DEFAULT }}
|
|
32
|
+
cache: pip
|
|
33
|
+
|
|
34
|
+
- name: Install lint tools
|
|
35
|
+
# Only install lint tools — no pyaudio/portaudio needed for static analysis
|
|
36
|
+
run: |
|
|
37
|
+
pip install ruff mypy types-requests
|
|
38
|
+
pip install -e "." --no-deps || true
|
|
39
|
+
pip install onnxruntime numpy scipy
|
|
40
|
+
pip install openwakeword --no-deps
|
|
41
|
+
|
|
42
|
+
- name: Run ruff (lint)
|
|
43
|
+
run: ruff check src/
|
|
44
|
+
|
|
45
|
+
- name: Run ruff (format check)
|
|
46
|
+
run: ruff format --check src/
|
|
47
|
+
|
|
48
|
+
- name: Run mypy
|
|
49
|
+
# Mypy config in pyproject.toml: --strict for core SDK, training/tools excluded.
|
|
50
|
+
# Non-blocking: numpy/torch types cause noise in strict mode. Track error count down.
|
|
51
|
+
continue-on-error: true
|
|
52
|
+
run: mypy src/violawake_sdk --exclude 'training|tools'
|
|
53
|
+
|
|
54
|
+
# Job 2: Unit tests (all platforms x Python versions)
|
|
55
|
+
test-unit:
|
|
56
|
+
name: Unit tests (Python ${{ matrix.python-version }}, ${{ matrix.os }})
|
|
57
|
+
runs-on: ${{ matrix.os }}
|
|
58
|
+
strategy:
|
|
59
|
+
fail-fast: false
|
|
60
|
+
matrix:
|
|
61
|
+
os: [ubuntu-22.04, windows-2022, macos-14]
|
|
62
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
63
|
+
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
|
|
67
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
68
|
+
uses: actions/setup-python@v5
|
|
69
|
+
with:
|
|
70
|
+
python-version: ${{ matrix.python-version }}
|
|
71
|
+
cache: pip
|
|
72
|
+
|
|
73
|
+
# PyAudio requires PortAudio headers.
|
|
74
|
+
- name: Install PortAudio (Linux)
|
|
75
|
+
if: runner.os == 'Linux'
|
|
76
|
+
run: sudo apt-get update && sudo apt-get install -y portaudio19-dev
|
|
77
|
+
|
|
78
|
+
- name: Install PortAudio (macOS)
|
|
79
|
+
if: runner.os == 'macOS'
|
|
80
|
+
run: brew install portaudio
|
|
81
|
+
|
|
82
|
+
- name: Install dependencies
|
|
83
|
+
# openwakeword is now an optional dep [oww]. Install it --no-deps to avoid
|
|
84
|
+
# tflite-runtime which has no Python 3.12 Linux wheels.
|
|
85
|
+
run: |
|
|
86
|
+
pip install openwakeword --no-deps
|
|
87
|
+
pip install onnxruntime numpy tqdm requests scipy
|
|
88
|
+
pip install -e ".[dev]"
|
|
89
|
+
|
|
90
|
+
- name: Smoke test install
|
|
91
|
+
run: |
|
|
92
|
+
python -c "from violawake_sdk import WakeDetector, __version__; print(f'violawake {__version__} OK')"
|
|
93
|
+
|
|
94
|
+
- name: Run unit tests
|
|
95
|
+
# Coverage floor: 50%. Hardware-dependent code (audio.py, pipeline.py) and
|
|
96
|
+
# CLI wrappers can't be tested without devices. Increase as mock tests are added.
|
|
97
|
+
run: pytest tests/unit/ -v --cov=violawake_sdk --cov-report=xml --cov-fail-under=50
|
|
98
|
+
|
|
99
|
+
- name: Upload coverage to Codecov
|
|
100
|
+
if: matrix.os == 'ubuntu-22.04' && matrix.python-version == env.PYTHON_DEFAULT
|
|
101
|
+
uses: codecov/codecov-action@v4
|
|
102
|
+
with:
|
|
103
|
+
files: coverage.xml
|
|
104
|
+
flags: unit
|
|
105
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
106
|
+
|
|
107
|
+
# Job 3: Integration tests (main branch + PRs with [integration] label)
|
|
108
|
+
test-integration:
|
|
109
|
+
name: Integration tests
|
|
110
|
+
runs-on: ubuntu-22.04
|
|
111
|
+
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'run-integration')
|
|
112
|
+
needs: [lint, test-unit]
|
|
113
|
+
|
|
114
|
+
steps:
|
|
115
|
+
- uses: actions/checkout@v4
|
|
116
|
+
|
|
117
|
+
- name: Set up Python
|
|
118
|
+
uses: actions/setup-python@v5
|
|
119
|
+
with:
|
|
120
|
+
python-version: ${{ env.PYTHON_DEFAULT }}
|
|
121
|
+
cache: pip
|
|
122
|
+
|
|
123
|
+
- name: Install PortAudio
|
|
124
|
+
run: sudo apt-get install -y portaudio19-dev
|
|
125
|
+
|
|
126
|
+
- name: Install all extras
|
|
127
|
+
run: |
|
|
128
|
+
pip install openwakeword --no-deps
|
|
129
|
+
pip install -e ".[all,dev]" || pip install -e ".[audio,download,tts,stt,vad,training,generate,dev]"
|
|
130
|
+
|
|
131
|
+
- name: Cache models
|
|
132
|
+
uses: actions/cache@v4
|
|
133
|
+
id: model-cache
|
|
134
|
+
with:
|
|
135
|
+
path: ~/.violawake/models
|
|
136
|
+
key: violawake-models-v1-${{ hashFiles('src/violawake_sdk/models.py') }}
|
|
137
|
+
|
|
138
|
+
- name: Download models (if cache miss)
|
|
139
|
+
if: steps.model-cache.outputs.cache-hit != 'true'
|
|
140
|
+
run: |
|
|
141
|
+
violawake-download --model temporal_cnn
|
|
142
|
+
violawake-download --model kokoro_v1_0
|
|
143
|
+
|
|
144
|
+
- name: Run integration tests
|
|
145
|
+
run: pytest tests/integration/ -v -m integration --cov=violawake_sdk --cov-report=xml
|
|
146
|
+
|
|
147
|
+
- name: Upload integration coverage
|
|
148
|
+
uses: codecov/codecov-action@v4
|
|
149
|
+
with:
|
|
150
|
+
files: coverage.xml
|
|
151
|
+
flags: integration
|
|
152
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
153
|
+
|
|
154
|
+
# Job 4: Benchmark regression check (nightly on main)
|
|
155
|
+
benchmark:
|
|
156
|
+
name: Benchmark regression check
|
|
157
|
+
runs-on: ubuntu-22.04
|
|
158
|
+
if: github.event_name == 'schedule' || (github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'))
|
|
159
|
+
needs: [test-unit]
|
|
160
|
+
|
|
161
|
+
steps:
|
|
162
|
+
- uses: actions/checkout@v4
|
|
163
|
+
|
|
164
|
+
- name: Set up Python
|
|
165
|
+
uses: actions/setup-python@v5
|
|
166
|
+
with:
|
|
167
|
+
python-version: ${{ env.PYTHON_DEFAULT }}
|
|
168
|
+
cache: pip
|
|
169
|
+
|
|
170
|
+
- name: Install PortAudio
|
|
171
|
+
run: sudo apt-get install -y portaudio19-dev
|
|
172
|
+
|
|
173
|
+
- name: Install all extras
|
|
174
|
+
run: |
|
|
175
|
+
pip install openwakeword --no-deps
|
|
176
|
+
pip install -e ".[all,dev]" || pip install -e ".[audio,download,tts,stt,vad,training,generate,dev]"
|
|
177
|
+
|
|
178
|
+
- name: Cache models
|
|
179
|
+
uses: actions/cache@v4
|
|
180
|
+
with:
|
|
181
|
+
path: ~/.violawake/models
|
|
182
|
+
key: violawake-models-v1-${{ hashFiles('src/violawake_sdk/models.py') }}
|
|
183
|
+
|
|
184
|
+
- name: Download models
|
|
185
|
+
run: |
|
|
186
|
+
violawake-download --model temporal_cnn
|
|
187
|
+
|
|
188
|
+
- name: Run latency benchmarks
|
|
189
|
+
run: |
|
|
190
|
+
mkdir -p benchmark-results
|
|
191
|
+
pytest tests/benchmarks/bench_latency.py \
|
|
192
|
+
--benchmark-json=benchmark-results/latency-${{ github.sha }}.json
|
|
193
|
+
|
|
194
|
+
- name: Check for regressions
|
|
195
|
+
# --threshold 0.10 = fail if any benchmark regresses by more than 10%.
|
|
196
|
+
# This catches meaningful latency regressions while ignoring normal
|
|
197
|
+
# run-to-run variance on CI machines (typically ~5%).
|
|
198
|
+
run: python tools/benchmark_regression_check.py --threshold 0.10
|
|
199
|
+
|
|
200
|
+
- name: Upload benchmark results
|
|
201
|
+
uses: actions/upload-artifact@v4
|
|
202
|
+
with:
|
|
203
|
+
name: benchmark-results-${{ github.sha }}
|
|
204
|
+
path: benchmark-results/
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
name: Console CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, develop]
|
|
6
|
+
paths:
|
|
7
|
+
- "console/**"
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
paths:
|
|
11
|
+
- "console/**"
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: console-ci-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
env:
|
|
18
|
+
PYTHON_DEFAULT: "3.11"
|
|
19
|
+
NODE_DEFAULT: "20"
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
# --------------------------------------------------------------
|
|
23
|
+
# Job 1: Backend lint (ruff)
|
|
24
|
+
# --------------------------------------------------------------
|
|
25
|
+
backend-lint:
|
|
26
|
+
name: Backend lint
|
|
27
|
+
runs-on: ubuntu-22.04
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
|
|
31
|
+
- name: Set up Python
|
|
32
|
+
uses: actions/setup-python@v5
|
|
33
|
+
with:
|
|
34
|
+
python-version: ${{ env.PYTHON_DEFAULT }}
|
|
35
|
+
cache: pip
|
|
36
|
+
cache-dependency-path: console/backend/requirements.txt
|
|
37
|
+
|
|
38
|
+
- name: Install lint dependencies
|
|
39
|
+
run: pip install ruff
|
|
40
|
+
|
|
41
|
+
- name: Run ruff (lint)
|
|
42
|
+
run: ruff check console/backend/
|
|
43
|
+
|
|
44
|
+
- name: Run ruff (format check)
|
|
45
|
+
run: ruff format --check console/backend/
|
|
46
|
+
|
|
47
|
+
# --------------------------------------------------------------
|
|
48
|
+
# Job 2: Backend tests
|
|
49
|
+
# --------------------------------------------------------------
|
|
50
|
+
backend-test:
|
|
51
|
+
name: Backend tests
|
|
52
|
+
runs-on: ubuntu-22.04
|
|
53
|
+
needs: [backend-lint]
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v4
|
|
56
|
+
|
|
57
|
+
- name: Set up Python
|
|
58
|
+
uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: ${{ env.PYTHON_DEFAULT }}
|
|
61
|
+
cache: pip
|
|
62
|
+
cache-dependency-path: console/backend/requirements.txt
|
|
63
|
+
|
|
64
|
+
- name: Install test dependencies
|
|
65
|
+
run: pip install -r console/backend/requirements.txt pytest httpx
|
|
66
|
+
|
|
67
|
+
- name: Run backend tests
|
|
68
|
+
run: pytest console/tests/test_backend.py -v
|
|
69
|
+
|
|
70
|
+
# --------------------------------------------------------------
|
|
71
|
+
# Job 3: Frontend build
|
|
72
|
+
# --------------------------------------------------------------
|
|
73
|
+
frontend-build:
|
|
74
|
+
name: Frontend build
|
|
75
|
+
runs-on: ubuntu-22.04
|
|
76
|
+
defaults:
|
|
77
|
+
run:
|
|
78
|
+
working-directory: console/frontend
|
|
79
|
+
steps:
|
|
80
|
+
- uses: actions/checkout@v4
|
|
81
|
+
|
|
82
|
+
- name: Set up Node.js
|
|
83
|
+
uses: actions/setup-node@v4
|
|
84
|
+
with:
|
|
85
|
+
node-version: ${{ env.NODE_DEFAULT }}
|
|
86
|
+
cache: npm
|
|
87
|
+
cache-dependency-path: console/frontend/package-lock.json
|
|
88
|
+
|
|
89
|
+
- name: Install dependencies
|
|
90
|
+
run: npm ci
|
|
91
|
+
|
|
92
|
+
- name: Build frontend
|
|
93
|
+
run: npm run build
|
|
94
|
+
|
|
95
|
+
- name: Upload frontend artifact
|
|
96
|
+
uses: actions/upload-artifact@v4
|
|
97
|
+
with:
|
|
98
|
+
name: console-frontend-dist
|
|
99
|
+
path: console/frontend/dist/
|
|
100
|
+
|
|
101
|
+
# --------------------------------------------------------------
|
|
102
|
+
# Job 4: Frontend typecheck
|
|
103
|
+
# --------------------------------------------------------------
|
|
104
|
+
frontend-typecheck:
|
|
105
|
+
name: Frontend typecheck
|
|
106
|
+
runs-on: ubuntu-22.04
|
|
107
|
+
defaults:
|
|
108
|
+
run:
|
|
109
|
+
working-directory: console/frontend
|
|
110
|
+
steps:
|
|
111
|
+
- uses: actions/checkout@v4
|
|
112
|
+
|
|
113
|
+
- name: Set up Node.js
|
|
114
|
+
uses: actions/setup-node@v4
|
|
115
|
+
with:
|
|
116
|
+
node-version: ${{ env.NODE_DEFAULT }}
|
|
117
|
+
cache: npm
|
|
118
|
+
cache-dependency-path: console/frontend/package-lock.json
|
|
119
|
+
|
|
120
|
+
- name: Install dependencies
|
|
121
|
+
run: npm ci
|
|
122
|
+
|
|
123
|
+
- name: Run TypeScript typecheck
|
|
124
|
+
run: npx tsc --noEmit
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
name: Model Verification
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Weekly on Monday at 06:00 UTC
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: "0 6 * * 1"
|
|
7
|
+
# On changes to model registry or this workflow
|
|
8
|
+
push:
|
|
9
|
+
branches: [main, develop]
|
|
10
|
+
paths:
|
|
11
|
+
- "src/violawake_sdk/models.py"
|
|
12
|
+
- ".github/workflows/model-verify.yml"
|
|
13
|
+
pull_request:
|
|
14
|
+
branches: [main]
|
|
15
|
+
paths:
|
|
16
|
+
- "src/violawake_sdk/models.py"
|
|
17
|
+
- ".github/workflows/model-verify.yml"
|
|
18
|
+
# Manual trigger
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
|
|
21
|
+
concurrency:
|
|
22
|
+
group: model-verify-${{ github.ref }}
|
|
23
|
+
cancel-in-progress: true
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
verify-models:
|
|
27
|
+
name: Verify models (Python ${{ matrix.python-version }})
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
strategy:
|
|
30
|
+
fail-fast: false
|
|
31
|
+
matrix:
|
|
32
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
33
|
+
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
38
|
+
uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: ${{ matrix.python-version }}
|
|
41
|
+
cache: pip
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: |
|
|
45
|
+
pip install -e ".[download]"
|
|
46
|
+
pip install onnxruntime
|
|
47
|
+
|
|
48
|
+
- name: Warn on placeholder hashes
|
|
49
|
+
run: |
|
|
50
|
+
python - <<'PY'
|
|
51
|
+
from violawake_sdk.models import MODEL_REGISTRY
|
|
52
|
+
|
|
53
|
+
seen = set()
|
|
54
|
+
placeholders = []
|
|
55
|
+
for name, spec in MODEL_REGISTRY.items():
|
|
56
|
+
if spec.name in seen:
|
|
57
|
+
continue
|
|
58
|
+
seen.add(spec.name)
|
|
59
|
+
if spec.sha256.startswith("PLACEHOLDER"):
|
|
60
|
+
placeholders.append(name)
|
|
61
|
+
|
|
62
|
+
if placeholders:
|
|
63
|
+
models = ", ".join(placeholders)
|
|
64
|
+
print(f"::warning::Placeholder SHA-256 values detected. Hash verification will be skipped for: {models}")
|
|
65
|
+
else:
|
|
66
|
+
print("All model hashes are populated.")
|
|
67
|
+
PY
|
|
68
|
+
|
|
69
|
+
- name: Cache downloaded models
|
|
70
|
+
uses: actions/cache@v4
|
|
71
|
+
id: model-cache
|
|
72
|
+
with:
|
|
73
|
+
path: ~/.violawake/models
|
|
74
|
+
key: model-verify-v1-${{ hashFiles('src/violawake_sdk/models.py') }}
|
|
75
|
+
restore-keys: |
|
|
76
|
+
model-verify-v1-
|
|
77
|
+
|
|
78
|
+
- name: Verify all models
|
|
79
|
+
run: python scripts/verify_models.py --ci
|
|
80
|
+
env:
|
|
81
|
+
VIOLAWAKE_MODEL_DIR: ~/.violawake/models
|
|
82
|
+
|
|
83
|
+
- name: Upload verification report
|
|
84
|
+
if: always()
|
|
85
|
+
uses: actions/upload-artifact@v4
|
|
86
|
+
with:
|
|
87
|
+
name: model-verification-py${{ matrix.python-version }}
|
|
88
|
+
path: model-verify-report.json
|
|
89
|
+
retention-days: 30
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write # for GitHub Release creation
|
|
10
|
+
id-token: write # for PyPI trusted publishing (OIDC)
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
# ──────────────────────────────────────────────
|
|
14
|
+
# Job 1: Validate the release
|
|
15
|
+
# ──────────────────────────────────────────────
|
|
16
|
+
validate:
|
|
17
|
+
name: Validate release tag
|
|
18
|
+
runs-on: ubuntu-22.04
|
|
19
|
+
outputs:
|
|
20
|
+
version: ${{ steps.extract-version.outputs.version }}
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Extract version from tag
|
|
26
|
+
id: extract-version
|
|
27
|
+
run: |
|
|
28
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
29
|
+
echo "version=${TAG}" >> "$GITHUB_OUTPUT"
|
|
30
|
+
echo "Release version: ${TAG}"
|
|
31
|
+
|
|
32
|
+
- name: Verify version matches pyproject.toml
|
|
33
|
+
run: |
|
|
34
|
+
PYPROJECT_VERSION=$(python -c "
|
|
35
|
+
try:
|
|
36
|
+
import tomllib
|
|
37
|
+
except ImportError:
|
|
38
|
+
import tomli as tomllib
|
|
39
|
+
d=tomllib.load(open('pyproject.toml','rb')); print(d['project']['version'])")
|
|
40
|
+
TAG_VERSION="${{ steps.extract-version.outputs.version }}"
|
|
41
|
+
if [ "$PYPROJECT_VERSION" != "$TAG_VERSION" ]; then
|
|
42
|
+
echo "ERROR: pyproject.toml version ($PYPROJECT_VERSION) != tag ($TAG_VERSION)"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
- name: Set up Python
|
|
47
|
+
uses: actions/setup-python@v5
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.11"
|
|
50
|
+
|
|
51
|
+
- name: Install PortAudio
|
|
52
|
+
run: sudo apt-get install -y portaudio19-dev
|
|
53
|
+
|
|
54
|
+
- name: Install and run full test suite
|
|
55
|
+
run: |
|
|
56
|
+
pip install -e ".[dev]"
|
|
57
|
+
pytest tests/unit/ -v --cov=violawake_sdk --cov-fail-under=65
|
|
58
|
+
|
|
59
|
+
# ──────────────────────────────────────────────
|
|
60
|
+
# Job 2: Build distribution artifacts
|
|
61
|
+
# ──────────────────────────────────────────────
|
|
62
|
+
build:
|
|
63
|
+
name: Build wheel + sdist
|
|
64
|
+
runs-on: ubuntu-22.04
|
|
65
|
+
needs: validate
|
|
66
|
+
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- name: Set up Python
|
|
71
|
+
uses: actions/setup-python@v5
|
|
72
|
+
with:
|
|
73
|
+
python-version: "3.11"
|
|
74
|
+
|
|
75
|
+
- name: Install hatch
|
|
76
|
+
run: pip install hatch
|
|
77
|
+
|
|
78
|
+
- name: Build wheel and sdist
|
|
79
|
+
run: hatch build
|
|
80
|
+
|
|
81
|
+
- name: Verify wheel contents
|
|
82
|
+
run: |
|
|
83
|
+
pip install twine
|
|
84
|
+
twine check dist/*
|
|
85
|
+
|
|
86
|
+
- name: Upload dist artifacts
|
|
87
|
+
uses: actions/upload-artifact@v4
|
|
88
|
+
with:
|
|
89
|
+
name: dist-artifacts
|
|
90
|
+
path: dist/
|
|
91
|
+
|
|
92
|
+
# ──────────────────────────────────────────────
|
|
93
|
+
# Job 3: Create GitHub Release with model assets
|
|
94
|
+
# ──────────────────────────────────────────────
|
|
95
|
+
github-release:
|
|
96
|
+
name: Create GitHub Release
|
|
97
|
+
runs-on: ubuntu-22.04
|
|
98
|
+
needs: [validate, build]
|
|
99
|
+
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v4
|
|
102
|
+
|
|
103
|
+
- name: Download dist artifacts
|
|
104
|
+
uses: actions/download-artifact@v4
|
|
105
|
+
with:
|
|
106
|
+
name: dist-artifacts
|
|
107
|
+
path: dist/
|
|
108
|
+
|
|
109
|
+
- name: Fetch model files from model artifact store
|
|
110
|
+
# Models are stored in a private artifact store (not in git).
|
|
111
|
+
# This step retrieves the models for the current version and
|
|
112
|
+
# attaches them to the GitHub Release.
|
|
113
|
+
env:
|
|
114
|
+
MODEL_STORE_TOKEN: ${{ secrets.MODEL_STORE_TOKEN }}
|
|
115
|
+
run: |
|
|
116
|
+
python tools/fetch_release_models.py \
|
|
117
|
+
--version ${{ needs.validate.outputs.version }} \
|
|
118
|
+
--output models/
|
|
119
|
+
|
|
120
|
+
- name: Create GitHub Release
|
|
121
|
+
uses: softprops/action-gh-release@v2
|
|
122
|
+
with:
|
|
123
|
+
tag_name: ${{ github.ref_name }}
|
|
124
|
+
name: ViolaWake SDK ${{ needs.validate.outputs.version }}
|
|
125
|
+
body_path: RELEASE_NOTES.md
|
|
126
|
+
draft: false
|
|
127
|
+
prerelease: ${{ contains(needs.validate.outputs.version, 'rc') || contains(needs.validate.outputs.version, 'alpha') || contains(needs.validate.outputs.version, 'beta') }}
|
|
128
|
+
files: |
|
|
129
|
+
dist/*.whl
|
|
130
|
+
dist/*.tar.gz
|
|
131
|
+
models/*.onnx
|
|
132
|
+
|
|
133
|
+
# ──────────────────────────────────────────────
|
|
134
|
+
# Job 4: Publish to PyPI (trusted publishing via OIDC)
|
|
135
|
+
# ──────────────────────────────────────────────
|
|
136
|
+
pypi-publish:
|
|
137
|
+
name: Publish to PyPI
|
|
138
|
+
runs-on: ubuntu-22.04
|
|
139
|
+
needs: [validate, build, github-release]
|
|
140
|
+
environment: pypi # required for OIDC trusted publishing
|
|
141
|
+
|
|
142
|
+
steps:
|
|
143
|
+
- name: Download dist artifacts
|
|
144
|
+
uses: actions/download-artifact@v4
|
|
145
|
+
with:
|
|
146
|
+
name: dist-artifacts
|
|
147
|
+
path: dist/
|
|
148
|
+
|
|
149
|
+
- name: Publish to PyPI
|
|
150
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
151
|
+
# Uses OIDC trusted publishing — no API token needed if configured
|
|
152
|
+
# in PyPI project settings. See:
|
|
153
|
+
# https://docs.pypi.org/trusted-publishers/
|
|
154
|
+
|
|
155
|
+
# ──────────────────────────────────────────────
|
|
156
|
+
# Job 5: Update model registry SHA-256s in docs
|
|
157
|
+
# ──────────────────────────────────────────────
|
|
158
|
+
update-docs:
|
|
159
|
+
name: Update model registry
|
|
160
|
+
runs-on: ubuntu-22.04
|
|
161
|
+
needs: github-release
|
|
162
|
+
|
|
163
|
+
steps:
|
|
164
|
+
- uses: actions/checkout@v4
|
|
165
|
+
with:
|
|
166
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
167
|
+
|
|
168
|
+
- name: Update model SHA-256s in models.py
|
|
169
|
+
run: |
|
|
170
|
+
python tools/update_model_registry.py \
|
|
171
|
+
--version ${{ needs.validate.outputs.version }}
|
|
172
|
+
|
|
173
|
+
- name: Commit updated registry
|
|
174
|
+
run: |
|
|
175
|
+
git config user.name "ViolaWake Release Bot"
|
|
176
|
+
git config user.email "bot@violawake.dev"
|
|
177
|
+
git add src/violawake_sdk/models.py
|
|
178
|
+
git commit -m "chore: update model registry for v${{ needs.validate.outputs.version }}" || echo "No changes to commit"
|
|
179
|
+
git push origin main
|