@absolutejs/voice 0.0.22-beta.180 → 0.0.22-beta.181
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 +56 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10059,8 +10059,24 @@ var summarizeVoiceBargeIn = (events, options = {}) => {
|
|
|
10059
10059
|
};
|
|
10060
10060
|
var renderVoiceBargeInHTML = (report, options = {}) => {
|
|
10061
10061
|
const title = options.title ?? "Voice Barge-In";
|
|
10062
|
+
const snippet = `const traceStore = createVoiceMemoryTraceEventStore();
|
|
10063
|
+
|
|
10064
|
+
app.use(
|
|
10065
|
+
createVoiceBargeInRoutes({
|
|
10066
|
+
htmlPath: '/barge-in',
|
|
10067
|
+
path: '/api/voice-barge-in',
|
|
10068
|
+
store: traceStore,
|
|
10069
|
+
thresholdMs: 250
|
|
10070
|
+
})
|
|
10071
|
+
);
|
|
10072
|
+
|
|
10073
|
+
// Browser/runtime side:
|
|
10074
|
+
const bargeInMonitor = createVoiceBargeInMonitor({
|
|
10075
|
+
path: '/api/voice-barge-in',
|
|
10076
|
+
sessionId
|
|
10077
|
+
});`;
|
|
10062
10078
|
const sessions = report.sessions.length ? report.sessions.map((session) => `<tr><td>${escapeHtml10(session.sessionId)}</td><td>${String(session.total)}</td><td>${String(session.passed)}</td><td>${String(session.failed)}</td><td>${String(session.averageLatencyMs ?? 0)}ms</td></tr>`).join("") : '<tr><td colspan="5">No barge-in events yet.</td></tr>';
|
|
10063
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml10(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn{color:#fbbf24}.fail{color:#fca5a5}.empty{color:#cbd5e1}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}</style></head><body><main><p class="eyebrow">Interruption quality</p><h1>${escapeHtml10(title)}</h1><p class="status ${escapeHtml10(report.status)}">Status: ${escapeHtml10(report.status)}</p><section class="metrics"><article><span>Interruptions</span><strong>${String(report.total)}</strong></article><article><span>Avg latency</span><strong>${String(report.averageLatencyMs ?? 0)}ms</strong></article><article><span>Passed</span><strong>${String(report.passed)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article></section><table><thead><tr><th>Session</th><th>Total</th><th>Passed</th><th>Failed</th><th>Avg latency</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
10079
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml10(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn{color:#fbbf24}.fail{color:#fca5a5}.empty{color:#cbd5e1}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article,.primitive{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}.primitive{margin:0 0 20px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2b3642;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}</style></head><body><main><p class="eyebrow">Interruption quality</p><h1>${escapeHtml10(title)}</h1><p class="status ${escapeHtml10(report.status)}">Status: ${escapeHtml10(report.status)}</p><section class="metrics"><article><span>Interruptions</span><strong>${String(report.total)}</strong></article><article><span>Avg latency</span><strong>${String(report.averageLatencyMs ?? 0)}ms</strong></article><article><span>Passed</span><strong>${String(report.passed)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceBargeInRoutes(...)</code> proves interruption quality</h2><p>Use the shared trace store for browser interrupts, readiness gates, trace timelines, and production evidence instead of trusting a black-box hosted dashboard.</p><pre><code>${escapeHtml10(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Total</th><th>Passed</th><th>Failed</th><th>Avg latency</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
10064
10080
|
};
|
|
10065
10081
|
var createVoiceBargeInRoutes = (options) => {
|
|
10066
10082
|
const path = options.path ?? "/api/voice-barge-in";
|
|
@@ -14672,11 +14688,29 @@ var summarizeVoiceTurnLatency = async (options) => {
|
|
|
14672
14688
|
var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
14673
14689
|
var renderVoiceTurnLatencyHTML = (report, options = {}) => {
|
|
14674
14690
|
const title = options.title ?? "Voice Turn Latency";
|
|
14691
|
+
const snippet = `app.use(
|
|
14692
|
+
createVoiceTurnLatencyRoutes({
|
|
14693
|
+
failAfterMs: 3200,
|
|
14694
|
+
htmlPath: '/turn-latency',
|
|
14695
|
+
path: '/api/turn-latency',
|
|
14696
|
+
store: sessionStore,
|
|
14697
|
+
traceStore,
|
|
14698
|
+
warnAfterMs: 1800
|
|
14699
|
+
})
|
|
14700
|
+
);
|
|
14701
|
+
|
|
14702
|
+
await traceStore.append({
|
|
14703
|
+
at: Date.now(),
|
|
14704
|
+
payload: { stage: 'assistant_audio_received' },
|
|
14705
|
+
sessionId,
|
|
14706
|
+
turnId,
|
|
14707
|
+
type: 'turn_latency.stage'
|
|
14708
|
+
});`;
|
|
14675
14709
|
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml24(turn.status)}">
|
|
14676
14710
|
<header><div><p class="eyebrow">${escapeHtml24(turn.sessionId)} \xB7 ${escapeHtml24(turn.turnId)}</p><h2>${escapeHtml24(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml24(turn.status)}</strong></header>
|
|
14677
14711
|
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml24(stage.label)}</dt><dd>${escapeHtml24(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
14678
14712
|
</article>`).join("");
|
|
14679
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml24(title)}</h1><div class="summary"><span class="pill ${escapeHtml24(report.status)}">${escapeHtml24(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml24(formatMs(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
14713
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn,.primitive{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2a323a;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml24(title)}</h1><div class="summary"><span class="pill ${escapeHtml24(report.status)}">${escapeHtml24(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml24(formatMs(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTurnLatencyRoutes(...)</code> exposes the full turn waterfall</h2><p>Attach stage traces for speech detection, commit, model response, TTS send, and first audio so teams can prove where latency actually comes from.</p><pre><code>${escapeHtml24(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
14680
14714
|
};
|
|
14681
14715
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
14682
14716
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -14751,8 +14785,27 @@ var summarizeVoiceLiveLatency = async (options) => {
|
|
|
14751
14785
|
var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
14752
14786
|
var renderVoiceLiveLatencyHTML = (report, options = {}) => {
|
|
14753
14787
|
const title = options.title ?? "Voice Live Latency";
|
|
14788
|
+
const snippet = `app.use(
|
|
14789
|
+
createVoiceLiveLatencyRoutes({
|
|
14790
|
+
failAfterMs: 3200,
|
|
14791
|
+
htmlPath: '/live-latency',
|
|
14792
|
+
path: '/api/live-latency',
|
|
14793
|
+
store: traceStore,
|
|
14794
|
+
warnAfterMs: 1800
|
|
14795
|
+
})
|
|
14796
|
+
);
|
|
14797
|
+
|
|
14798
|
+
await traceStore.append({
|
|
14799
|
+
at: Date.now(),
|
|
14800
|
+
payload: {
|
|
14801
|
+
latencyMs,
|
|
14802
|
+
status: 'assistant_audio_started'
|
|
14803
|
+
},
|
|
14804
|
+
sessionId,
|
|
14805
|
+
type: 'client.live_latency'
|
|
14806
|
+
});`;
|
|
14754
14807
|
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml25(sample.sessionId)}</td><td>${escapeHtml25(formatMs2(sample.latencyMs))}</td><td>${escapeHtml25(sample.status ?? "unknown")}</td><td>${escapeHtml25(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
14755
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml25(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml25(report.status)}">Status: ${escapeHtml25(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml25(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml25(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml25(formatMs2(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
14808
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table,.primitive{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article,.primitive{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}.primitive{margin:0 0 18px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#080b10;border:1px solid #26313d;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml25(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml25(report.status)}">Status: ${escapeHtml25(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml25(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml25(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml25(formatMs2(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceLiveLatencyRoutes(...)</code> turns real browser timing into a release gate</h2><p>Persist live timing samples into the trace store so readiness, simulations, and trace timelines all point at the same self-hosted proof.</p><pre><code>${escapeHtml25(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
14756
14809
|
};
|
|
14757
14810
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
14758
14811
|
const path = options.path ?? "/api/live-latency";
|