omnius 1.0.633 → 1.0.634
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 +16 -4
- package/dist/index.js +17581 -14391
- package/dist/memory-maintenance-worker.js +116 -0
- package/dist/scripts/audio-clap-semantic-worker.py +171 -0
- package/dist/scripts/audio-speaker-embedding-worker.py +259 -0
- package/dist/scripts/audio-yamnet-tensorrt-worker.py +69 -21
- package/dist/scripts/embed-image.py +34 -0
- package/dist/scripts/embed-text.py +26 -0
- package/dist/update-worker.js +33 -0
- package/docs/DISCOVERY.json +1285 -7
- package/docs/DISCOVERY.md +13 -1
- package/docs/reference/rest-api.md +13 -1
- package/docs/rest/INDEX.md +1 -1
- package/docs/rest/REST-DOCS-MANIFEST.json +1 -1
- package/docs/rest/endpoints/memory.md +54 -0
- package/docs/rest/endpoints/voice-vision.md +122 -1
- package/npm-shrinkwrap.json +8 -8
- package/package.json +2 -2
|
@@ -154,7 +154,12 @@ def read_wav(path: str, np):
|
|
|
154
154
|
raise RuntimeError(
|
|
155
155
|
f"Expected at most 6 seconds of caller-conditioned audio, received {waveform.size / sample_rate:.3f} seconds"
|
|
156
156
|
)
|
|
157
|
-
return
|
|
157
|
+
return (
|
|
158
|
+
waveform,
|
|
159
|
+
sample_rate,
|
|
160
|
+
(time.perf_counter() - started) * 1000,
|
|
161
|
+
"sha256:" + hashlib.sha256(raw).hexdigest(),
|
|
162
|
+
)
|
|
158
163
|
|
|
159
164
|
|
|
160
165
|
class YAMNetTensorRT:
|
|
@@ -193,6 +198,8 @@ class YAMNetTensorRT:
|
|
|
193
198
|
self.output_names.append(name)
|
|
194
199
|
if self.input_name is None or not self.output_names:
|
|
195
200
|
raise RuntimeError("YAMNet TensorRT engine did not expose input and output tensors")
|
|
201
|
+
self.score_output_name = self._unique_output_name(521, "AudioSet score")
|
|
202
|
+
self.embedding_output_name = self._unique_output_name(1024, "YAMNet embedding")
|
|
196
203
|
with open(class_map_path, newline="", encoding="utf8") as handle:
|
|
197
204
|
self.classes = [row["display_name"] for row in csv.DictReader(handle)]
|
|
198
205
|
if len(self.classes) != 521:
|
|
@@ -205,13 +212,28 @@ class YAMNetTensorRT:
|
|
|
205
212
|
# namespace to exactly the approved Jetson GPU before process launch.
|
|
206
213
|
return self.cuda.device_metadata()
|
|
207
214
|
|
|
215
|
+
def _unique_output_name(self, width: int, label: str):
|
|
216
|
+
matches = []
|
|
217
|
+
for name in self.output_names:
|
|
218
|
+
shape = tuple(self.engine.get_tensor_shape(name))
|
|
219
|
+
if shape and int(shape[-1]) == width:
|
|
220
|
+
matches.append(name)
|
|
221
|
+
if len(matches) != 1:
|
|
222
|
+
raise RuntimeError(
|
|
223
|
+
f"YAMNet TensorRT engine must expose exactly one {label} output with width {width}; found {matches}"
|
|
224
|
+
)
|
|
225
|
+
return matches[0]
|
|
226
|
+
|
|
208
227
|
def warm(self):
|
|
209
228
|
# YAMNet needs >=0.975 seconds. This is a model-load probe, not a
|
|
210
229
|
# captured-audio classification, and it verifies the TensorRT path is
|
|
211
230
|
# actually executable before readiness is reported.
|
|
212
|
-
|
|
231
|
+
# Exercise and validate both exported model heads before reporting the
|
|
232
|
+
# persistent worker as ready. A stale score-only plan must fail here,
|
|
233
|
+
# rather than after an embedding caller has acquired the queue slot.
|
|
234
|
+
self.infer(self.np.zeros(15600, dtype=self.np.float32), 1, include_embedding=True)
|
|
213
235
|
|
|
214
|
-
def infer(self, waveform, top_k: int):
|
|
236
|
+
def infer(self, waveform, top_k: int | None = None, include_embedding: bool = False):
|
|
215
237
|
started = time.perf_counter()
|
|
216
238
|
np = self.np
|
|
217
239
|
if waveform.ndim != 1 or waveform.size < 15600:
|
|
@@ -246,16 +268,34 @@ class YAMNetTensorRT:
|
|
|
246
268
|
for name, (host, device) in host_outputs.items():
|
|
247
269
|
self.cuda.d2h(host, device, self.stream, name)
|
|
248
270
|
self.cuda.synchronize(self.stream)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
271
|
+
result = {}
|
|
272
|
+
if top_k is not None:
|
|
273
|
+
scores = host_outputs[self.score_output_name][0]
|
|
274
|
+
if scores.ndim != 2 or scores.shape[-1] != 521:
|
|
275
|
+
raise RuntimeError(f"YAMNet score output shape is invalid: {scores.shape}")
|
|
276
|
+
mean_scores = np.mean(scores, axis=0)
|
|
277
|
+
indices = np.argsort(mean_scores)[-top_k:][::-1]
|
|
278
|
+
result["classifications"] = [
|
|
279
|
+
{"label": self.classes[int(index)], "confidence": float(mean_scores[int(index)])}
|
|
280
|
+
for index in indices
|
|
281
|
+
]
|
|
282
|
+
if include_embedding:
|
|
283
|
+
frame_embeddings = host_outputs[self.embedding_output_name][0]
|
|
284
|
+
if frame_embeddings.ndim != 2 or frame_embeddings.shape[-1] != 1024 or frame_embeddings.shape[0] < 1:
|
|
285
|
+
raise RuntimeError(f"YAMNet embedding output shape is invalid: {frame_embeddings.shape}")
|
|
286
|
+
vector = np.mean(frame_embeddings.astype(np.float32, copy=False), axis=0)
|
|
287
|
+
norm = float(np.linalg.norm(vector))
|
|
288
|
+
if not np.isfinite(norm) or norm <= 0.0:
|
|
289
|
+
raise RuntimeError("YAMNet embedding has an invalid L2 norm")
|
|
290
|
+
result["embedding"] = {
|
|
291
|
+
"dimension": 1024,
|
|
292
|
+
"frame_count": int(frame_embeddings.shape[0]),
|
|
293
|
+
"pooling": "mean_l2",
|
|
294
|
+
"dtype": "float32",
|
|
295
|
+
"normalization": "l2",
|
|
296
|
+
"values": (vector / norm).astype(np.float32).tolist(),
|
|
297
|
+
}
|
|
298
|
+
return result, (time.perf_counter() - started) * 1000
|
|
259
299
|
finally:
|
|
260
300
|
for allocation in allocations:
|
|
261
301
|
try:
|
|
@@ -307,40 +347,48 @@ def main() -> int:
|
|
|
307
347
|
if request.get("type") == "shutdown":
|
|
308
348
|
emit({"type": "stopped"})
|
|
309
349
|
return 0
|
|
310
|
-
|
|
311
|
-
|
|
350
|
+
action = str(request.get("action") or request.get("type") or "").strip().lower()
|
|
351
|
+
if action not in ("classify", "embed"):
|
|
352
|
+
raise RuntimeError("unknown audio analysis action")
|
|
312
353
|
request_id = str(request.get("id") or "")
|
|
313
354
|
file_path = str(request.get("file") or "")
|
|
314
355
|
if not request_id or not file_path:
|
|
315
|
-
raise RuntimeError("
|
|
316
|
-
waveform, sample_rate, decode_ms = read_wav(file_path, worker.np)
|
|
356
|
+
raise RuntimeError("audio analysis requires id and file")
|
|
357
|
+
waveform, sample_rate, decode_ms, input_digest = read_wav(file_path, worker.np)
|
|
317
358
|
rms = float(worker.np.sqrt(worker.np.mean(worker.np.square(waveform)))) if waveform.size else 0.0
|
|
318
359
|
peak = float(worker.np.max(worker.np.abs(waveform))) if waveform.size else 0.0
|
|
319
360
|
# Do not force YAMNet to invent an AudioSet label for digital or
|
|
320
361
|
# near-digital silence. This remains a valid, grounded result.
|
|
321
362
|
low_information = rms < 0.0005 and peak < 0.002
|
|
322
363
|
if low_information:
|
|
323
|
-
|
|
364
|
+
result, inference_ms = (
|
|
365
|
+
{"classifications": []} if action == "classify" else {"embedding": None},
|
|
366
|
+
0.0,
|
|
367
|
+
)
|
|
324
368
|
else:
|
|
325
|
-
|
|
369
|
+
result, inference_ms = worker.infer(
|
|
326
370
|
waveform,
|
|
327
|
-
max(1, min(int(request.get("top_k", 5)), 25)),
|
|
371
|
+
top_k=max(1, min(int(request.get("top_k", 5)), 25)) if action == "classify" else None,
|
|
372
|
+
include_embedding=action == "embed",
|
|
328
373
|
)
|
|
329
374
|
emit({
|
|
330
375
|
"type": "result",
|
|
331
376
|
"id": request_id,
|
|
377
|
+
"action": action,
|
|
332
378
|
"success": True,
|
|
333
379
|
"sample_rate_hz": sample_rate,
|
|
334
380
|
"duration_seconds": round(float(waveform.size) / sample_rate, 6),
|
|
335
|
-
"
|
|
381
|
+
"input_digest": input_digest,
|
|
336
382
|
"low_information": low_information,
|
|
337
383
|
"acoustic": {"rms": round(rms, 8), "peak": round(peak, 8)},
|
|
338
384
|
"timings_ms": {"decode": round(decode_ms, 3), "inference": round(inference_ms, 3)},
|
|
385
|
+
**result,
|
|
339
386
|
})
|
|
340
387
|
except Exception as exc: # keep the persistent worker alive per request
|
|
341
388
|
emit({
|
|
342
389
|
"type": "result",
|
|
343
390
|
"id": str(locals().get("request", {}).get("id", "")),
|
|
391
|
+
"action": str(locals().get("action", "")),
|
|
344
392
|
"success": False,
|
|
345
393
|
"error": str(exc),
|
|
346
394
|
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import sys, json, base64, io
|
|
3
|
+
try:
|
|
4
|
+
import torch
|
|
5
|
+
import open_clip
|
|
6
|
+
from PIL import Image
|
|
7
|
+
except Exception as e:
|
|
8
|
+
print(json.dumps({"error":"deps_missing","message":str(e)}))
|
|
9
|
+
sys.exit(0)
|
|
10
|
+
|
|
11
|
+
def load_image_from_input(data):
|
|
12
|
+
if data.get('path'):
|
|
13
|
+
return Image.open(data['path']).convert('RGB')
|
|
14
|
+
if data.get('bytesBase64'):
|
|
15
|
+
b = base64.b64decode(data['bytesBase64'])
|
|
16
|
+
return Image.open(io.BytesIO(b)).convert('RGB')
|
|
17
|
+
raise RuntimeError('no input provided')
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
raw = sys.stdin.read()
|
|
21
|
+
data = json.loads(raw) if raw.strip() else {}
|
|
22
|
+
image = load_image_from_input(data)
|
|
23
|
+
model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k')
|
|
24
|
+
model.eval()
|
|
25
|
+
with torch.no_grad():
|
|
26
|
+
img_t = preprocess(image).unsqueeze(0)
|
|
27
|
+
emb = model.encode_image(img_t)
|
|
28
|
+
emb = emb / emb.norm(dim=-1, keepdim=True)
|
|
29
|
+
arr = emb.squeeze(0).cpu().numpy().astype('float32').tolist()
|
|
30
|
+
print(json.dumps({"embedding": arr}))
|
|
31
|
+
|
|
32
|
+
if __name__ == '__main__':
|
|
33
|
+
main()
|
|
34
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import sys, json
|
|
3
|
+
try:
|
|
4
|
+
import torch
|
|
5
|
+
import open_clip
|
|
6
|
+
except Exception as e:
|
|
7
|
+
print(json.dumps({"error":"deps_missing","message":str(e)}))
|
|
8
|
+
sys.exit(0)
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
raw = sys.stdin.read()
|
|
12
|
+
data = json.loads(raw) if raw.strip() else {}
|
|
13
|
+
text = data.get('text') or ''
|
|
14
|
+
model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k')
|
|
15
|
+
tokenizer = open_clip.get_tokenizer('ViT-B-32')
|
|
16
|
+
model.eval()
|
|
17
|
+
with torch.no_grad():
|
|
18
|
+
tokens = tokenizer([text])
|
|
19
|
+
emb = model.encode_text(tokens)
|
|
20
|
+
emb = emb / emb.norm(dim=-1, keepdim=True)
|
|
21
|
+
arr = emb.squeeze(0).cpu().numpy().astype('float32').tolist()
|
|
22
|
+
print(json.dumps({"embedding": arr}))
|
|
23
|
+
|
|
24
|
+
if __name__ == '__main__':
|
|
25
|
+
main()
|
|
26
|
+
|
package/dist/update-worker.js
CHANGED
|
@@ -245085,6 +245085,24 @@ var MODEL_URL = `https://huggingface.co/zeropointnine/yamnet-onnx/resolve/${MODE
|
|
|
245085
245085
|
var CLASS_MAP_URL = `https://huggingface.co/zeropointnine/yamnet-onnx/resolve/${MODEL_REVISION}/yamnet_class_map.csv`;
|
|
245086
245086
|
var SETUP_TIMEOUT_MS = 20 * 6e4;
|
|
245087
245087
|
|
|
245088
|
+
// packages/execution/dist/speaker-diarization-runtime.js
|
|
245089
|
+
init_model_store();
|
|
245090
|
+
|
|
245091
|
+
// packages/execution/dist/audio-semantic-embedding-runtime.js
|
|
245092
|
+
init_process_async();
|
|
245093
|
+
init_model_store();
|
|
245094
|
+
init_venv_paths();
|
|
245095
|
+
var SETUP_TIMEOUT_MS2 = 30 * 6e4;
|
|
245096
|
+
|
|
245097
|
+
// packages/execution/dist/speaker-embedding-runtime.js
|
|
245098
|
+
init_jetson_monitor();
|
|
245099
|
+
init_process_async();
|
|
245100
|
+
init_model_store();
|
|
245101
|
+
init_venv_paths();
|
|
245102
|
+
var MODEL_REVISION2 = "acf623ad8ca746e50baa432255cf8fc57c669c45";
|
|
245103
|
+
var MODEL_URL2 = `https://huggingface.co/Wespeaker/wespeaker-voxceleb-campplus/resolve/${MODEL_REVISION2}/voxceleb_CAM%2B%2B.onnx`;
|
|
245104
|
+
var SETUP_TIMEOUT_MS3 = 10 * 6e4;
|
|
245105
|
+
|
|
245088
245106
|
// packages/execution/dist/ocr-advanced-runtime.js
|
|
245089
245107
|
init_process_async();
|
|
245090
245108
|
init_jetson_monitor();
|
|
@@ -290433,6 +290451,21 @@ except Exception as exc:
|
|
|
290433
290451
|
sys.exit(1)
|
|
290434
290452
|
`;
|
|
290435
290453
|
|
|
290454
|
+
// packages/memory/dist/audioNoveltyPrototype.js
|
|
290455
|
+
var AUDIO_NOVELTY_WEIGHTS = Object.freeze({
|
|
290456
|
+
distance: 0.6,
|
|
290457
|
+
uncertainty: 0.1,
|
|
290458
|
+
recurrence: 0.15,
|
|
290459
|
+
direction: 0.075,
|
|
290460
|
+
scene: 0.075
|
|
290461
|
+
});
|
|
290462
|
+
|
|
290463
|
+
// packages/memory/dist/speakerIdentityStore.js
|
|
290464
|
+
var DEFAULT_THRESHOLDS = Object.freeze({
|
|
290465
|
+
provisional: 0.78,
|
|
290466
|
+
ambiguityMargin: 0.04
|
|
290467
|
+
});
|
|
290468
|
+
|
|
290436
290469
|
// packages/memory/dist/crl/index.js
|
|
290437
290470
|
var CRL_SYMBOLS = {
|
|
290438
290471
|
// Logical operators (Core)
|