@fonoster/amd 0.26.0 → 0.30.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.
package/README.md CHANGED
@@ -59,10 +59,15 @@ as a channel variable.
59
59
 
60
60
  Set it from the dialplan by giving `AMD_MODE` a value before the `AGI()`
61
61
  call — apiserver already does this for API-originated calls via
62
- `APISERVER_AMD_MODE` (see below).
62
+ `amd.mode` in `fonoster.yaml` (see below).
63
63
 
64
64
  ## Configuration
65
65
 
66
+ The sidecar reads these from its container environment only; it never loads a
67
+ `.env` file, in development either. Set them in the container's environment
68
+ (Compose `environment:`, a Kubernetes `env:`), or export them before
69
+ `npm run start:dev`.
70
+
66
71
  | env | default | meaning |
67
72
  |---|---|---|
68
73
  | `AMD_AGI_PORT` | `4573` | FastAGI listener port |
@@ -76,11 +81,11 @@ call — apiserver already does this for API-originated calls via
76
81
 
77
82
  ## Enabling it end-to-end
78
83
 
79
- Set `APISERVER_AMD_ENABLED=true` and `APISERVER_AMD_ENGINE=ml` on `apiserver`
80
- (next to the existing native-AMD env vars). With `AMD_ENGINE` unset or set to
81
- anything but `ml`, behavior is unchanged from Asterisk's native `AMD()`.
82
- Additionally set `APISERVER_AMD_MODE=full` to opt into the richer variable
83
- set — omit it (or leave it `compact`) to stay native-AMD-compatible.
84
+ Set `amd.enabled: true` and `amd.engine: ml` in the API server's
85
+ `config/fonoster.yaml`. With the engine unset or set to anything but `ml`,
86
+ behavior is unchanged from Asterisk's native `AMD()`. Additionally set
87
+ `amd.mode: full` to opt into the richer variable set — omit it (or leave it
88
+ `compact`) to stay native-AMD-compatible.
84
89
 
85
90
  ## Regression corpus
86
91
 
@@ -118,38 +123,11 @@ AGI+AudioSocket mechanism and the mode flag work end-to-end; run it with:
118
123
  npm run integration
