@fonoster/amd 0.30.0 → 0.31.0

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.
@@ -1,110 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.runProbe = runProbe;
13
- /**
14
- * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
15
- * http://github.com/fonoster/fonoster
16
- *
17
- * This file is part of Fonoster
18
- *
19
- * Licensed under the MIT License (the "License");
20
- * you may not use this file except in compliance with
21
- * the License. You may obtain a copy of the License at
22
- *
23
- * https://opensource.org/licenses/MIT
24
- *
25
- * Unless required by applicable law or agreed to in writing, software
26
- * distributed under the License is distributed on an "AS IS" BASIS,
27
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28
- * See the License for the specific language governing permissions and
29
- * limitations under the License.
30
- */
31
- const logger_1 = require("@fonoster/logger");
32
- const AmdModel_1 = require("../amd/AmdModel");
33
- const collectPcm_1 = require("./collectPcm");
34
- const upsample_1 = require("./upsample");
35
- const logger = (0, logger_1.getLogger)({ service: "amd", filePath: __filename });
36
- /**
37
- * Runs Answering Machine Detection on the leading audio of one AGI/AudioSocket
38
- * session. Always resolves and never throws: any model error, timeout, or
39
- * empty capture yields `{ kind: "unknown" }` so the caller can always report
40
- * *something* back over AGI. Confidence thresholding is deliberately not
41
- * applied here — see `buildAmdVariables`.
42
- */
43
- function runProbe(params) {
44
- return __awaiter(this, void 0, void 0, function* () {
45
- var _a;
46
- const { stream, probeMs, timeoutMs, modelDir } = params;
47
- const classify = (_a = params.classify) !== null && _a !== void 0 ? _a : ((pcm) => (0, AmdModel_1.classifyPcm)(pcm, modelDir !== null && modelDir !== void 0 ? modelDir : AmdModel_1.DEFAULT_MODEL_DIR));
48
- const startedAt = Date.now();
49
- const latencyMs = () => Date.now() - startedAt;
50
- const unknown = (cause) => ({
51
- kind: "unknown",
52
- cause,
53
- latencyMs: latencyMs()
54
- });
55
- const controller = new AbortController();
56
- const deadline = setTimeout(() => controller.abort(), timeoutMs);
57
- const TIMED_OUT = Symbol("amd-timed-out");
58
- const onDeadline = new Promise((resolve) => {
59
- if (controller.signal.aborted)
60
- resolve(TIMED_OUT);
61
- else
62
- controller.signal.addEventListener("abort", () => resolve(TIMED_OUT), {
63
- once: true
64
- });
65
- });
66
- try {
67
- const pcm = yield (0, collectPcm_1.collectPcm)({
68
- stream,
69
- probeMs,
70
- signal: controller.signal
71
- });
72
- if (controller.signal.aborted) {
73
- logger.warn("amd probe: deadline hit while collecting audio");
74
- return unknown("ML-TIMEOUT");
75
- }
76
- if (pcm.length === 0) {
77
- logger.verbose("amd probe: no usable audio before deadline");
78
- return unknown("ML-NO-AUDIO");
79
- }
80
- // The deadline must also bound classification: a cold model load or a hung
81
- // inference cannot be allowed to stall the AGI session. ONNX Runtime has no
82
- // cancellation, so the losing promise is left to settle on its own.
83
- // The model was trained on 16 kHz input; AudioSocket delivers 8 kHz.
84
- const classification = classify((0, upsample_1.upsample8kTo16k)(pcm));
85
- classification.catch(() => undefined); // no unhandled rejection if the deadline wins
86
- const outcome = yield Promise.race([classification, onDeadline]);
87
- if (outcome === TIMED_OUT) {
88
- logger.warn("amd probe: classification did not finish before the deadline");
89
- return unknown("ML-TIMEOUT");
90
- }
91
- logger.verbose("amd probe: verdict", outcome);
92
- return {
93
- kind: "classified",
94
- status: outcome.status,
95
- confidence: outcome.confidence,
96
- detector: outcome.detector,
97
- latencyMs: latencyMs()
98
- };
99
- }
100
- catch (err) {
101
- logger.warn("amd probe failed; reporting unknown", {
102
- error: err.message
103
- });
104
- return unknown("ML-ERROR");
105
- }
106
- finally {
107
- clearTimeout(deadline);
108
- }
109
- });
110
- }
@@ -1,3 +0,0 @@
1
- /** Upsamples 8 kHz s16le mono PCM to 16 kHz s16le mono. */
2
- declare function upsample8kTo16k(pcm: Buffer): Buffer;
3
- export { upsample8kTo16k };
@@ -1,53 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.upsample8kTo16k = upsample8kTo16k;
4
- /**
5
- * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
6
- * http://github.com/fonoster/fonoster
7
- *
8
- * This file is part of Fonoster
9
- *
10
- * Licensed under the MIT License (the "License");
11
- * you may not use this file except in compliance with
12
- * the License. You may obtain a copy of the License at
13
- *
14
- * https://opensource.org/licenses/MIT
15
- *
16
- * Unless required by applicable law or agreed to in writing, software
17
- * distributed under the License is distributed on an "AS IS" BASIS,
18
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
- * See the License for the specific language governing permissions and
20
- * limitations under the License.
21
- */
22
- const HALF_TAPS = 16;
23
- // Half-band windowed-sinc (Blackman) taps at offsets ±(k + 0.5), normalized
24
- // to unity DC gain. Linear interpolation measurably loses accuracy here: its
25
- // imaging above 4 kHz is enough to lower the classifier's confidence.
26
- const TAPS = (() => {
27
- const taps = new Float64Array(HALF_TAPS);
28
- let sum = 0;
29
- for (let k = 0; k < HALF_TAPS; k++) {
30
- const offset = k + 0.5;
31
- const sinc = Math.sin(Math.PI * offset) / (Math.PI * offset);
32
- const u = (offset + HALF_TAPS) / (2 * HALF_TAPS);
33
- const window = 0.42 - 0.5 * Math.cos(2 * Math.PI * u) + 0.08 * Math.cos(4 * Math.PI * u);
34
- taps[k] = sinc * window;
35
- sum += 2 * taps[k];
36
- }
37
- return taps.map((t) => t / sum);
38
- })();
39
- /** Upsamples 8 kHz s16le mono PCM to 16 kHz s16le mono. */
40
- function upsample8kTo16k(pcm) {
41
- const count = Math.floor(pcm.length / 2);
42
- const out = Buffer.alloc(count * 4);
43
- const sample = (i) => pcm.readInt16LE(2 * Math.min(Math.max(i, 0), count - 1));
44
- for (let i = 0; i < count; i++) {
45
- let interpolated = 0;
46
- for (let k = 0; k < HALF_TAPS; k++) {
47
- interpolated += TAPS[k] * (sample(i - k) + sample(i + 1 + k));
48
- }
49
- out.writeInt16LE(pcm.readInt16LE(2 * i), 4 * i);
50
- out.writeInt16LE(Math.max(-32768, Math.min(32767, Math.round(interpolated))), 4 * i + 2);
51
- }
52
- return out;
53
- }
package/dist/server.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/server.js DELETED
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
4
- * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
5
- * http://github.com/fonoster/fonoster
6
- *
7
- * This file is part of Fonoster
8
- *
9
- * Licensed under the MIT License (the "License");
10
- * you may not use this file except in compliance with
11
- * the License. You may obtain a copy of the License at
12
- *
13
- * https://opensource.org/licenses/MIT
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
- const logger_1 = require("@fonoster/logger");
22
- const server_1 = require("./agi/server");
23
- const server_2 = require("./audiosocket/server");
24
- const logger = (0, logger_1.getLogger)({ service: "amd", filePath: __filename });
25
- logger.info("starting amd");
26
- (0, server_2.startAudioSocketServer)();
27
- (0, server_1.startAgiServer)();