omnius 1.0.409 → 1.0.410
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/dist/index.js +257 -58
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -601886,7 +601886,8 @@ __export(image_ascii_preview_exports, {
|
|
|
601886
601886
|
buildImageAsciiPreview: () => buildImageAsciiPreview,
|
|
601887
601887
|
defaultAsciiPreviewSize: () => defaultAsciiPreviewSize,
|
|
601888
601888
|
extractSavedImagePath: () => extractSavedImagePath,
|
|
601889
|
-
formatImageAsciiContext: () => formatImageAsciiContext
|
|
601889
|
+
formatImageAsciiContext: () => formatImageAsciiContext,
|
|
601890
|
+
isLowInformationAsciiPreview: () => isLowInformationAsciiPreview
|
|
601890
601891
|
});
|
|
601891
601892
|
import { createRequire as createRequire5 } from "node:module";
|
|
601892
601893
|
import { existsSync as existsSync108, readFileSync as readFileSync87, statSync as statSync42 } from "node:fs";
|
|
@@ -602054,6 +602055,15 @@ function normalizeImageToAsciiResult(converted, width, height) {
|
|
|
602054
602055
|
if (!ascii2) return { ascii: null, error: "empty normalized renderer output" };
|
|
602055
602056
|
return { ascii: ascii2, plainAscii: plainAscii || void 0 };
|
|
602056
602057
|
}
|
|
602058
|
+
function isLowInformationAsciiPreview(ascii2) {
|
|
602059
|
+
const plain = stripAsciiAnsi(String(ascii2 ?? "")).replace(/\r/g, "").split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0).join("\n");
|
|
602060
|
+
if (!plain) return true;
|
|
602061
|
+
const visible = plain.replace(/\s/g, "");
|
|
602062
|
+
if (visible.length < 12) return true;
|
|
602063
|
+
const unique2 = new Set(Array.from(visible));
|
|
602064
|
+
if (unique2.size <= 2 && /[█▓▒░#@]/u.test(visible)) return true;
|
|
602065
|
+
return false;
|
|
602066
|
+
}
|
|
602057
602067
|
function previewFailure(message2, width) {
|
|
602058
602068
|
const clean5 = message2.replace(/\s+/g, " ").trim();
|
|
602059
602069
|
const text2 = `[image-to-ascii preview failed: ${clean5 || "unknown error"}]`;
|
|
@@ -602172,10 +602182,14 @@ async function buildImageAsciiPreview(inputPath, options2 = {}) {
|
|
|
602172
602182
|
if (options2.preferPackage !== false) {
|
|
602173
602183
|
const result = await convertWithImageToAscii(imagePath, width, height, timeoutMs);
|
|
602174
602184
|
if (result.ascii) {
|
|
602185
|
+
let plainAscii = result.plainAscii;
|
|
602186
|
+
if (isLowInformationAsciiPreview(plainAscii)) {
|
|
602187
|
+
plainAscii = await convertWithFfmpeg(imagePath, width, height, timeoutMs) ?? plainAscii;
|
|
602188
|
+
}
|
|
602175
602189
|
return {
|
|
602176
602190
|
path: imagePath,
|
|
602177
602191
|
ascii: result.ascii,
|
|
602178
|
-
plainAscii
|
|
602192
|
+
plainAscii,
|
|
602179
602193
|
renderer: "image-to-ascii",
|
|
602180
602194
|
width,
|
|
602181
602195
|
height
|
|
@@ -602405,23 +602419,16 @@ function stripDashboardAnsi(value2) {
|
|
|
602405
602419
|
return value2.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "");
|
|
602406
602420
|
}
|
|
602407
602421
|
function dashboardPreviewLines(camera) {
|
|
602408
|
-
const raw = camera.plainAscii
|
|
602409
|
-
return raw.replace(/\r/g, "").split("\n").map((line) => stripDashboardAnsi(line).replace(/\s+$/g, "")).filter((line) => line.trim().length > 0)
|
|
602410
|
-
}
|
|
602411
|
-
function centerDashboardCell(value2, width) {
|
|
602412
|
-
const text2 = stripDashboardAnsi(String(value2 ?? "")).replace(/\r?\n/g, " ");
|
|
602413
|
-
if (width <= 1) return text2.slice(0, Math.max(0, width));
|
|
602414
|
-
const clipped = text2.length > width ? `${text2.slice(0, Math.max(1, width - 1))}…` : text2;
|
|
602415
|
-
const left = Math.floor((width - clipped.length) / 2);
|
|
602416
|
-
return `${" ".repeat(Math.max(0, left))}${clipped}${" ".repeat(Math.max(0, width - clipped.length - left))}`;
|
|
602422
|
+
const raw = camera.plainAscii && !isLowInformationAsciiPreview(camera.plainAscii) ? camera.plainAscii : "";
|
|
602423
|
+
return raw.replace(/\r/g, "").split("\n").map((line) => stripDashboardAnsi(line).replace(/\s+$/g, "")).filter((line) => line.trim().length > 0);
|
|
602417
602424
|
}
|
|
602418
602425
|
function dashboardPreviewAspect(lines) {
|
|
602419
602426
|
const widths = lines.map((line) => stripDashboardAnsi(line).length).filter((n2) => n2 > 0);
|
|
602420
602427
|
const maxWidth = Math.max(1, ...widths);
|
|
602421
602428
|
return Math.max(0.12, Math.min(1.6, lines.length / maxWidth));
|
|
602422
602429
|
}
|
|
602423
|
-
function fitDashboardPane(lines, paneWidth, paneHeight) {
|
|
602424
|
-
const source = lines.length > 0 ? lines : [
|
|
602430
|
+
function fitDashboardPane(lines, paneWidth, paneHeight, fallback) {
|
|
602431
|
+
const source = lines.length > 0 ? lines : [fallback];
|
|
602425
602432
|
const normalized = [];
|
|
602426
602433
|
for (let i2 = 0; i2 < paneHeight; i2++) {
|
|
602427
602434
|
const sourceIndex = source.length <= paneHeight ? i2 : Math.min(source.length - 1, Math.floor(i2 * source.length / paneHeight));
|
|
@@ -602430,6 +602437,31 @@ function fitDashboardPane(lines, paneWidth, paneHeight) {
|
|
|
602430
602437
|
while (normalized.length < paneHeight) normalized.push(" ".repeat(paneWidth));
|
|
602431
602438
|
return normalized;
|
|
602432
602439
|
}
|
|
602440
|
+
function liveDashboardPaneLayout(width, cameraCount) {
|
|
602441
|
+
const innerWidth = Math.max(10, width - 2);
|
|
602442
|
+
const paneCount = Math.max(1, Math.min(cameraCount || 1, width >= 92 ? 2 : 1));
|
|
602443
|
+
const gutter = paneCount - 1;
|
|
602444
|
+
const paneWidth = Math.max(28, Math.floor((innerWidth - gutter) / paneCount));
|
|
602445
|
+
return { innerWidth, paneCount, paneWidth, paneContentWidth: Math.max(10, paneWidth - 2) };
|
|
602446
|
+
}
|
|
602447
|
+
function liveDashboardPreviewWidthForSources(sourceCount, termWidth = process.stdout.columns || 100) {
|
|
602448
|
+
const { paneContentWidth } = liveDashboardPaneLayout(Math.max(60, termWidth), sourceCount);
|
|
602449
|
+
return Math.max(42, Math.min(120, paneContentWidth));
|
|
602450
|
+
}
|
|
602451
|
+
function formatCameraPane(camera, paneWidth, paneHeight, now2) {
|
|
602452
|
+
const contentWidth = Math.max(10, paneWidth - 2);
|
|
602453
|
+
const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
|
|
602454
|
+
const title = `${compactSourceId(camera.source)} ${age}s`;
|
|
602455
|
+
const topTitle = ` ${title} `;
|
|
602456
|
+
const left = Math.max(0, Math.floor((contentWidth - topTitle.length) / 2));
|
|
602457
|
+
const right = Math.max(0, contentWidth - topTitle.length - left);
|
|
602458
|
+
const top = `╭${"─".repeat(left)}${topTitle.slice(0, contentWidth)}${"─".repeat(right)}╮`;
|
|
602459
|
+
const bottom = `╰${"─".repeat(contentWidth)}╯`;
|
|
602460
|
+
const previewLines = dashboardPreviewLines(camera);
|
|
602461
|
+
const fallback = camera.framePath ? "preview refreshing" : camera.error ? "capture failed" : "awaiting frame";
|
|
602462
|
+
const body = fitDashboardPane(previewLines, contentWidth, paneHeight, fallback);
|
|
602463
|
+
return [top, ...body.map((line) => `│${truncateCell(line, contentWidth)}│`), bottom];
|
|
602464
|
+
}
|
|
602433
602465
|
function pushDashboardWrapped(lines, value2, width) {
|
|
602434
602466
|
const contentWidth = Math.max(10, width - 2);
|
|
602435
602467
|
const words = stripDashboardAnsi(value2).replace(/\s+/g, " ").trim().split(" ").filter(Boolean);
|
|
@@ -602457,6 +602489,160 @@ function isAudioFailureText(value2) {
|
|
|
602457
602489
|
if (!text2) return false;
|
|
602458
602490
|
return /^(?:ASR|VAD|Transcription)\s+(?:failed|unavailable)|No module named ['"]?transcribe_cli|torchcodec|torchaudio version/i.test(text2);
|
|
602459
602491
|
}
|
|
602492
|
+
function readPcm16WavActivity(filePath, bins = 36) {
|
|
602493
|
+
try {
|
|
602494
|
+
const buf = readFileSync88(filePath);
|
|
602495
|
+
if (buf.length < 44 || buf.toString("ascii", 0, 4) !== "RIFF" || buf.toString("ascii", 8, 12) !== "WAVE") return void 0;
|
|
602496
|
+
let offset = 12;
|
|
602497
|
+
let channels = 1;
|
|
602498
|
+
let bitsPerSample = 16;
|
|
602499
|
+
let dataStart = -1;
|
|
602500
|
+
let dataSize = 0;
|
|
602501
|
+
while (offset + 8 <= buf.length) {
|
|
602502
|
+
const id2 = buf.toString("ascii", offset, offset + 4);
|
|
602503
|
+
const size = buf.readUInt32LE(offset + 4);
|
|
602504
|
+
const start2 = offset + 8;
|
|
602505
|
+
if (id2 === "fmt " && start2 + 16 <= buf.length) {
|
|
602506
|
+
channels = Math.max(1, buf.readUInt16LE(start2 + 2));
|
|
602507
|
+
bitsPerSample = buf.readUInt16LE(start2 + 14);
|
|
602508
|
+
} else if (id2 === "data") {
|
|
602509
|
+
dataStart = start2;
|
|
602510
|
+
dataSize = Math.min(size, buf.length - start2);
|
|
602511
|
+
break;
|
|
602512
|
+
}
|
|
602513
|
+
offset = start2 + size + size % 2;
|
|
602514
|
+
}
|
|
602515
|
+
if (dataStart < 0 || dataSize <= 0 || bitsPerSample !== 16) return void 0;
|
|
602516
|
+
const frameBytes = channels * 2;
|
|
602517
|
+
const frames = Math.floor(dataSize / frameBytes);
|
|
602518
|
+
if (frames <= 0) return void 0;
|
|
602519
|
+
let sumSquares = 0;
|
|
602520
|
+
let peak = 0;
|
|
602521
|
+
let active = 0;
|
|
602522
|
+
const bucketSquares = new Array(Math.max(1, bins)).fill(0);
|
|
602523
|
+
const bucketCounts = new Array(Math.max(1, bins)).fill(0);
|
|
602524
|
+
for (let i2 = 0; i2 < frames; i2++) {
|
|
602525
|
+
let sampleSum = 0;
|
|
602526
|
+
for (let ch = 0; ch < channels; ch++) {
|
|
602527
|
+
sampleSum += buf.readInt16LE(dataStart + i2 * frameBytes + ch * 2) / 32768;
|
|
602528
|
+
}
|
|
602529
|
+
const sample = sampleSum / channels;
|
|
602530
|
+
const abs = Math.abs(sample);
|
|
602531
|
+
peak = Math.max(peak, abs);
|
|
602532
|
+
sumSquares += sample * sample;
|
|
602533
|
+
if (abs > 0.018) active++;
|
|
602534
|
+
const b = Math.min(bucketSquares.length - 1, Math.floor(i2 / frames * bucketSquares.length));
|
|
602535
|
+
bucketSquares[b] += sample * sample;
|
|
602536
|
+
bucketCounts[b] += 1;
|
|
602537
|
+
}
|
|
602538
|
+
const rms = Math.sqrt(sumSquares / frames);
|
|
602539
|
+
const chars = "▁▂▃▄▅▆▇█";
|
|
602540
|
+
const waveform = bucketSquares.map((sum, idx) => {
|
|
602541
|
+
const count = Math.max(1, bucketCounts[idx] ?? 1);
|
|
602542
|
+
const level = Math.sqrt(sum / count);
|
|
602543
|
+
const normalized = Math.max(0, Math.min(1, level / Math.max(0.02, peak || 0.02)));
|
|
602544
|
+
return chars[Math.min(chars.length - 1, Math.round(normalized * (chars.length - 1)))] ?? "▁";
|
|
602545
|
+
}).join("");
|
|
602546
|
+
return {
|
|
602547
|
+
rms: Number(rms.toFixed(4)),
|
|
602548
|
+
peak: Number(peak.toFixed(4)),
|
|
602549
|
+
rmsDb: Number((20 * Math.log10(Math.max(1e-6, rms))).toFixed(1)),
|
|
602550
|
+
activeRatio: Number((active / frames).toFixed(3)),
|
|
602551
|
+
waveform
|
|
602552
|
+
};
|
|
602553
|
+
} catch {
|
|
602554
|
+
return void 0;
|
|
602555
|
+
}
|
|
602556
|
+
}
|
|
602557
|
+
function extractAsrBackend(output) {
|
|
602558
|
+
const match = String(output ?? "").match(/^Backend:\s*(.+)$/m);
|
|
602559
|
+
if (!match?.[1]) return void 0;
|
|
602560
|
+
const backend = match[1].trim();
|
|
602561
|
+
if (/managed openai-whisper|transcribe-cli|whisper/i.test(backend)) return backend;
|
|
602562
|
+
return backend.slice(0, 80);
|
|
602563
|
+
}
|
|
602564
|
+
function parseLiveAudioIntakeDecision(value2) {
|
|
602565
|
+
const parsed = parseJsonObjectFromText(value2);
|
|
602566
|
+
if (!parsed) return null;
|
|
602567
|
+
const intended = parsed["intended_for_agent"] ?? parsed["intendedForAgent"] ?? parsed["addressed_to_agent"];
|
|
602568
|
+
const confidence2 = Math.max(0, Math.min(1, Number(parsed["confidence"] ?? 0)));
|
|
602569
|
+
if (typeof intended !== "boolean" || !Number.isFinite(confidence2)) return null;
|
|
602570
|
+
const actionRaw = String(parsed["action"] ?? (intended ? "respond" : "ignore")).toLowerCase();
|
|
602571
|
+
const action = actionRaw === "respond" || actionRaw === "monitor" || actionRaw === "ignore" ? actionRaw : intended ? "respond" : "ignore";
|
|
602572
|
+
return {
|
|
602573
|
+
intendedForAgent: intended,
|
|
602574
|
+
confidence: confidence2,
|
|
602575
|
+
action,
|
|
602576
|
+
reason: trimOneLine(parsed["reason"] ?? "", 220) || "intake classifier decision"
|
|
602577
|
+
};
|
|
602578
|
+
}
|
|
602579
|
+
function fallbackLiveAudioIntakeDecision(transcript) {
|
|
602580
|
+
const text2 = transcript.toLowerCase();
|
|
602581
|
+
const addressed = /\b(omnius|hey\s+omnius|assistant|agent|computer)\b/.test(text2) || /\?$/.test(transcript.trim());
|
|
602582
|
+
return {
|
|
602583
|
+
intendedForAgent: addressed,
|
|
602584
|
+
confidence: addressed ? 0.58 : 0.35,
|
|
602585
|
+
action: addressed ? "respond" : "monitor",
|
|
602586
|
+
reason: addressed ? "fallback detected direct address or question shape" : "fallback could not establish that ambient speech was addressed to Omnius"
|
|
602587
|
+
};
|
|
602588
|
+
}
|
|
602589
|
+
async function classifyLiveAudioIntake(transcript, config) {
|
|
602590
|
+
const now2 = Date.now();
|
|
602591
|
+
const clean5 = transcript.trim();
|
|
602592
|
+
if (!clean5) {
|
|
602593
|
+
return {
|
|
602594
|
+
intendedForAgent: false,
|
|
602595
|
+
confidence: 1,
|
|
602596
|
+
action: "ignore",
|
|
602597
|
+
reason: "empty transcript",
|
|
602598
|
+
source: "fallback",
|
|
602599
|
+
updatedAt: now2
|
|
602600
|
+
};
|
|
602601
|
+
}
|
|
602602
|
+
if (config?.backendUrl && config.model) {
|
|
602603
|
+
const url = `${config.backendUrl.replace(/\/+$/, "")}/v1/chat/completions`;
|
|
602604
|
+
const body = {
|
|
602605
|
+
model: config.model,
|
|
602606
|
+
temperature: 0,
|
|
602607
|
+
max_tokens: 180,
|
|
602608
|
+
think: false,
|
|
602609
|
+
messages: [
|
|
602610
|
+
{
|
|
602611
|
+
role: "system",
|
|
602612
|
+
content: [
|
|
602613
|
+
"You are a live-audio intake classifier for Omnius.",
|
|
602614
|
+
"Decide whether a transcribed utterance is intended for the agent or is ambient/background speech.",
|
|
602615
|
+
'Return only JSON: {"intended_for_agent": boolean, "confidence": 0.0-1.0, "action": "respond"|"ignore"|"monitor", "reason": "brief evidence"}.',
|
|
602616
|
+
"Do not answer the utterance. Do not treat all room speech as addressed to the agent."
|
|
602617
|
+
].join("\n")
|
|
602618
|
+
},
|
|
602619
|
+
{ role: "user", content: clean5.slice(0, 1200) }
|
|
602620
|
+
]
|
|
602621
|
+
};
|
|
602622
|
+
try {
|
|
602623
|
+
const controller = new AbortController();
|
|
602624
|
+
const timer = setTimeout(() => controller.abort(), 6e3).unref();
|
|
602625
|
+
const resp = await fetch(url, {
|
|
602626
|
+
method: "POST",
|
|
602627
|
+
headers: {
|
|
602628
|
+
"Content-Type": "application/json",
|
|
602629
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
602630
|
+
},
|
|
602631
|
+
body: JSON.stringify(body),
|
|
602632
|
+
signal: controller.signal
|
|
602633
|
+
});
|
|
602634
|
+
clearTimeout(timer);
|
|
602635
|
+
if (resp.ok) {
|
|
602636
|
+
const json = await resp.json();
|
|
602637
|
+
const content = json.choices?.[0]?.message?.content ?? "";
|
|
602638
|
+
const parsed = parseLiveAudioIntakeDecision(content);
|
|
602639
|
+
if (parsed) return { ...parsed, source: "intake-agent", updatedAt: now2 };
|
|
602640
|
+
}
|
|
602641
|
+
} catch {
|
|
602642
|
+
}
|
|
602643
|
+
}
|
|
602644
|
+
return { ...fallbackLiveAudioIntakeDecision(clean5), source: "fallback", updatedAt: now2 };
|
|
602645
|
+
}
|
|
602460
602646
|
function summarizeInference(value2) {
|
|
602461
602647
|
if (!value2) return "objects: pending";
|
|
602462
602648
|
const lines = value2.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
@@ -602491,24 +602677,18 @@ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
|
|
|
602491
602677
|
}
|
|
602492
602678
|
if (cameras.length > 0) {
|
|
602493
602679
|
lines.push(`├${horizontal}┤`);
|
|
602494
|
-
const
|
|
602495
|
-
const innerWidth = width - 2;
|
|
602496
|
-
const gutter = paneCount - 1;
|
|
602497
|
-
const paneWidth = Math.max(24, Math.floor((innerWidth - gutter) / paneCount));
|
|
602680
|
+
const { innerWidth, paneCount, paneWidth, paneContentWidth } = liveDashboardPaneLayout(width, cameras.length);
|
|
602498
602681
|
for (let start2 = 0; start2 < cameras.length; start2 += paneCount) {
|
|
602499
602682
|
const group = cameras.slice(start2, start2 + paneCount);
|
|
602500
602683
|
const sourceLines = group.map((camera) => dashboardPreviewLines(camera));
|
|
602501
|
-
const
|
|
602502
|
-
const
|
|
602503
|
-
|
|
602684
|
+
const aspect = Math.max(0.22, Math.min(0.7, Math.max(...sourceLines.map(dashboardPreviewAspect))));
|
|
602685
|
+
const paneHeight = Math.max(10, Math.min(32, Math.round(paneContentWidth * aspect)));
|
|
602686
|
+
const panes = group.map((camera) => formatCameraPane(camera, paneWidth, paneHeight, now2));
|
|
602687
|
+
const rowCount = Math.max(...panes.map((pane) => pane.length));
|
|
602688
|
+
for (let row = 0; row < rowCount; row++) {
|
|
602504
602689
|
const body = panes.map((pane) => pane[row] ?? " ".repeat(paneWidth)).join(" ");
|
|
602505
602690
|
lines.push(`│${truncateCell(body, innerWidth)}│`);
|
|
602506
602691
|
}
|
|
602507
|
-
const labels = group.map((camera) => {
|
|
602508
|
-
const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
|
|
602509
|
-
return centerDashboardCell(`${compactSourceId(camera.source)} age=${age}s`, paneWidth);
|
|
602510
|
-
}).join(" ");
|
|
602511
|
-
lines.push(`│${truncateCell(labels, innerWidth)}│`);
|
|
602512
602692
|
}
|
|
602513
602693
|
}
|
|
602514
602694
|
if (cameras.length > 0) {
|
|
@@ -602535,11 +602715,13 @@ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
|
|
|
602535
602715
|
const audioError = [snapshot.audio.error, transcriptFailure].filter(Boolean).join(" | ");
|
|
602536
602716
|
const audioBits = [
|
|
602537
602717
|
`audio input=${snapshot.audio.input || snapshot.config.selectedAudioInput || "none"}`,
|
|
602718
|
+
snapshot.audio.activity ? `activity ${snapshot.audio.activity.waveform} rms=${snapshot.audio.activity.rmsDb.toFixed(1)}dB active=${Math.round(snapshot.audio.activity.activeRatio * 100)}%` : "",
|
|
602538
602719
|
audioError ? `error=${trimOneLine(audioError, 120)}` : "",
|
|
602539
|
-
transcript ? `asr=${trimOneLine(transcript, 120)}` : "",
|
|
602720
|
+
transcript ? `asr${snapshot.audio.asrBackend ? `(${snapshot.audio.asrBackend})` : ""}=${trimOneLine(transcript, 120)}` : "",
|
|
602721
|
+
snapshot.audio.intake ? `intake=${snapshot.audio.intake.intendedForAgent ? "for-agent" : "ambient"} conf=${snapshot.audio.intake.confidence.toFixed(2)} ${snapshot.audio.intake.action}` : "",
|
|
602540
602722
|
snapshot.audio.analysis ? `sound=${trimOneLine(snapshot.audio.analysis, 120)}` : ""
|
|
602541
602723
|
].filter(Boolean);
|
|
602542
|
-
for (const item of audioBits.slice(0,
|
|
602724
|
+
for (const item of audioBits.slice(0, 6)) lines.push(`│${truncateCell(` ${item}`, width - 2)}│`);
|
|
602543
602725
|
}
|
|
602544
602726
|
lines.push(`╰${horizontal}╯`);
|
|
602545
602727
|
return lines;
|
|
@@ -602909,10 +603091,17 @@ function formatLiveSensorContextFromSnapshot(snapshot, opts = {}) {
|
|
|
602909
603091
|
lines.push(`timestamp: ${nowIso3(snapshot.audio.updatedAt)} age=${Math.max(0, Math.round(age / 1e3))}s${age > maxAgeMs ? " STALE" : ""}`);
|
|
602910
603092
|
if (audioError) lines.push(`error: ${audioError}`);
|
|
602911
603093
|
if (snapshot.audio.recordingPath) lines.push(`recording: ${snapshot.audio.recordingPath}`);
|
|
603094
|
+
if (snapshot.audio.activity) {
|
|
603095
|
+
lines.push(`activity: ${snapshot.audio.activity.waveform} rms_db=${snapshot.audio.activity.rmsDb.toFixed(1)} peak=${snapshot.audio.activity.peak.toFixed(3)} active=${Math.round(snapshot.audio.activity.activeRatio * 100)}%`);
|
|
603096
|
+
}
|
|
602912
603097
|
if (transcript) {
|
|
602913
|
-
lines.push(
|
|
603098
|
+
lines.push(`Live ASR${snapshot.audio.asrBackend ? ` (${snapshot.audio.asrBackend})` : ""}:`);
|
|
602914
603099
|
lines.push(cleanPreview(transcript, 1200));
|
|
602915
603100
|
}
|
|
603101
|
+
if (snapshot.audio.intake) {
|
|
603102
|
+
lines.push(`Live audio intake: intended_for_agent=${snapshot.audio.intake.intendedForAgent ? "true" : "false"} confidence=${snapshot.audio.intake.confidence.toFixed(2)} action=${snapshot.audio.intake.action} source=${snapshot.audio.intake.source}`);
|
|
603103
|
+
lines.push(`intake_reason: ${snapshot.audio.intake.reason}`);
|
|
603104
|
+
}
|
|
602916
603105
|
if (snapshot.audio.analysis) {
|
|
602917
603106
|
lines.push("Live sound analysis:");
|
|
602918
603107
|
lines.push(cleanPreview(snapshot.audio.analysis, 1600));
|
|
@@ -603174,6 +603363,7 @@ var init_live_sensors = __esm({
|
|
|
603174
603363
|
lastAgentReviewAt = 0;
|
|
603175
603364
|
autoOrientationInFlight = /* @__PURE__ */ new Set();
|
|
603176
603365
|
lastFeedbackAt = /* @__PURE__ */ new Map();
|
|
603366
|
+
intakeAgentConfig;
|
|
603177
603367
|
setStatusSink(sink) {
|
|
603178
603368
|
this.statusSink = sink ?? null;
|
|
603179
603369
|
this.emitStatus();
|
|
@@ -603184,6 +603374,9 @@ var init_live_sensors = __esm({
|
|
|
603184
603374
|
setAgentActionSink(sink) {
|
|
603185
603375
|
this.agentActionSink = sink ?? null;
|
|
603186
603376
|
}
|
|
603377
|
+
setAudioIntakeAgentConfig(config) {
|
|
603378
|
+
this.intakeAgentConfig = config && config.backendUrl && config.model ? { backendUrl: config.backendUrl, model: config.model, apiKey: config.apiKey } : void 0;
|
|
603379
|
+
}
|
|
603187
603380
|
getConfig() {
|
|
603188
603381
|
return { ...this.config };
|
|
603189
603382
|
}
|
|
@@ -603479,7 +603672,7 @@ var init_live_sensors = __esm({
|
|
|
603479
603672
|
const framePath = extractSavedImagePath(result.output, this.repoRoot);
|
|
603480
603673
|
if (!framePath) return { ok: false, message: "Camera capture succeeded but no saved image path was returned." };
|
|
603481
603674
|
const displayPath = relative11(this.repoRoot, framePath).startsWith("..") ? framePath : relative11(this.repoRoot, framePath);
|
|
603482
|
-
const previewWidth = Math.max(
|
|
603675
|
+
const previewWidth = Math.max(42, Math.min(120, Math.floor(Number(options2.previewWidth ?? (process.stdout.columns || 100) - 14))));
|
|
603483
603676
|
const preview = await buildImageAsciiPreview(framePath, { width: previewWidth });
|
|
603484
603677
|
const asciiContext = preview ? formatImageAsciiContext(preview, displayPath) : void 0;
|
|
603485
603678
|
const observedAt = Date.now();
|
|
@@ -603523,6 +603716,7 @@ var init_live_sensors = __esm({
|
|
|
603523
603716
|
imagePath: framePath,
|
|
603524
603717
|
displayPath,
|
|
603525
603718
|
ascii: preview?.ascii,
|
|
603719
|
+
plainAscii: preview?.plainAscii,
|
|
603526
603720
|
renderer: preview?.renderer
|
|
603527
603721
|
});
|
|
603528
603722
|
}
|
|
@@ -603532,6 +603726,7 @@ var init_live_sensors = __esm({
|
|
|
603532
603726
|
framePath,
|
|
603533
603727
|
displayPath,
|
|
603534
603728
|
ascii: preview?.ascii,
|
|
603729
|
+
plainAscii: preview?.plainAscii,
|
|
603535
603730
|
renderer: preview?.renderer
|
|
603536
603731
|
};
|
|
603537
603732
|
}
|
|
@@ -603577,8 +603772,8 @@ var init_live_sensors = __esm({
|
|
|
603577
603772
|
return message2;
|
|
603578
603773
|
}
|
|
603579
603774
|
}
|
|
603580
|
-
async sampleSingleVideoNow(source, forceInfer) {
|
|
603581
|
-
const preview = await this.previewCamera(source, { emit: false });
|
|
603775
|
+
async sampleSingleVideoNow(source, forceInfer, previewWidth) {
|
|
603776
|
+
const preview = await this.previewCamera(source, { emit: false, previewWidth });
|
|
603582
603777
|
let inference = "";
|
|
603583
603778
|
let clipSummary = "";
|
|
603584
603779
|
const orientation = this.getCameraOrientation(source);
|
|
@@ -603667,8 +603862,9 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
|
|
|
603667
603862
|
const sources = this.activeVideoSources();
|
|
603668
603863
|
if (sources.length === 0) return "No camera selected. Use /live refresh after connecting hardware.";
|
|
603669
603864
|
const outputs = [];
|
|
603865
|
+
const previewWidth = liveDashboardPreviewWidthForSources(sources.length);
|
|
603670
603866
|
for (const source of sources) {
|
|
603671
|
-
outputs.push(await this.sampleSingleVideoNow(source, forceInfer));
|
|
603867
|
+
outputs.push(await this.sampleSingleVideoNow(source, forceInfer, previewWidth));
|
|
603672
603868
|
}
|
|
603673
603869
|
this.emitDashboard();
|
|
603674
603870
|
return outputs.map((output, index) => `## Camera ${sources[index]}
|
|
@@ -603686,7 +603882,9 @@ ${output}`).join("\n\n");
|
|
|
603686
603882
|
ensureLiveDir(this.repoRoot);
|
|
603687
603883
|
const recordingPath = join124(outputDir2, `audio-${Date.now()}.wav`);
|
|
603688
603884
|
let transcript = "";
|
|
603885
|
+
let asrBackend = "";
|
|
603689
603886
|
let analysis = "";
|
|
603887
|
+
let intake;
|
|
603690
603888
|
const audioErrors = [];
|
|
603691
603889
|
const capture = await recordAudioSampleWithRecovery(input, this.devices.audioInputs, 3, recordingPath);
|
|
603692
603890
|
if (!capture.ok) {
|
|
@@ -603710,11 +603908,13 @@ ${output}`).join("\n\n");
|
|
|
603710
603908
|
if (capture.device !== this.config.selectedAudioInput) {
|
|
603711
603909
|
this.config.selectedAudioInput = capture.device;
|
|
603712
603910
|
}
|
|
603911
|
+
const activity = readPcm16WavActivity(recordingPath);
|
|
603713
603912
|
if (this.config.asrEnabled) {
|
|
603714
603913
|
try {
|
|
603715
603914
|
const asr = await new TranscribeFileTool(this.repoRoot).execute({ path: recordingPath, model: "tiny" });
|
|
603716
603915
|
if (asr.success) {
|
|
603717
603916
|
transcript = cleanPreview(typeof asr.llmContent === "string" ? asr.llmContent : "", 1600);
|
|
603917
|
+
asrBackend = extractAsrBackend(asr.output) ?? "whisper";
|
|
603718
603918
|
} else {
|
|
603719
603919
|
audioErrors.push(`ASR unavailable: ${asr.error || asr.output || "unknown error"}`);
|
|
603720
603920
|
}
|
|
@@ -603740,13 +603940,19 @@ ${output}`).join("\n\n");
|
|
|
603740
603940
|
}
|
|
603741
603941
|
analysis = parts.filter(Boolean).join("\n");
|
|
603742
603942
|
}
|
|
603943
|
+
if (transcript) {
|
|
603944
|
+
intake = await classifyLiveAudioIntake(transcript, this.intakeAgentConfig);
|
|
603945
|
+
}
|
|
603743
603946
|
this.snapshot.audio = {
|
|
603744
603947
|
updatedAt: Date.now(),
|
|
603745
603948
|
input: capture.device,
|
|
603746
603949
|
output: this.config.selectedAudioOutput,
|
|
603747
603950
|
recordingPath,
|
|
603748
603951
|
transcript,
|
|
603952
|
+
asrBackend: asrBackend || void 0,
|
|
603749
603953
|
analysis,
|
|
603954
|
+
activity,
|
|
603955
|
+
intake,
|
|
603750
603956
|
error: audioErrors.length > 0 ? audioErrors.join("\n") : void 0
|
|
603751
603957
|
};
|
|
603752
603958
|
const audioEvents = [];
|
|
@@ -603774,12 +603980,20 @@ ${output}`).join("\n\n");
|
|
|
603774
603980
|
}
|
|
603775
603981
|
this.snapshot.events = mergeRecentById(this.snapshot.events, audioEvents, 50);
|
|
603776
603982
|
this.persist();
|
|
603983
|
+
if (transcript && intake?.intendedForAgent) {
|
|
603984
|
+
this.maybeRequestAgentReview(
|
|
603985
|
+
"Live audio intake classified speech as intended for Omnius",
|
|
603986
|
+
`transcript=${transcript}; confidence=${intake.confidence.toFixed(2)}; reason=${intake.reason}`
|
|
603987
|
+
);
|
|
603988
|
+
}
|
|
603777
603989
|
this.emitDashboard();
|
|
603778
603990
|
return [
|
|
603779
603991
|
`Audio sample captured from ${capture.device}${capture.device !== input ? ` (recovered from ${input})` : ""}: ${recordingPath}`,
|
|
603780
603992
|
transcript ? `
|
|
603781
|
-
ASR:
|
|
603993
|
+
ASR${asrBackend ? ` (${asrBackend})` : ""}:
|
|
603782
603994
|
${transcript}` : "",
|
|
603995
|
+
intake ? `
|
|
603996
|
+
Intake: ${intake.intendedForAgent ? "intended for agent" : "ambient/monitor"} confidence=${intake.confidence.toFixed(2)} (${intake.source})` : "",
|
|
603783
603997
|
analysis ? `
|
|
603784
603998
|
Sound analysis:
|
|
603785
603999
|
${analysis}` : ""
|
|
@@ -624395,15 +624609,6 @@ var init_status_bar = __esm({
|
|
|
624395
624609
|
const cmdPrefix = cmd.startsWith("view:") ? "omnius-view:" + cmd.slice(5) : "omnius-cmd:" + cmd;
|
|
624396
624610
|
return `\x1B]8;;${cmdPrefix}\x07${label}\x1B]8;;\x07`;
|
|
624397
624611
|
};
|
|
624398
|
-
const buttonFg = (cmd) => {
|
|
624399
|
-
let fg2 = TEXT_DIM;
|
|
624400
|
-
if (cmd === "voice" && this._voiceActive) fg2 = 82;
|
|
624401
|
-
if (cmd.startsWith("live") && (this._liveMediaStatus.audio || this._liveMediaStatus.video)) fg2 = 82;
|
|
624402
|
-
if (cmd === "nexus") {
|
|
624403
|
-
fg2 = this._nexusStatus === "connected" ? 82 : this._nexusStatus === "connecting" ? 208 : 196;
|
|
624404
|
-
}
|
|
624405
|
-
return fg2;
|
|
624406
|
-
};
|
|
624407
624612
|
const decorateMenuButton = (cmd, label) => {
|
|
624408
624613
|
return `${HEADER_BUTTON_GLYPH_FG}${HEADER_BUTTON_LEFT}\x1B[0m${HEADER_BUTTON_BG}${HEADER_BUTTON_FG}${label}\x1B[0m${PANEL_BG_SEQ}${HEADER_BUTTON_GLYPH_FG}${HEADER_BUTTON_RIGHT}\x1B[0m${PANEL_BG_SEQ}`;
|
|
624409
624614
|
};
|
|
@@ -624414,14 +624619,7 @@ var init_status_bar = __esm({
|
|
|
624414
624619
|
return `\x1B[38;5;${color}m${HEADER_BUTTON_LEFT}\x1B[0m${weight}${fg2}${bg}${content}\x1B[0m${PANEL_BG_SEQ}\x1B[38;5;${color}m${HEADER_BUTTON_RIGHT}\x1B[0m${PANEL_BG_SEQ}`;
|
|
624415
624620
|
};
|
|
624416
624621
|
const renderBtn = (cmd, label) => {
|
|
624417
|
-
|
|
624418
|
-
const btnW = label.length + 2;
|
|
624419
|
-
const availW2 = getTermWidth() - identity3.width - 1;
|
|
624420
|
-
if (btnW > availW2) return linkify(cmd, `\x1B[38;5;${fg2}m${label}`);
|
|
624421
|
-
return linkify(
|
|
624422
|
-
cmd,
|
|
624423
|
-
`${PANEL_BG_SEQ}${HEADER_BUTTON_GLYPH_FG}${HEADER_BUTTON_LEFT}\x1B[0m${PANEL_BG_SEQ}\x1B[38;5;${fg2}m${label}\x1B[0m${PANEL_BG_SEQ}${HEADER_BUTTON_GLYPH_FG}${HEADER_BUTTON_RIGHT}\x1B[0m${PANEL_BG_SEQ}`
|
|
624424
|
-
);
|
|
624622
|
+
return linkify(cmd, decorateMenuButton(cmd, label));
|
|
624425
624623
|
};
|
|
624426
624624
|
const identity3 = this.buildHeaderIdentityRender();
|
|
624427
624625
|
const modelLabel = this.summarizeHeaderModelName() || "model";
|
|
@@ -624494,10 +624692,9 @@ var init_status_bar = __esm({
|
|
|
624494
624692
|
};
|
|
624495
624693
|
if (this._activeViewId !== "main") {
|
|
624496
624694
|
const mainLabel = ` ↩ main `;
|
|
624497
|
-
const mainColored = `\x1B[38;5;110m${mainLabel}\x1B[0m`;
|
|
624498
624695
|
sysItems.push({
|
|
624499
|
-
render: () =>
|
|
624500
|
-
w: mainLabel.length + 1
|
|
624696
|
+
render: () => linkify("view:main", decorateMenuButton("view:main", mainLabel)) + " ",
|
|
624697
|
+
w: mainLabel.length + 2 + 1
|
|
624501
624698
|
});
|
|
624502
624699
|
}
|
|
624503
624700
|
if (this._agentViews.size > 1) {
|
|
@@ -624535,10 +624732,7 @@ var init_status_bar = __esm({
|
|
|
624535
624732
|
const telegramDot = this._telegramStatus.active ? "●" : "○";
|
|
624536
624733
|
const telegramLabel = this._telegramStatus.activeSubAgents > 0 ? ` ✈ tg ${this._telegramStatus.activeSubAgents} ` : " ✈ tg ";
|
|
624537
624734
|
sysItems.push({
|
|
624538
|
-
render: () => renderBtn(
|
|
624539
|
-
"telegram",
|
|
624540
|
-
`${HEADER_TELEGRAM_FG}${telegramDot}${telegramLabel}\x1B[0m`
|
|
624541
|
-
) + " ",
|
|
624735
|
+
render: () => renderBtn("telegram", `${telegramDot}${telegramLabel}`) + " ",
|
|
624542
624736
|
w: telegramLabel.length + 2
|
|
624543
624737
|
});
|
|
624544
624738
|
const liveMediaActive = this._liveMediaStatus.audio || this._liveMediaStatus.video;
|
|
@@ -624683,7 +624877,7 @@ var init_status_bar = __esm({
|
|
|
624683
624877
|
const trunc3 = (s2) => s2.trim().split(/\s+/).slice(0, 3).join(" ");
|
|
624684
624878
|
if (this._activeViewId !== "main") {
|
|
624685
624879
|
const mainLabel = ` ↩ main `;
|
|
624686
|
-
zones.push({ w: mainLabel.length + 1, id: "main", render: () => "" });
|
|
624880
|
+
zones.push({ w: mainLabel.length + 2 + 1, id: "main", render: () => "" });
|
|
624687
624881
|
}
|
|
624688
624882
|
if (this._agentViews.size > 1) {
|
|
624689
624883
|
for (const view of this._agentViews.values()) {
|
|
@@ -655606,6 +655800,11 @@ ${feedback.message}`);
|
|
|
655606
655800
|
function attachLiveSinks(ctx3, manager, agentEnabled = false) {
|
|
655607
655801
|
manager.setStatusSink(ctx3.setLiveMediaStatus);
|
|
655608
655802
|
manager.setFeedbackSink((feedback) => renderLiveFeedback(ctx3, manager, feedback));
|
|
655803
|
+
manager.setAudioIntakeAgentConfig({
|
|
655804
|
+
backendUrl: ctx3.config.backendUrl,
|
|
655805
|
+
model: ctx3.config.model,
|
|
655806
|
+
apiKey: ctx3.config.apiKey
|
|
655807
|
+
});
|
|
655609
655808
|
if (agentEnabled && ctx3.startBackgroundPrompt) {
|
|
655610
655809
|
manager.setAgentActionSink((prompt) => {
|
|
655611
655810
|
const id2 = ctx3.startBackgroundPrompt?.(prompt);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.410",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.410",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED