@iobroker/assistant-satellite 0.0.1

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.
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.WakeWord = void 0;
37
+ /**
38
+ * OpenWakeWord inference in Node via onnxruntime-node.
39
+ *
40
+ * Pipeline (streaming): 16 kHz mono int16 audio → melspectrogram model → sliding embedding model
41
+ * (Google speech embeddings) → wake-word classifier → score in [0,1].
42
+ *
43
+ * Shapes follow the openWakeWord models:
44
+ * melspec: in [1, samples] (int16 values as float32) → out [1,1,F,32]; then mel = mel/10 + 2
45
+ * embedding: in [1,76,32,1] → out [1,1,1,96]; window of 76 mel frames, hop 8
46
+ * wakeword: in [1,16,96] → out [1,1] ; last 16 embeddings
47
+ *
48
+ * ⚠️ The exact frame counts (mel frames per chunk, warm-up) can vary by model version — validate the
49
+ * detection threshold on the target device and adjust `wakewordThreshold`.
50
+ */
51
+ const ort = __importStar(require("onnxruntime-node"));
52
+ const MEL_BINS = 32;
53
+ const EMB_WINDOW = 76; // mel frames per embedding
54
+ const EMB_HOP = 8; // mel frames advanced per embedding
55
+ const WW_FRAMES = 16; // embeddings per wake-word inference
56
+ const EMB_DIM = 96;
57
+ class WakeWord {
58
+ models;
59
+ threshold;
60
+ log;
61
+ melspec;
62
+ embedding;
63
+ classifier;
64
+ melBuffer = []; // rows of 32 mel bins
65
+ melProcessed = 0; // mel frames already turned into embeddings
66
+ embBuffer = []; // rows of 96 embedding dims
67
+ melShapeLogged = false;
68
+ embShapeLogged = false;
69
+ constructor(models, threshold, log) {
70
+ this.models = models;
71
+ this.threshold = threshold;
72
+ this.log = log;
73
+ }
74
+ async load() {
75
+ this.melspec = await ort.InferenceSession.create(this.models.melspec);
76
+ this.embedding = await ort.InferenceSession.create(this.models.embedding);
77
+ this.classifier = await ort.InferenceSession.create(this.models.wakeword);
78
+ this.log.info('Wake-word models loaded.');
79
+ this.log.info(` melspec IO: in=[${this.melspec.inputNames}] out=[${this.melspec.outputNames}]`);
80
+ this.log.info(` embedding IO: in=[${this.embedding.inputNames}] out=[${this.embedding.outputNames}]`);
81
+ this.log.info(` classifier IO: in=[${this.classifier.inputNames}] out=[${this.classifier.outputNames}]`);
82
+ }
83
+ /** Reset the streaming buffers (call after a detection so it re-arms cleanly). */
84
+ reset() {
85
+ this.melBuffer = [];
86
+ this.melProcessed = 0;
87
+ this.embBuffer = [];
88
+ }
89
+ /**
90
+ * Feed one audio chunk (16-bit signed LE PCM, ideally ~1280 samples = 80 ms) and return the
91
+ * current wake-word score, or null if not enough context yet.
92
+ */
93
+ async process(pcm) {
94
+ await this.appendMel(pcm);
95
+ await this.appendEmbeddings();
96
+ if (this.embBuffer.length < WW_FRAMES) {
97
+ return null;
98
+ }
99
+ return this.classify();
100
+ }
101
+ /** True when the given score crosses the configured detection threshold. */
102
+ triggered(score) {
103
+ return score !== null && score >= this.threshold;
104
+ }
105
+ async appendMel(pcm) {
106
+ const n = Math.floor(pcm.length / 2);
107
+ const audio = new Float32Array(n);
108
+ for (let i = 0; i < n; i++) {
109
+ audio[i] = pcm.readInt16LE(i * 2); // int16 value as float (openWakeWord convention)
110
+ }
111
+ const inName = this.melspec.inputNames[0];
112
+ const outName = this.melspec.outputNames[0];
113
+ const out = await this.melspec.run({ [inName]: new ort.Tensor('float32', audio, [1, n]) });
114
+ const t = out[outName];
115
+ const data = t.data;
116
+ if (!this.melShapeLogged) {
117
+ this.log.info(`melspec output dims for ${n} samples: [${t.dims.join(',')}] (expected [1,1,F,32])`);
118
+ this.melShapeLogged = true;
119
+ }
120
+ // dims [1,1,F,32]
121
+ const frames = Number(t.dims[2]);
122
+ for (let f = 0; f < frames; f++) {
123
+ const row = new Array(MEL_BINS);
124
+ for (let b = 0; b < MEL_BINS; b++) {
125
+ row[b] = data[f * MEL_BINS + b] / 10 + 2; // openWakeWord mel transform
126
+ }
127
+ this.melBuffer.push(row);
128
+ }
129
+ }
130
+ async appendEmbeddings() {
131
+ const inName = this.embedding.inputNames[0];
132
+ const outName = this.embedding.outputNames[0];
133
+ while (this.melProcessed + EMB_WINDOW <= this.melBuffer.length) {
134
+ const flat = new Float32Array(EMB_WINDOW * MEL_BINS);
135
+ for (let f = 0; f < EMB_WINDOW; f++) {
136
+ const row = this.melBuffer[this.melProcessed + f];
137
+ for (let b = 0; b < MEL_BINS; b++) {
138
+ flat[f * MEL_BINS + b] = row[b];
139
+ }
140
+ }
141
+ const out = await this.embedding.run({
142
+ [inName]: new ort.Tensor('float32', flat, [1, EMB_WINDOW, MEL_BINS, 1]),
143
+ });
144
+ if (!this.embShapeLogged) {
145
+ this.log.info(`embedding output dims: [${out[outName].dims.join(',')}] (expected [1,1,1,96])`);
146
+ this.embShapeLogged = true;
147
+ }
148
+ const emb = out[outName].data; // [1,1,1,96]
149
+ this.embBuffer.push(Array.from(emb.slice(0, EMB_DIM)));
150
+ this.melProcessed += EMB_HOP;
151
+ }
152
+ // Trim consumed mel frames to keep memory bounded.
153
+ if (this.melProcessed > EMB_WINDOW) {
154
+ const drop = this.melProcessed - EMB_WINDOW;
155
+ this.melBuffer.splice(0, drop);
156
+ this.melProcessed -= drop;
157
+ }
158
+ if (this.embBuffer.length > WW_FRAMES * 4) {
159
+ this.embBuffer.splice(0, this.embBuffer.length - WW_FRAMES * 4);
160
+ }
161
+ }
162
+ async classify() {
163
+ const inName = this.classifier.inputNames[0];
164
+ const outName = this.classifier.outputNames[0];
165
+ const window = this.embBuffer.slice(-WW_FRAMES);
166
+ const flat = new Float32Array(WW_FRAMES * EMB_DIM);
167
+ for (let f = 0; f < WW_FRAMES; f++) {
168
+ for (let d = 0; d < EMB_DIM; d++) {
169
+ flat[f * EMB_DIM + d] = window[f][d];
170
+ }
171
+ }
172
+ const out = await this.classifier.run({
173
+ [inName]: new ort.Tensor('float32', flat, [1, WW_FRAMES, EMB_DIM]),
174
+ });
175
+ return out[outName].data[0];
176
+ }
177
+ }
178
+ exports.WakeWord = WakeWord;
179
+ //# sourceMappingURL=wakeword.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wakeword.js","sourceRoot":"","sources":["../src/wakeword.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ {
2
+ "logLevel": "info",
3
+ "device": "wohnzimmer",
4
+ "room": "Wohnzimmer",
5
+
6
+ "host": "192.168.1.129",
7
+ "port": 7775,
8
+ "listenPort": 7776,
9
+
10
+ "audioBackend": "auto",
11
+ "micDevice": "plughw:2,0",
12
+ "speakerDevice": "plughw:2,0",
13
+
14
+ "wakewordModel": "hey_jarvis",
15
+ "wakewordThreshold": 0.5,
16
+ "modelsDir": "models",
17
+
18
+ "silenceThreshold": 300,
19
+ "silenceMs": 800,
20
+ "minRecordMs": 800,
21
+ "maxRecordMs": 8000,
22
+ "preBufferChunks": 5
23
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@iobroker/assistant-satellite",
3
+ "version": "0.0.1",
4
+ "description": "Standalone voice satellite for the ioBroker.assistant adapter (wake word + mic streaming + TTS playback over the Hannah UDP protocol). Runs on a bare Pi via npx, no ioBroker required.",
5
+ "author": "ioBroker",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "license": "MIT",
10
+ "keywords": ["iobroker", "assistant", "voice", "satellite", "wakeword", "openwakeword"],
11
+ "type": "commonjs",
12
+ "main": "build/index.js",
13
+ "types": "build/index.d.ts",
14
+ "bin": {
15
+ "assistant-satellite": "build/cli.js"
16
+ },
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "files": ["build/", "config.example.json", "README.md", "LICENSE"],
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "watch": "tsc -w -p tsconfig.json",
24
+ "start": "node build/cli.js",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "dependencies": {
28
+ "mqtt": "^5.10.1",
29
+ "onnxruntime-node": "^1.20.1"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.19.43",
33
+ "typescript": "^5.7.2"
34
+ }
35
+ }