@absolutejs/voice 0.0.22-beta.65 → 0.0.22-beta.67
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/angular/index.d.ts +2 -0
- package/dist/angular/index.js +272 -26
- package/dist/angular/voice-provider-capabilities.service.d.ts +12 -0
- package/dist/angular/voice-turn-quality.service.d.ts +12 -0
- package/dist/client/index.d.ts +8 -0
- package/dist/client/index.js +397 -0
- package/dist/client/providerCapabilities.d.ts +19 -0
- package/dist/client/providerCapabilitiesWidget.d.ts +32 -0
- package/dist/client/turnQuality.d.ts +19 -0
- package/dist/client/turnQualityWidget.d.ts +32 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +123 -2
- package/dist/react/VoiceProviderCapabilities.d.ts +6 -0
- package/dist/react/VoiceTurnQuality.d.ts +6 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +672 -83
- package/dist/react/useVoiceProviderCapabilities.d.ts +8 -0
- package/dist/react/useVoiceTurnQuality.d.ts +8 -0
- package/dist/svelte/createVoiceProviderCapabilities.d.ts +10 -0
- package/dist/svelte/createVoiceTurnQuality.d.ts +10 -0
- package/dist/svelte/index.d.ts +2 -0
- package/dist/svelte/index.js +440 -33
- package/dist/turnQuality.d.ts +94 -0
- package/dist/vue/VoiceProviderCapabilities.d.ts +51 -0
- package/dist/vue/VoiceTurnQuality.d.ts +51 -0
- package/dist/vue/index.d.ts +4 -0
- package/dist/vue/index.js +664 -84
- package/dist/vue/useVoiceProviderCapabilities.d.ts +9 -0
- package/dist/vue/useVoiceTurnQuality.d.ts +9 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10294,6 +10294,122 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
10294
10294
|
}
|
|
10295
10295
|
return routes;
|
|
10296
10296
|
};
|
|
10297
|
+
// src/turnQuality.ts
|
|
10298
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
10299
|
+
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
10300
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10301
|
+
var getTurnLatencyMs = (turn) => {
|
|
10302
|
+
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
10303
|
+
if (firstTranscriptAt === undefined) {
|
|
10304
|
+
return;
|
|
10305
|
+
}
|
|
10306
|
+
return Math.max(0, turn.committedAt - firstTranscriptAt);
|
|
10307
|
+
};
|
|
10308
|
+
var summarizeTurn = (sessionId, turn, options) => {
|
|
10309
|
+
const quality = turn.quality;
|
|
10310
|
+
const correctionChanged = quality?.correction?.changed === true;
|
|
10311
|
+
const fallbackUsed = quality?.fallbackUsed === true;
|
|
10312
|
+
const lowConfidence = typeof quality?.averageConfidence === "number" && quality.averageConfidence < options.confidenceWarnThreshold;
|
|
10313
|
+
const hasNoQuality = !quality;
|
|
10314
|
+
const status = hasNoQuality ? "unknown" : quality.selectedTranscriptCount === 0 || turn.text.trim().length === 0 ? "fail" : fallbackUsed || correctionChanged || lowConfidence ? "warn" : "pass";
|
|
10315
|
+
return {
|
|
10316
|
+
averageConfidence: quality?.averageConfidence,
|
|
10317
|
+
committedAt: turn.committedAt,
|
|
10318
|
+
correctionChanged,
|
|
10319
|
+
correctionProvider: quality?.correction?.provider,
|
|
10320
|
+
correctionReason: quality?.correction?.reason,
|
|
10321
|
+
costUnits: quality?.cost?.estimatedRelativeCostUnits,
|
|
10322
|
+
fallbackSelectionReason: quality?.fallback?.selectionReason,
|
|
10323
|
+
fallbackUsed,
|
|
10324
|
+
finalTranscriptCount: quality?.finalTranscriptCount ?? 0,
|
|
10325
|
+
latencyMs: getTurnLatencyMs(turn),
|
|
10326
|
+
partialTranscriptCount: quality?.partialTranscriptCount ?? 0,
|
|
10327
|
+
selectedTranscriptCount: quality?.selectedTranscriptCount ?? 0,
|
|
10328
|
+
sessionId,
|
|
10329
|
+
source: quality?.source,
|
|
10330
|
+
status,
|
|
10331
|
+
text: turn.text,
|
|
10332
|
+
turnId: turn.id
|
|
10333
|
+
};
|
|
10334
|
+
};
|
|
10335
|
+
var resolveSessions = async (options) => {
|
|
10336
|
+
if (options.sessions) {
|
|
10337
|
+
return options.sessions;
|
|
10338
|
+
}
|
|
10339
|
+
if (!options.store) {
|
|
10340
|
+
return [];
|
|
10341
|
+
}
|
|
10342
|
+
const summaries = await options.store.list();
|
|
10343
|
+
const ids = options.sessionIds ?? summaries.map((summary) => summary.id);
|
|
10344
|
+
const hydrated = await Promise.all(ids.slice(0, options.limit ?? 25).map((id) => options.store?.get(id)));
|
|
10345
|
+
const sessions = [];
|
|
10346
|
+
for (const session of hydrated) {
|
|
10347
|
+
if (session) {
|
|
10348
|
+
sessions.push(session);
|
|
10349
|
+
}
|
|
10350
|
+
}
|
|
10351
|
+
return sessions;
|
|
10352
|
+
};
|
|
10353
|
+
var summarizeVoiceTurnQuality = async (options) => {
|
|
10354
|
+
const sessions = await resolveSessions(options);
|
|
10355
|
+
const confidenceWarnThreshold = options.confidenceWarnThreshold ?? DEFAULT_CONFIDENCE_WARN_THRESHOLD;
|
|
10356
|
+
const turns = sessions.flatMap((session) => session.turns.map((turn) => summarizeTurn(session.id, turn, { confidenceWarnThreshold }))).sort((left, right) => right.committedAt - left.committedAt);
|
|
10357
|
+
const failed = turns.filter((turn) => turn.status === "fail").length;
|
|
10358
|
+
const warnings = turns.filter((turn) => turn.status === "warn").length;
|
|
10359
|
+
return {
|
|
10360
|
+
checkedAt: Date.now(),
|
|
10361
|
+
failed,
|
|
10362
|
+
sessions: sessions.length,
|
|
10363
|
+
status: failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
|
|
10364
|
+
total: turns.length,
|
|
10365
|
+
turns,
|
|
10366
|
+
warnings
|
|
10367
|
+
};
|
|
10368
|
+
};
|
|
10369
|
+
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
10370
|
+
const title = options.title ?? "Voice Turn Quality";
|
|
10371
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml15(turn.status)}">
|
|
10372
|
+
<div class="turn-header">
|
|
10373
|
+
<div>
|
|
10374
|
+
<p class="eyebrow">${escapeHtml15(turn.sessionId)} \xB7 ${escapeHtml15(turn.turnId)}</p>
|
|
10375
|
+
<h2>${escapeHtml15(turn.text || "Empty turn")}</h2>
|
|
10376
|
+
</div>
|
|
10377
|
+
<strong>${escapeHtml15(turn.status)}</strong>
|
|
10378
|
+
</div>
|
|
10379
|
+
<dl>
|
|
10380
|
+
<div><dt>Source</dt><dd>${escapeHtml15(turn.source ?? "unknown")}</dd></div>
|
|
10381
|
+
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
10382
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml15(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
10383
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml15(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
10384
|
+
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
10385
|
+
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
10386
|
+
</dl>
|
|
10387
|
+
</article>`).join("");
|
|
10388
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(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(251,191,36,.16),rgba(34,197,94,.1))}.eyebrow{color:#fbbf24;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,.unknown{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{margin:0}@media(max-width:800px){main{padding:18px}.turn-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime STT Debugging</p><h1>${escapeHtml15(title)}</h1><div class="summary"><span class="pill ${escapeHtml15(report.status)}">${escapeHtml15(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span><span class="pill">${String(report.sessions)} sessions</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
10389
|
+
};
|
|
10390
|
+
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
10391
|
+
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
10392
|
+
const report = await summarizeVoiceTurnQuality(options);
|
|
10393
|
+
const render = options.render ?? ((input) => renderVoiceTurnQualityHTML(input, options));
|
|
10394
|
+
const body = await render(report);
|
|
10395
|
+
return new Response(body, {
|
|
10396
|
+
headers: {
|
|
10397
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
10398
|
+
...options.headers
|
|
10399
|
+
}
|
|
10400
|
+
});
|
|
10401
|
+
};
|
|
10402
|
+
var createVoiceTurnQualityRoutes = (options) => {
|
|
10403
|
+
const path = options.path ?? "/api/turn-quality";
|
|
10404
|
+
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
10405
|
+
const routes = new Elysia14({
|
|
10406
|
+
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
10407
|
+
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
10408
|
+
if (htmlPath) {
|
|
10409
|
+
routes.get(htmlPath, createVoiceTurnQualityHTMLHandler(options));
|
|
10410
|
+
}
|
|
10411
|
+
return routes;
|
|
10412
|
+
};
|
|
10297
10413
|
// src/fileStore.ts
|
|
10298
10414
|
import { mkdir as mkdir2, readFile, readdir, rename, rm, writeFile } from "fs/promises";
|
|
10299
10415
|
import { join } from "path";
|
|
@@ -12387,7 +12503,7 @@ var createVoiceMemoryStore = () => {
|
|
|
12387
12503
|
return { get, getOrCreate, list, remove, set };
|
|
12388
12504
|
};
|
|
12389
12505
|
// src/opsWebhook.ts
|
|
12390
|
-
import { Elysia as
|
|
12506
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12391
12507
|
var toHex5 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
12392
12508
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
12393
12509
|
const encoder = new TextEncoder;
|
|
@@ -12517,7 +12633,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
12517
12633
|
};
|
|
12518
12634
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
12519
12635
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
12520
|
-
return new
|
|
12636
|
+
return new Elysia15().post(path, async ({ body, request, set }) => {
|
|
12521
12637
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
12522
12638
|
if (options.signingSecret) {
|
|
12523
12639
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -14664,6 +14780,7 @@ export {
|
|
|
14664
14780
|
validateVoiceWorkflowRouteResult,
|
|
14665
14781
|
transcodeTwilioInboundPayloadToPCM16,
|
|
14666
14782
|
transcodePCMToTwilioOutboundPayload,
|
|
14783
|
+
summarizeVoiceTurnQuality,
|
|
14667
14784
|
summarizeVoiceTraceSinkDeliveries,
|
|
14668
14785
|
summarizeVoiceTrace,
|
|
14669
14786
|
summarizeVoiceSessions,
|
|
@@ -14703,6 +14820,7 @@ export {
|
|
|
14703
14820
|
resolveAudioConditioningConfig,
|
|
14704
14821
|
requeueVoiceOpsTask,
|
|
14705
14822
|
reopenVoiceOpsTask,
|
|
14823
|
+
renderVoiceTurnQualityHTML,
|
|
14706
14824
|
renderVoiceTraceMarkdown,
|
|
14707
14825
|
renderVoiceTraceHTML,
|
|
14708
14826
|
renderVoiceToolContractHTML,
|
|
@@ -14757,6 +14875,9 @@ export {
|
|
|
14757
14875
|
createVoiceWebhookDeliveryWorkerLoop,
|
|
14758
14876
|
createVoiceWebhookDeliveryWorker,
|
|
14759
14877
|
createVoiceTwilioRedirectHandoffAdapter,
|
|
14878
|
+
createVoiceTurnQualityRoutes,
|
|
14879
|
+
createVoiceTurnQualityJSONHandler,
|
|
14880
|
+
createVoiceTurnQualityHTMLHandler,
|
|
14760
14881
|
createVoiceTraceSinkStore,
|
|
14761
14882
|
createVoiceTraceSinkDeliveryWorkerLoop,
|
|
14762
14883
|
createVoiceTraceSinkDeliveryWorker,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type VoiceProviderCapabilitiesWidgetOptions } from '../client/providerCapabilitiesWidget';
|
|
2
|
+
export type VoiceProviderCapabilitiesProps = VoiceProviderCapabilitiesWidgetOptions & {
|
|
3
|
+
className?: string;
|
|
4
|
+
path?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const VoiceProviderCapabilities: ({ className, path, ...options }: VoiceProviderCapabilitiesProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type VoiceTurnQualityWidgetOptions } from '../client/turnQualityWidget';
|
|
2
|
+
export type VoiceTurnQualityProps = VoiceTurnQualityWidgetOptions & {
|
|
3
|
+
className?: string;
|
|
4
|
+
path?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const VoiceTurnQuality: ({ className, path, ...options }: VoiceTurnQualityProps) => import("react/jsx-runtime").JSX.Element;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
export { VoiceOpsStatus } from './VoiceOpsStatus';
|
|
2
2
|
export { VoiceProviderSimulationControls } from './VoiceProviderSimulationControls';
|
|
3
|
+
export { VoiceProviderCapabilities } from './VoiceProviderCapabilities';
|
|
3
4
|
export { VoiceProviderStatus } from './VoiceProviderStatus';
|
|
4
5
|
export { VoiceRoutingStatus } from './VoiceRoutingStatus';
|
|
6
|
+
export { VoiceTurnQuality } from './VoiceTurnQuality';
|
|
5
7
|
export { useVoiceAppKitStatus } from './useVoiceAppKitStatus';
|
|
6
8
|
export { useVoiceStream } from './useVoiceStream';
|
|
7
9
|
export { useVoiceController } from './useVoiceController';
|
|
8
10
|
export { useVoiceProviderStatus } from './useVoiceProviderStatus';
|
|
11
|
+
export { useVoiceProviderCapabilities } from './useVoiceProviderCapabilities';
|
|
9
12
|
export { useVoiceProviderSimulationControls } from './useVoiceProviderSimulationControls';
|
|
10
13
|
export { useVoiceRoutingStatus } from './useVoiceRoutingStatus';
|
|
14
|
+
export { useVoiceTurnQuality } from './useVoiceTurnQuality';
|
|
11
15
|
export { useVoiceWorkflowStatus } from './useVoiceWorkflowStatus';
|