119
124
  ```
120
125
 
121
- ## Isolated smoke test (manual, against real Asterisk)
122
-
123
- This service can also be exercised without `apiserver`, `autopilot`, NATS, or
124
- Postgres — just this container and a bare Asterisk instance. Unlike the
125
- integration test above, this path has not been run against a real Asterisk
126
- box in this repo's CI; treat it as a documented starting point to validate by
127
- hand:
128
-
129
- ```sh
130
- docker compose -f mods/amd/docker-compose.smoke.yaml up --build
131
- ```
132
-
133
- That starts `amd` alongside a `fonoster/asterisk` container using
134
- `mods/amd/smoke/extensions.conf`, a minimal dialplan with one test
135
- extension:
126
+ ## Status after the rebuild
136
127
 
137
- ```
138
- exten => 7000,1,Answer()
139
- same => n,Wait(1)
140
- same => n,AGI(agi://amd:4573)
141
- same => n,Verbose(1,AMDSTATUS=${AMDSTATUS} AMDCAUSE=${AMDCAUSE})
142
- same => n,Hangup()
143
- ```
144
-
145
- Originate a call into extension `7000` playing a known recorded sample (a
146
- human greeting vs. a voicemail greeting) and check the Asterisk console log
147
- for the `AMDSTATUS`/`AMDCAUSE` line the `Verbose()` step prints, e.g.:
148
-
149
- ```sh
150
- docker compose -f mods/amd/docker-compose.smoke.yaml exec asterisk \
151
- asterisk -rx "channel originate Local/7000@smoke-test application Playback /path/to/sample"
152
- ```
128
+ Asterisk is retired (cleanbreak CB-B6), so the AGI and AudioSocket front end has no caller and its
129
+ Asterisk smoke test is gone. The classifier stays: it moves behind a voice-worker listener in
130
+ `add-media-node` task 4.3.
153
131
 
154
132
  ## Development
155
133
 
@@ -10,6 +10,11 @@ declare function softmaxTop(logits: ArrayLike<number>): {
10
10
  index: number;
11
11
  confidence: number;
12
12
  };
13
+ /**
14
+ * Releases the loaded ONNX session. Call it before the process exits on purpose (tests): ONNX
15
+ * Runtime's threads abort the process ("mutex lock failed") if they are still alive at exit.
16
+ */
17
+ export declare function releaseAmdModel(): Promise<void>;
13
18
  /**
14
19
  * Classify a buffer of raw slin16 PCM (16 kHz mono) as human / voicemail / IVR /
15
20
  * machine. Loads and caches the ONNX session on first call. Throws on model or
@@ -43,6 +43,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
43
43
  };
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.DEFAULT_MODEL_DIR = void 0;
46
+ exports.releaseAmdModel = releaseAmdModel;
46
47
  exports.classifyPcm = classifyPcm;
47
48
  exports.mapLabelToStatus = mapLabelToStatus;
48
49
  exports.softmaxTop = softmaxTop;
@@ -114,6 +115,24 @@ function softmaxTop(logits) {
114
115
  return { index, confidence: sum > 0 ? exps[index] / sum : 0 };
115
116
  }
116
117
  let loaded = null;
118
+ /**
119
+ * Releases the loaded ONNX session. Call it before the process exits on purpose (tests): ONNX
120
+ * Runtime's threads abort the process ("mutex lock failed") if they are still alive at exit.
121
+ */
122
+ function releaseAmdModel() {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ const entry = loaded;
125
+ loaded = null;
126
+ if (!entry)
127
+ return;
128
+ try {
129
+ yield (yield entry.session).release();
130
+ }
131
+ catch (_a) {
132
+ // never loaded, nothing to release
133
+ }
134
+ });
135
+ }
117
136
  function load(modelDir) {
118
137
  var _a;
119
138
  if (loaded && loaded.dir === modelDir)
package/dist/envs.js CHANGED
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.MODEL_PATH = exports.MIN_CONFIDENCE = exports.TIMEOUT_MS = exports.PROBE_MS = exports.AUDIOSOCKET_ADVERTISE_HOST = exports.AUDIOSOCKET_BIND_ADDR = exports.AUDIOSOCKET_PORT = exports.AGI_PORT = void 0;
7
4
  /**
@@ -22,11 +19,9 @@ exports.MODEL_PATH = exports.MIN_CONFIDENCE = exports.TIMEOUT_MS = exports.PROBE
22
19
  * See the License for the specific language governing permissions and
23
20
  * limitations under the License.
24
21
  */
25
- const path_1 = require("path");
26
- const dotenv_1 = __importDefault(require("dotenv"));
27
- if (process.env.NODE_ENV === "development") {
28
- dotenv_1.default.config({ path: (0, path_1.join)(__dirname, "..", "..", "..", ".env") });
29
- }
22
+ // The sidecar's settings come from its container environment (AMD_*), which
23
+ // the deployment sets. It never loads a .env file, not even in development
24
+ // (fix-config-and-placement-gaps).
30
25
  const e = process.env;
31
26
  // A malformed AMD_* number must not silently break the probe (NaN
32
27
  // thresholds disable the deadline / confidence gate), so fall back to the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fonoster/amd",
3
- "version": "0.26.0",
3
+ "version": "0.30.0",
4
4
  "description": "Standalone answering-machine-detection sidecar for the Fonoster platform",
5
5
  "author": "Pedro Sanders <psanders@fonoster.com>",
6
6
  "homepage": "https://github.com/fonoster/fonoster#readme",
@@ -19,10 +19,10 @@
19
19
  "start:dev": "nodemon --exec tsx --watch src src/server.ts"
20
20
  },
21
21
  "dependencies": {
22
- "@fonoster/common": "^0.26.0",
23
- "@fonoster/logger": "^0.26.0",
24
- "@fonoster/streams": "^0.26.0",
25
- "@fonoster/types": "^0.26.0",
22
+ "@fonoster/common": "^0.30.0",
23
+ "@fonoster/logger": "^0.30.0",
24
+ "@fonoster/streams": "^0.30.0",
25
+ "@fonoster/types": "^0.30.0",
26
26
  "onnxruntime-node": "1.21.1",
27
27
  "uuid": "^11.0.3"
28
28
  },
@@ -43,5 +43,5 @@
43
43
  "bugs": {
44
44
  "url": "https://github.com/fonoster/fonoster/issues"
45
45
  },
46
- "gitHead": "d14f414d791a33f92e8c4225f7e462abc440a142"
46
+ "gitHead": "b59b06a3ef325abe3f188c0fb87cc22d50ed5471"
47
47
  }