@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
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type VoiceProviderCapabilitiesClientOptions } from '../client/providerCapabilities';
|
|
2
|
+
export declare const useVoiceProviderCapabilities: <TProvider extends string = string>(path?: string, options?: VoiceProviderCapabilitiesClientOptions) => {
|
|
3
|
+
refresh: () => Promise<import("..").VoiceProviderCapabilityReport<TProvider> | undefined>;
|
|
4
|
+
error: string | null;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
report?: import("..").VoiceProviderCapabilityReport<TProvider> | undefined;
|
|
7
|
+
updatedAt?: number;
|
|
8
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type VoiceTurnQualityClientOptions } from '../client/turnQuality';
|
|
2
|
+
export declare const useVoiceTurnQuality: (path?: string, options?: VoiceTurnQualityClientOptions) => {
|
|
3
|
+
refresh: () => Promise<import("..").VoiceTurnQualityReport | undefined>;
|
|
4
|
+
error: string | null;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
report?: import("..").VoiceTurnQualityReport;
|
|
7
|
+
updatedAt?: number;
|
|
8
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type VoiceProviderCapabilitiesWidgetOptions } from '../client/providerCapabilitiesWidget';
|
|
2
|
+
export declare const createVoiceProviderCapabilities: <TProvider extends string = string>(path?: string, options?: VoiceProviderCapabilitiesWidgetOptions) => {
|
|
3
|
+
getHTML: () => string;
|
|
4
|
+
getViewModel: () => import("../client").VoiceProviderCapabilitiesViewModel<TProvider>;
|
|
5
|
+
close: () => void;
|
|
6
|
+
getServerSnapshot: () => import("../client").VoiceProviderCapabilitiesSnapshot<TProvider>;
|
|
7
|
+
getSnapshot: () => import("../client").VoiceProviderCapabilitiesSnapshot<TProvider>;
|
|
8
|
+
refresh: () => Promise<import("..").VoiceProviderCapabilityReport<TProvider> | undefined>;
|
|
9
|
+
subscribe: (listener: () => void) => () => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type VoiceTurnQualityWidgetOptions } from '../client/turnQualityWidget';
|
|
2
|
+
export declare const createVoiceTurnQuality: (path?: string, options?: VoiceTurnQualityWidgetOptions) => {
|
|
3
|
+
getHTML: () => string;
|
|
4
|
+
getViewModel: () => import("../client").VoiceTurnQualityViewModel;
|
|
5
|
+
close: () => void;
|
|
6
|
+
getServerSnapshot: () => import("../client").VoiceTurnQualitySnapshot;
|
|
7
|
+
getSnapshot: () => import("../client").VoiceTurnQualitySnapshot;
|
|
8
|
+
refresh: () => Promise<import("..").VoiceTurnQualityReport | undefined>;
|
|
9
|
+
subscribe: (listener: () => void) => () => void;
|
|
10
|
+
};
|
package/dist/svelte/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { createVoiceAppKitStatus } from './createVoiceAppKitStatus';
|
|
2
2
|
export { createVoiceOpsStatus } from './createVoiceOpsStatus';
|
|
3
3
|
export { createVoiceProviderSimulationControls } from './createVoiceProviderSimulationControls';
|
|
4
|
+
export { createVoiceProviderCapabilities } from './createVoiceProviderCapabilities';
|
|
4
5
|
export { createVoiceStream } from './createVoiceStream';
|
|
5
6
|
export { createVoiceProviderStatus } from './createVoiceProviderStatus';
|
|
6
7
|
export { createVoiceRoutingStatus } from './createVoiceRoutingStatus';
|
|
8
|
+
export { createVoiceTurnQuality } from './createVoiceTurnQuality';
|
|
7
9
|
export { createVoiceWorkflowStatus } from './createVoiceWorkflowStatus';
|
|
8
10
|
export { createVoiceController } from '../client/controller';
|
package/dist/svelte/index.js
CHANGED
|
@@ -473,6 +473,211 @@ var createVoiceProviderSimulationControls = (options) => {
|
|
|
473
473
|
getViewModel: () => createVoiceProviderSimulationControlsViewModel(store.getSnapshot(), options)
|
|
474
474
|
};
|
|
475
475
|
};
|
|
476
|
+
// src/client/providerCapabilities.ts
|
|
477
|
+
var fetchVoiceProviderCapabilities = async (path = "/api/provider-capabilities", options = {}) => {
|
|
478
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
479
|
+
const response = await fetchImpl(path);
|
|
480
|
+
if (!response.ok) {
|
|
481
|
+
throw new Error(`Voice provider capabilities failed: HTTP ${response.status}`);
|
|
482
|
+
}
|
|
483
|
+
return await response.json();
|
|
484
|
+
};
|
|
485
|
+
var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities", options = {}) => {
|
|
486
|
+
const listeners = new Set;
|
|
487
|
+
let closed = false;
|
|
488
|
+
let timer;
|
|
489
|
+
let snapshot = {
|
|
490
|
+
error: null,
|
|
491
|
+
isLoading: false
|
|
492
|
+
};
|
|
493
|
+
const emit = () => {
|
|
494
|
+
for (const listener of listeners) {
|
|
495
|
+
listener();
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
const refresh = async () => {
|
|
499
|
+
if (closed) {
|
|
500
|
+
return snapshot.report;
|
|
501
|
+
}
|
|
502
|
+
snapshot = {
|
|
503
|
+
...snapshot,
|
|
504
|
+
error: null,
|
|
505
|
+
isLoading: true
|
|
506
|
+
};
|
|
507
|
+
emit();
|
|
508
|
+
try {
|
|
509
|
+
const report = await fetchVoiceProviderCapabilities(path, options);
|
|
510
|
+
snapshot = {
|
|
511
|
+
error: null,
|
|
512
|
+
isLoading: false,
|
|
513
|
+
report,
|
|
514
|
+
updatedAt: Date.now()
|
|
515
|
+
};
|
|
516
|
+
emit();
|
|
517
|
+
return report;
|
|
518
|
+
} catch (error) {
|
|
519
|
+
snapshot = {
|
|
520
|
+
...snapshot,
|
|
521
|
+
error: error instanceof Error ? error.message : String(error),
|
|
522
|
+
isLoading: false
|
|
523
|
+
};
|
|
524
|
+
emit();
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
const close = () => {
|
|
529
|
+
closed = true;
|
|
530
|
+
if (timer) {
|
|
531
|
+
clearInterval(timer);
|
|
532
|
+
timer = undefined;
|
|
533
|
+
}
|
|
534
|
+
listeners.clear();
|
|
535
|
+
};
|
|
536
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
537
|
+
timer = setInterval(() => {
|
|
538
|
+
refresh().catch(() => {});
|
|
539
|
+
}, options.intervalMs);
|
|
540
|
+
}
|
|
541
|
+
return {
|
|
542
|
+
close,
|
|
543
|
+
getServerSnapshot: () => snapshot,
|
|
544
|
+
getSnapshot: () => snapshot,
|
|
545
|
+
refresh,
|
|
546
|
+
subscribe: (listener) => {
|
|
547
|
+
listeners.add(listener);
|
|
548
|
+
return () => {
|
|
549
|
+
listeners.delete(listener);
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
// src/client/providerCapabilitiesWidget.ts
|
|
556
|
+
var DEFAULT_TITLE2 = "Provider Capabilities";
|
|
557
|
+
var DEFAULT_DESCRIPTION2 = "Configured, selected, and healthy voice providers for this deployment.";
|
|
558
|
+
var escapeHtml3 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
559
|
+
var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
560
|
+
var formatKind2 = (kind) => kind.toUpperCase();
|
|
561
|
+
var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
562
|
+
var getCapabilityDetail = (capability) => {
|
|
563
|
+
if (!capability.configured) {
|
|
564
|
+
return "Not configured in this deployment.";
|
|
565
|
+
}
|
|
566
|
+
if (capability.selected) {
|
|
567
|
+
return `Selected ${capability.kind.toUpperCase()} provider for new sessions.`;
|
|
568
|
+
}
|
|
569
|
+
if (capability.health?.status === "healthy") {
|
|
570
|
+
return "Configured and healthy fallback candidate.";
|
|
571
|
+
}
|
|
572
|
+
if (capability.health?.status === "idle") {
|
|
573
|
+
return "Configured; no traffic observed yet.";
|
|
574
|
+
}
|
|
575
|
+
if (capability.health?.lastError) {
|
|
576
|
+
return capability.health.lastError;
|
|
577
|
+
}
|
|
578
|
+
return "Configured and available.";
|
|
579
|
+
};
|
|
580
|
+
var isWarningStatus = (status) => status === "degraded" || status === "rate-limited" || status === "suppressed" || status === "unconfigured";
|
|
581
|
+
var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
|
|
582
|
+
const capabilities = (snapshot.report?.capabilities ?? []).map((capability) => ({
|
|
583
|
+
...capability,
|
|
584
|
+
detail: getCapabilityDetail(capability),
|
|
585
|
+
label: `${formatProvider(capability.provider)} ${formatKind2(capability.kind)}`,
|
|
586
|
+
rows: [
|
|
587
|
+
{ label: "Status", value: formatStatus(capability.status) },
|
|
588
|
+
{ label: "Selected", value: capability.selected ? "Yes" : "No" },
|
|
589
|
+
{ label: "Model", value: capability.model ?? "Default" },
|
|
590
|
+
{
|
|
591
|
+
label: "Features",
|
|
592
|
+
value: capability.features?.join(", ") || "Not specified"
|
|
593
|
+
},
|
|
594
|
+
{ label: "Runs", value: String(capability.health?.runCount ?? 0) },
|
|
595
|
+
{ label: "Errors", value: String(capability.health?.errorCount ?? 0) }
|
|
596
|
+
]
|
|
597
|
+
}));
|
|
598
|
+
const warningCount = capabilities.filter((capability) => isWarningStatus(capability.status)).length;
|
|
599
|
+
const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
|
|
600
|
+
return {
|
|
601
|
+
capabilities,
|
|
602
|
+
description: options.description ?? DEFAULT_DESCRIPTION2,
|
|
603
|
+
error: snapshot.error,
|
|
604
|
+
isLoading: snapshot.isLoading,
|
|
605
|
+
label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
|
|
606
|
+
status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
607
|
+
title: options.title ?? DEFAULT_TITLE2,
|
|
608
|
+
updatedAt: snapshot.updatedAt
|
|
609
|
+
};
|
|
610
|
+
};
|
|
611
|
+
var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
|
|
612
|
+
const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
|
|
613
|
+
const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml3(capability.status)}">
|
|
614
|
+
<header>
|
|
615
|
+
<strong>${escapeHtml3(capability.label)}</strong>
|
|
616
|
+
<span>${escapeHtml3(formatStatus(capability.status))}</span>
|
|
617
|
+
</header>
|
|
618
|
+
<p>${escapeHtml3(capability.detail)}</p>
|
|
619
|
+
<dl>${capability.rows.map((row) => `<div>
|
|
620
|
+
<dt>${escapeHtml3(row.label)}</dt>
|
|
621
|
+
<dd>${escapeHtml3(row.value)}</dd>
|
|
622
|
+
</div>`).join("")}</dl>
|
|
623
|
+
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
|
|
624
|
+
return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml3(model.status)}">
|
|
625
|
+
<header class="absolute-voice-provider-capabilities__header">
|
|
626
|
+
<span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml3(model.title)}</span>
|
|
627
|
+
<strong class="absolute-voice-provider-capabilities__label">${escapeHtml3(model.label)}</strong>
|
|
628
|
+
</header>
|
|
629
|
+
<p class="absolute-voice-provider-capabilities__description">${escapeHtml3(model.description)}</p>
|
|
630
|
+
${capabilities}
|
|
631
|
+
${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml3(model.error)}</p>` : ""}
|
|
632
|
+
</section>`;
|
|
633
|
+
};
|
|
634
|
+
var getVoiceProviderCapabilitiesCSS = () => `.absolute-voice-provider-capabilities{border:1px solid #bfd7ea;border-radius:20px;background:#f6fbff;color:#08131f;padding:18px;box-shadow:0 18px 40px rgba(14,51,78,.12);font-family:inherit}.absolute-voice-provider-capabilities--error,.absolute-voice-provider-capabilities--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-capabilities__header,.absolute-voice-provider-capabilities__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-capabilities__eyebrow{color:#255f85;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-capabilities__label{font-size:24px;line-height:1}.absolute-voice-provider-capabilities__description,.absolute-voice-provider-capabilities__provider p,.absolute-voice-provider-capabilities__provider dt,.absolute-voice-provider-capabilities__empty{color:#405467}.absolute-voice-provider-capabilities__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-capabilities__provider{background:#fff;border:1px solid #d7e7f3;border-radius:16px;padding:14px}.absolute-voice-provider-capabilities__provider--selected,.absolute-voice-provider-capabilities__provider--healthy{border-color:#86efac}.absolute-voice-provider-capabilities__provider--degraded,.absolute-voice-provider-capabilities__provider--rate-limited,.absolute-voice-provider-capabilities__provider--suppressed,.absolute-voice-provider-capabilities__provider--unconfigured{border-color:#f2a7a7}.absolute-voice-provider-capabilities__provider p{margin:10px 0}.absolute-voice-provider-capabilities__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-capabilities__provider div{background:#f6fbff;border:1px solid #d7e7f3;border-radius:12px;padding:8px}.absolute-voice-provider-capabilities__provider dt{font-size:12px}.absolute-voice-provider-capabilities__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-capabilities__empty{margin:14px 0 0}.absolute-voice-provider-capabilities__error{color:#9f1239;font-weight:700}`;
|
|
635
|
+
var mountVoiceProviderCapabilities = (element, path = "/api/provider-capabilities", options = {}) => {
|
|
636
|
+
const store = createVoiceProviderCapabilitiesStore(path, options);
|
|
637
|
+
const render = () => {
|
|
638
|
+
element.innerHTML = renderVoiceProviderCapabilitiesHTML(store.getSnapshot(), options);
|
|
639
|
+
};
|
|
640
|
+
const unsubscribe = store.subscribe(render);
|
|
641
|
+
render();
|
|
642
|
+
store.refresh().catch(() => {});
|
|
643
|
+
return {
|
|
644
|
+
close: () => {
|
|
645
|
+
unsubscribe();
|
|
646
|
+
store.close();
|
|
647
|
+
},
|
|
648
|
+
refresh: store.refresh
|
|
649
|
+
};
|
|
650
|
+
};
|
|
651
|
+
var defineVoiceProviderCapabilitiesElement = (tagName = "absolute-voice-provider-capabilities") => {
|
|
652
|
+
if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
customElements.define(tagName, class AbsoluteVoiceProviderCapabilitiesElement extends HTMLElement {
|
|
656
|
+
mounted;
|
|
657
|
+
connectedCallback() {
|
|
658
|
+
const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
|
|
659
|
+
this.mounted = mountVoiceProviderCapabilities(this, this.getAttribute("path") ?? "/api/provider-capabilities", {
|
|
660
|
+
description: this.getAttribute("description") ?? undefined,
|
|
661
|
+
intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
|
|
662
|
+
title: this.getAttribute("title") ?? undefined
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
disconnectedCallback() {
|
|
666
|
+
this.mounted?.close();
|
|
667
|
+
this.mounted = undefined;
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
// src/svelte/createVoiceProviderCapabilities.ts
|
|
673
|
+
var createVoiceProviderCapabilities = (path = "/api/provider-capabilities", options = {}) => {
|
|
674
|
+
const store = createVoiceProviderCapabilitiesStore(path, options);
|
|
675
|
+
return {
|
|
676
|
+
...store,
|
|
677
|
+
getHTML: () => renderVoiceProviderCapabilitiesHTML(store.getSnapshot(), options),
|
|
678
|
+
getViewModel: () => createVoiceProviderCapabilitiesViewModel(store.getSnapshot(), options)
|
|
679
|
+
};
|
|
680
|
+
};
|
|
476
681
|
// src/client/actions.ts
|
|
477
682
|
var normalizeErrorMessage = (value) => {
|
|
478
683
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -1069,11 +1274,11 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1069
1274
|
};
|
|
1070
1275
|
|
|
1071
1276
|
// src/client/providerStatusWidget.ts
|
|
1072
|
-
var
|
|
1073
|
-
var
|
|
1074
|
-
var
|
|
1075
|
-
var
|
|
1076
|
-
var
|
|
1277
|
+
var DEFAULT_TITLE3 = "Voice Providers";
|
|
1278
|
+
var DEFAULT_DESCRIPTION3 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
|
|
1279
|
+
var escapeHtml4 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1280
|
+
var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
1281
|
+
var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
1077
1282
|
var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
|
|
1078
1283
|
var formatSuppression = (value) => typeof value === "number" ? `${Math.ceil(value / 1000)}s` : "None";
|
|
1079
1284
|
var getProviderDetail = (provider) => {
|
|
@@ -1094,12 +1299,12 @@ var getProviderDetail = (provider) => {
|
|
|
1094
1299
|
}
|
|
1095
1300
|
return "No provider traffic observed yet.";
|
|
1096
1301
|
};
|
|
1097
|
-
var
|
|
1302
|
+
var isWarningStatus2 = (status) => status === "degraded" || status === "rate-limited" || status === "recoverable" || status === "suppressed";
|
|
1098
1303
|
var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
1099
1304
|
const providers = snapshot.providers.map((provider) => ({
|
|
1100
1305
|
...provider,
|
|
1101
1306
|
detail: getProviderDetail(provider),
|
|
1102
|
-
label: `${
|
|
1307
|
+
label: `${formatProvider2(provider.provider)}${provider.recommended ? " recommended" : ""}`,
|
|
1103
1308
|
rows: [
|
|
1104
1309
|
{ label: "Runs", value: String(provider.runCount) },
|
|
1105
1310
|
{ label: "Avg latency", value: formatLatency(provider.averageElapsedMs) },
|
|
@@ -1112,40 +1317,40 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
|
1112
1317
|
}
|
|
1113
1318
|
]
|
|
1114
1319
|
}));
|
|
1115
|
-
const warningCount = providers.filter((provider) =>
|
|
1320
|
+
const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
|
|
1116
1321
|
const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
|
|
1117
1322
|
return {
|
|
1118
|
-
description: options.description ??
|
|
1323
|
+
description: options.description ?? DEFAULT_DESCRIPTION3,
|
|
1119
1324
|
error: snapshot.error,
|
|
1120
1325
|
isLoading: snapshot.isLoading,
|
|
1121
1326
|
label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
|
|
1122
1327
|
providers,
|
|
1123
1328
|
status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
1124
|
-
title: options.title ??
|
|
1329
|
+
title: options.title ?? DEFAULT_TITLE3,
|
|
1125
1330
|
updatedAt: snapshot.updatedAt
|
|
1126
1331
|
};
|
|
1127
1332
|
};
|
|
1128
1333
|
var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
|
|
1129
1334
|
const model = createVoiceProviderStatusViewModel(snapshot, options);
|
|
1130
|
-
const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${
|
|
1335
|
+
const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml4(provider.status)}">
|
|
1131
1336
|
<header>
|
|
1132
|
-
<strong>${
|
|
1133
|
-
<span>${
|
|
1337
|
+
<strong>${escapeHtml4(provider.label)}</strong>
|
|
1338
|
+
<span>${escapeHtml4(formatStatus2(provider.status))}</span>
|
|
1134
1339
|
</header>
|
|
1135
|
-
<p>${
|
|
1340
|
+
<p>${escapeHtml4(provider.detail)}</p>
|
|
1136
1341
|
<dl>${provider.rows.map((row) => `<div>
|
|
1137
|
-
<dt>${
|
|
1138
|
-
<dd>${
|
|
1342
|
+
<dt>${escapeHtml4(row.label)}</dt>
|
|
1343
|
+
<dd>${escapeHtml4(row.value)}</dd>
|
|
1139
1344
|
</div>`).join("")}</dl>
|
|
1140
1345
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
|
|
1141
|
-
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${
|
|
1346
|
+
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml4(model.status)}">
|
|
1142
1347
|
<header class="absolute-voice-provider-status__header">
|
|
1143
|
-
<span class="absolute-voice-provider-status__eyebrow">${
|
|
1144
|
-
<strong class="absolute-voice-provider-status__label">${
|
|
1348
|
+
<span class="absolute-voice-provider-status__eyebrow">${escapeHtml4(model.title)}</span>
|
|
1349
|
+
<strong class="absolute-voice-provider-status__label">${escapeHtml4(model.label)}</strong>
|
|
1145
1350
|
</header>
|
|
1146
|
-
<p class="absolute-voice-provider-status__description">${
|
|
1351
|
+
<p class="absolute-voice-provider-status__description">${escapeHtml4(model.description)}</p>
|
|
1147
1352
|
${providers}
|
|
1148
|
-
${model.error ? `<p class="absolute-voice-provider-status__error">${
|
|
1353
|
+
${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml4(model.error)}</p>` : ""}
|
|
1149
1354
|
</section>`;
|
|
1150
1355
|
};
|
|
1151
1356
|
var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
|
|
@@ -1276,9 +1481,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
|
|
|
1276
1481
|
};
|
|
1277
1482
|
|
|
1278
1483
|
// src/client/routingStatusWidget.ts
|
|
1279
|
-
var
|
|
1280
|
-
var
|
|
1281
|
-
var
|
|
1484
|
+
var DEFAULT_TITLE4 = "Voice Routing";
|
|
1485
|
+
var DEFAULT_DESCRIPTION4 = "Latest provider routing decision from the self-hosted trace store.";
|
|
1486
|
+
var escapeHtml5 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1282
1487
|
var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
|
|
1283
1488
|
var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
1284
1489
|
const decision = snapshot.decision;
|
|
@@ -1302,30 +1507,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
|
1302
1507
|
] : [];
|
|
1303
1508
|
return {
|
|
1304
1509
|
decision,
|
|
1305
|
-
description: options.description ??
|
|
1510
|
+
description: options.description ?? DEFAULT_DESCRIPTION4,
|
|
1306
1511
|
error: snapshot.error,
|
|
1307
1512
|
isLoading: snapshot.isLoading,
|
|
1308
1513
|
label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
|
|
1309
1514
|
rows,
|
|
1310
1515
|
status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
1311
|
-
title: options.title ??
|
|
1516
|
+
title: options.title ?? DEFAULT_TITLE4,
|
|
1312
1517
|
updatedAt: snapshot.updatedAt
|
|
1313
1518
|
};
|
|
1314
1519
|
};
|
|
1315
1520
|
var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
|
|
1316
1521
|
const model = createVoiceRoutingStatusViewModel(snapshot, options);
|
|
1317
1522
|
const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
|
|
1318
|
-
<span>${
|
|
1319
|
-
<strong>${
|
|
1523
|
+
<span>${escapeHtml5(row.label)}</span>
|
|
1524
|
+
<strong>${escapeHtml5(row.value)}</strong>
|
|
1320
1525
|
</div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
|
|
1321
|
-
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${
|
|
1526
|
+
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml5(model.status)}">
|
|
1322
1527
|
<header class="absolute-voice-routing-status__header">
|
|
1323
|
-
<span class="absolute-voice-routing-status__eyebrow">${
|
|
1324
|
-
<strong class="absolute-voice-routing-status__label">${
|
|
1528
|
+
<span class="absolute-voice-routing-status__eyebrow">${escapeHtml5(model.title)}</span>
|
|
1529
|
+
<strong class="absolute-voice-routing-status__label">${escapeHtml5(model.label)}</strong>
|
|
1325
1530
|
</header>
|
|
1326
|
-
<p class="absolute-voice-routing-status__description">${
|
|
1531
|
+
<p class="absolute-voice-routing-status__description">${escapeHtml5(model.description)}</p>
|
|
1327
1532
|
${rows}
|
|
1328
|
-
${model.error ? `<p class="absolute-voice-routing-status__error">${
|
|
1533
|
+
${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml5(model.error)}</p>` : ""}
|
|
1329
1534
|
</section>`;
|
|
1330
1535
|
};
|
|
1331
1536
|
var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
|
|
@@ -1375,6 +1580,206 @@ var createVoiceRoutingStatus = (path = "/api/routing/latest", options = {}) => {
|
|
|
1375
1580
|
getViewModel: () => createVoiceRoutingStatusViewModel(store.getSnapshot(), options)
|
|
1376
1581
|
};
|
|
1377
1582
|
};
|
|
1583
|
+
// src/client/turnQuality.ts
|
|
1584
|
+
var fetchVoiceTurnQuality = async (path = "/api/turn-quality", options = {}) => {
|
|
1585
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1586
|
+
const response = await fetchImpl(path);
|
|
1587
|
+
if (!response.ok) {
|
|
1588
|
+
throw new Error(`Voice turn quality failed: HTTP ${response.status}`);
|
|
1589
|
+
}
|
|
1590
|
+
return await response.json();
|
|
1591
|
+
};
|
|
1592
|
+
var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) => {
|
|
1593
|
+
const listeners = new Set;
|
|
1594
|
+
let closed = false;
|
|
1595
|
+
let timer;
|
|
1596
|
+
let snapshot = {
|
|
1597
|
+
error: null,
|
|
1598
|
+
isLoading: false
|
|
1599
|
+
};
|
|
1600
|
+
const emit = () => {
|
|
1601
|
+
for (const listener of listeners) {
|
|
1602
|
+
listener();
|
|
1603
|
+
}
|
|
1604
|
+
};
|
|
1605
|
+
const refresh = async () => {
|
|
1606
|
+
if (closed) {
|
|
1607
|
+
return snapshot.report;
|
|
1608
|
+
}
|
|
1609
|
+
snapshot = {
|
|
1610
|
+
...snapshot,
|
|
1611
|
+
error: null,
|
|
1612
|
+
isLoading: true
|
|
1613
|
+
};
|
|
1614
|
+
emit();
|
|
1615
|
+
try {
|
|
1616
|
+
const report = await fetchVoiceTurnQuality(path, options);
|
|
1617
|
+
snapshot = {
|
|
1618
|
+
error: null,
|
|
1619
|
+
isLoading: false,
|
|
1620
|
+
report,
|
|
1621
|
+
updatedAt: Date.now()
|
|
1622
|
+
};
|
|
1623
|
+
emit();
|
|
1624
|
+
return report;
|
|
1625
|
+
} catch (error) {
|
|
1626
|
+
snapshot = {
|
|
1627
|
+
...snapshot,
|
|
1628
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1629
|
+
isLoading: false
|
|
1630
|
+
};
|
|
1631
|
+
emit();
|
|
1632
|
+
throw error;
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
const close = () => {
|
|
1636
|
+
closed = true;
|
|
1637
|
+
if (timer) {
|
|
1638
|
+
clearInterval(timer);
|
|
1639
|
+
timer = undefined;
|
|
1640
|
+
}
|
|
1641
|
+
listeners.clear();
|
|
1642
|
+
};
|
|
1643
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
1644
|
+
timer = setInterval(() => {
|
|
1645
|
+
refresh().catch(() => {});
|
|
1646
|
+
}, options.intervalMs);
|
|
1647
|
+
}
|
|
1648
|
+
return {
|
|
1649
|
+
close,
|
|
1650
|
+
getServerSnapshot: () => snapshot,
|
|
1651
|
+
getSnapshot: () => snapshot,
|
|
1652
|
+
refresh,
|
|
1653
|
+
subscribe: (listener) => {
|
|
1654
|
+
listeners.add(listener);
|
|
1655
|
+
return () => {
|
|
1656
|
+
listeners.delete(listener);
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
};
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1662
|
+
// src/client/turnQualityWidget.ts
|
|
1663
|
+
var DEFAULT_TITLE5 = "Turn Quality";
|
|
1664
|
+
var DEFAULT_DESCRIPTION5 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
|
|
1665
|
+
var escapeHtml6 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1666
|
+
var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
|
|
1667
|
+
var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
|
|
1668
|
+
var getTurnDetail = (turn) => {
|
|
1669
|
+
if (turn.status === "fail") {
|
|
1670
|
+
return "Empty or unusable committed turn; inspect transcripts and adapter events.";
|
|
1671
|
+
}
|
|
1672
|
+
if (turn.fallbackUsed) {
|
|
1673
|
+
return `Fallback STT selected${turn.fallbackSelectionReason ? ` by ${turn.fallbackSelectionReason}` : ""}.`;
|
|
1674
|
+
}
|
|
1675
|
+
if (turn.correctionChanged) {
|
|
1676
|
+
return `Correction changed the turn${turn.correctionProvider ? ` via ${turn.correctionProvider}` : ""}.`;
|
|
1677
|
+
}
|
|
1678
|
+
if (turn.status === "warn") {
|
|
1679
|
+
return "Turn completed with quality warnings.";
|
|
1680
|
+
}
|
|
1681
|
+
if (turn.status === "unknown") {
|
|
1682
|
+
return "No quality diagnostics were recorded for this turn.";
|
|
1683
|
+
}
|
|
1684
|
+
return "Turn quality looks healthy.";
|
|
1685
|
+
};
|
|
1686
|
+
var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
|
|
1687
|
+
const turns = (snapshot.report?.turns ?? []).map((turn) => ({
|
|
1688
|
+
...turn,
|
|
1689
|
+
detail: getTurnDetail(turn),
|
|
1690
|
+
label: turn.text || "Empty turn",
|
|
1691
|
+
rows: [
|
|
1692
|
+
{ label: "Source", value: turn.source ?? "unknown" },
|
|
1693
|
+
{ label: "Confidence", value: formatConfidence(turn.averageConfidence) },
|
|
1694
|
+
{ label: "Fallback", value: turn.fallbackUsed ? "Yes" : "No" },
|
|
1695
|
+
{ label: "Correction", value: turn.correctionChanged ? "Changed" : "None" },
|
|
1696
|
+
{ label: "Transcripts", value: `${turn.selectedTranscriptCount} selected` },
|
|
1697
|
+
{ label: "Cost", value: formatMaybe(turn.costUnits) }
|
|
1698
|
+
]
|
|
1699
|
+
}));
|
|
1700
|
+
const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
|
|
1701
|
+
const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
|
|
1702
|
+
return {
|
|
1703
|
+
description: options.description ?? DEFAULT_DESCRIPTION5,
|
|
1704
|
+
error: snapshot.error,
|
|
1705
|
+
isLoading: snapshot.isLoading,
|
|
1706
|
+
label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
|
|
1707
|
+
status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
1708
|
+
title: options.title ?? DEFAULT_TITLE5,
|
|
1709
|
+
turns,
|
|
1710
|
+
updatedAt: snapshot.updatedAt
|
|
1711
|
+
};
|
|
1712
|
+
};
|
|
1713
|
+
var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
|
|
1714
|
+
const model = createVoiceTurnQualityViewModel(snapshot, options);
|
|
1715
|
+
const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml6(turn.status)}">
|
|
1716
|
+
<header>
|
|
1717
|
+
<strong>${escapeHtml6(turn.label)}</strong>
|
|
1718
|
+
<span>${escapeHtml6(turn.status)}</span>
|
|
1719
|
+
</header>
|
|
1720
|
+
<p>${escapeHtml6(turn.detail)}</p>
|
|
1721
|
+
<dl>${turn.rows.map((row) => `<div>
|
|
1722
|
+
<dt>${escapeHtml6(row.label)}</dt>
|
|
1723
|
+
<dd>${escapeHtml6(row.value)}</dd>
|
|
1724
|
+
</div>`).join("")}</dl>
|
|
1725
|
+
</article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
|
|
1726
|
+
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml6(model.status)}">
|
|
1727
|
+
<header class="absolute-voice-turn-quality__header">
|
|
1728
|
+
<span class="absolute-voice-turn-quality__eyebrow">${escapeHtml6(model.title)}</span>
|
|
1729
|
+
<strong class="absolute-voice-turn-quality__label">${escapeHtml6(model.label)}</strong>
|
|
1730
|
+
</header>
|
|
1731
|
+
<p class="absolute-voice-turn-quality__description">${escapeHtml6(model.description)}</p>
|
|
1732
|
+
${turns}
|
|
1733
|
+
${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml6(model.error)}</p>` : ""}
|
|
1734
|
+
</section>`;
|
|
1735
|
+
};
|
|
1736
|
+
var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;
|
|
1737
|
+
var mountVoiceTurnQuality = (element, path = "/api/turn-quality", options = {}) => {
|
|
1738
|
+
const store = createVoiceTurnQualityStore(path, options);
|
|
1739
|
+
const render = () => {
|
|
1740
|
+
element.innerHTML = renderVoiceTurnQualityHTML(store.getSnapshot(), options);
|
|
1741
|
+
};
|
|
1742
|
+
const unsubscribe = store.subscribe(render);
|
|
1743
|
+
render();
|
|
1744
|
+
store.refresh().catch(() => {});
|
|
1745
|
+
return {
|
|
1746
|
+
close: () => {
|
|
1747
|
+
unsubscribe();
|
|
1748
|
+
store.close();
|
|
1749
|
+
},
|
|
1750
|
+
refresh: store.refresh
|
|
1751
|
+
};
|
|
1752
|
+
};
|
|
1753
|
+
var defineVoiceTurnQualityElement = (tagName = "absolute-voice-turn-quality") => {
|
|
1754
|
+
if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
customElements.define(tagName, class AbsoluteVoiceTurnQualityElement extends HTMLElement {
|
|
1758
|
+
mounted;
|
|
1759
|
+
connectedCallback() {
|
|
1760
|
+
const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
|
|
1761
|
+
this.mounted = mountVoiceTurnQuality(this, this.getAttribute("path") ?? "/api/turn-quality", {
|
|
1762
|
+
description: this.getAttribute("description") ?? undefined,
|
|
1763
|
+
intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
|
|
1764
|
+
title: this.getAttribute("title") ?? undefined
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
disconnectedCallback() {
|
|
1768
|
+
this.mounted?.close();
|
|
1769
|
+
this.mounted = undefined;
|
|
1770
|
+
}
|
|
1771
|
+
});
|
|
1772
|
+
};
|
|
1773
|
+
|
|
1774
|
+
// src/svelte/createVoiceTurnQuality.ts
|
|
1775
|
+
var createVoiceTurnQuality = (path = "/api/turn-quality", options = {}) => {
|
|
1776
|
+
const store = createVoiceTurnQualityStore(path, options);
|
|
1777
|
+
return {
|
|
1778
|
+
...store,
|
|
1779
|
+
getHTML: () => renderVoiceTurnQualityHTML(store.getSnapshot(), options),
|
|
1780
|
+
getViewModel: () => createVoiceTurnQualityViewModel(store.getSnapshot(), options)
|
|
1781
|
+
};
|
|
1782
|
+
};
|
|
1378
1783
|
// src/client/workflowStatus.ts
|
|
1379
1784
|
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
1380
1785
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
@@ -2087,10 +2492,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
2087
2492
|
};
|
|
2088
2493
|
export {
|
|
2089
2494
|
createVoiceWorkflowStatus,
|
|
2495
|
+
createVoiceTurnQuality,
|
|
2090
2496
|
createVoiceStream2 as createVoiceStream,
|
|
2091
2497
|
createVoiceRoutingStatus,
|
|
2092
2498
|
createVoiceProviderStatus,
|
|
2093
2499
|
createVoiceProviderSimulationControls,
|
|
2500
|
+
createVoiceProviderCapabilities,
|
|
2094
2501
|
createVoiceOpsStatus,
|
|
2095
2502
|
createVoiceController,
|
|
2096
2503
|
createVoiceAppKitStatus
|