@absolutejs/voice 0.0.22-beta.3 → 0.0.22-beta.300
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3232 -82
- package/dist/agent.d.ts +62 -0
- package/dist/agentSquadContract.d.ts +98 -0
- package/dist/angular/index.d.ts +17 -0
- package/dist/angular/index.js +3598 -1058
- package/dist/angular/voice-agent-squad-status.service.d.ts +12 -0
- package/dist/angular/voice-campaign-dialer-proof.service.d.ts +14 -0
- package/dist/angular/voice-controller.service.d.ts +1 -0
- package/dist/angular/voice-delivery-runtime.component.d.ts +17 -0
- package/dist/angular/voice-delivery-runtime.service.d.ts +16 -0
- package/dist/angular/voice-live-ops.service.d.ts +11 -0
- package/dist/angular/voice-ops-action-center.service.d.ts +13 -0
- package/dist/angular/voice-ops-status.component.d.ts +15 -0
- package/dist/angular/voice-ops-status.service.d.ts +12 -0
- package/dist/angular/voice-platform-coverage.service.d.ts +12 -0
- package/dist/angular/voice-proof-trends.service.d.ts +12 -0
- package/dist/angular/voice-provider-capabilities.service.d.ts +12 -0
- package/dist/angular/voice-provider-contracts.service.d.ts +12 -0
- package/dist/angular/voice-provider-status.service.d.ts +12 -0
- package/dist/angular/voice-readiness-failures.service.d.ts +13 -0
- package/dist/angular/voice-routing-status.service.d.ts +11 -0
- package/dist/angular/voice-stream.service.d.ts +3 -0
- package/dist/angular/voice-trace-timeline.service.d.ts +12 -0
- package/dist/angular/voice-turn-latency.service.d.ts +13 -0
- package/dist/angular/voice-turn-quality.service.d.ts +12 -0
- package/dist/angular/voice-workflow-status.service.d.ts +12 -0
- package/dist/assistant.d.ts +20 -0
- package/dist/assistantHealth.d.ts +81 -0
- package/dist/assistantMemory.d.ts +63 -0
- package/dist/audit.d.ts +128 -0
- package/dist/auditDeliveryRoutes.d.ts +85 -0
- package/dist/auditExport.d.ts +34 -0
- package/dist/auditRoutes.d.ts +66 -0
- package/dist/auditSinks.d.ts +151 -0
- package/dist/bargeInRoutes.d.ts +56 -0
- package/dist/campaign.d.ts +768 -0
- package/dist/campaignDialers.d.ts +111 -0
- package/dist/client/actions.d.ts +105 -0
- package/dist/client/agentSquadStatus.d.ts +37 -0
- package/dist/client/agentSquadStatusWidget.d.ts +24 -0
- package/dist/client/bargeInMonitor.d.ts +7 -0
- package/dist/client/campaignDialerProof.d.ts +23 -0
- package/dist/client/connection.d.ts +3 -0
- package/dist/client/deliveryRuntime.d.ts +34 -0
- package/dist/client/deliveryRuntimeWidget.d.ts +37 -0
- package/dist/client/duplex.d.ts +1 -1
- package/dist/client/htmxBootstrap.js +747 -15
- package/dist/client/index.d.ts +72 -0
- package/dist/client/index.js +5371 -10
- package/dist/client/liveOps.d.ts +22 -0
- package/dist/client/liveOpsWidget.d.ts +23 -0
- package/dist/client/liveTurnLatency.d.ts +41 -0
- package/dist/client/opsActionCenter.d.ts +54 -0
- package/dist/client/opsActionCenterWidget.d.ts +29 -0
- package/dist/client/opsActionHistory.d.ts +19 -0
- package/dist/client/opsActionHistoryWidget.d.ts +11 -0
- package/dist/client/opsStatus.d.ts +19 -0
- package/dist/client/opsStatusWidget.d.ts +40 -0
- package/dist/client/platformCoverage.d.ts +19 -0
- package/dist/client/platformCoverageWidget.d.ts +37 -0
- package/dist/client/proofTrends.d.ts +19 -0
- package/dist/client/proofTrendsWidget.d.ts +37 -0
- package/dist/client/providerCapabilities.d.ts +19 -0
- package/dist/client/providerCapabilitiesWidget.d.ts +32 -0
- package/dist/client/providerContracts.d.ts +19 -0
- package/dist/client/providerContractsWidget.d.ts +37 -0
- package/dist/client/providerSimulationControls.d.ts +33 -0
- package/dist/client/providerSimulationControlsWidget.d.ts +20 -0
- package/dist/client/providerStatus.d.ts +19 -0
- package/dist/client/providerStatusWidget.d.ts +32 -0
- package/dist/client/readinessFailures.d.ts +19 -0
- package/dist/client/readinessFailuresWidget.d.ts +42 -0
- package/dist/client/routingStatus.d.ts +19 -0
- package/dist/client/routingStatusWidget.d.ts +28 -0
- package/dist/client/traceTimeline.d.ts +19 -0
- package/dist/client/traceTimelineWidget.d.ts +36 -0
- package/dist/client/turnLatency.d.ts +22 -0
- package/dist/client/turnLatencyWidget.d.ts +33 -0
- package/dist/client/turnQuality.d.ts +19 -0
- package/dist/client/turnQualityWidget.d.ts +32 -0
- package/dist/client/workflowStatus.d.ts +19 -0
- package/dist/dataControl.d.ts +180 -0
- package/dist/deliveryRuntime.d.ts +158 -0
- package/dist/deliverySinkRoutes.d.ts +117 -0
- package/dist/demoReadyRoutes.d.ts +98 -0
- package/dist/diagnosticsRoutes.d.ts +44 -0
- package/dist/evalRoutes.d.ts +219 -0
- package/dist/fileStore.d.ts +17 -2
- package/dist/guardrails.d.ts +128 -0
- package/dist/handoff.d.ts +54 -0
- package/dist/handoffHealth.d.ts +94 -0
- package/dist/incidentBundle.d.ts +116 -0
- package/dist/index.d.ts +151 -10
- package/dist/index.js +28252 -3426
- package/dist/latencySlo.d.ts +56 -0
- package/dist/liveLatency.d.ts +78 -0
- package/dist/liveOps.d.ts +190 -0
- package/dist/modelAdapters.d.ts +151 -0
- package/dist/observabilityExport.d.ts +481 -0
- package/dist/openaiRealtime.d.ts +27 -0
- package/dist/openaiTTS.d.ts +18 -0
- package/dist/operationsRecord.d.ts +254 -0
- package/dist/opsActionAuditRoutes.d.ts +99 -0
- package/dist/opsConsoleRoutes.d.ts +80 -0
- package/dist/opsRecovery.d.ts +137 -0
- package/dist/opsStatus.d.ts +76 -0
- package/dist/opsStatusRoutes.d.ts +33 -0
- package/dist/opsWebhook.d.ts +126 -0
- package/dist/outcomeContract.d.ts +146 -0
- package/dist/phoneAgent.d.ts +139 -0
- package/dist/phoneAgentProductionSmoke.d.ts +115 -0
- package/dist/platformCoverage.d.ts +91 -0
- package/dist/postCallAnalysis.d.ts +98 -0
- package/dist/postgresStore.d.ts +13 -2
- package/dist/productionReadiness.d.ts +559 -0
- package/dist/proofTrends.d.ts +133 -0
- package/dist/providerAdapters.d.ts +48 -0
- package/dist/providerCapabilities.d.ts +92 -0
- package/dist/providerDecisionTraces.d.ts +130 -0
- package/dist/providerHealth.d.ts +79 -0
- package/dist/providerOrchestration.d.ts +109 -0
- package/dist/providerRoutingContract.d.ts +71 -0
- package/dist/providerSlo.d.ts +142 -0
- package/dist/providerStackRecommendations.d.ts +187 -0
- package/dist/qualityRoutes.d.ts +76 -0
- package/dist/queue.d.ts +61 -0
- package/dist/react/VoiceAgentSquadStatus.d.ts +5 -0
- package/dist/react/VoiceDeliveryRuntime.d.ts +7 -0
- package/dist/react/VoiceOpsActionCenter.d.ts +5 -0
- package/dist/react/VoiceOpsStatus.d.ts +6 -0
- package/dist/react/VoicePlatformCoverage.d.ts +6 -0
- package/dist/react/VoiceProofTrends.d.ts +6 -0
- package/dist/react/VoiceProviderCapabilities.d.ts +6 -0
- package/dist/react/VoiceProviderContracts.d.ts +6 -0
- package/dist/react/VoiceProviderSimulationControls.d.ts +5 -0
- package/dist/react/VoiceProviderStatus.d.ts +6 -0
- package/dist/react/VoiceReadinessFailures.d.ts +6 -0
- package/dist/react/VoiceRoutingStatus.d.ts +6 -0
- package/dist/react/VoiceTraceTimeline.d.ts +6 -0
- package/dist/react/VoiceTurnLatency.d.ts +6 -0
- package/dist/react/VoiceTurnQuality.d.ts +6 -0
- package/dist/react/index.d.ts +33 -0
- package/dist/react/index.js +5188 -14
- package/dist/react/useVoiceAgentSquadStatus.d.ts +8 -0
- package/dist/react/useVoiceCampaignDialerProof.d.ts +10 -0
- package/dist/react/useVoiceController.d.ts +3 -0
- package/dist/react/useVoiceDeliveryRuntime.d.ts +13 -0
- package/dist/react/useVoiceLiveOps.d.ts +9 -0
- package/dist/react/useVoiceOpsActionCenter.d.ts +11 -0
- package/dist/react/useVoiceOpsStatus.d.ts +8 -0
- package/dist/react/useVoicePlatformCoverage.d.ts +8 -0
- package/dist/react/useVoiceProofTrends.d.ts +8 -0
- package/dist/react/useVoiceProviderCapabilities.d.ts +8 -0
- package/dist/react/useVoiceProviderContracts.d.ts +8 -0
- package/dist/react/useVoiceProviderSimulationControls.d.ts +10 -0
- package/dist/react/useVoiceProviderStatus.d.ts +8 -0
- package/dist/react/useVoiceReadinessFailures.d.ts +8 -0
- package/dist/react/useVoiceRoutingStatus.d.ts +8 -0
- package/dist/react/useVoiceStream.d.ts +3 -0
- package/dist/react/useVoiceTraceTimeline.d.ts +8 -0
- package/dist/react/useVoiceTurnLatency.d.ts +9 -0
- package/dist/react/useVoiceTurnQuality.d.ts +8 -0
- package/dist/react/useVoiceWorkflowStatus.d.ts +8 -0
- package/dist/readinessProfiles.d.ts +38 -0
- package/dist/reconnectContract.d.ts +88 -0
- package/dist/resilienceRoutes.d.ts +143 -0
- package/dist/sessionReplay.d.ts +187 -0
- package/dist/simulationSuite.d.ts +143 -0
- package/dist/sloCalibration.d.ts +185 -0
- package/dist/sqliteStore.d.ts +13 -2
- package/dist/svelte/createVoiceAgentSquadStatus.d.ts +9 -0
- package/dist/svelte/createVoiceCampaignDialerProof.d.ts +9 -0
- package/dist/svelte/createVoiceDeliveryRuntime.d.ts +11 -0
- package/dist/svelte/createVoiceLiveOps.d.ts +13 -0
- package/dist/svelte/createVoiceOpsActionCenter.d.ts +10 -0
- package/dist/svelte/createVoiceOpsStatus.d.ts +9 -0
- package/dist/svelte/createVoicePlatformCoverage.d.ts +7 -0
- package/dist/svelte/createVoiceProofTrends.d.ts +7 -0
- package/dist/svelte/createVoiceProviderCapabilities.d.ts +10 -0
- package/dist/svelte/createVoiceProviderContracts.d.ts +10 -0
- package/dist/svelte/createVoiceProviderSimulationControls.d.ts +11 -0
- package/dist/svelte/createVoiceProviderStatus.d.ts +10 -0
- package/dist/svelte/createVoiceReadinessFailures.d.ts +7 -0
- package/dist/svelte/createVoiceRoutingStatus.d.ts +10 -0
- package/dist/svelte/createVoiceTraceTimeline.d.ts +10 -0
- package/dist/svelte/createVoiceTurnLatency.d.ts +11 -0
- package/dist/svelte/createVoiceTurnQuality.d.ts +10 -0
- package/dist/svelte/createVoiceWorkflowStatus.d.ts +8 -0
- package/dist/svelte/index.d.ts +18 -0
- package/dist/svelte/index.js +5036 -407
- package/dist/telephony/contract.d.ts +61 -0
- package/dist/telephony/matrix.d.ts +97 -0
- package/dist/telephony/plivo.d.ts +303 -0
- package/dist/telephony/security.d.ts +182 -0
- package/dist/telephony/telnyx.d.ts +291 -0
- package/dist/telephony/twilio.d.ts +135 -2
- package/dist/telephonyOutcome.d.ts +273 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +3206 -180
- package/dist/testing/ioProviderSimulator.d.ts +41 -0
- package/dist/testing/providerSimulator.d.ts +44 -0
- package/dist/toolContract.d.ts +161 -0
- package/dist/toolRuntime.d.ts +50 -0
- package/dist/trace.d.ts +19 -1
- package/dist/traceDeliveryRoutes.d.ts +86 -0
- package/dist/traceTimeline.d.ts +97 -0
- package/dist/turnLatency.d.ts +95 -0
- package/dist/turnQuality.d.ts +94 -0
- package/dist/types.d.ts +180 -4
- package/dist/voiceMonitoring.d.ts +444 -0
- package/dist/vue/VoiceDeliveryRuntime.d.ts +30 -0
- package/dist/vue/VoiceOpsActionCenter.d.ts +13 -0
- package/dist/vue/VoiceOpsStatus.d.ts +30 -0
- package/dist/vue/VoicePlatformCoverage.d.ts +23 -0
- package/dist/vue/VoiceProofTrends.d.ts +21 -0
- package/dist/vue/VoiceProviderCapabilities.d.ts +51 -0
- package/dist/vue/VoiceProviderContracts.d.ts +21 -0
- package/dist/vue/VoiceProviderSimulationControls.d.ts +88 -0
- package/dist/vue/VoiceProviderStatus.d.ts +51 -0
- package/dist/vue/VoiceReadinessFailures.d.ts +21 -0
- package/dist/vue/VoiceRoutingStatus.d.ts +51 -0
- package/dist/vue/VoiceTurnLatency.d.ts +69 -0
- package/dist/vue/VoiceTurnQuality.d.ts +51 -0
- package/dist/vue/index.d.ts +31 -0
- package/dist/vue/index.js +4962 -31
- package/dist/vue/useVoiceAgentSquadStatus.d.ts +9 -0
- package/dist/vue/useVoiceCampaignDialerProof.d.ts +11 -0
- package/dist/vue/useVoiceController.d.ts +2 -1
- package/dist/vue/useVoiceDeliveryRuntime.d.ts +13 -0
- package/dist/vue/useVoiceLiveOps.d.ts +9 -0
- package/dist/vue/useVoiceOpsActionCenter.d.ts +11 -0
- package/dist/vue/useVoiceOpsStatus.d.ts +9 -0
- package/dist/vue/useVoicePlatformCoverage.d.ts +9 -0
- package/dist/vue/useVoiceProofTrends.d.ts +9 -0
- package/dist/vue/useVoiceProviderCapabilities.d.ts +9 -0
- package/dist/vue/useVoiceProviderContracts.d.ts +9 -0
- package/dist/vue/useVoiceProviderSimulationControls.d.ts +24 -0
- package/dist/vue/useVoiceProviderStatus.d.ts +9 -0
- package/dist/vue/useVoiceReadinessFailures.d.ts +775 -0
- package/dist/vue/useVoiceRoutingStatus.d.ts +8 -0
- package/dist/vue/useVoiceStream.d.ts +4 -1
- package/dist/vue/useVoiceTraceTimeline.d.ts +9 -0
- package/dist/vue/useVoiceTurnLatency.d.ts +10 -0
- package/dist/vue/useVoiceTurnQuality.d.ts +9 -0
- package/dist/vue/useVoiceWorkflowStatus.d.ts +9 -0
- package/dist/workflowContract.d.ts +91 -0
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -69,1226 +69,3766 @@ var __decorateElement = (array, flags, name, decorators, target, extra) => {
|
|
|
69
69
|
return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
// src/angular/voice-
|
|
72
|
+
// src/angular/voice-ops-status.service.ts
|
|
73
73
|
import { computed, Injectable, signal } from "@angular/core";
|
|
74
74
|
|
|
75
|
-
// src/client/
|
|
76
|
-
var
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return value.message;
|
|
75
|
+
// src/client/opsStatus.ts
|
|
76
|
+
var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
|
|
77
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
78
|
+
const response = await fetchImpl(path);
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw new Error(`Voice ops status failed: HTTP ${response.status}`);
|
|
82
81
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
82
|
+
return await response.json();
|
|
83
|
+
};
|
|
84
|
+
var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) => {
|
|
85
|
+
const listeners = new Set;
|
|
86
|
+
let closed = false;
|
|
87
|
+
let timer;
|
|
88
|
+
let snapshot = {
|
|
89
|
+
error: null,
|
|
90
|
+
isLoading: false
|
|
91
|
+
};
|
|
92
|
+
const emit = () => {
|
|
93
|
+
for (const listener of listeners) {
|
|
94
|
+
listener();
|
|
93
95
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
};
|
|
97
|
+
const refresh = async () => {
|
|
98
|
+
if (closed) {
|
|
99
|
+
return snapshot.report;
|
|
96
100
|
}
|
|
101
|
+
snapshot = {
|
|
102
|
+
...snapshot,
|
|
103
|
+
error: null,
|
|
104
|
+
isLoading: true
|
|
105
|
+
};
|
|
106
|
+
emit();
|
|
97
107
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
switch (message.type) {
|
|
105
|
-
case "audio":
|
|
106
|
-
return {
|
|
107
|
-
chunk: Uint8Array.from(atob(message.chunkBase64), (char) => char.charCodeAt(0)),
|
|
108
|
-
format: message.format,
|
|
109
|
-
receivedAt: message.receivedAt,
|
|
110
|
-
turnId: message.turnId,
|
|
111
|
-
type: "audio"
|
|
112
|
-
};
|
|
113
|
-
case "assistant":
|
|
114
|
-
return {
|
|
115
|
-
text: message.text,
|
|
116
|
-
type: "assistant"
|
|
117
|
-
};
|
|
118
|
-
case "complete":
|
|
119
|
-
return {
|
|
120
|
-
sessionId: message.sessionId,
|
|
121
|
-
type: "complete"
|
|
122
|
-
};
|
|
123
|
-
case "error":
|
|
124
|
-
return {
|
|
125
|
-
message: normalizeErrorMessage(message.message),
|
|
126
|
-
type: "error"
|
|
127
|
-
};
|
|
128
|
-
case "final":
|
|
129
|
-
return {
|
|
130
|
-
transcript: message.transcript,
|
|
131
|
-
type: "final"
|
|
132
|
-
};
|
|
133
|
-
case "partial":
|
|
134
|
-
return {
|
|
135
|
-
transcript: message.transcript,
|
|
136
|
-
type: "partial"
|
|
108
|
+
const report = await fetchVoiceOpsStatus(path, options);
|
|
109
|
+
snapshot = {
|
|
110
|
+
error: null,
|
|
111
|
+
isLoading: false,
|
|
112
|
+
report,
|
|
113
|
+
updatedAt: Date.now()
|
|
137
114
|
};
|
|
138
|
-
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
case "turn":
|
|
146
|
-
return {
|
|
147
|
-
turn: message.turn,
|
|
148
|
-
type: "turn"
|
|
115
|
+
emit();
|
|
116
|
+
return report;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
snapshot = {
|
|
119
|
+
...snapshot,
|
|
120
|
+
error: error instanceof Error ? error.message : String(error),
|
|
121
|
+
isLoading: false
|
|
149
122
|
};
|
|
150
|
-
|
|
151
|
-
|
|
123
|
+
emit();
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const close = () => {
|
|
128
|
+
closed = true;
|
|
129
|
+
if (timer) {
|
|
130
|
+
clearInterval(timer);
|
|
131
|
+
timer = undefined;
|
|
132
|
+
}
|
|
133
|
+
listeners.clear();
|
|
134
|
+
};
|
|
135
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
136
|
+
timer = setInterval(() => {
|
|
137
|
+
refresh().catch(() => {});
|
|
138
|
+
}, options.intervalMs);
|
|
152
139
|
}
|
|
140
|
+
return {
|
|
141
|
+
close,
|
|
142
|
+
getServerSnapshot: () => snapshot,
|
|
143
|
+
getSnapshot: () => snapshot,
|
|
144
|
+
refresh,
|
|
145
|
+
subscribe: (listener) => {
|
|
146
|
+
listeners.add(listener);
|
|
147
|
+
return () => {
|
|
148
|
+
listeners.delete(listener);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
};
|
|
153
152
|
};
|
|
154
153
|
|
|
155
|
-
// src/
|
|
156
|
-
var
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
var
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
154
|
+
// src/angular/voice-ops-status.service.ts
|
|
155
|
+
var _dec = [
|
|
156
|
+
Injectable({ providedIn: "root" })
|
|
157
|
+
];
|
|
158
|
+
var _init = __decoratorStart(undefined);
|
|
159
|
+
|
|
160
|
+
class VoiceOpsStatusService {
|
|
161
|
+
connect(path = "/api/voice/ops-status", options = {}) {
|
|
162
|
+
const store = createVoiceOpsStatusStore(path, options);
|
|
163
|
+
const errorSignal = signal(null);
|
|
164
|
+
const isLoadingSignal = signal(false);
|
|
165
|
+
const reportSignal = signal(undefined);
|
|
166
|
+
const updatedAtSignal = signal(undefined);
|
|
167
|
+
const sync = () => {
|
|
168
|
+
const snapshot = store.getSnapshot();
|
|
169
|
+
errorSignal.set(snapshot.error);
|
|
170
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
171
|
+
reportSignal.set(snapshot.report);
|
|
172
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
173
|
+
};
|
|
174
|
+
const unsubscribe = store.subscribe(sync);
|
|
175
|
+
sync();
|
|
176
|
+
if (typeof window !== "undefined") {
|
|
177
|
+
store.refresh().catch(() => {});
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
close: () => {
|
|
181
|
+
unsubscribe();
|
|
182
|
+
store.close();
|
|
183
|
+
},
|
|
184
|
+
error: computed(() => errorSignal()),
|
|
185
|
+
isLoading: computed(() => isLoadingSignal()),
|
|
186
|
+
refresh: store.refresh,
|
|
187
|
+
report: computed(() => reportSignal()),
|
|
188
|
+
updatedAt: computed(() => updatedAtSignal())
|
|
189
|
+
};
|
|
185
190
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
+
}
|
|
192
|
+
VoiceOpsStatusService = __decorateElement(_init, 0, "VoiceOpsStatusService", _dec, VoiceOpsStatusService);
|
|
193
|
+
__runInitializers(_init, 1, VoiceOpsStatusService);
|
|
194
|
+
__decoratorMetadata(_init, VoiceOpsStatusService);
|
|
195
|
+
let _VoiceOpsStatusService = VoiceOpsStatusService;
|
|
196
|
+
// src/angular/voice-platform-coverage.service.ts
|
|
197
|
+
import { computed as computed2, Injectable as Injectable2, signal as signal2 } from "@angular/core";
|
|
198
|
+
|
|
199
|
+
// src/client/platformCoverage.ts
|
|
200
|
+
var fetchVoicePlatformCoverage = async (path = "/api/voice/platform-coverage", options = {}) => {
|
|
201
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
202
|
+
const response = await fetchImpl(path);
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
throw new Error(`Voice platform coverage failed: HTTP ${response.status}`);
|
|
191
205
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
206
|
+
return await response.json();
|
|
207
|
+
};
|
|
208
|
+
var createVoicePlatformCoverageStore = (path = "/api/voice/platform-coverage", options = {}) => {
|
|
209
|
+
const listeners = new Set;
|
|
210
|
+
let closed = false;
|
|
211
|
+
let timer;
|
|
212
|
+
let snapshot = {
|
|
213
|
+
error: null,
|
|
214
|
+
isLoading: false
|
|
215
|
+
};
|
|
216
|
+
const emit = () => {
|
|
217
|
+
for (const listener of listeners) {
|
|
218
|
+
listener();
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const refresh = async () => {
|
|
222
|
+
if (closed) {
|
|
223
|
+
return snapshot.report;
|
|
224
|
+
}
|
|
225
|
+
snapshot = {
|
|
226
|
+
...snapshot,
|
|
227
|
+
error: null,
|
|
228
|
+
isLoading: true
|
|
229
|
+
};
|
|
230
|
+
emit();
|
|
231
|
+
try {
|
|
232
|
+
const report = await fetchVoicePlatformCoverage(path, options);
|
|
233
|
+
snapshot = {
|
|
234
|
+
error: null,
|
|
235
|
+
isLoading: false,
|
|
236
|
+
report,
|
|
237
|
+
updatedAt: Date.now()
|
|
238
|
+
};
|
|
239
|
+
emit();
|
|
240
|
+
return report;
|
|
241
|
+
} catch (error) {
|
|
242
|
+
snapshot = {
|
|
243
|
+
...snapshot,
|
|
244
|
+
error: error instanceof Error ? error.message : String(error),
|
|
245
|
+
isLoading: false
|
|
246
|
+
};
|
|
247
|
+
emit();
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const close = () => {
|
|
252
|
+
closed = true;
|
|
253
|
+
if (timer) {
|
|
254
|
+
clearInterval(timer);
|
|
255
|
+
timer = undefined;
|
|
256
|
+
}
|
|
257
|
+
listeners.clear();
|
|
258
|
+
};
|
|
259
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
260
|
+
timer = setInterval(() => {
|
|
261
|
+
refresh().catch(() => {});
|
|
262
|
+
}, options.intervalMs);
|
|
205
263
|
}
|
|
264
|
+
return {
|
|
265
|
+
close,
|
|
266
|
+
getServerSnapshot: () => snapshot,
|
|
267
|
+
getSnapshot: () => snapshot,
|
|
268
|
+
refresh,
|
|
269
|
+
subscribe: (listener) => {
|
|
270
|
+
listeners.add(listener);
|
|
271
|
+
return () => {
|
|
272
|
+
listeners.delete(listener);
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
};
|
|
206
276
|
};
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
277
|
+
|
|
278
|
+
// src/angular/voice-platform-coverage.service.ts
|
|
279
|
+
var _dec = [
|
|
280
|
+
Injectable2({ providedIn: "root" })
|
|
281
|
+
];
|
|
282
|
+
var _init = __decoratorStart(undefined);
|
|
283
|
+
|
|
284
|
+
class VoicePlatformCoverageService {
|
|
285
|
+
connect(path = "/api/voice/platform-coverage", options = {}) {
|
|
286
|
+
const store = createVoicePlatformCoverageStore(path, options);
|
|
287
|
+
const errorSignal = signal2(null);
|
|
288
|
+
const isLoadingSignal = signal2(false);
|
|
289
|
+
const reportSignal = signal2(undefined);
|
|
290
|
+
const updatedAtSignal = signal2(undefined);
|
|
291
|
+
const sync = () => {
|
|
292
|
+
const snapshot = store.getSnapshot();
|
|
293
|
+
errorSignal.set(snapshot.error);
|
|
294
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
295
|
+
reportSignal.set(snapshot.report);
|
|
296
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
297
|
+
};
|
|
298
|
+
const unsubscribe = store.subscribe(sync);
|
|
299
|
+
sync();
|
|
300
|
+
if (typeof window !== "undefined") {
|
|
301
|
+
store.refresh().catch(() => {});
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
close: () => {
|
|
305
|
+
unsubscribe();
|
|
306
|
+
store.close();
|
|
307
|
+
},
|
|
308
|
+
error: computed2(() => errorSignal()),
|
|
309
|
+
isLoading: computed2(() => isLoadingSignal()),
|
|
310
|
+
refresh: store.refresh,
|
|
311
|
+
report: computed2(() => reportSignal()),
|
|
312
|
+
updatedAt: computed2(() => updatedAtSignal())
|
|
313
|
+
};
|
|
210
314
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
315
|
+
}
|
|
316
|
+
VoicePlatformCoverageService = __decorateElement(_init, 0, "VoicePlatformCoverageService", _dec, VoicePlatformCoverageService);
|
|
317
|
+
__runInitializers(_init, 1, VoicePlatformCoverageService);
|
|
318
|
+
__decoratorMetadata(_init, VoicePlatformCoverageService);
|
|
319
|
+
let _VoicePlatformCoverageService = VoicePlatformCoverageService;
|
|
320
|
+
// src/angular/voice-proof-trends.service.ts
|
|
321
|
+
import { computed as computed3, Injectable as Injectable3, signal as signal3 } from "@angular/core";
|
|
322
|
+
|
|
323
|
+
// src/client/proofTrends.ts
|
|
324
|
+
var fetchVoiceProofTrends = async (path = "/api/voice/proof-trends", options = {}) => {
|
|
325
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
326
|
+
const response = await fetchImpl(path);
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
throw new Error(`Voice proof trends failed: HTTP ${response.status}`);
|
|
216
329
|
}
|
|
330
|
+
return await response.json();
|
|
217
331
|
};
|
|
218
|
-
var
|
|
219
|
-
if (typeof window === "undefined") {
|
|
220
|
-
return NOOP_CONNECTION;
|
|
221
|
-
}
|
|
332
|
+
var createVoiceProofTrendsStore = (path = "/api/voice/proof-trends", options = {}) => {
|
|
222
333
|
const listeners = new Set;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
pendingMessages: [],
|
|
229
|
-
scenarioId: options.scenarioId ?? null,
|
|
230
|
-
pingInterval: null,
|
|
231
|
-
reconnectAttempts: 0,
|
|
232
|
-
reconnectTimeout: null,
|
|
233
|
-
sessionId: options.sessionId ?? createSessionId(),
|
|
234
|
-
ws: null
|
|
334
|
+
let closed = false;
|
|
335
|
+
let timer;
|
|
336
|
+
let snapshot = {
|
|
337
|
+
error: null,
|
|
338
|
+
isLoading: false
|
|
235
339
|
};
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
state.pingInterval = null;
|
|
340
|
+
const emit = () => {
|
|
341
|
+
for (const listener of listeners) {
|
|
342
|
+
listener();
|
|
240
343
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
344
|
+
};
|
|
345
|
+
const refresh = async () => {
|
|
346
|
+
if (closed) {
|
|
347
|
+
return snapshot.report;
|
|
348
|
+
}
|
|
349
|
+
snapshot = {
|
|
350
|
+
...snapshot,
|
|
351
|
+
error: null,
|
|
352
|
+
isLoading: true
|
|
353
|
+
};
|
|
354
|
+
emit();
|
|
355
|
+
try {
|
|
356
|
+
const report = await fetchVoiceProofTrends(path, options);
|
|
357
|
+
snapshot = {
|
|
358
|
+
error: null,
|
|
359
|
+
isLoading: false,
|
|
360
|
+
report,
|
|
361
|
+
updatedAt: Date.now()
|
|
362
|
+
};
|
|
363
|
+
emit();
|
|
364
|
+
return report;
|
|
365
|
+
} catch (error) {
|
|
366
|
+
snapshot = {
|
|
367
|
+
...snapshot,
|
|
368
|
+
error: error instanceof Error ? error.message : String(error),
|
|
369
|
+
isLoading: false
|
|
370
|
+
};
|
|
371
|
+
emit();
|
|
372
|
+
throw error;
|
|
244
373
|
}
|
|
245
374
|
};
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
375
|
+
const close = () => {
|
|
376
|
+
closed = true;
|
|
377
|
+
if (timer) {
|
|
378
|
+
clearInterval(timer);
|
|
379
|
+
timer = undefined;
|
|
249
380
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
381
|
+
listeners.clear();
|
|
382
|
+
};
|
|
383
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
384
|
+
timer = setInterval(() => {
|
|
385
|
+
refresh().catch(() => {});
|
|
386
|
+
}, options.intervalMs);
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
close,
|
|
390
|
+
getServerSnapshot: () => snapshot,
|
|
391
|
+
getSnapshot: () => snapshot,
|
|
392
|
+
refresh,
|
|
393
|
+
subscribe: (listener) => {
|
|
394
|
+
listeners.add(listener);
|
|
395
|
+
return () => {
|
|
396
|
+
listeners.delete(listener);
|
|
397
|
+
};
|
|
255
398
|
}
|
|
256
399
|
};
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}));
|
|
279
|
-
state.pingInterval = setInterval(() => {
|
|
280
|
-
if (ws.readyState === WS_OPEN) {
|
|
281
|
-
ws.send(JSON.stringify({ type: "ping" }));
|
|
282
|
-
}
|
|
283
|
-
}, pingInterval);
|
|
284
|
-
};
|
|
285
|
-
ws.onmessage = (event) => {
|
|
286
|
-
const parsed = parseServerMessage(event);
|
|
287
|
-
if (!parsed) {
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
if (parsed.type === "session") {
|
|
291
|
-
state.sessionId = parsed.sessionId;
|
|
292
|
-
state.scenarioId = parsed.scenarioId ?? state.scenarioId;
|
|
293
|
-
}
|
|
294
|
-
listeners.forEach((listener) => listener(parsed));
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// src/angular/voice-proof-trends.service.ts
|
|
403
|
+
var _dec = [
|
|
404
|
+
Injectable3({ providedIn: "root" })
|
|
405
|
+
];
|
|
406
|
+
var _init = __decoratorStart(undefined);
|
|
407
|
+
|
|
408
|
+
class VoiceProofTrendsService {
|
|
409
|
+
connect(path = "/api/voice/proof-trends", options = {}) {
|
|
410
|
+
const store = createVoiceProofTrendsStore(path, options);
|
|
411
|
+
const errorSignal = signal3(null);
|
|
412
|
+
const isLoadingSignal = signal3(false);
|
|
413
|
+
const reportSignal = signal3(undefined);
|
|
414
|
+
const updatedAtSignal = signal3(undefined);
|
|
415
|
+
const sync = () => {
|
|
416
|
+
const snapshot = store.getSnapshot();
|
|
417
|
+
errorSignal.set(snapshot.error);
|
|
418
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
419
|
+
reportSignal.set(snapshot.report);
|
|
420
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
295
421
|
};
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
422
|
+
const unsubscribe = store.subscribe(sync);
|
|
423
|
+
sync();
|
|
424
|
+
if (typeof window !== "undefined") {
|
|
425
|
+
store.refresh().catch(() => {});
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
close: () => {
|
|
429
|
+
unsubscribe();
|
|
430
|
+
store.close();
|
|
431
|
+
},
|
|
432
|
+
error: computed3(() => errorSignal()),
|
|
433
|
+
isLoading: computed3(() => isLoadingSignal()),
|
|
434
|
+
refresh: store.refresh,
|
|
435
|
+
report: computed3(() => reportSignal()),
|
|
436
|
+
updatedAt: computed3(() => updatedAtSignal())
|
|
303
437
|
};
|
|
304
|
-
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
VoiceProofTrendsService = __decorateElement(_init, 0, "VoiceProofTrendsService", _dec, VoiceProofTrendsService);
|
|
441
|
+
__runInitializers(_init, 1, VoiceProofTrendsService);
|
|
442
|
+
__decoratorMetadata(_init, VoiceProofTrendsService);
|
|
443
|
+
let _VoiceProofTrendsService = VoiceProofTrendsService;
|
|
444
|
+
// src/angular/voice-readiness-failures.service.ts
|
|
445
|
+
import { computed as computed4, Injectable as Injectable4, signal as signal4 } from "@angular/core";
|
|
446
|
+
|
|
447
|
+
// src/client/readinessFailures.ts
|
|
448
|
+
var fetchVoiceReadinessFailures = async (path = "/api/production-readiness", options = {}) => {
|
|
449
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
450
|
+
const response = await fetchImpl(path);
|
|
451
|
+
if (!response.ok) {
|
|
452
|
+
throw new Error(`Voice readiness failed: HTTP ${response.status}`);
|
|
453
|
+
}
|
|
454
|
+
return await response.json();
|
|
455
|
+
};
|
|
456
|
+
var createVoiceReadinessFailuresStore = (path = "/api/production-readiness", options = {}) => {
|
|
457
|
+
const listeners = new Set;
|
|
458
|
+
let closed = false;
|
|
459
|
+
let timer;
|
|
460
|
+
let snapshot = {
|
|
461
|
+
error: null,
|
|
462
|
+
isLoading: false
|
|
305
463
|
};
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
return;
|
|
464
|
+
const emit = () => {
|
|
465
|
+
for (const listener of listeners) {
|
|
466
|
+
listener();
|
|
310
467
|
}
|
|
311
|
-
state.pendingMessages.push(value);
|
|
312
468
|
};
|
|
313
|
-
const
|
|
314
|
-
|
|
469
|
+
const refresh = async () => {
|
|
470
|
+
if (closed) {
|
|
471
|
+
return snapshot.report;
|
|
472
|
+
}
|
|
473
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
474
|
+
emit();
|
|
475
|
+
try {
|
|
476
|
+
const report = await fetchVoiceReadinessFailures(path, options);
|
|
477
|
+
snapshot = {
|
|
478
|
+
error: null,
|
|
479
|
+
isLoading: false,
|
|
480
|
+
report,
|
|
481
|
+
updatedAt: Date.now()
|
|
482
|
+
};
|
|
483
|
+
emit();
|
|
484
|
+
return report;
|
|
485
|
+
} catch (error) {
|
|
486
|
+
snapshot = {
|
|
487
|
+
...snapshot,
|
|
488
|
+
error: error instanceof Error ? error.message : String(error),
|
|
489
|
+
isLoading: false
|
|
490
|
+
};
|
|
491
|
+
emit();
|
|
492
|
+
throw error;
|
|
493
|
+
}
|
|
315
494
|
};
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
495
|
+
const close = () => {
|
|
496
|
+
closed = true;
|
|
497
|
+
if (timer) {
|
|
498
|
+
clearInterval(timer);
|
|
499
|
+
timer = undefined;
|
|
319
500
|
}
|
|
320
|
-
|
|
321
|
-
|
|
501
|
+
listeners.clear();
|
|
502
|
+
};
|
|
503
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
504
|
+
timer = setInterval(() => {
|
|
505
|
+
refresh().catch(() => {});
|
|
506
|
+
}, options.intervalMs);
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
close,
|
|
510
|
+
getServerSnapshot: () => snapshot,
|
|
511
|
+
getSnapshot: () => snapshot,
|
|
512
|
+
refresh,
|
|
513
|
+
subscribe: (listener) => {
|
|
514
|
+
listeners.add(listener);
|
|
515
|
+
return () => {
|
|
516
|
+
listeners.delete(listener);
|
|
517
|
+
};
|
|
322
518
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
519
|
+
};
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
// src/angular/voice-readiness-failures.service.ts
|
|
523
|
+
var _dec = [
|
|
524
|
+
Injectable4({ providedIn: "root" })
|
|
525
|
+
];
|
|
526
|
+
var _init = __decoratorStart(undefined);
|
|
527
|
+
|
|
528
|
+
class VoiceReadinessFailuresService {
|
|
529
|
+
connect(path = "/api/production-readiness", options = {}) {
|
|
530
|
+
const store = createVoiceReadinessFailuresStore(path, options);
|
|
531
|
+
const errorSignal = signal4(null);
|
|
532
|
+
const isLoadingSignal = signal4(false);
|
|
533
|
+
const reportSignal = signal4(undefined);
|
|
534
|
+
const updatedAtSignal = signal4(undefined);
|
|
535
|
+
const sync = () => {
|
|
536
|
+
const snapshot = store.getSnapshot();
|
|
537
|
+
errorSignal.set(snapshot.error);
|
|
538
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
539
|
+
reportSignal.set(snapshot.report);
|
|
540
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
541
|
+
};
|
|
542
|
+
const unsubscribe = store.subscribe(sync);
|
|
543
|
+
sync();
|
|
544
|
+
if (typeof window !== "undefined") {
|
|
545
|
+
store.refresh().catch(() => {});
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
close: () => {
|
|
549
|
+
unsubscribe();
|
|
550
|
+
store.close();
|
|
551
|
+
},
|
|
552
|
+
error: computed4(() => errorSignal()),
|
|
553
|
+
explanations: computed4(() => reportSignal()?.checks.filter((check) => check.status !== "pass" && !!check.gateExplanation) ?? []),
|
|
554
|
+
isLoading: computed4(() => isLoadingSignal()),
|
|
555
|
+
refresh: store.refresh,
|
|
556
|
+
report: computed4(() => reportSignal()),
|
|
557
|
+
updatedAt: computed4(() => updatedAtSignal())
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
VoiceReadinessFailuresService = __decorateElement(_init, 0, "VoiceReadinessFailuresService", _dec, VoiceReadinessFailuresService);
|
|
562
|
+
__runInitializers(_init, 1, VoiceReadinessFailuresService);
|
|
563
|
+
__decoratorMetadata(_init, VoiceReadinessFailuresService);
|
|
564
|
+
let _VoiceReadinessFailuresService = VoiceReadinessFailuresService;
|
|
565
|
+
// src/angular/voice-ops-action-center.service.ts
|
|
566
|
+
import { computed as computed5, Injectable as Injectable5, signal as signal5 } from "@angular/core";
|
|
567
|
+
|
|
568
|
+
// src/client/opsActionCenter.ts
|
|
569
|
+
var recordVoiceOpsActionResult = async (result, options = {}) => {
|
|
570
|
+
if (options.auditPath === false) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const path = options.auditPath ?? "/api/voice/ops-actions/audit";
|
|
574
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
575
|
+
const response = await fetchImpl(path, {
|
|
576
|
+
body: JSON.stringify(result),
|
|
577
|
+
headers: {
|
|
578
|
+
"Content-Type": "application/json"
|
|
579
|
+
},
|
|
580
|
+
method: "POST"
|
|
581
|
+
});
|
|
582
|
+
if (!response.ok) {
|
|
583
|
+
throw new Error(`Voice ops action audit failed: HTTP ${response.status}`);
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
var createVoiceOpsActionCenterActions = (options = {}) => {
|
|
587
|
+
const deliveryRuntimePath = options.deliveryRuntimePath ?? "/api/voice-delivery-runtime";
|
|
588
|
+
const actions = [];
|
|
589
|
+
if (options.includeProductionReadiness !== false) {
|
|
590
|
+
actions.push({
|
|
591
|
+
description: "Refresh the production readiness report.",
|
|
592
|
+
id: "production-readiness",
|
|
593
|
+
label: "Refresh readiness",
|
|
594
|
+
method: "GET",
|
|
595
|
+
path: options.productionReadinessPath ?? "/api/production-readiness"
|
|
327
596
|
});
|
|
597
|
+
}
|
|
598
|
+
if (options.includeDeliveryRuntime !== false) {
|
|
599
|
+
actions.push({
|
|
600
|
+
description: "Drain pending and failed audit/trace deliveries.",
|
|
601
|
+
id: "delivery-runtime.tick",
|
|
602
|
+
label: "Tick delivery workers",
|
|
603
|
+
method: "POST",
|
|
604
|
+
path: `${deliveryRuntimePath.replace(/\/$/, "")}/tick`
|
|
605
|
+
}, {
|
|
606
|
+
description: "Move reviewed dead letters back to live delivery queues.",
|
|
607
|
+
id: "delivery-runtime.requeue-dead-letters",
|
|
608
|
+
label: "Requeue dead letters",
|
|
609
|
+
method: "POST",
|
|
610
|
+
path: `${deliveryRuntimePath.replace(/\/$/, "")}/requeue-dead-letters`
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
if (options.includeTurnLatencyProof !== false) {
|
|
614
|
+
actions.push({
|
|
615
|
+
description: "Run the synthetic turn latency proof.",
|
|
616
|
+
id: "turn-latency.proof",
|
|
617
|
+
label: "Run latency proof",
|
|
618
|
+
method: "POST",
|
|
619
|
+
path: options.turnLatencyProofPath ?? "/api/turn-latency/proof"
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
if (options.includeProviderSimulation !== false) {
|
|
623
|
+
const pathPrefix = options.providerSimulationPathPrefix ?? "/api/stt-simulate";
|
|
624
|
+
for (const provider of options.providers ?? []) {
|
|
625
|
+
actions.push({
|
|
626
|
+
description: `Simulate ${provider} provider failure.`,
|
|
627
|
+
id: `provider.${provider}.failure`,
|
|
628
|
+
label: `Simulate ${provider} failure`,
|
|
629
|
+
method: "POST",
|
|
630
|
+
path: `${pathPrefix}/failure?provider=${encodeURIComponent(provider)}`
|
|
631
|
+
}, {
|
|
632
|
+
description: `Mark ${provider} provider recovered.`,
|
|
633
|
+
id: `provider.${provider}.recovery`,
|
|
634
|
+
label: `Recover ${provider}`,
|
|
635
|
+
method: "POST",
|
|
636
|
+
path: `${pathPrefix}/recovery?provider=${encodeURIComponent(provider)}`
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return actions;
|
|
641
|
+
};
|
|
642
|
+
var runVoiceOpsAction = async (action, options = {}) => {
|
|
643
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
644
|
+
const response = await fetchImpl(action.path, {
|
|
645
|
+
method: action.method ?? "POST"
|
|
646
|
+
});
|
|
647
|
+
const body = await response.json().catch(() => null);
|
|
648
|
+
if (!response.ok) {
|
|
649
|
+
const message = body && typeof body === "object" && "error" in body ? String(body.error) : `Voice ops action "${action.id}" failed: HTTP ${response.status}`;
|
|
650
|
+
throw new Error(message);
|
|
651
|
+
}
|
|
652
|
+
return {
|
|
653
|
+
actionId: action.id,
|
|
654
|
+
body,
|
|
655
|
+
ok: response.ok,
|
|
656
|
+
ranAt: Date.now(),
|
|
657
|
+
status: response.status
|
|
328
658
|
};
|
|
329
|
-
|
|
330
|
-
|
|
659
|
+
};
|
|
660
|
+
var createVoiceOpsActionCenterStore = (options = {}) => {
|
|
661
|
+
const listeners = new Set;
|
|
662
|
+
let closed = false;
|
|
663
|
+
let timer;
|
|
664
|
+
let snapshot = {
|
|
665
|
+
actions: options.actions ?? createVoiceOpsActionCenterActions(),
|
|
666
|
+
error: null,
|
|
667
|
+
isRunning: false
|
|
331
668
|
};
|
|
332
|
-
const
|
|
333
|
-
|
|
669
|
+
const emit = () => {
|
|
670
|
+
for (const listener of listeners) {
|
|
671
|
+
listener();
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
const setActions = (actions) => {
|
|
675
|
+
snapshot = { ...snapshot, actions, updatedAt: Date.now() };
|
|
676
|
+
emit();
|
|
677
|
+
};
|
|
678
|
+
const run = async (actionId) => {
|
|
679
|
+
if (closed) {
|
|
680
|
+
return snapshot.lastResult;
|
|
681
|
+
}
|
|
682
|
+
const action = snapshot.actions.find((item) => item.id === actionId);
|
|
683
|
+
if (!action) {
|
|
684
|
+
throw new Error(`Voice ops action "${actionId}" is not configured.`);
|
|
685
|
+
}
|
|
686
|
+
if (action.disabled) {
|
|
687
|
+
throw new Error(`Voice ops action "${actionId}" is disabled.`);
|
|
688
|
+
}
|
|
689
|
+
snapshot = {
|
|
690
|
+
...snapshot,
|
|
691
|
+
error: null,
|
|
692
|
+
isRunning: true,
|
|
693
|
+
runningActionId: action.id
|
|
694
|
+
};
|
|
695
|
+
emit();
|
|
696
|
+
try {
|
|
697
|
+
const result = await runVoiceOpsAction(action, options);
|
|
698
|
+
await options.onActionResult?.(result);
|
|
699
|
+
await recordVoiceOpsActionResult(result, options);
|
|
700
|
+
snapshot = {
|
|
701
|
+
...snapshot,
|
|
702
|
+
error: null,
|
|
703
|
+
isRunning: false,
|
|
704
|
+
lastResult: result,
|
|
705
|
+
runningActionId: undefined,
|
|
706
|
+
updatedAt: Date.now()
|
|
707
|
+
};
|
|
708
|
+
emit();
|
|
709
|
+
return result;
|
|
710
|
+
} catch (error) {
|
|
711
|
+
const result = {
|
|
712
|
+
actionId: action.id,
|
|
713
|
+
body: null,
|
|
714
|
+
error: error instanceof Error ? error.message : String(error),
|
|
715
|
+
ok: false,
|
|
716
|
+
ranAt: Date.now(),
|
|
717
|
+
status: 0
|
|
718
|
+
};
|
|
719
|
+
await options.onActionResult?.(result);
|
|
720
|
+
await recordVoiceOpsActionResult(result, options).catch(() => {});
|
|
721
|
+
snapshot = {
|
|
722
|
+
...snapshot,
|
|
723
|
+
error: error instanceof Error ? error.message : String(error),
|
|
724
|
+
isRunning: false,
|
|
725
|
+
runningActionId: undefined
|
|
726
|
+
};
|
|
727
|
+
emit();
|
|
728
|
+
throw error;
|
|
729
|
+
}
|
|
334
730
|
};
|
|
335
731
|
const close = () => {
|
|
336
|
-
|
|
337
|
-
if (
|
|
338
|
-
|
|
339
|
-
|
|
732
|
+
closed = true;
|
|
733
|
+
if (timer) {
|
|
734
|
+
clearInterval(timer);
|
|
735
|
+
timer = undefined;
|
|
340
736
|
}
|
|
341
|
-
state.isConnected = false;
|
|
342
737
|
listeners.clear();
|
|
343
738
|
};
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
739
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
740
|
+
timer = setInterval(() => {
|
|
741
|
+
emit();
|
|
742
|
+
}, options.intervalMs);
|
|
743
|
+
}
|
|
744
|
+
return {
|
|
745
|
+
close,
|
|
746
|
+
getServerSnapshot: () => snapshot,
|
|
747
|
+
getSnapshot: () => snapshot,
|
|
748
|
+
run,
|
|
749
|
+
setActions,
|
|
750
|
+
subscribe: (listener) => {
|
|
751
|
+
listeners.add(listener);
|
|
752
|
+
return () => {
|
|
753
|
+
listeners.delete(listener);
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
// src/angular/voice-ops-action-center.service.ts
|
|
760
|
+
var _dec = [
|
|
761
|
+
Injectable5({ providedIn: "root" })
|
|
762
|
+
];
|
|
763
|
+
var _init = __decoratorStart(undefined);
|
|
764
|
+
|
|
765
|
+
class VoiceOpsActionCenterService {
|
|
766
|
+
connect(options = {}) {
|
|
767
|
+
const store = createVoiceOpsActionCenterStore(options);
|
|
768
|
+
const actionsSignal = signal5([]);
|
|
769
|
+
const errorSignal = signal5(null);
|
|
770
|
+
const isRunningSignal = signal5(false);
|
|
771
|
+
const lastResultSignal = signal5(undefined);
|
|
772
|
+
const runningActionIdSignal = signal5(undefined);
|
|
773
|
+
const sync = () => {
|
|
774
|
+
const snapshot = store.getSnapshot();
|
|
775
|
+
actionsSignal.set(snapshot.actions);
|
|
776
|
+
errorSignal.set(snapshot.error);
|
|
777
|
+
isRunningSignal.set(snapshot.isRunning);
|
|
778
|
+
lastResultSignal.set(snapshot.lastResult);
|
|
779
|
+
runningActionIdSignal.set(snapshot.runningActionId);
|
|
780
|
+
};
|
|
781
|
+
const unsubscribe = store.subscribe(sync);
|
|
782
|
+
sync();
|
|
783
|
+
return {
|
|
784
|
+
actions: computed5(() => actionsSignal()),
|
|
785
|
+
close: () => {
|
|
786
|
+
unsubscribe();
|
|
787
|
+
store.close();
|
|
788
|
+
},
|
|
789
|
+
error: computed5(() => errorSignal()),
|
|
790
|
+
isRunning: computed5(() => isRunningSignal()),
|
|
791
|
+
lastResult: computed5(() => lastResultSignal()),
|
|
792
|
+
run: store.run,
|
|
793
|
+
runningActionId: computed5(() => runningActionIdSignal()),
|
|
794
|
+
setActions: store.setActions
|
|
348
795
|
};
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
VoiceOpsActionCenterService = __decorateElement(_init, 0, "VoiceOpsActionCenterService", _dec, VoiceOpsActionCenterService);
|
|
799
|
+
__runInitializers(_init, 1, VoiceOpsActionCenterService);
|
|
800
|
+
__decoratorMetadata(_init, VoiceOpsActionCenterService);
|
|
801
|
+
let _VoiceOpsActionCenterService = VoiceOpsActionCenterService;
|
|
802
|
+
// src/angular/voice-live-ops.service.ts
|
|
803
|
+
import { computed as computed6, Injectable as Injectable6, signal as signal6 } from "@angular/core";
|
|
804
|
+
|
|
805
|
+
// src/client/liveOps.ts
|
|
806
|
+
var postVoiceLiveOpsAction = async (input, options = {}) => {
|
|
807
|
+
if (!input.sessionId) {
|
|
808
|
+
throw new Error("Start a voice session before running live ops actions.");
|
|
809
|
+
}
|
|
810
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
811
|
+
const response = await fetchImpl(options.actionPath ?? "/api/voice/live-ops/action", {
|
|
812
|
+
body: JSON.stringify(input),
|
|
813
|
+
headers: {
|
|
814
|
+
"Content-Type": "application/json"
|
|
815
|
+
},
|
|
816
|
+
method: "POST"
|
|
817
|
+
});
|
|
818
|
+
const payload = await response.json().catch(() => null);
|
|
819
|
+
if (!response.ok || !payload?.ok) {
|
|
820
|
+
const message = payload && typeof payload === "object" && "error" in payload ? String(payload.error) : `Voice live ops action failed: HTTP ${response.status}`;
|
|
821
|
+
throw new Error(message);
|
|
822
|
+
}
|
|
823
|
+
return payload;
|
|
824
|
+
};
|
|
825
|
+
var createVoiceLiveOpsStore = (options = {}) => {
|
|
826
|
+
const listeners = new Set;
|
|
827
|
+
let closed = false;
|
|
828
|
+
let snapshot = {
|
|
829
|
+
error: null,
|
|
830
|
+
isRunning: false
|
|
831
|
+
};
|
|
832
|
+
const emit = () => {
|
|
833
|
+
for (const listener of listeners) {
|
|
834
|
+
listener();
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
const run = async (input) => {
|
|
838
|
+
if (closed) {
|
|
839
|
+
return snapshot.lastResult;
|
|
840
|
+
}
|
|
841
|
+
snapshot = {
|
|
842
|
+
...snapshot,
|
|
843
|
+
error: null,
|
|
844
|
+
isRunning: true,
|
|
845
|
+
runningAction: input.action
|
|
846
|
+
};
|
|
847
|
+
emit();
|
|
848
|
+
try {
|
|
849
|
+
const result = await postVoiceLiveOpsAction(input, options);
|
|
850
|
+
await options.onControl?.(result);
|
|
851
|
+
snapshot = {
|
|
852
|
+
...snapshot,
|
|
853
|
+
error: null,
|
|
854
|
+
isRunning: false,
|
|
855
|
+
lastResult: result,
|
|
856
|
+
runningAction: undefined,
|
|
857
|
+
updatedAt: Date.now()
|
|
858
|
+
};
|
|
859
|
+
emit();
|
|
860
|
+
return result;
|
|
861
|
+
} catch (error) {
|
|
862
|
+
snapshot = {
|
|
863
|
+
...snapshot,
|
|
864
|
+
error: error instanceof Error ? error.message : String(error),
|
|
865
|
+
isRunning: false,
|
|
866
|
+
runningAction: undefined,
|
|
867
|
+
updatedAt: Date.now()
|
|
868
|
+
};
|
|
869
|
+
emit();
|
|
870
|
+
throw error;
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
const close = () => {
|
|
874
|
+
closed = true;
|
|
875
|
+
listeners.clear();
|
|
349
876
|
};
|
|
350
|
-
connect();
|
|
351
877
|
return {
|
|
352
|
-
start,
|
|
353
878
|
close,
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
879
|
+
getServerSnapshot: () => snapshot,
|
|
880
|
+
getSnapshot: () => snapshot,
|
|
881
|
+
run,
|
|
882
|
+
subscribe: (listener) => {
|
|
883
|
+
listeners.add(listener);
|
|
884
|
+
return () => {
|
|
885
|
+
listeners.delete(listener);
|
|
886
|
+
};
|
|
887
|
+
}
|
|
361
888
|
};
|
|
362
889
|
};
|
|
363
890
|
|
|
364
|
-
// src/
|
|
365
|
-
var
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
891
|
+
// src/angular/voice-live-ops.service.ts
|
|
892
|
+
var _dec = [
|
|
893
|
+
Injectable6({ providedIn: "root" })
|
|
894
|
+
];
|
|
895
|
+
var _init = __decoratorStart(undefined);
|
|
896
|
+
|
|
897
|
+
class VoiceLiveOpsService {
|
|
898
|
+
connect(options = {}) {
|
|
899
|
+
const store = createVoiceLiveOpsStore(options);
|
|
900
|
+
const errorSignal = signal6(null);
|
|
901
|
+
const isRunningSignal = signal6(false);
|
|
902
|
+
const lastResultSignal = signal6(undefined);
|
|
903
|
+
const runningActionSignal = signal6(undefined);
|
|
904
|
+
const sync = () => {
|
|
905
|
+
const snapshot = store.getSnapshot();
|
|
906
|
+
errorSignal.set(snapshot.error);
|
|
907
|
+
isRunningSignal.set(snapshot.isRunning);
|
|
908
|
+
lastResultSignal.set(snapshot.lastResult);
|
|
909
|
+
runningActionSignal.set(snapshot.runningAction);
|
|
910
|
+
};
|
|
911
|
+
const unsubscribe = store.subscribe(sync);
|
|
912
|
+
sync();
|
|
913
|
+
return {
|
|
914
|
+
close: () => {
|
|
915
|
+
unsubscribe();
|
|
916
|
+
store.close();
|
|
917
|
+
},
|
|
918
|
+
error: computed6(() => errorSignal()),
|
|
919
|
+
isRunning: computed6(() => isRunningSignal()),
|
|
920
|
+
lastResult: computed6(() => lastResultSignal()),
|
|
921
|
+
run: store.run,
|
|
922
|
+
runningAction: computed6(() => runningActionSignal())
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
VoiceLiveOpsService = __decorateElement(_init, 0, "VoiceLiveOpsService", _dec, VoiceLiveOpsService);
|
|
927
|
+
__runInitializers(_init, 1, VoiceLiveOpsService);
|
|
928
|
+
__decoratorMetadata(_init, VoiceLiveOpsService);
|
|
929
|
+
let _VoiceLiveOpsService = VoiceLiveOpsService;
|
|
930
|
+
// src/angular/voice-delivery-runtime.service.ts
|
|
931
|
+
import { computed as computed7, Injectable as Injectable7, signal as signal7 } from "@angular/core";
|
|
932
|
+
|
|
933
|
+
// src/client/deliveryRuntime.ts
|
|
934
|
+
var getDefaultActionPath = (path, action, options) => {
|
|
935
|
+
if (action === "tick") {
|
|
936
|
+
return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
|
|
937
|
+
}
|
|
938
|
+
return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
|
|
939
|
+
};
|
|
940
|
+
var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
941
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
942
|
+
const response = await fetchImpl(path);
|
|
943
|
+
if (!response.ok) {
|
|
944
|
+
throw new Error(`Voice delivery runtime failed: HTTP ${response.status}`);
|
|
945
|
+
}
|
|
946
|
+
return await response.json();
|
|
947
|
+
};
|
|
948
|
+
var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
949
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
950
|
+
const response = await fetchImpl(getDefaultActionPath(path, action, options), {
|
|
951
|
+
method: "POST"
|
|
952
|
+
});
|
|
953
|
+
if (!response.ok) {
|
|
954
|
+
throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
|
|
955
|
+
}
|
|
956
|
+
const body = await response.json();
|
|
957
|
+
return {
|
|
958
|
+
action,
|
|
959
|
+
result: body.result,
|
|
960
|
+
summary: body.summary,
|
|
961
|
+
updatedAt: Date.now()
|
|
381
962
|
};
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
};
|
|
397
|
-
break;
|
|
398
|
-
case "assistant":
|
|
399
|
-
state = {
|
|
400
|
-
...state,
|
|
401
|
-
assistantTexts: [...state.assistantTexts, action.text]
|
|
402
|
-
};
|
|
403
|
-
break;
|
|
404
|
-
case "complete":
|
|
405
|
-
state = {
|
|
406
|
-
...state,
|
|
407
|
-
sessionId: action.sessionId,
|
|
408
|
-
status: "completed"
|
|
409
|
-
};
|
|
410
|
-
break;
|
|
411
|
-
case "connected":
|
|
412
|
-
state = {
|
|
413
|
-
...state,
|
|
414
|
-
isConnected: true
|
|
415
|
-
};
|
|
416
|
-
break;
|
|
417
|
-
case "disconnected":
|
|
418
|
-
state = {
|
|
419
|
-
...state,
|
|
420
|
-
isConnected: false
|
|
421
|
-
};
|
|
422
|
-
break;
|
|
423
|
-
case "error":
|
|
424
|
-
state = {
|
|
425
|
-
...state,
|
|
426
|
-
error: action.message
|
|
427
|
-
};
|
|
428
|
-
break;
|
|
429
|
-
case "final":
|
|
430
|
-
state = {
|
|
431
|
-
...state,
|
|
432
|
-
partial: action.transcript.text,
|
|
433
|
-
turns: state.turns.map((turn) => turn)
|
|
434
|
-
};
|
|
435
|
-
break;
|
|
436
|
-
case "partial":
|
|
437
|
-
state = {
|
|
438
|
-
...state,
|
|
439
|
-
partial: action.transcript.text
|
|
440
|
-
};
|
|
441
|
-
break;
|
|
442
|
-
case "session":
|
|
443
|
-
state = {
|
|
444
|
-
...state,
|
|
445
|
-
error: null,
|
|
446
|
-
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
447
|
-
isConnected: action.status === "active",
|
|
448
|
-
sessionId: action.sessionId,
|
|
449
|
-
status: action.status
|
|
450
|
-
};
|
|
451
|
-
break;
|
|
452
|
-
case "turn":
|
|
453
|
-
state = {
|
|
454
|
-
...state,
|
|
455
|
-
partial: "",
|
|
456
|
-
turns: [...state.turns, action.turn]
|
|
457
|
-
};
|
|
458
|
-
break;
|
|
963
|
+
};
|
|
964
|
+
var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
965
|
+
const listeners = new Set;
|
|
966
|
+
let closed = false;
|
|
967
|
+
let timer;
|
|
968
|
+
let snapshot = {
|
|
969
|
+
actionError: null,
|
|
970
|
+
actionStatus: "idle",
|
|
971
|
+
error: null,
|
|
972
|
+
isLoading: false
|
|
973
|
+
};
|
|
974
|
+
const emit = () => {
|
|
975
|
+
for (const listener of listeners) {
|
|
976
|
+
listener();
|
|
459
977
|
}
|
|
460
|
-
notify();
|
|
461
978
|
};
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
979
|
+
const refresh = async () => {
|
|
980
|
+
if (closed) {
|
|
981
|
+
return snapshot.report;
|
|
982
|
+
}
|
|
983
|
+
snapshot = {
|
|
984
|
+
...snapshot,
|
|
985
|
+
error: null,
|
|
986
|
+
isLoading: true
|
|
987
|
+
};
|
|
988
|
+
emit();
|
|
989
|
+
try {
|
|
990
|
+
const report = await fetchVoiceDeliveryRuntime(path, options);
|
|
991
|
+
snapshot = {
|
|
992
|
+
...snapshot,
|
|
993
|
+
error: null,
|
|
994
|
+
isLoading: false,
|
|
995
|
+
report,
|
|
996
|
+
updatedAt: Date.now()
|
|
997
|
+
};
|
|
998
|
+
emit();
|
|
999
|
+
return report;
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
snapshot = {
|
|
1002
|
+
...snapshot,
|
|
1003
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1004
|
+
isLoading: false
|
|
470
1005
|
};
|
|
1006
|
+
emit();
|
|
1007
|
+
throw error;
|
|
471
1008
|
}
|
|
472
1009
|
};
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
1010
|
+
const runAction = async (action) => {
|
|
1011
|
+
if (closed) {
|
|
1012
|
+
return snapshot.lastAction;
|
|
1013
|
+
}
|
|
1014
|
+
snapshot = {
|
|
1015
|
+
...snapshot,
|
|
1016
|
+
actionError: null,
|
|
1017
|
+
actionStatus: "running"
|
|
1018
|
+
};
|
|
1019
|
+
emit();
|
|
1020
|
+
try {
|
|
1021
|
+
const result = await runVoiceDeliveryRuntimeAction(action, path, options);
|
|
1022
|
+
snapshot = {
|
|
1023
|
+
...snapshot,
|
|
1024
|
+
actionError: null,
|
|
1025
|
+
actionStatus: "completed",
|
|
1026
|
+
lastAction: result
|
|
1027
|
+
};
|
|
1028
|
+
emit();
|
|
1029
|
+
await refresh();
|
|
1030
|
+
return result;
|
|
1031
|
+
} catch (error) {
|
|
1032
|
+
snapshot = {
|
|
1033
|
+
...snapshot,
|
|
1034
|
+
actionError: error instanceof Error ? error.message : String(error),
|
|
1035
|
+
actionStatus: "failed"
|
|
1036
|
+
};
|
|
1037
|
+
emit();
|
|
1038
|
+
throw error;
|
|
483
1039
|
}
|
|
484
|
-
connection.start(input);
|
|
485
|
-
});
|
|
486
|
-
const notify = () => {
|
|
487
|
-
subscribers.forEach((subscriber) => subscriber());
|
|
488
1040
|
};
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
|
|
1041
|
+
const close = () => {
|
|
1042
|
+
closed = true;
|
|
1043
|
+
if (timer) {
|
|
1044
|
+
clearInterval(timer);
|
|
1045
|
+
timer = undefined;
|
|
494
1046
|
}
|
|
495
|
-
|
|
1047
|
+
listeners.clear();
|
|
1048
|
+
};
|
|
1049
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
1050
|
+
timer = setInterval(() => {
|
|
1051
|
+
refresh().catch(() => {});
|
|
1052
|
+
}, options.intervalMs);
|
|
1053
|
+
}
|
|
496
1054
|
return {
|
|
497
|
-
close
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
},
|
|
506
|
-
get error() {
|
|
507
|
-
return store.getSnapshot().error;
|
|
508
|
-
},
|
|
509
|
-
getServerSnapshot() {
|
|
510
|
-
return store.getServerSnapshot();
|
|
511
|
-
},
|
|
512
|
-
getSnapshot() {
|
|
513
|
-
return store.getSnapshot();
|
|
514
|
-
},
|
|
515
|
-
get isConnected() {
|
|
516
|
-
return store.getSnapshot().isConnected;
|
|
517
|
-
},
|
|
518
|
-
get scenarioId() {
|
|
519
|
-
return store.getSnapshot().scenarioId;
|
|
520
|
-
},
|
|
521
|
-
start,
|
|
522
|
-
get partial() {
|
|
523
|
-
return store.getSnapshot().partial;
|
|
524
|
-
},
|
|
525
|
-
get sessionId() {
|
|
526
|
-
return connection.getSessionId();
|
|
527
|
-
},
|
|
528
|
-
get status() {
|
|
529
|
-
return store.getSnapshot().status;
|
|
530
|
-
},
|
|
531
|
-
get turns() {
|
|
532
|
-
return store.getSnapshot().turns;
|
|
533
|
-
},
|
|
534
|
-
get assistantTexts() {
|
|
535
|
-
return store.getSnapshot().assistantTexts;
|
|
536
|
-
},
|
|
537
|
-
get assistantAudio() {
|
|
538
|
-
return store.getSnapshot().assistantAudio;
|
|
539
|
-
},
|
|
540
|
-
sendAudio(audio) {
|
|
541
|
-
connection.sendAudio(audio);
|
|
542
|
-
},
|
|
543
|
-
subscribe(subscriber) {
|
|
544
|
-
subscribers.add(subscriber);
|
|
1055
|
+
close,
|
|
1056
|
+
getServerSnapshot: () => snapshot,
|
|
1057
|
+
getSnapshot: () => snapshot,
|
|
1058
|
+
requeueDeadLetters: () => runAction("requeue-dead-letters"),
|
|
1059
|
+
refresh,
|
|
1060
|
+
tick: () => runAction("tick"),
|
|
1061
|
+
subscribe: (listener) => {
|
|
1062
|
+
listeners.add(listener);
|
|
545
1063
|
return () => {
|
|
546
|
-
|
|
1064
|
+
listeners.delete(listener);
|
|
547
1065
|
};
|
|
548
1066
|
}
|
|
549
1067
|
};
|
|
550
1068
|
};
|
|
551
1069
|
|
|
552
|
-
// src/angular/voice-
|
|
1070
|
+
// src/angular/voice-delivery-runtime.service.ts
|
|
553
1071
|
var _dec = [
|
|
554
|
-
|
|
1072
|
+
Injectable7({ providedIn: "root" })
|
|
555
1073
|
];
|
|
556
1074
|
var _init = __decoratorStart(undefined);
|
|
557
1075
|
|
|
558
|
-
class
|
|
559
|
-
connect(path, options = {}) {
|
|
560
|
-
const
|
|
561
|
-
const
|
|
562
|
-
const
|
|
563
|
-
const errorSignal =
|
|
564
|
-
const
|
|
565
|
-
const
|
|
566
|
-
const
|
|
567
|
-
const statusSignal = signal(stream.status);
|
|
568
|
-
const turnsSignal = signal([]);
|
|
1076
|
+
class VoiceDeliveryRuntimeService {
|
|
1077
|
+
connect(path = "/api/voice-delivery-runtime", options = {}) {
|
|
1078
|
+
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
1079
|
+
const actionErrorSignal = signal7(null);
|
|
1080
|
+
const actionStatusSignal = signal7("idle");
|
|
1081
|
+
const errorSignal = signal7(null);
|
|
1082
|
+
const isLoadingSignal = signal7(false);
|
|
1083
|
+
const reportSignal = signal7(undefined);
|
|
1084
|
+
const updatedAtSignal = signal7(undefined);
|
|
569
1085
|
const sync = () => {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
turnsSignal.set([...stream.turns]);
|
|
1086
|
+
const snapshot = store.getSnapshot();
|
|
1087
|
+
actionErrorSignal.set(snapshot.actionError);
|
|
1088
|
+
actionStatusSignal.set(snapshot.actionStatus);
|
|
1089
|
+
errorSignal.set(snapshot.error);
|
|
1090
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
1091
|
+
reportSignal.set(snapshot.report);
|
|
1092
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
578
1093
|
};
|
|
579
|
-
const unsubscribe =
|
|
1094
|
+
const unsubscribe = store.subscribe(sync);
|
|
580
1095
|
sync();
|
|
1096
|
+
if (typeof window !== "undefined") {
|
|
1097
|
+
store.refresh().catch(() => {});
|
|
1098
|
+
}
|
|
581
1099
|
return {
|
|
582
|
-
assistantAudio: computed(() => assistantAudioSignal()),
|
|
583
|
-
assistantTexts: computed(() => assistantTextsSignal()),
|
|
584
1100
|
close: () => {
|
|
585
1101
|
unsubscribe();
|
|
586
|
-
|
|
1102
|
+
store.close();
|
|
587
1103
|
},
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
1104
|
+
error: computed7(() => errorSignal()),
|
|
1105
|
+
actionError: computed7(() => actionErrorSignal()),
|
|
1106
|
+
actionStatus: computed7(() => actionStatusSignal()),
|
|
1107
|
+
isLoading: computed7(() => isLoadingSignal()),
|
|
1108
|
+
requeueDeadLetters: store.requeueDeadLetters,
|
|
1109
|
+
refresh: store.refresh,
|
|
1110
|
+
report: computed7(() => reportSignal()),
|
|
1111
|
+
tick: store.tick,
|
|
1112
|
+
updatedAt: computed7(() => updatedAtSignal())
|
|
596
1113
|
};
|
|
597
1114
|
}
|
|
598
1115
|
}
|
|
599
|
-
|
|
600
|
-
__runInitializers(_init, 1,
|
|
601
|
-
__decoratorMetadata(_init,
|
|
602
|
-
let
|
|
603
|
-
// src/angular/voice-
|
|
604
|
-
import { computed as
|
|
1116
|
+
VoiceDeliveryRuntimeService = __decorateElement(_init, 0, "VoiceDeliveryRuntimeService", _dec, VoiceDeliveryRuntimeService);
|
|
1117
|
+
__runInitializers(_init, 1, VoiceDeliveryRuntimeService);
|
|
1118
|
+
__decoratorMetadata(_init, VoiceDeliveryRuntimeService);
|
|
1119
|
+
let _VoiceDeliveryRuntimeService = VoiceDeliveryRuntimeService;
|
|
1120
|
+
// src/angular/voice-campaign-dialer-proof.service.ts
|
|
1121
|
+
import { computed as computed8, Injectable as Injectable8, signal as signal8 } from "@angular/core";
|
|
605
1122
|
|
|
606
|
-
// src/client/
|
|
607
|
-
var
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
if (
|
|
611
|
-
|
|
1123
|
+
// src/client/campaignDialerProof.ts
|
|
1124
|
+
var fetchVoiceCampaignDialerProofStatus = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
1125
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1126
|
+
const response = await fetchImpl(path);
|
|
1127
|
+
if (!response.ok) {
|
|
1128
|
+
throw new Error(`Voice campaign dialer proof status failed: HTTP ${response.status}`);
|
|
612
1129
|
}
|
|
613
|
-
return
|
|
1130
|
+
return await response.json();
|
|
614
1131
|
};
|
|
615
|
-
var
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const url = new URL(baseRoute, window.location.origin);
|
|
621
|
-
if (sessionId) {
|
|
622
|
-
url.searchParams.set(queryParam, sessionId);
|
|
623
|
-
} else {
|
|
624
|
-
url.searchParams.delete(queryParam);
|
|
1132
|
+
var runVoiceCampaignDialerProofAction = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
1133
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1134
|
+
const response = await fetchImpl(path, { method: "POST" });
|
|
1135
|
+
if (!response.ok) {
|
|
1136
|
+
throw new Error(`Voice campaign dialer proof failed: HTTP ${response.status}`);
|
|
625
1137
|
}
|
|
626
|
-
return
|
|
1138
|
+
return await response.json();
|
|
627
1139
|
};
|
|
628
|
-
var
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
const htmxWindow = window;
|
|
640
|
-
const nextRoute = buildRoute(element, options.route, queryParam, stream.sessionId);
|
|
641
|
-
if (nextRoute) {
|
|
642
|
-
element.setAttribute("hx-get", nextRoute);
|
|
1140
|
+
var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
1141
|
+
const listeners = new Set;
|
|
1142
|
+
let closed = false;
|
|
1143
|
+
let timer;
|
|
1144
|
+
let snapshot = {
|
|
1145
|
+
error: null,
|
|
1146
|
+
isLoading: false
|
|
1147
|
+
};
|
|
1148
|
+
const emit = () => {
|
|
1149
|
+
for (const listener of listeners) {
|
|
1150
|
+
listener();
|
|
643
1151
|
}
|
|
644
|
-
htmxWindow.htmx?.process?.(element);
|
|
645
|
-
htmxWindow.htmx?.trigger?.(element, eventName);
|
|
646
1152
|
};
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
1153
|
+
const refresh = async () => {
|
|
1154
|
+
if (closed) {
|
|
1155
|
+
return snapshot.status;
|
|
1156
|
+
}
|
|
1157
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
1158
|
+
emit();
|
|
1159
|
+
try {
|
|
1160
|
+
const status = await fetchVoiceCampaignDialerProofStatus(path, options);
|
|
1161
|
+
snapshot = {
|
|
1162
|
+
...snapshot,
|
|
1163
|
+
error: null,
|
|
1164
|
+
isLoading: false,
|
|
1165
|
+
status,
|
|
1166
|
+
updatedAt: Date.now()
|
|
1167
|
+
};
|
|
1168
|
+
emit();
|
|
1169
|
+
return status;
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
snapshot = {
|
|
1172
|
+
...snapshot,
|
|
1173
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1174
|
+
isLoading: false
|
|
1175
|
+
};
|
|
1176
|
+
emit();
|
|
1177
|
+
throw error;
|
|
1178
|
+
}
|
|
651
1179
|
};
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
684
|
-
const ratio = sourceRate / targetRate;
|
|
685
|
-
const length = Math.round(input.length / ratio);
|
|
686
|
-
const output = new Float32Array(length);
|
|
687
|
-
let offsetResult = 0;
|
|
688
|
-
let offsetBuffer = 0;
|
|
689
|
-
while (offsetResult < output.length) {
|
|
690
|
-
const nextOffsetBuffer = Math.round((offsetResult + 1) * ratio);
|
|
691
|
-
let accum = 0;
|
|
692
|
-
let count = 0;
|
|
693
|
-
for (let index = offsetBuffer;index < nextOffsetBuffer && index < input.length; index += 1) {
|
|
694
|
-
accum += input[index] ?? 0;
|
|
695
|
-
count += 1;
|
|
696
|
-
}
|
|
697
|
-
output[offsetResult] = count > 0 ? accum / count : 0;
|
|
698
|
-
offsetResult += 1;
|
|
699
|
-
offsetBuffer = nextOffsetBuffer;
|
|
700
|
-
}
|
|
701
|
-
return output;
|
|
702
|
-
};
|
|
703
|
-
var createMicrophoneCapture = (options) => {
|
|
704
|
-
let audioContext = null;
|
|
705
|
-
let sourceNode = null;
|
|
706
|
-
let processorNode = null;
|
|
707
|
-
let mediaStream = null;
|
|
708
|
-
const start = async () => {
|
|
709
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
710
|
-
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
1180
|
+
const runProof = async () => {
|
|
1181
|
+
const runPath = options.runPath ?? snapshot.status?.runPath ?? path;
|
|
1182
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
1183
|
+
emit();
|
|
1184
|
+
try {
|
|
1185
|
+
const report = await runVoiceCampaignDialerProofAction(runPath, options);
|
|
1186
|
+
snapshot = {
|
|
1187
|
+
...snapshot,
|
|
1188
|
+
error: null,
|
|
1189
|
+
isLoading: false,
|
|
1190
|
+
report,
|
|
1191
|
+
status: {
|
|
1192
|
+
generatedAt: Date.now(),
|
|
1193
|
+
mode: report.mode,
|
|
1194
|
+
ok: report.ok,
|
|
1195
|
+
providers: report.providers.map((provider) => provider.provider),
|
|
1196
|
+
runPath,
|
|
1197
|
+
safe: true
|
|
1198
|
+
},
|
|
1199
|
+
updatedAt: Date.now()
|
|
1200
|
+
};
|
|
1201
|
+
emit();
|
|
1202
|
+
return report;
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
snapshot = {
|
|
1205
|
+
...snapshot,
|
|
1206
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1207
|
+
isLoading: false
|
|
1208
|
+
};
|
|
1209
|
+
emit();
|
|
1210
|
+
throw error;
|
|
711
1211
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
1212
|
+
};
|
|
1213
|
+
const close = () => {
|
|
1214
|
+
closed = true;
|
|
1215
|
+
if (timer) {
|
|
1216
|
+
clearInterval(timer);
|
|
1217
|
+
timer = undefined;
|
|
715
1218
|
}
|
|
716
|
-
|
|
717
|
-
audio: {
|
|
718
|
-
channelCount: options.channelCount ?? 1
|
|
719
|
-
}
|
|
720
|
-
});
|
|
721
|
-
audioContext = new AudioContextCtor;
|
|
722
|
-
sourceNode = audioContext.createMediaStreamSource(mediaStream);
|
|
723
|
-
processorNode = audioContext.createScriptProcessor(4096, 1, 1);
|
|
724
|
-
processorNode.onaudioprocess = (event) => {
|
|
725
|
-
const channel = event.inputBuffer.getChannelData(0);
|
|
726
|
-
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
727
|
-
const pcm = floatTo16BitPCM(downsampled);
|
|
728
|
-
options.onLevel?.(getPcmLevel(pcm));
|
|
729
|
-
options.onAudio(pcm);
|
|
730
|
-
};
|
|
731
|
-
sourceNode.connect(processorNode);
|
|
732
|
-
processorNode.connect(audioContext.destination);
|
|
1219
|
+
listeners.clear();
|
|
733
1220
|
};
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
1221
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
1222
|
+
timer = setInterval(() => {
|
|
1223
|
+
refresh().catch(() => {});
|
|
1224
|
+
}, options.intervalMs);
|
|
1225
|
+
}
|
|
1226
|
+
return {
|
|
1227
|
+
close,
|
|
1228
|
+
getServerSnapshot: () => snapshot,
|
|
1229
|
+
getSnapshot: () => snapshot,
|
|
1230
|
+
refresh,
|
|
1231
|
+
runProof,
|
|
1232
|
+
subscribe: (listener) => {
|
|
1233
|
+
listeners.add(listener);
|
|
1234
|
+
return () => {
|
|
1235
|
+
listeners.delete(listener);
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
744
1238
|
};
|
|
745
|
-
return { start, stop };
|
|
746
1239
|
};
|
|
747
1240
|
|
|
748
|
-
// src/
|
|
749
|
-
var
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
var
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
1241
|
+
// src/angular/voice-campaign-dialer-proof.service.ts
|
|
1242
|
+
var _dec = [
|
|
1243
|
+
Injectable8({ providedIn: "root" })
|
|
1244
|
+
];
|
|
1245
|
+
var _init = __decoratorStart(undefined);
|
|
1246
|
+
|
|
1247
|
+
class VoiceCampaignDialerProofService {
|
|
1248
|
+
connect(path = "/api/voice/campaigns/dialer-proof", options = {}) {
|
|
1249
|
+
const store = createVoiceCampaignDialerProofStore(path, options);
|
|
1250
|
+
const errorSignal = signal8(null);
|
|
1251
|
+
const isLoadingSignal = signal8(false);
|
|
1252
|
+
const reportSignal = signal8(undefined);
|
|
1253
|
+
const statusSignal = signal8(undefined);
|
|
1254
|
+
const updatedAtSignal = signal8(undefined);
|
|
1255
|
+
const sync = () => {
|
|
1256
|
+
const snapshot = store.getSnapshot();
|
|
1257
|
+
errorSignal.set(snapshot.error);
|
|
1258
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
1259
|
+
reportSignal.set(snapshot.report);
|
|
1260
|
+
statusSignal.set(snapshot.status);
|
|
1261
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
1262
|
+
};
|
|
1263
|
+
const unsubscribe = store.subscribe(sync);
|
|
1264
|
+
sync();
|
|
1265
|
+
store.refresh().catch(() => {});
|
|
1266
|
+
return {
|
|
1267
|
+
close: () => {
|
|
1268
|
+
unsubscribe();
|
|
1269
|
+
store.close();
|
|
1270
|
+
},
|
|
1271
|
+
error: computed8(() => errorSignal()),
|
|
1272
|
+
isLoading: computed8(() => isLoadingSignal()),
|
|
1273
|
+
refresh: store.refresh,
|
|
1274
|
+
report: computed8(() => reportSignal()),
|
|
1275
|
+
runProof: store.runProof,
|
|
1276
|
+
status: computed8(() => statusSignal()),
|
|
1277
|
+
updatedAt: computed8(() => updatedAtSignal())
|
|
1278
|
+
};
|
|
756
1279
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
1280
|
+
}
|
|
1281
|
+
VoiceCampaignDialerProofService = __decorateElement(_init, 0, "VoiceCampaignDialerProofService", _dec, VoiceCampaignDialerProofService);
|
|
1282
|
+
__runInitializers(_init, 1, VoiceCampaignDialerProofService);
|
|
1283
|
+
__decoratorMetadata(_init, VoiceCampaignDialerProofService);
|
|
1284
|
+
let _VoiceCampaignDialerProofService = VoiceCampaignDialerProofService;
|
|
1285
|
+
// src/angular/voice-stream.service.ts
|
|
1286
|
+
import { computed as computed9, Injectable as Injectable9, signal as signal9 } from "@angular/core";
|
|
1287
|
+
|
|
1288
|
+
// src/client/actions.ts
|
|
1289
|
+
var normalizeErrorMessage = (value) => {
|
|
1290
|
+
if (typeof value === "string" && value.trim()) {
|
|
1291
|
+
return value;
|
|
762
1292
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
const normalized = sample / 32768;
|
|
766
|
-
sumSquares += normalized * normalized;
|
|
1293
|
+
if (value instanceof Error && value.message.trim()) {
|
|
1294
|
+
return value.message;
|
|
767
1295
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
1296
|
+
if (value && typeof value === "object") {
|
|
1297
|
+
const record = value;
|
|
1298
|
+
for (const key of ["message", "reason", "description"]) {
|
|
1299
|
+
const candidate = record[key];
|
|
1300
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
1301
|
+
return candidate;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
if ("error" in record) {
|
|
1305
|
+
return normalizeErrorMessage(record.error);
|
|
1306
|
+
}
|
|
1307
|
+
if ("cause" in record) {
|
|
1308
|
+
return normalizeErrorMessage(record.cause);
|
|
1309
|
+
}
|
|
1310
|
+
try {
|
|
1311
|
+
return JSON.stringify(value);
|
|
1312
|
+
} catch {}
|
|
773
1313
|
}
|
|
774
|
-
return
|
|
775
|
-
enabled: true,
|
|
776
|
-
maxGain: config.maxGain ?? DEFAULT_MAX_GAIN,
|
|
777
|
-
noiseGateAttenuation: config.noiseGateAttenuation ?? DEFAULT_NOISE_GATE_ATTENUATION,
|
|
778
|
-
noiseGateThreshold: config.noiseGateThreshold ?? DEFAULT_NOISE_GATE_THRESHOLD,
|
|
779
|
-
targetLevel: config.targetLevel ?? DEFAULT_TARGET_LEVEL
|
|
780
|
-
};
|
|
1314
|
+
return "Unexpected error";
|
|
781
1315
|
};
|
|
782
|
-
var
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
1316
|
+
var serverMessageToAction = (message) => {
|
|
1317
|
+
switch (message.type) {
|
|
1318
|
+
case "audio":
|
|
1319
|
+
return {
|
|
1320
|
+
chunk: Uint8Array.from(atob(message.chunkBase64), (char) => char.charCodeAt(0)),
|
|
1321
|
+
format: message.format,
|
|
1322
|
+
receivedAt: message.receivedAt,
|
|
1323
|
+
turnId: message.turnId,
|
|
1324
|
+
type: "audio"
|
|
1325
|
+
};
|
|
1326
|
+
case "assistant":
|
|
1327
|
+
return {
|
|
1328
|
+
text: message.text,
|
|
1329
|
+
type: "assistant"
|
|
1330
|
+
};
|
|
1331
|
+
case "complete":
|
|
1332
|
+
return {
|
|
1333
|
+
sessionId: message.sessionId,
|
|
1334
|
+
type: "complete"
|
|
1335
|
+
};
|
|
1336
|
+
case "connection":
|
|
1337
|
+
return {
|
|
1338
|
+
reconnect: message.reconnect,
|
|
1339
|
+
type: "connection"
|
|
1340
|
+
};
|
|
1341
|
+
case "call_lifecycle":
|
|
1342
|
+
return {
|
|
1343
|
+
event: message.event,
|
|
1344
|
+
sessionId: message.sessionId,
|
|
1345
|
+
type: "call_lifecycle"
|
|
1346
|
+
};
|
|
1347
|
+
case "error":
|
|
1348
|
+
return {
|
|
1349
|
+
message: normalizeErrorMessage(message.message),
|
|
1350
|
+
type: "error"
|
|
1351
|
+
};
|
|
1352
|
+
case "final":
|
|
1353
|
+
return {
|
|
1354
|
+
transcript: message.transcript,
|
|
1355
|
+
type: "final"
|
|
1356
|
+
};
|
|
1357
|
+
case "partial":
|
|
1358
|
+
return {
|
|
1359
|
+
transcript: message.transcript,
|
|
1360
|
+
type: "partial"
|
|
1361
|
+
};
|
|
1362
|
+
case "replay":
|
|
1363
|
+
return {
|
|
1364
|
+
assistantTexts: message.assistantTexts,
|
|
1365
|
+
call: message.call,
|
|
1366
|
+
partial: message.partial,
|
|
1367
|
+
scenarioId: message.scenarioId,
|
|
1368
|
+
sessionId: message.sessionId,
|
|
1369
|
+
status: message.status,
|
|
1370
|
+
turns: message.turns,
|
|
1371
|
+
type: "replay"
|
|
1372
|
+
};
|
|
1373
|
+
case "session":
|
|
1374
|
+
return {
|
|
1375
|
+
sessionId: message.sessionId,
|
|
1376
|
+
scenarioId: message.scenarioId,
|
|
1377
|
+
status: message.status,
|
|
1378
|
+
type: "session"
|
|
1379
|
+
};
|
|
1380
|
+
case "turn":
|
|
1381
|
+
return {
|
|
1382
|
+
turn: message.turn,
|
|
1383
|
+
type: "turn"
|
|
1384
|
+
};
|
|
1385
|
+
default:
|
|
1386
|
+
return null;
|
|
799
1387
|
}
|
|
800
|
-
return new Uint8Array(output.buffer);
|
|
801
1388
|
};
|
|
802
1389
|
|
|
803
|
-
// src/
|
|
804
|
-
var
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
1390
|
+
// src/client/connection.ts
|
|
1391
|
+
var WS_OPEN = 1;
|
|
1392
|
+
var WS_CLOSED = 3;
|
|
1393
|
+
var WS_NORMAL_CLOSURE = 1000;
|
|
1394
|
+
var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
|
|
1395
|
+
var DEFAULT_PING_INTERVAL = 30000;
|
|
1396
|
+
var RECONNECT_DELAY_MS = 500;
|
|
1397
|
+
var DEFAULT_SCENARIO_QUERY_PARAM = "scenarioId";
|
|
1398
|
+
var noop = () => {};
|
|
1399
|
+
var noopUnsubscribe = () => noop;
|
|
1400
|
+
var NOOP_CONNECTION = {
|
|
1401
|
+
callControl: noop,
|
|
1402
|
+
close: noop,
|
|
1403
|
+
endTurn: noop,
|
|
1404
|
+
getReadyState: () => WS_CLOSED,
|
|
1405
|
+
getScenarioId: () => "",
|
|
1406
|
+
getSessionId: () => "",
|
|
1407
|
+
send: noop,
|
|
1408
|
+
sendAudio: noop,
|
|
1409
|
+
start: () => {},
|
|
1410
|
+
subscribe: noopUnsubscribe
|
|
1411
|
+
};
|
|
1412
|
+
var createSessionId = () => crypto.randomUUID();
|
|
1413
|
+
var buildWsUrl = (path, sessionId, scenarioId) => {
|
|
1414
|
+
const { hostname, port, protocol } = window.location;
|
|
1415
|
+
const wsProtocol = protocol === "https:" ? "wss:" : "ws:";
|
|
1416
|
+
const portSuffix = port ? `:${port}` : "";
|
|
1417
|
+
const url = new URL(`${wsProtocol}//${hostname}${portSuffix}${path}`);
|
|
1418
|
+
url.searchParams.set("sessionId", sessionId);
|
|
1419
|
+
if (scenarioId) {
|
|
1420
|
+
url.searchParams.set(DEFAULT_SCENARIO_QUERY_PARAM, scenarioId);
|
|
1421
|
+
}
|
|
1422
|
+
return url.toString();
|
|
1423
|
+
};
|
|
1424
|
+
var isVoiceServerMessage = (value) => {
|
|
1425
|
+
if (!value || typeof value !== "object" || !("type" in value)) {
|
|
1426
|
+
return false;
|
|
1427
|
+
}
|
|
1428
|
+
switch (value.type) {
|
|
1429
|
+
case "audio":
|
|
1430
|
+
case "assistant":
|
|
1431
|
+
case "call_lifecycle":
|
|
1432
|
+
case "complete":
|
|
1433
|
+
case "connection":
|
|
1434
|
+
case "error":
|
|
1435
|
+
case "final":
|
|
1436
|
+
case "partial":
|
|
1437
|
+
case "pong":
|
|
1438
|
+
case "replay":
|
|
1439
|
+
case "session":
|
|
1440
|
+
case "turn":
|
|
1441
|
+
return true;
|
|
1442
|
+
default:
|
|
1443
|
+
return false;
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
var parseServerMessage = (event) => {
|
|
1447
|
+
if (typeof event.data !== "string") {
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
try {
|
|
1451
|
+
const parsed = JSON.parse(event.data);
|
|
1452
|
+
return isVoiceServerMessage(parsed) ? parsed : null;
|
|
1453
|
+
} catch {
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1457
|
+
var createVoiceConnection = (path, options = {}) => {
|
|
1458
|
+
if (typeof window === "undefined") {
|
|
1459
|
+
return NOOP_CONNECTION;
|
|
1460
|
+
}
|
|
1461
|
+
const listeners = new Set;
|
|
1462
|
+
const shouldReconnect = options.reconnect !== false;
|
|
1463
|
+
const maxReconnectAttempts = options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS;
|
|
1464
|
+
const pingInterval = options.pingInterval ?? DEFAULT_PING_INTERVAL;
|
|
1465
|
+
const state = {
|
|
1466
|
+
isConnected: false,
|
|
1467
|
+
pendingMessages: [],
|
|
1468
|
+
scenarioId: options.scenarioId ?? null,
|
|
1469
|
+
pingInterval: null,
|
|
1470
|
+
reconnectAttempts: 0,
|
|
1471
|
+
reconnectTimeout: null,
|
|
1472
|
+
sessionId: options.sessionId ?? createSessionId(),
|
|
1473
|
+
ws: null
|
|
1474
|
+
};
|
|
1475
|
+
const emitConnection = (reconnect) => {
|
|
1476
|
+
listeners.forEach((listener) => listener(reconnect));
|
|
1477
|
+
};
|
|
1478
|
+
const clearTimers = () => {
|
|
1479
|
+
if (state.pingInterval) {
|
|
1480
|
+
clearInterval(state.pingInterval);
|
|
1481
|
+
state.pingInterval = null;
|
|
1482
|
+
}
|
|
1483
|
+
if (state.reconnectTimeout) {
|
|
1484
|
+
clearTimeout(state.reconnectTimeout);
|
|
1485
|
+
state.reconnectTimeout = null;
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
const flushPendingMessages = () => {
|
|
1489
|
+
if (state.ws?.readyState !== WS_OPEN) {
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
while (state.pendingMessages.length > 0) {
|
|
1493
|
+
const next = state.pendingMessages.shift();
|
|
1494
|
+
if (next !== undefined) {
|
|
1495
|
+
state.ws.send(next);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
const scheduleReconnect = () => {
|
|
1500
|
+
const nextAttemptAt = Date.now() + RECONNECT_DELAY_MS;
|
|
1501
|
+
state.reconnectAttempts += 1;
|
|
1502
|
+
emitConnection({
|
|
1503
|
+
reconnect: {
|
|
1504
|
+
attempts: state.reconnectAttempts,
|
|
1505
|
+
lastDisconnectAt: Date.now(),
|
|
1506
|
+
maxAttempts: maxReconnectAttempts,
|
|
1507
|
+
nextAttemptAt,
|
|
1508
|
+
status: "reconnecting"
|
|
1509
|
+
},
|
|
1510
|
+
type: "connection"
|
|
1511
|
+
});
|
|
1512
|
+
state.reconnectTimeout = setTimeout(() => {
|
|
1513
|
+
if (state.reconnectAttempts > maxReconnectAttempts) {
|
|
1514
|
+
emitConnection({
|
|
1515
|
+
reconnect: {
|
|
1516
|
+
attempts: state.reconnectAttempts,
|
|
1517
|
+
maxAttempts: maxReconnectAttempts,
|
|
1518
|
+
status: "exhausted"
|
|
1519
|
+
},
|
|
1520
|
+
type: "connection"
|
|
1521
|
+
});
|
|
1522
|
+
return;
|
|
1523
|
+
}
|
|
1524
|
+
connect();
|
|
1525
|
+
}, RECONNECT_DELAY_MS);
|
|
1526
|
+
};
|
|
1527
|
+
const connect = () => {
|
|
1528
|
+
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId));
|
|
1529
|
+
ws.binaryType = "arraybuffer";
|
|
1530
|
+
ws.onopen = () => {
|
|
1531
|
+
const wasReconnecting = state.reconnectAttempts > 0;
|
|
1532
|
+
state.isConnected = true;
|
|
1533
|
+
flushPendingMessages();
|
|
1534
|
+
if (wasReconnecting) {
|
|
1535
|
+
emitConnection({
|
|
1536
|
+
reconnect: {
|
|
1537
|
+
attempts: state.reconnectAttempts,
|
|
1538
|
+
lastResumedAt: Date.now(),
|
|
1539
|
+
maxAttempts: maxReconnectAttempts,
|
|
1540
|
+
status: "resumed"
|
|
1541
|
+
},
|
|
1542
|
+
type: "connection"
|
|
1543
|
+
});
|
|
1544
|
+
state.reconnectAttempts = 0;
|
|
1545
|
+
}
|
|
1546
|
+
listeners.forEach((listener) => listener({
|
|
1547
|
+
scenarioId: state.scenarioId ?? undefined,
|
|
1548
|
+
sessionId: state.sessionId,
|
|
1549
|
+
status: "active",
|
|
1550
|
+
type: "session"
|
|
1551
|
+
}));
|
|
1552
|
+
state.pingInterval = setInterval(() => {
|
|
1553
|
+
if (ws.readyState === WS_OPEN) {
|
|
1554
|
+
ws.send(JSON.stringify({ type: "ping" }));
|
|
1555
|
+
}
|
|
1556
|
+
}, pingInterval);
|
|
1557
|
+
};
|
|
1558
|
+
ws.onmessage = (event) => {
|
|
1559
|
+
const parsed = parseServerMessage(event);
|
|
1560
|
+
if (!parsed) {
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
if (parsed.type === "session") {
|
|
1564
|
+
state.sessionId = parsed.sessionId;
|
|
1565
|
+
state.scenarioId = parsed.scenarioId ?? state.scenarioId;
|
|
1566
|
+
}
|
|
1567
|
+
listeners.forEach((listener) => listener(parsed));
|
|
1568
|
+
};
|
|
1569
|
+
ws.onclose = (event) => {
|
|
1570
|
+
state.isConnected = false;
|
|
1571
|
+
clearTimers();
|
|
1572
|
+
const reconnectable = shouldReconnect && event.code !== WS_NORMAL_CLOSURE && state.reconnectAttempts < maxReconnectAttempts;
|
|
1573
|
+
if (reconnectable) {
|
|
1574
|
+
scheduleReconnect();
|
|
1575
|
+
} else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
|
|
1576
|
+
emitConnection({
|
|
1577
|
+
reconnect: {
|
|
1578
|
+
attempts: state.reconnectAttempts,
|
|
1579
|
+
lastDisconnectAt: Date.now(),
|
|
1580
|
+
maxAttempts: maxReconnectAttempts,
|
|
1581
|
+
status: "exhausted"
|
|
1582
|
+
},
|
|
1583
|
+
type: "connection"
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
};
|
|
1587
|
+
state.ws = ws;
|
|
1588
|
+
};
|
|
1589
|
+
const sendSerialized = (value) => {
|
|
1590
|
+
if (state.ws?.readyState === WS_OPEN) {
|
|
1591
|
+
state.ws.send(value);
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
state.pendingMessages.push(value);
|
|
1595
|
+
};
|
|
1596
|
+
const send = (message) => {
|
|
1597
|
+
sendSerialized(JSON.stringify(message));
|
|
1598
|
+
};
|
|
1599
|
+
const start = (input = {}) => {
|
|
1600
|
+
if (input.sessionId) {
|
|
1601
|
+
state.sessionId = input.sessionId;
|
|
1602
|
+
}
|
|
1603
|
+
if (input.scenarioId) {
|
|
1604
|
+
state.scenarioId = input.scenarioId;
|
|
1605
|
+
}
|
|
1606
|
+
send({
|
|
1607
|
+
type: "start",
|
|
1608
|
+
sessionId: state.sessionId,
|
|
1609
|
+
scenarioId: state.scenarioId ?? undefined
|
|
1610
|
+
});
|
|
1611
|
+
};
|
|
1612
|
+
const sendAudio = (audio) => {
|
|
1613
|
+
sendSerialized(audio);
|
|
1614
|
+
};
|
|
1615
|
+
const endTurn = () => {
|
|
1616
|
+
send({ type: "end_turn" });
|
|
1617
|
+
};
|
|
1618
|
+
const callControl = (message) => {
|
|
1619
|
+
send({
|
|
1620
|
+
...message,
|
|
1621
|
+
type: "call_control"
|
|
1622
|
+
});
|
|
1623
|
+
};
|
|
1624
|
+
const close = () => {
|
|
1625
|
+
clearTimers();
|
|
1626
|
+
if (state.ws) {
|
|
1627
|
+
state.ws.close(WS_NORMAL_CLOSURE);
|
|
1628
|
+
state.ws = null;
|
|
1629
|
+
}
|
|
1630
|
+
state.isConnected = false;
|
|
1631
|
+
listeners.clear();
|
|
1632
|
+
};
|
|
1633
|
+
const subscribe = (callback) => {
|
|
1634
|
+
listeners.add(callback);
|
|
1635
|
+
return () => {
|
|
1636
|
+
listeners.delete(callback);
|
|
1637
|
+
};
|
|
1638
|
+
};
|
|
1639
|
+
connect();
|
|
1640
|
+
return {
|
|
1641
|
+
callControl,
|
|
1642
|
+
close,
|
|
1643
|
+
endTurn,
|
|
1644
|
+
getReadyState: () => state.ws?.readyState ?? WS_CLOSED,
|
|
1645
|
+
getScenarioId: () => state.scenarioId ?? "",
|
|
1646
|
+
getSessionId: () => state.sessionId,
|
|
1647
|
+
send,
|
|
1648
|
+
sendAudio,
|
|
1649
|
+
start,
|
|
1650
|
+
subscribe
|
|
1651
|
+
};
|
|
1652
|
+
};
|
|
1653
|
+
|
|
1654
|
+
// src/client/store.ts
|
|
1655
|
+
var createInitialReconnectState = () => ({
|
|
1656
|
+
attempts: 0,
|
|
1657
|
+
maxAttempts: 0,
|
|
1658
|
+
status: "idle"
|
|
1659
|
+
});
|
|
1660
|
+
var createInitialState = () => ({
|
|
1661
|
+
assistantAudio: [],
|
|
1662
|
+
assistantTexts: [],
|
|
1663
|
+
call: null,
|
|
1664
|
+
error: null,
|
|
1665
|
+
isConnected: false,
|
|
1666
|
+
scenarioId: null,
|
|
1667
|
+
partial: "",
|
|
1668
|
+
reconnect: createInitialReconnectState(),
|
|
1669
|
+
sessionId: null,
|
|
1670
|
+
status: "idle",
|
|
1671
|
+
turns: []
|
|
1672
|
+
});
|
|
1673
|
+
var createVoiceStreamStore = () => {
|
|
1674
|
+
let state = createInitialState();
|
|
1675
|
+
const subscribers = new Set;
|
|
1676
|
+
const notify = () => {
|
|
1677
|
+
subscribers.forEach((subscriber) => subscriber());
|
|
1678
|
+
};
|
|
1679
|
+
const dispatch = (action) => {
|
|
1680
|
+
switch (action.type) {
|
|
1681
|
+
case "audio":
|
|
1682
|
+
state = {
|
|
1683
|
+
...state,
|
|
1684
|
+
assistantAudio: [
|
|
1685
|
+
...state.assistantAudio,
|
|
1686
|
+
{
|
|
1687
|
+
chunk: action.chunk,
|
|
1688
|
+
format: action.format,
|
|
1689
|
+
receivedAt: action.receivedAt,
|
|
1690
|
+
turnId: action.turnId
|
|
1691
|
+
}
|
|
1692
|
+
]
|
|
1693
|
+
};
|
|
1694
|
+
break;
|
|
1695
|
+
case "assistant":
|
|
1696
|
+
state = {
|
|
1697
|
+
...state,
|
|
1698
|
+
assistantTexts: [...state.assistantTexts, action.text]
|
|
1699
|
+
};
|
|
1700
|
+
break;
|
|
1701
|
+
case "complete":
|
|
1702
|
+
state = {
|
|
1703
|
+
...state,
|
|
1704
|
+
sessionId: action.sessionId,
|
|
1705
|
+
status: "completed"
|
|
1706
|
+
};
|
|
1707
|
+
break;
|
|
1708
|
+
case "call_lifecycle":
|
|
1709
|
+
state = {
|
|
1710
|
+
...state,
|
|
1711
|
+
call: {
|
|
1712
|
+
...state.call,
|
|
1713
|
+
disposition: action.event.type === "end" ? action.event.disposition : state.call?.disposition,
|
|
1714
|
+
endedAt: action.event.type === "end" ? action.event.at : state.call?.endedAt,
|
|
1715
|
+
events: [...state.call?.events ?? [], action.event],
|
|
1716
|
+
lastEventAt: action.event.at,
|
|
1717
|
+
startedAt: state.call?.startedAt ?? action.event.at
|
|
1718
|
+
},
|
|
1719
|
+
sessionId: action.sessionId
|
|
1720
|
+
};
|
|
1721
|
+
break;
|
|
1722
|
+
case "connected":
|
|
1723
|
+
state = {
|
|
1724
|
+
...state,
|
|
1725
|
+
isConnected: true,
|
|
1726
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
1727
|
+
...state.reconnect,
|
|
1728
|
+
lastResumedAt: Date.now(),
|
|
1729
|
+
nextAttemptAt: undefined,
|
|
1730
|
+
status: "resumed"
|
|
1731
|
+
} : state.reconnect
|
|
1732
|
+
};
|
|
1733
|
+
break;
|
|
1734
|
+
case "connection":
|
|
1735
|
+
state = {
|
|
1736
|
+
...state,
|
|
1737
|
+
reconnect: action.reconnect
|
|
1738
|
+
};
|
|
1739
|
+
break;
|
|
1740
|
+
case "disconnected":
|
|
1741
|
+
state = {
|
|
1742
|
+
...state,
|
|
1743
|
+
isConnected: false
|
|
1744
|
+
};
|
|
1745
|
+
break;
|
|
1746
|
+
case "error":
|
|
1747
|
+
state = {
|
|
1748
|
+
...state,
|
|
1749
|
+
error: action.message
|
|
1750
|
+
};
|
|
1751
|
+
break;
|
|
1752
|
+
case "final":
|
|
1753
|
+
state = {
|
|
1754
|
+
...state,
|
|
1755
|
+
partial: action.transcript.text,
|
|
1756
|
+
turns: state.turns.map((turn) => turn)
|
|
1757
|
+
};
|
|
1758
|
+
break;
|
|
1759
|
+
case "partial":
|
|
1760
|
+
state = {
|
|
1761
|
+
...state,
|
|
1762
|
+
partial: action.transcript.text
|
|
1763
|
+
};
|
|
1764
|
+
break;
|
|
1765
|
+
case "replay":
|
|
1766
|
+
state = {
|
|
1767
|
+
...state,
|
|
1768
|
+
assistantTexts: [...action.assistantTexts],
|
|
1769
|
+
call: action.call ?? null,
|
|
1770
|
+
error: null,
|
|
1771
|
+
isConnected: action.status === "active",
|
|
1772
|
+
partial: action.partial,
|
|
1773
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
1774
|
+
...state.reconnect,
|
|
1775
|
+
lastResumedAt: Date.now(),
|
|
1776
|
+
nextAttemptAt: undefined,
|
|
1777
|
+
status: "resumed"
|
|
1778
|
+
} : state.reconnect,
|
|
1779
|
+
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1780
|
+
sessionId: action.sessionId,
|
|
1781
|
+
status: action.status,
|
|
1782
|
+
turns: [...action.turns]
|
|
1783
|
+
};
|
|
1784
|
+
break;
|
|
1785
|
+
case "session":
|
|
1786
|
+
state = {
|
|
1787
|
+
...state,
|
|
1788
|
+
error: null,
|
|
1789
|
+
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1790
|
+
isConnected: action.status === "active",
|
|
1791
|
+
sessionId: action.sessionId,
|
|
1792
|
+
status: action.status
|
|
1793
|
+
};
|
|
1794
|
+
break;
|
|
1795
|
+
case "turn":
|
|
1796
|
+
state = {
|
|
1797
|
+
...state,
|
|
1798
|
+
partial: "",
|
|
1799
|
+
turns: [...state.turns, action.turn]
|
|
1800
|
+
};
|
|
1801
|
+
break;
|
|
1802
|
+
}
|
|
1803
|
+
notify();
|
|
1804
|
+
};
|
|
1805
|
+
return {
|
|
1806
|
+
dispatch,
|
|
1807
|
+
getServerSnapshot: () => state,
|
|
1808
|
+
getSnapshot: () => state,
|
|
1809
|
+
subscribe: (subscriber) => {
|
|
1810
|
+
subscribers.add(subscriber);
|
|
1811
|
+
return () => {
|
|
1812
|
+
subscribers.delete(subscriber);
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
};
|
|
1817
|
+
|
|
1818
|
+
// src/client/createVoiceStream.ts
|
|
1819
|
+
var createVoiceStream = (path, options = {}) => {
|
|
1820
|
+
const connection = createVoiceConnection(path, options);
|
|
1821
|
+
const store = createVoiceStreamStore();
|
|
1822
|
+
const subscribers = new Set;
|
|
1823
|
+
const start = (input) => Promise.resolve().then(() => {
|
|
1824
|
+
if (!input?.sessionId && !input?.scenarioId) {
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
connection.start(input);
|
|
1828
|
+
});
|
|
1829
|
+
const notify = () => {
|
|
1830
|
+
subscribers.forEach((subscriber) => subscriber());
|
|
1831
|
+
};
|
|
1832
|
+
const reportReconnect = () => {
|
|
1833
|
+
if (!options.reconnectReportPath || typeof fetch === "undefined") {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
const snapshot = store.getSnapshot();
|
|
1837
|
+
const body = JSON.stringify({
|
|
1838
|
+
at: Date.now(),
|
|
1839
|
+
reconnect: snapshot.reconnect,
|
|
1840
|
+
scenarioId: snapshot.scenarioId,
|
|
1841
|
+
sessionId: connection.getSessionId(),
|
|
1842
|
+
turnIds: snapshot.turns.map((turn) => turn.id)
|
|
1843
|
+
});
|
|
1844
|
+
fetch(options.reconnectReportPath, {
|
|
1845
|
+
body,
|
|
1846
|
+
headers: {
|
|
1847
|
+
"Content-Type": "application/json"
|
|
1848
|
+
},
|
|
1849
|
+
keepalive: true,
|
|
1850
|
+
method: "POST"
|
|
1851
|
+
}).catch(() => {});
|
|
1852
|
+
};
|
|
1853
|
+
const unsubscribeConnection = connection.subscribe((message) => {
|
|
1854
|
+
const action = serverMessageToAction(message);
|
|
1855
|
+
if (action) {
|
|
1856
|
+
store.dispatch(action);
|
|
1857
|
+
if (message.type === "connection") {
|
|
1858
|
+
reportReconnect();
|
|
1859
|
+
}
|
|
1860
|
+
notify();
|
|
1861
|
+
}
|
|
1862
|
+
});
|
|
1863
|
+
return {
|
|
1864
|
+
callControl(message) {
|
|
1865
|
+
connection.callControl(message);
|
|
1866
|
+
},
|
|
1867
|
+
close() {
|
|
1868
|
+
unsubscribeConnection();
|
|
1869
|
+
connection.close();
|
|
1870
|
+
store.dispatch({ type: "disconnected" });
|
|
1871
|
+
notify();
|
|
1872
|
+
},
|
|
1873
|
+
endTurn() {
|
|
1874
|
+
connection.endTurn();
|
|
1875
|
+
},
|
|
1876
|
+
get error() {
|
|
1877
|
+
return store.getSnapshot().error;
|
|
1878
|
+
},
|
|
1879
|
+
getServerSnapshot() {
|
|
1880
|
+
return store.getServerSnapshot();
|
|
1881
|
+
},
|
|
1882
|
+
getSnapshot() {
|
|
1883
|
+
return store.getSnapshot();
|
|
1884
|
+
},
|
|
1885
|
+
get isConnected() {
|
|
1886
|
+
return store.getSnapshot().isConnected;
|
|
1887
|
+
},
|
|
1888
|
+
get scenarioId() {
|
|
1889
|
+
return store.getSnapshot().scenarioId;
|
|
1890
|
+
},
|
|
1891
|
+
start,
|
|
1892
|
+
get partial() {
|
|
1893
|
+
return store.getSnapshot().partial;
|
|
1894
|
+
},
|
|
1895
|
+
get reconnect() {
|
|
1896
|
+
return store.getSnapshot().reconnect;
|
|
1897
|
+
},
|
|
1898
|
+
get sessionId() {
|
|
1899
|
+
return connection.getSessionId();
|
|
1900
|
+
},
|
|
1901
|
+
get status() {
|
|
1902
|
+
return store.getSnapshot().status;
|
|
1903
|
+
},
|
|
1904
|
+
get turns() {
|
|
1905
|
+
return store.getSnapshot().turns;
|
|
1906
|
+
},
|
|
1907
|
+
get assistantTexts() {
|
|
1908
|
+
return store.getSnapshot().assistantTexts;
|
|
1909
|
+
},
|
|
1910
|
+
get assistantAudio() {
|
|
1911
|
+
return store.getSnapshot().assistantAudio;
|
|
1912
|
+
},
|
|
1913
|
+
get call() {
|
|
1914
|
+
return store.getSnapshot().call;
|
|
1915
|
+
},
|
|
1916
|
+
sendAudio(audio) {
|
|
1917
|
+
connection.sendAudio(audio);
|
|
1918
|
+
},
|
|
1919
|
+
subscribe(subscriber) {
|
|
1920
|
+
subscribers.add(subscriber);
|
|
1921
|
+
return () => {
|
|
1922
|
+
subscribers.delete(subscriber);
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
};
|
|
1926
|
+
};
|
|
1927
|
+
|
|
1928
|
+
// src/angular/voice-stream.service.ts
|
|
1929
|
+
var _dec = [
|
|
1930
|
+
Injectable9({ providedIn: "root" })
|
|
1931
|
+
];
|
|
1932
|
+
var _init = __decoratorStart(undefined);
|
|
1933
|
+
|
|
1934
|
+
class VoiceStreamService {
|
|
1935
|
+
connect(path, options = {}) {
|
|
1936
|
+
const stream = createVoiceStream(path, options);
|
|
1937
|
+
const assistantAudioSignal = signal9([]);
|
|
1938
|
+
const assistantTextsSignal = signal9([]);
|
|
1939
|
+
const callSignal = signal9(null);
|
|
1940
|
+
const errorSignal = signal9(null);
|
|
1941
|
+
const isConnectedSignal = signal9(false);
|
|
1942
|
+
const partialSignal = signal9("");
|
|
1943
|
+
const reconnectSignal = signal9(stream.reconnect);
|
|
1944
|
+
const sessionIdSignal = signal9(stream.sessionId);
|
|
1945
|
+
const statusSignal = signal9(stream.status);
|
|
1946
|
+
const turnsSignal = signal9([]);
|
|
1947
|
+
const sync = () => {
|
|
1948
|
+
assistantAudioSignal.set([...stream.assistantAudio]);
|
|
1949
|
+
assistantTextsSignal.set([...stream.assistantTexts]);
|
|
1950
|
+
callSignal.set(stream.call);
|
|
1951
|
+
errorSignal.set(stream.error);
|
|
1952
|
+
isConnectedSignal.set(stream.isConnected);
|
|
1953
|
+
partialSignal.set(stream.partial);
|
|
1954
|
+
reconnectSignal.set(stream.reconnect);
|
|
1955
|
+
sessionIdSignal.set(stream.sessionId);
|
|
1956
|
+
statusSignal.set(stream.status);
|
|
1957
|
+
turnsSignal.set([...stream.turns]);
|
|
1958
|
+
};
|
|
1959
|
+
const unsubscribe = stream.subscribe(sync);
|
|
1960
|
+
sync();
|
|
1961
|
+
return {
|
|
1962
|
+
assistantAudio: computed9(() => assistantAudioSignal()),
|
|
1963
|
+
assistantTexts: computed9(() => assistantTextsSignal()),
|
|
1964
|
+
call: computed9(() => callSignal()),
|
|
1965
|
+
callControl: (message) => stream.callControl(message),
|
|
1966
|
+
close: () => {
|
|
1967
|
+
unsubscribe();
|
|
1968
|
+
stream.close();
|
|
1969
|
+
},
|
|
1970
|
+
endTurn: () => stream.endTurn(),
|
|
1971
|
+
error: computed9(() => errorSignal()),
|
|
1972
|
+
isConnected: computed9(() => isConnectedSignal()),
|
|
1973
|
+
partial: computed9(() => partialSignal()),
|
|
1974
|
+
reconnect: computed9(() => reconnectSignal()),
|
|
1975
|
+
sendAudio: (audio) => stream.sendAudio(audio),
|
|
1976
|
+
sessionId: computed9(() => sessionIdSignal()),
|
|
1977
|
+
status: computed9(() => statusSignal()),
|
|
1978
|
+
turns: computed9(() => turnsSignal())
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
VoiceStreamService = __decorateElement(_init, 0, "VoiceStreamService", _dec, VoiceStreamService);
|
|
1983
|
+
__runInitializers(_init, 1, VoiceStreamService);
|
|
1984
|
+
__decoratorMetadata(_init, VoiceStreamService);
|
|
1985
|
+
let _VoiceStreamService = VoiceStreamService;
|
|
1986
|
+
// src/angular/voice-controller.service.ts
|
|
1987
|
+
import { computed as computed10, Injectable as Injectable10, signal as signal10 } from "@angular/core";
|
|
1988
|
+
|
|
1989
|
+
// src/client/htmx.ts
|
|
1990
|
+
var DEFAULT_EVENT_NAME = "voice-refresh";
|
|
1991
|
+
var DEFAULT_QUERY_PARAM = "sessionId";
|
|
1992
|
+
var resolveElement = (input) => {
|
|
1993
|
+
if (typeof input !== "string") {
|
|
1994
|
+
return input;
|
|
1995
|
+
}
|
|
1996
|
+
return document.querySelector(input);
|
|
1997
|
+
};
|
|
1998
|
+
var buildRoute = (element, route, queryParam, sessionId) => {
|
|
1999
|
+
const baseRoute = route ?? element.getAttribute("hx-get") ?? "";
|
|
2000
|
+
if (!baseRoute) {
|
|
2001
|
+
return "";
|
|
2002
|
+
}
|
|
2003
|
+
const url = new URL(baseRoute, window.location.origin);
|
|
2004
|
+
if (sessionId) {
|
|
2005
|
+
url.searchParams.set(queryParam, sessionId);
|
|
2006
|
+
} else {
|
|
2007
|
+
url.searchParams.delete(queryParam);
|
|
2008
|
+
}
|
|
2009
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
2010
|
+
};
|
|
2011
|
+
var bindVoiceHTMX = (stream, options) => {
|
|
2012
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
2013
|
+
return () => {};
|
|
2014
|
+
}
|
|
2015
|
+
const element = resolveElement(options.element);
|
|
2016
|
+
if (!element) {
|
|
2017
|
+
return () => {};
|
|
2018
|
+
}
|
|
2019
|
+
const eventName = options.eventName ?? DEFAULT_EVENT_NAME;
|
|
2020
|
+
const queryParam = options.sessionQueryParam ?? DEFAULT_QUERY_PARAM;
|
|
2021
|
+
const sync = () => {
|
|
2022
|
+
const htmxWindow = window;
|
|
2023
|
+
const nextRoute = buildRoute(element, options.route, queryParam, stream.sessionId);
|
|
2024
|
+
if (nextRoute) {
|
|
2025
|
+
element.setAttribute("hx-get", nextRoute);
|
|
2026
|
+
}
|
|
2027
|
+
htmxWindow.htmx?.process?.(element);
|
|
2028
|
+
htmxWindow.htmx?.trigger?.(element, eventName);
|
|
2029
|
+
};
|
|
2030
|
+
const unsubscribe = stream.subscribe(sync);
|
|
2031
|
+
sync();
|
|
2032
|
+
return () => {
|
|
2033
|
+
unsubscribe();
|
|
2034
|
+
};
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
// src/client/microphone.ts
|
|
2038
|
+
var clampSample = (value) => Math.max(-1, Math.min(1, value));
|
|
2039
|
+
var floatTo16BitPCM = (input) => {
|
|
2040
|
+
const output = new Int16Array(input.length);
|
|
2041
|
+
for (let index = 0;index < input.length; index += 1) {
|
|
2042
|
+
const sample = clampSample(input[index] ?? 0);
|
|
2043
|
+
output[index] = sample < 0 ? sample * 32768 : sample * 32767;
|
|
2044
|
+
}
|
|
2045
|
+
return new Uint8Array(output.buffer);
|
|
2046
|
+
};
|
|
2047
|
+
var getPcmLevel = (audio) => {
|
|
2048
|
+
const bytes = audio instanceof Uint8Array ? audio : new Uint8Array(audio);
|
|
2049
|
+
if (bytes.byteLength < 2) {
|
|
2050
|
+
return 0;
|
|
2051
|
+
}
|
|
2052
|
+
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
2053
|
+
if (samples.length === 0) {
|
|
2054
|
+
return 0;
|
|
2055
|
+
}
|
|
2056
|
+
let sumSquares = 0;
|
|
2057
|
+
for (const sample of samples) {
|
|
2058
|
+
const normalized = sample / 32768;
|
|
2059
|
+
sumSquares += normalized * normalized;
|
|
2060
|
+
}
|
|
2061
|
+
return Math.min(1, Math.max(0, Math.sqrt(sumSquares / samples.length) * 5.5));
|
|
2062
|
+
};
|
|
2063
|
+
var downsampleBuffer = (input, sourceRate, targetRate) => {
|
|
2064
|
+
if (sourceRate === targetRate) {
|
|
2065
|
+
return input;
|
|
2066
|
+
}
|
|
2067
|
+
const ratio = sourceRate / targetRate;
|
|
2068
|
+
const length = Math.round(input.length / ratio);
|
|
2069
|
+
const output = new Float32Array(length);
|
|
2070
|
+
let offsetResult = 0;
|
|
2071
|
+
let offsetBuffer = 0;
|
|
2072
|
+
while (offsetResult < output.length) {
|
|
2073
|
+
const nextOffsetBuffer = Math.round((offsetResult + 1) * ratio);
|
|
2074
|
+
let accum = 0;
|
|
2075
|
+
let count = 0;
|
|
2076
|
+
for (let index = offsetBuffer;index < nextOffsetBuffer && index < input.length; index += 1) {
|
|
2077
|
+
accum += input[index] ?? 0;
|
|
2078
|
+
count += 1;
|
|
2079
|
+
}
|
|
2080
|
+
output[offsetResult] = count > 0 ? accum / count : 0;
|
|
2081
|
+
offsetResult += 1;
|
|
2082
|
+
offsetBuffer = nextOffsetBuffer;
|
|
2083
|
+
}
|
|
2084
|
+
return output;
|
|
2085
|
+
};
|
|
2086
|
+
var createMicrophoneCapture = (options) => {
|
|
2087
|
+
let audioContext = null;
|
|
2088
|
+
let sourceNode = null;
|
|
2089
|
+
let processorNode = null;
|
|
2090
|
+
let mediaStream = null;
|
|
2091
|
+
const start = async () => {
|
|
2092
|
+
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
2093
|
+
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
2094
|
+
}
|
|
2095
|
+
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
2096
|
+
if (!AudioContextCtor) {
|
|
2097
|
+
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
2098
|
+
}
|
|
2099
|
+
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
2100
|
+
audio: {
|
|
2101
|
+
channelCount: options.channelCount ?? 1
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
audioContext = new AudioContextCtor;
|
|
2105
|
+
sourceNode = audioContext.createMediaStreamSource(mediaStream);
|
|
2106
|
+
processorNode = audioContext.createScriptProcessor(4096, 1, 1);
|
|
2107
|
+
processorNode.onaudioprocess = (event) => {
|
|
2108
|
+
const channel = event.inputBuffer.getChannelData(0);
|
|
2109
|
+
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
2110
|
+
const pcm = floatTo16BitPCM(downsampled);
|
|
2111
|
+
options.onLevel?.(getPcmLevel(pcm));
|
|
2112
|
+
options.onAudio(pcm);
|
|
2113
|
+
};
|
|
2114
|
+
sourceNode.connect(processorNode);
|
|
2115
|
+
processorNode.connect(audioContext.destination);
|
|
2116
|
+
};
|
|
2117
|
+
const stop = () => {
|
|
2118
|
+
processorNode?.disconnect();
|
|
2119
|
+
sourceNode?.disconnect();
|
|
2120
|
+
mediaStream?.getTracks().forEach((track) => track.stop());
|
|
2121
|
+
audioContext?.close();
|
|
2122
|
+
options.onLevel?.(0);
|
|
2123
|
+
audioContext = null;
|
|
2124
|
+
mediaStream = null;
|
|
2125
|
+
processorNode = null;
|
|
2126
|
+
sourceNode = null;
|
|
2127
|
+
};
|
|
2128
|
+
return { start, stop };
|
|
2129
|
+
};
|
|
2130
|
+
|
|
2131
|
+
// src/audioConditioning.ts
|
|
2132
|
+
var DEFAULT_TARGET_LEVEL = 0.08;
|
|
2133
|
+
var DEFAULT_MAX_GAIN = 3;
|
|
2134
|
+
var DEFAULT_NOISE_GATE_THRESHOLD = 0.006;
|
|
2135
|
+
var DEFAULT_NOISE_GATE_ATTENUATION = 0.15;
|
|
2136
|
+
var toInt16Array = (audio) => {
|
|
2137
|
+
if (audio instanceof ArrayBuffer) {
|
|
2138
|
+
return new Int16Array(audio, 0, Math.floor(audio.byteLength / 2));
|
|
2139
|
+
}
|
|
2140
|
+
return new Int16Array(audio.buffer, audio.byteOffset, Math.floor(audio.byteLength / 2));
|
|
2141
|
+
};
|
|
2142
|
+
var computeRms = (samples) => {
|
|
2143
|
+
if (samples.length === 0) {
|
|
2144
|
+
return 0;
|
|
2145
|
+
}
|
|
2146
|
+
let sumSquares = 0;
|
|
2147
|
+
for (const sample of samples) {
|
|
2148
|
+
const normalized = sample / 32768;
|
|
2149
|
+
sumSquares += normalized * normalized;
|
|
2150
|
+
}
|
|
2151
|
+
return Math.sqrt(sumSquares / samples.length);
|
|
2152
|
+
};
|
|
2153
|
+
var resolveAudioConditioningConfig = (config) => {
|
|
2154
|
+
if (!config || config.enabled === false) {
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2157
|
+
return {
|
|
2158
|
+
enabled: true,
|
|
2159
|
+
maxGain: config.maxGain ?? DEFAULT_MAX_GAIN,
|
|
2160
|
+
noiseGateAttenuation: config.noiseGateAttenuation ?? DEFAULT_NOISE_GATE_ATTENUATION,
|
|
2161
|
+
noiseGateThreshold: config.noiseGateThreshold ?? DEFAULT_NOISE_GATE_THRESHOLD,
|
|
2162
|
+
targetLevel: config.targetLevel ?? DEFAULT_TARGET_LEVEL
|
|
2163
|
+
};
|
|
2164
|
+
};
|
|
2165
|
+
var conditionAudioChunk = (audio, config) => {
|
|
2166
|
+
if (!config) {
|
|
2167
|
+
return audio;
|
|
2168
|
+
}
|
|
2169
|
+
const source = toInt16Array(audio);
|
|
2170
|
+
if (source.length === 0) {
|
|
2171
|
+
return audio;
|
|
2172
|
+
}
|
|
2173
|
+
const rms = computeRms(source);
|
|
2174
|
+
const output = new Int16Array(source.length);
|
|
2175
|
+
const gateFactor = rms < config.noiseGateThreshold ? config.noiseGateAttenuation : 1;
|
|
2176
|
+
const baseLevel = Math.max(rms * gateFactor, 0.000001);
|
|
2177
|
+
const gain = Math.min(config.maxGain, config.targetLevel / baseLevel);
|
|
2178
|
+
const appliedGain = Math.max(0.25, gain) * gateFactor;
|
|
2179
|
+
for (let index = 0;index < source.length; index += 1) {
|
|
2180
|
+
const next = Math.round(source[index] * appliedGain);
|
|
2181
|
+
output[index] = Math.max(-32768, Math.min(32767, next));
|
|
2182
|
+
}
|
|
2183
|
+
return new Uint8Array(output.buffer);
|
|
2184
|
+
};
|
|
2185
|
+
|
|
2186
|
+
// src/turnProfiles.ts
|
|
2187
|
+
var TURN_PROFILE_DEFAULTS = {
|
|
2188
|
+
balanced: {
|
|
2189
|
+
qualityProfile: "general",
|
|
2190
|
+
silenceMs: 1400,
|
|
2191
|
+
speechThreshold: 0.012,
|
|
2192
|
+
transcriptStabilityMs: 1000
|
|
2193
|
+
},
|
|
2194
|
+
fast: {
|
|
2195
|
+
qualityProfile: "general",
|
|
2196
|
+
silenceMs: 700,
|
|
2197
|
+
speechThreshold: 0.015,
|
|
2198
|
+
transcriptStabilityMs: 450
|
|
2199
|
+
},
|
|
2200
|
+
"long-form": {
|
|
2201
|
+
qualityProfile: "general",
|
|
819
2202
|
silenceMs: 2200,
|
|
820
2203
|
speechThreshold: 0.01,
|
|
821
2204
|
transcriptStabilityMs: 1500
|
|
822
2205
|
}
|
|
823
2206
|
};
|
|
824
|
-
var QUALITY_PROFILE_DEFAULTS = {
|
|
825
|
-
general: {},
|
|
826
|
-
"accent-heavy": {
|
|
827
|
-
silenceMs: 1200,
|
|
828
|
-
speechThreshold: 0.01,
|
|
829
|
-
transcriptStabilityMs: 1200
|
|
830
|
-
},
|
|
831
|
-
"noisy-room": {
|
|
832
|
-
silenceMs: 2000,
|
|
833
|
-
speechThreshold: 0.02,
|
|
834
|
-
transcriptStabilityMs: 1600
|
|
835
|
-
},
|
|
836
|
-
"short-command": {
|
|
837
|
-
silenceMs: 500,
|
|
838
|
-
speechThreshold: 0.016,
|
|
839
|
-
transcriptStabilityMs: 420
|
|
2207
|
+
var QUALITY_PROFILE_DEFAULTS = {
|
|
2208
|
+
general: {},
|
|
2209
|
+
"accent-heavy": {
|
|
2210
|
+
silenceMs: 1200,
|
|
2211
|
+
speechThreshold: 0.01,
|
|
2212
|
+
transcriptStabilityMs: 1200
|
|
2213
|
+
},
|
|
2214
|
+
"noisy-room": {
|
|
2215
|
+
silenceMs: 2000,
|
|
2216
|
+
speechThreshold: 0.02,
|
|
2217
|
+
transcriptStabilityMs: 1600
|
|
2218
|
+
},
|
|
2219
|
+
"short-command": {
|
|
2220
|
+
silenceMs: 500,
|
|
2221
|
+
speechThreshold: 0.016,
|
|
2222
|
+
transcriptStabilityMs: 420
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2225
|
+
var DEFAULT_TURN_PROFILE = "fast";
|
|
2226
|
+
var DEFAULT_QUALITY_PROFILE = "general";
|
|
2227
|
+
var resolveTurnDetectionConfig = (config) => {
|
|
2228
|
+
const profile = config?.profile ?? DEFAULT_TURN_PROFILE;
|
|
2229
|
+
const qualityProfile = config?.qualityProfile ?? DEFAULT_QUALITY_PROFILE;
|
|
2230
|
+
const preset = TURN_PROFILE_DEFAULTS[profile];
|
|
2231
|
+
const quality = QUALITY_PROFILE_DEFAULTS[qualityProfile];
|
|
2232
|
+
return {
|
|
2233
|
+
profile,
|
|
2234
|
+
qualityProfile,
|
|
2235
|
+
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
2236
|
+
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
2237
|
+
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
2238
|
+
};
|
|
2239
|
+
};
|
|
2240
|
+
|
|
2241
|
+
// src/presets.ts
|
|
2242
|
+
var PRESET_INPUTS = {
|
|
2243
|
+
chat: {
|
|
2244
|
+
audioConditioning: {
|
|
2245
|
+
enabled: true,
|
|
2246
|
+
maxGain: 2.5,
|
|
2247
|
+
noiseGateAttenuation: 0,
|
|
2248
|
+
noiseGateThreshold: 0.004,
|
|
2249
|
+
targetLevel: 0.08
|
|
2250
|
+
},
|
|
2251
|
+
capture: {
|
|
2252
|
+
channelCount: 1,
|
|
2253
|
+
sampleRateHz: 16000
|
|
2254
|
+
},
|
|
2255
|
+
connection: {
|
|
2256
|
+
maxReconnectAttempts: 10,
|
|
2257
|
+
pingInterval: 30000,
|
|
2258
|
+
reconnect: true
|
|
2259
|
+
},
|
|
2260
|
+
sttLifecycle: "continuous",
|
|
2261
|
+
turnDetection: {
|
|
2262
|
+
qualityProfile: "short-command",
|
|
2263
|
+
profile: "balanced"
|
|
2264
|
+
}
|
|
2265
|
+
},
|
|
2266
|
+
default: {
|
|
2267
|
+
capture: {
|
|
2268
|
+
channelCount: 1,
|
|
2269
|
+
sampleRateHz: 16000
|
|
2270
|
+
},
|
|
2271
|
+
connection: {
|
|
2272
|
+
maxReconnectAttempts: 10,
|
|
2273
|
+
pingInterval: 30000,
|
|
2274
|
+
reconnect: true
|
|
2275
|
+
},
|
|
2276
|
+
sttLifecycle: "continuous",
|
|
2277
|
+
turnDetection: {
|
|
2278
|
+
qualityProfile: "general",
|
|
2279
|
+
profile: "fast"
|
|
2280
|
+
}
|
|
2281
|
+
},
|
|
2282
|
+
dictation: {
|
|
2283
|
+
audioConditioning: {
|
|
2284
|
+
enabled: true,
|
|
2285
|
+
maxGain: 2.25,
|
|
2286
|
+
noiseGateAttenuation: 0.05,
|
|
2287
|
+
noiseGateThreshold: 0.003,
|
|
2288
|
+
targetLevel: 0.08
|
|
2289
|
+
},
|
|
2290
|
+
capture: {
|
|
2291
|
+
channelCount: 1,
|
|
2292
|
+
sampleRateHz: 16000
|
|
2293
|
+
},
|
|
2294
|
+
connection: {
|
|
2295
|
+
maxReconnectAttempts: 12,
|
|
2296
|
+
pingInterval: 30000,
|
|
2297
|
+
reconnect: true
|
|
2298
|
+
},
|
|
2299
|
+
sttLifecycle: "continuous",
|
|
2300
|
+
turnDetection: {
|
|
2301
|
+
qualityProfile: "accent-heavy",
|
|
2302
|
+
profile: "long-form"
|
|
2303
|
+
}
|
|
2304
|
+
},
|
|
2305
|
+
"guided-intake": {
|
|
2306
|
+
audioConditioning: {
|
|
2307
|
+
enabled: true,
|
|
2308
|
+
maxGain: 2.5,
|
|
2309
|
+
noiseGateAttenuation: 0,
|
|
2310
|
+
noiseGateThreshold: 0.004,
|
|
2311
|
+
targetLevel: 0.08
|
|
2312
|
+
},
|
|
2313
|
+
capture: {
|
|
2314
|
+
channelCount: 1,
|
|
2315
|
+
sampleRateHz: 16000
|
|
2316
|
+
},
|
|
2317
|
+
connection: {
|
|
2318
|
+
maxReconnectAttempts: 12,
|
|
2319
|
+
pingInterval: 30000,
|
|
2320
|
+
reconnect: true
|
|
2321
|
+
},
|
|
2322
|
+
sttLifecycle: "turn-scoped",
|
|
2323
|
+
turnDetection: {
|
|
2324
|
+
qualityProfile: "accent-heavy",
|
|
2325
|
+
profile: "long-form"
|
|
2326
|
+
}
|
|
2327
|
+
},
|
|
2328
|
+
"noisy-room": {
|
|
2329
|
+
audioConditioning: {
|
|
2330
|
+
enabled: true,
|
|
2331
|
+
maxGain: 3,
|
|
2332
|
+
noiseGateAttenuation: 0.12,
|
|
2333
|
+
noiseGateThreshold: 0.006,
|
|
2334
|
+
targetLevel: 0.085
|
|
2335
|
+
},
|
|
2336
|
+
capture: {
|
|
2337
|
+
channelCount: 1,
|
|
2338
|
+
sampleRateHz: 16000
|
|
2339
|
+
},
|
|
2340
|
+
connection: {
|
|
2341
|
+
maxReconnectAttempts: 14,
|
|
2342
|
+
pingInterval: 45000,
|
|
2343
|
+
reconnect: true
|
|
2344
|
+
},
|
|
2345
|
+
sttLifecycle: "continuous",
|
|
2346
|
+
turnDetection: {
|
|
2347
|
+
qualityProfile: "noisy-room",
|
|
2348
|
+
profile: "long-form",
|
|
2349
|
+
silenceMs: 2100,
|
|
2350
|
+
speechThreshold: 0.02,
|
|
2351
|
+
transcriptStabilityMs: 1650
|
|
2352
|
+
}
|
|
2353
|
+
},
|
|
2354
|
+
"pstn-balanced": {
|
|
2355
|
+
audioConditioning: {
|
|
2356
|
+
enabled: true,
|
|
2357
|
+
maxGain: 2.8,
|
|
2358
|
+
noiseGateAttenuation: 0.07,
|
|
2359
|
+
noiseGateThreshold: 0.005,
|
|
2360
|
+
targetLevel: 0.08
|
|
2361
|
+
},
|
|
2362
|
+
capture: {
|
|
2363
|
+
channelCount: 1,
|
|
2364
|
+
sampleRateHz: 16000
|
|
2365
|
+
},
|
|
2366
|
+
connection: {
|
|
2367
|
+
maxReconnectAttempts: 14,
|
|
2368
|
+
pingInterval: 45000,
|
|
2369
|
+
reconnect: true
|
|
2370
|
+
},
|
|
2371
|
+
sttLifecycle: "continuous",
|
|
2372
|
+
turnDetection: {
|
|
2373
|
+
qualityProfile: "noisy-room",
|
|
2374
|
+
profile: "long-form",
|
|
2375
|
+
silenceMs: 660,
|
|
2376
|
+
speechThreshold: 0.012,
|
|
2377
|
+
transcriptStabilityMs: 300
|
|
2378
|
+
}
|
|
2379
|
+
},
|
|
2380
|
+
"pstn-fast": {
|
|
2381
|
+
audioConditioning: {
|
|
2382
|
+
enabled: true,
|
|
2383
|
+
maxGain: 2.75,
|
|
2384
|
+
noiseGateAttenuation: 0.06,
|
|
2385
|
+
noiseGateThreshold: 0.005,
|
|
2386
|
+
targetLevel: 0.08
|
|
2387
|
+
},
|
|
2388
|
+
capture: {
|
|
2389
|
+
channelCount: 1,
|
|
2390
|
+
sampleRateHz: 16000
|
|
2391
|
+
},
|
|
2392
|
+
connection: {
|
|
2393
|
+
maxReconnectAttempts: 14,
|
|
2394
|
+
pingInterval: 45000,
|
|
2395
|
+
reconnect: true
|
|
2396
|
+
},
|
|
2397
|
+
sttLifecycle: "continuous",
|
|
2398
|
+
turnDetection: {
|
|
2399
|
+
qualityProfile: "noisy-room",
|
|
2400
|
+
profile: "long-form",
|
|
2401
|
+
silenceMs: 620,
|
|
2402
|
+
speechThreshold: 0.012,
|
|
2403
|
+
transcriptStabilityMs: 280
|
|
2404
|
+
}
|
|
2405
|
+
},
|
|
2406
|
+
reliability: {
|
|
2407
|
+
audioConditioning: {
|
|
2408
|
+
enabled: true,
|
|
2409
|
+
maxGain: 2.9,
|
|
2410
|
+
noiseGateAttenuation: 0.08,
|
|
2411
|
+
noiseGateThreshold: 0.005,
|
|
2412
|
+
targetLevel: 0.08
|
|
2413
|
+
},
|
|
2414
|
+
capture: {
|
|
2415
|
+
channelCount: 1,
|
|
2416
|
+
sampleRateHz: 16000
|
|
2417
|
+
},
|
|
2418
|
+
connection: {
|
|
2419
|
+
maxReconnectAttempts: 14,
|
|
2420
|
+
pingInterval: 45000,
|
|
2421
|
+
reconnect: true
|
|
2422
|
+
},
|
|
2423
|
+
sttLifecycle: "continuous",
|
|
2424
|
+
turnDetection: {
|
|
2425
|
+
qualityProfile: "noisy-room",
|
|
2426
|
+
profile: "long-form"
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2430
|
+
var resolveVoiceRuntimePreset = (name = "default") => {
|
|
2431
|
+
const preset = PRESET_INPUTS[name];
|
|
2432
|
+
return {
|
|
2433
|
+
audioConditioning: resolveAudioConditioningConfig(preset.audioConditioning),
|
|
2434
|
+
capture: {
|
|
2435
|
+
channelCount: preset.capture?.channelCount ?? 1,
|
|
2436
|
+
sampleRateHz: preset.capture?.sampleRateHz ?? 16000
|
|
2437
|
+
},
|
|
2438
|
+
connection: {
|
|
2439
|
+
...preset.connection
|
|
2440
|
+
},
|
|
2441
|
+
name,
|
|
2442
|
+
sttLifecycle: preset.sttLifecycle ?? "continuous",
|
|
2443
|
+
turnDetection: resolveTurnDetectionConfig(preset.turnDetection)
|
|
2444
|
+
};
|
|
2445
|
+
};
|
|
2446
|
+
|
|
2447
|
+
// src/client/controller.ts
|
|
2448
|
+
var createInitialState2 = (stream) => ({
|
|
2449
|
+
assistantAudio: [...stream.assistantAudio],
|
|
2450
|
+
assistantTexts: [...stream.assistantTexts],
|
|
2451
|
+
call: stream.call,
|
|
2452
|
+
error: stream.error,
|
|
2453
|
+
isConnected: stream.isConnected,
|
|
2454
|
+
isRecording: false,
|
|
2455
|
+
partial: stream.partial,
|
|
2456
|
+
reconnect: stream.reconnect,
|
|
2457
|
+
recordingError: null,
|
|
2458
|
+
sessionId: stream.sessionId,
|
|
2459
|
+
scenarioId: stream.scenarioId,
|
|
2460
|
+
status: stream.status,
|
|
2461
|
+
turns: [...stream.turns]
|
|
2462
|
+
});
|
|
2463
|
+
var createVoiceController = (path, options = {}) => {
|
|
2464
|
+
const preset = resolveVoiceRuntimePreset(options.preset);
|
|
2465
|
+
const stream = createVoiceStream(path, {
|
|
2466
|
+
...preset.connection,
|
|
2467
|
+
...options.connection
|
|
2468
|
+
});
|
|
2469
|
+
let capture = null;
|
|
2470
|
+
let state = createInitialState2(stream);
|
|
2471
|
+
const subscribers = new Set;
|
|
2472
|
+
const notify = () => {
|
|
2473
|
+
for (const subscriber of subscribers) {
|
|
2474
|
+
subscriber();
|
|
2475
|
+
}
|
|
2476
|
+
};
|
|
2477
|
+
const sync = () => {
|
|
2478
|
+
state = {
|
|
2479
|
+
...state,
|
|
2480
|
+
assistantAudio: [...stream.assistantAudio],
|
|
2481
|
+
assistantTexts: [...stream.assistantTexts],
|
|
2482
|
+
call: stream.call,
|
|
2483
|
+
error: stream.error,
|
|
2484
|
+
isConnected: stream.isConnected,
|
|
2485
|
+
partial: stream.partial,
|
|
2486
|
+
reconnect: stream.reconnect,
|
|
2487
|
+
sessionId: stream.sessionId,
|
|
2488
|
+
scenarioId: stream.scenarioId,
|
|
2489
|
+
status: stream.status,
|
|
2490
|
+
turns: [...stream.turns]
|
|
2491
|
+
};
|
|
2492
|
+
if (options.autoStopOnComplete !== false && state.status === "completed" && state.isRecording) {
|
|
2493
|
+
capture?.stop();
|
|
2494
|
+
capture = null;
|
|
2495
|
+
state = {
|
|
2496
|
+
...state,
|
|
2497
|
+
isRecording: false
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
notify();
|
|
2501
|
+
};
|
|
2502
|
+
const unsubscribeStream = stream.subscribe(sync);
|
|
2503
|
+
sync();
|
|
2504
|
+
const ensureCapture = () => {
|
|
2505
|
+
if (capture) {
|
|
2506
|
+
return capture;
|
|
2507
|
+
}
|
|
2508
|
+
capture = createMicrophoneCapture({
|
|
2509
|
+
channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
|
|
2510
|
+
onLevel: options.capture?.onLevel,
|
|
2511
|
+
onAudio: (audio) => {
|
|
2512
|
+
if (options.capture?.onAudio) {
|
|
2513
|
+
options.capture.onAudio(audio, stream.sendAudio);
|
|
2514
|
+
return;
|
|
2515
|
+
}
|
|
2516
|
+
stream.sendAudio(audio);
|
|
2517
|
+
},
|
|
2518
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
2519
|
+
});
|
|
2520
|
+
return capture;
|
|
2521
|
+
};
|
|
2522
|
+
const stopRecording = () => {
|
|
2523
|
+
capture?.stop();
|
|
2524
|
+
capture = null;
|
|
2525
|
+
state = {
|
|
2526
|
+
...state,
|
|
2527
|
+
isRecording: false
|
|
2528
|
+
};
|
|
2529
|
+
notify();
|
|
2530
|
+
};
|
|
2531
|
+
const startRecording = async () => {
|
|
2532
|
+
if (state.isRecording) {
|
|
2533
|
+
return;
|
|
2534
|
+
}
|
|
2535
|
+
try {
|
|
2536
|
+
state = {
|
|
2537
|
+
...state,
|
|
2538
|
+
recordingError: null
|
|
2539
|
+
};
|
|
2540
|
+
notify();
|
|
2541
|
+
await ensureCapture().start();
|
|
2542
|
+
state = {
|
|
2543
|
+
...state,
|
|
2544
|
+
isRecording: true
|
|
2545
|
+
};
|
|
2546
|
+
notify();
|
|
2547
|
+
} catch (error) {
|
|
2548
|
+
capture = null;
|
|
2549
|
+
state = {
|
|
2550
|
+
...state,
|
|
2551
|
+
isRecording: false,
|
|
2552
|
+
recordingError: error instanceof Error ? error.message : String(error)
|
|
2553
|
+
};
|
|
2554
|
+
notify();
|
|
2555
|
+
throw error;
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
const close = () => {
|
|
2559
|
+
unsubscribeStream();
|
|
2560
|
+
stopRecording();
|
|
2561
|
+
stream.close();
|
|
2562
|
+
};
|
|
2563
|
+
return {
|
|
2564
|
+
bindHTMX(bindingOptions) {
|
|
2565
|
+
return bindVoiceHTMX(stream, bindingOptions);
|
|
2566
|
+
},
|
|
2567
|
+
callControl: (message) => stream.callControl(message),
|
|
2568
|
+
close,
|
|
2569
|
+
endTurn: () => stream.endTurn(),
|
|
2570
|
+
get error() {
|
|
2571
|
+
return state.error;
|
|
2572
|
+
},
|
|
2573
|
+
getServerSnapshot: () => state,
|
|
2574
|
+
getSnapshot: () => state,
|
|
2575
|
+
get isConnected() {
|
|
2576
|
+
return state.isConnected;
|
|
2577
|
+
},
|
|
2578
|
+
get isRecording() {
|
|
2579
|
+
return state.isRecording;
|
|
2580
|
+
},
|
|
2581
|
+
get partial() {
|
|
2582
|
+
return state.partial;
|
|
2583
|
+
},
|
|
2584
|
+
get recordingError() {
|
|
2585
|
+
return state.recordingError;
|
|
2586
|
+
},
|
|
2587
|
+
get reconnect() {
|
|
2588
|
+
return state.reconnect;
|
|
2589
|
+
},
|
|
2590
|
+
sendAudio: (audio) => stream.sendAudio(audio),
|
|
2591
|
+
get sessionId() {
|
|
2592
|
+
return state.sessionId;
|
|
2593
|
+
},
|
|
2594
|
+
get scenarioId() {
|
|
2595
|
+
return state.scenarioId;
|
|
2596
|
+
},
|
|
2597
|
+
startRecording,
|
|
2598
|
+
get status() {
|
|
2599
|
+
return state.status;
|
|
2600
|
+
},
|
|
2601
|
+
stopRecording,
|
|
2602
|
+
subscribe: (subscriber) => {
|
|
2603
|
+
subscribers.add(subscriber);
|
|
2604
|
+
return () => {
|
|
2605
|
+
subscribers.delete(subscriber);
|
|
2606
|
+
};
|
|
2607
|
+
},
|
|
2608
|
+
toggleRecording: async () => {
|
|
2609
|
+
if (state.isRecording) {
|
|
2610
|
+
stopRecording();
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
await startRecording();
|
|
2614
|
+
},
|
|
2615
|
+
get turns() {
|
|
2616
|
+
return state.turns;
|
|
2617
|
+
},
|
|
2618
|
+
get assistantTexts() {
|
|
2619
|
+
return state.assistantTexts;
|
|
2620
|
+
},
|
|
2621
|
+
get assistantAudio() {
|
|
2622
|
+
return state.assistantAudio;
|
|
2623
|
+
},
|
|
2624
|
+
get call() {
|
|
2625
|
+
return state.call;
|
|
2626
|
+
}
|
|
2627
|
+
};
|
|
2628
|
+
};
|
|
2629
|
+
|
|
2630
|
+
// src/angular/voice-controller.service.ts
|
|
2631
|
+
var _dec = [
|
|
2632
|
+
Injectable10({ providedIn: "root" })
|
|
2633
|
+
];
|
|
2634
|
+
var _init = __decoratorStart(undefined);
|
|
2635
|
+
|
|
2636
|
+
class VoiceControllerService {
|
|
2637
|
+
connect(path, options = {}) {
|
|
2638
|
+
const controller = createVoiceController(path, options);
|
|
2639
|
+
const assistantAudioSignal = signal10([]);
|
|
2640
|
+
const assistantTextsSignal = signal10([]);
|
|
2641
|
+
const errorSignal = signal10(null);
|
|
2642
|
+
const isConnectedSignal = signal10(false);
|
|
2643
|
+
const isRecordingSignal = signal10(false);
|
|
2644
|
+
const partialSignal = signal10("");
|
|
2645
|
+
const reconnectSignal = signal10(controller.reconnect);
|
|
2646
|
+
const recordingErrorSignal = signal10(null);
|
|
2647
|
+
const sessionIdSignal = signal10(controller.sessionId);
|
|
2648
|
+
const statusSignal = signal10(controller.status);
|
|
2649
|
+
const turnsSignal = signal10([]);
|
|
2650
|
+
const sync = () => {
|
|
2651
|
+
assistantAudioSignal.set([...controller.assistantAudio]);
|
|
2652
|
+
assistantTextsSignal.set([...controller.assistantTexts]);
|
|
2653
|
+
errorSignal.set(controller.error);
|
|
2654
|
+
isConnectedSignal.set(controller.isConnected);
|
|
2655
|
+
isRecordingSignal.set(controller.isRecording);
|
|
2656
|
+
partialSignal.set(controller.partial);
|
|
2657
|
+
reconnectSignal.set(controller.reconnect);
|
|
2658
|
+
recordingErrorSignal.set(controller.recordingError);
|
|
2659
|
+
sessionIdSignal.set(controller.sessionId);
|
|
2660
|
+
statusSignal.set(controller.status);
|
|
2661
|
+
turnsSignal.set([...controller.turns]);
|
|
2662
|
+
};
|
|
2663
|
+
const unsubscribe = controller.subscribe(sync);
|
|
2664
|
+
sync();
|
|
2665
|
+
return {
|
|
2666
|
+
assistantAudio: computed10(() => assistantAudioSignal()),
|
|
2667
|
+
assistantTexts: computed10(() => assistantTextsSignal()),
|
|
2668
|
+
bindHTMX: controller.bindHTMX,
|
|
2669
|
+
close: () => {
|
|
2670
|
+
unsubscribe();
|
|
2671
|
+
controller.close();
|
|
2672
|
+
},
|
|
2673
|
+
endTurn: () => controller.endTurn(),
|
|
2674
|
+
error: computed10(() => errorSignal()),
|
|
2675
|
+
isConnected: computed10(() => isConnectedSignal()),
|
|
2676
|
+
isRecording: computed10(() => isRecordingSignal()),
|
|
2677
|
+
partial: computed10(() => partialSignal()),
|
|
2678
|
+
reconnect: computed10(() => reconnectSignal()),
|
|
2679
|
+
recordingError: computed10(() => recordingErrorSignal()),
|
|
2680
|
+
sendAudio: (audio) => controller.sendAudio(audio),
|
|
2681
|
+
sessionId: computed10(() => sessionIdSignal()),
|
|
2682
|
+
startRecording: () => controller.startRecording(),
|
|
2683
|
+
status: computed10(() => statusSignal()),
|
|
2684
|
+
stopRecording: () => controller.stopRecording(),
|
|
2685
|
+
toggleRecording: () => controller.toggleRecording(),
|
|
2686
|
+
turns: computed10(() => turnsSignal())
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
VoiceControllerService = __decorateElement(_init, 0, "VoiceControllerService", _dec, VoiceControllerService);
|
|
2691
|
+
__runInitializers(_init, 1, VoiceControllerService);
|
|
2692
|
+
__decoratorMetadata(_init, VoiceControllerService);
|
|
2693
|
+
let _VoiceControllerService = VoiceControllerService;
|
|
2694
|
+
// src/angular/voice-provider-capabilities.service.ts
|
|
2695
|
+
import { computed as computed11, Injectable as Injectable11, signal as signal11 } from "@angular/core";
|
|
2696
|
+
|
|
2697
|
+
// src/client/providerCapabilities.ts
|
|
2698
|
+
var fetchVoiceProviderCapabilities = async (path = "/api/provider-capabilities", options = {}) => {
|
|
2699
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2700
|
+
const response = await fetchImpl(path);
|
|
2701
|
+
if (!response.ok) {
|
|
2702
|
+
throw new Error(`Voice provider capabilities failed: HTTP ${response.status}`);
|
|
2703
|
+
}
|
|
2704
|
+
return await response.json();
|
|
2705
|
+
};
|
|
2706
|
+
var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities", options = {}) => {
|
|
2707
|
+
const listeners = new Set;
|
|
2708
|
+
let closed = false;
|
|
2709
|
+
let timer;
|
|
2710
|
+
let snapshot = {
|
|
2711
|
+
error: null,
|
|
2712
|
+
isLoading: false
|
|
2713
|
+
};
|
|
2714
|
+
const emit = () => {
|
|
2715
|
+
for (const listener of listeners) {
|
|
2716
|
+
listener();
|
|
2717
|
+
}
|
|
2718
|
+
};
|
|
2719
|
+
const refresh = async () => {
|
|
2720
|
+
if (closed) {
|
|
2721
|
+
return snapshot.report;
|
|
2722
|
+
}
|
|
2723
|
+
snapshot = {
|
|
2724
|
+
...snapshot,
|
|
2725
|
+
error: null,
|
|
2726
|
+
isLoading: true
|
|
2727
|
+
};
|
|
2728
|
+
emit();
|
|
2729
|
+
try {
|
|
2730
|
+
const report = await fetchVoiceProviderCapabilities(path, options);
|
|
2731
|
+
snapshot = {
|
|
2732
|
+
error: null,
|
|
2733
|
+
isLoading: false,
|
|
2734
|
+
report,
|
|
2735
|
+
updatedAt: Date.now()
|
|
2736
|
+
};
|
|
2737
|
+
emit();
|
|
2738
|
+
return report;
|
|
2739
|
+
} catch (error) {
|
|
2740
|
+
snapshot = {
|
|
2741
|
+
...snapshot,
|
|
2742
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2743
|
+
isLoading: false
|
|
2744
|
+
};
|
|
2745
|
+
emit();
|
|
2746
|
+
throw error;
|
|
2747
|
+
}
|
|
2748
|
+
};
|
|
2749
|
+
const close = () => {
|
|
2750
|
+
closed = true;
|
|
2751
|
+
if (timer) {
|
|
2752
|
+
clearInterval(timer);
|
|
2753
|
+
timer = undefined;
|
|
2754
|
+
}
|
|
2755
|
+
listeners.clear();
|
|
2756
|
+
};
|
|
2757
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
2758
|
+
timer = setInterval(() => {
|
|
2759
|
+
refresh().catch(() => {});
|
|
2760
|
+
}, options.intervalMs);
|
|
2761
|
+
}
|
|
2762
|
+
return {
|
|
2763
|
+
close,
|
|
2764
|
+
getServerSnapshot: () => snapshot,
|
|
2765
|
+
getSnapshot: () => snapshot,
|
|
2766
|
+
refresh,
|
|
2767
|
+
subscribe: (listener) => {
|
|
2768
|
+
listeners.add(listener);
|
|
2769
|
+
return () => {
|
|
2770
|
+
listeners.delete(listener);
|
|
2771
|
+
};
|
|
2772
|
+
}
|
|
2773
|
+
};
|
|
2774
|
+
};
|
|
2775
|
+
|
|
2776
|
+
// src/angular/voice-provider-capabilities.service.ts
|
|
2777
|
+
var _dec = [
|
|
2778
|
+
Injectable11({ providedIn: "root" })
|
|
2779
|
+
];
|
|
2780
|
+
var _init = __decoratorStart(undefined);
|
|
2781
|
+
|
|
2782
|
+
class VoiceProviderCapabilitiesService {
|
|
2783
|
+
connect(path = "/api/provider-capabilities", options = {}) {
|
|
2784
|
+
const store = createVoiceProviderCapabilitiesStore(path, options);
|
|
2785
|
+
const errorSignal = signal11(null);
|
|
2786
|
+
const isLoadingSignal = signal11(false);
|
|
2787
|
+
const reportSignal = signal11(undefined);
|
|
2788
|
+
const updatedAtSignal = signal11(undefined);
|
|
2789
|
+
const sync = () => {
|
|
2790
|
+
const snapshot = store.getSnapshot();
|
|
2791
|
+
errorSignal.set(snapshot.error);
|
|
2792
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
2793
|
+
reportSignal.set(snapshot.report);
|
|
2794
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
2795
|
+
};
|
|
2796
|
+
const unsubscribe = store.subscribe(sync);
|
|
2797
|
+
sync();
|
|
2798
|
+
store.refresh().catch(() => {});
|
|
2799
|
+
return {
|
|
2800
|
+
close: () => {
|
|
2801
|
+
unsubscribe();
|
|
2802
|
+
store.close();
|
|
2803
|
+
},
|
|
2804
|
+
error: computed11(() => errorSignal()),
|
|
2805
|
+
isLoading: computed11(() => isLoadingSignal()),
|
|
2806
|
+
refresh: store.refresh,
|
|
2807
|
+
report: computed11(() => reportSignal()),
|
|
2808
|
+
updatedAt: computed11(() => updatedAtSignal())
|
|
2809
|
+
};
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
VoiceProviderCapabilitiesService = __decorateElement(_init, 0, "VoiceProviderCapabilitiesService", _dec, VoiceProviderCapabilitiesService);
|
|
2813
|
+
__runInitializers(_init, 1, VoiceProviderCapabilitiesService);
|
|
2814
|
+
__decoratorMetadata(_init, VoiceProviderCapabilitiesService);
|
|
2815
|
+
let _VoiceProviderCapabilitiesService = VoiceProviderCapabilitiesService;
|
|
2816
|
+
// src/angular/voice-provider-contracts.service.ts
|
|
2817
|
+
import { computed as computed12, Injectable as Injectable12, signal as signal12 } from "@angular/core";
|
|
2818
|
+
|
|
2819
|
+
// src/client/providerContracts.ts
|
|
2820
|
+
var fetchVoiceProviderContracts = async (path = "/api/provider-contracts", options = {}) => {
|
|
2821
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2822
|
+
const response = await fetchImpl(path);
|
|
2823
|
+
if (!response.ok) {
|
|
2824
|
+
throw new Error(`Voice provider contracts failed: HTTP ${response.status}`);
|
|
2825
|
+
}
|
|
2826
|
+
return await response.json();
|
|
2827
|
+
};
|
|
2828
|
+
var createVoiceProviderContractsStore = (path = "/api/provider-contracts", options = {}) => {
|
|
2829
|
+
const listeners = new Set;
|
|
2830
|
+
let closed = false;
|
|
2831
|
+
let timer;
|
|
2832
|
+
let snapshot = {
|
|
2833
|
+
error: null,
|
|
2834
|
+
isLoading: false
|
|
2835
|
+
};
|
|
2836
|
+
const emit = () => {
|
|
2837
|
+
for (const listener of listeners) {
|
|
2838
|
+
listener();
|
|
2839
|
+
}
|
|
2840
|
+
};
|
|
2841
|
+
const refresh = async () => {
|
|
2842
|
+
if (closed) {
|
|
2843
|
+
return snapshot.report;
|
|
2844
|
+
}
|
|
2845
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
2846
|
+
emit();
|
|
2847
|
+
try {
|
|
2848
|
+
const report = await fetchVoiceProviderContracts(path, options);
|
|
2849
|
+
snapshot = {
|
|
2850
|
+
error: null,
|
|
2851
|
+
isLoading: false,
|
|
2852
|
+
report,
|
|
2853
|
+
updatedAt: Date.now()
|
|
2854
|
+
};
|
|
2855
|
+
emit();
|
|
2856
|
+
return report;
|
|
2857
|
+
} catch (error) {
|
|
2858
|
+
snapshot = {
|
|
2859
|
+
...snapshot,
|
|
2860
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2861
|
+
isLoading: false
|
|
2862
|
+
};
|
|
2863
|
+
emit();
|
|
2864
|
+
throw error;
|
|
2865
|
+
}
|
|
2866
|
+
};
|
|
2867
|
+
const close = () => {
|
|
2868
|
+
closed = true;
|
|
2869
|
+
if (timer) {
|
|
2870
|
+
clearInterval(timer);
|
|
2871
|
+
timer = undefined;
|
|
2872
|
+
}
|
|
2873
|
+
listeners.clear();
|
|
2874
|
+
};
|
|
2875
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
2876
|
+
timer = setInterval(() => {
|
|
2877
|
+
refresh().catch(() => {});
|
|
2878
|
+
}, options.intervalMs);
|
|
2879
|
+
}
|
|
2880
|
+
return {
|
|
2881
|
+
close,
|
|
2882
|
+
getServerSnapshot: () => snapshot,
|
|
2883
|
+
getSnapshot: () => snapshot,
|
|
2884
|
+
refresh,
|
|
2885
|
+
subscribe: (listener) => {
|
|
2886
|
+
listeners.add(listener);
|
|
2887
|
+
return () => {
|
|
2888
|
+
listeners.delete(listener);
|
|
2889
|
+
};
|
|
2890
|
+
}
|
|
2891
|
+
};
|
|
2892
|
+
};
|
|
2893
|
+
|
|
2894
|
+
// src/angular/voice-provider-contracts.service.ts
|
|
2895
|
+
var _dec = [
|
|
2896
|
+
Injectable12({ providedIn: "root" })
|
|
2897
|
+
];
|
|
2898
|
+
var _init = __decoratorStart(undefined);
|
|
2899
|
+
|
|
2900
|
+
class VoiceProviderContractsService {
|
|
2901
|
+
connect(path = "/api/provider-contracts", options = {}) {
|
|
2902
|
+
const store = createVoiceProviderContractsStore(path, options);
|
|
2903
|
+
const errorSignal = signal12(null);
|
|
2904
|
+
const isLoadingSignal = signal12(false);
|
|
2905
|
+
const reportSignal = signal12(undefined);
|
|
2906
|
+
const updatedAtSignal = signal12(undefined);
|
|
2907
|
+
const sync = () => {
|
|
2908
|
+
const snapshot = store.getSnapshot();
|
|
2909
|
+
errorSignal.set(snapshot.error);
|
|
2910
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
2911
|
+
reportSignal.set(snapshot.report);
|
|
2912
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
2913
|
+
};
|
|
2914
|
+
const unsubscribe = store.subscribe(sync);
|
|
2915
|
+
sync();
|
|
2916
|
+
store.refresh().catch(() => {});
|
|
2917
|
+
return {
|
|
2918
|
+
close: () => {
|
|
2919
|
+
unsubscribe();
|
|
2920
|
+
store.close();
|
|
2921
|
+
},
|
|
2922
|
+
error: computed12(() => errorSignal()),
|
|
2923
|
+
isLoading: computed12(() => isLoadingSignal()),
|
|
2924
|
+
refresh: store.refresh,
|
|
2925
|
+
report: computed12(() => reportSignal()),
|
|
2926
|
+
updatedAt: computed12(() => updatedAtSignal())
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
VoiceProviderContractsService = __decorateElement(_init, 0, "VoiceProviderContractsService", _dec, VoiceProviderContractsService);
|
|
2931
|
+
__runInitializers(_init, 1, VoiceProviderContractsService);
|
|
2932
|
+
__decoratorMetadata(_init, VoiceProviderContractsService);
|
|
2933
|
+
let _VoiceProviderContractsService = VoiceProviderContractsService;
|
|
2934
|
+
// src/angular/voice-provider-status.service.ts
|
|
2935
|
+
import { computed as computed13, Injectable as Injectable13, signal as signal13 } from "@angular/core";
|
|
2936
|
+
|
|
2937
|
+
// src/client/providerStatus.ts
|
|
2938
|
+
var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
|
|
2939
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2940
|
+
const response = await fetchImpl(path);
|
|
2941
|
+
if (!response.ok) {
|
|
2942
|
+
throw new Error(`Voice provider status failed: HTTP ${response.status}`);
|
|
2943
|
+
}
|
|
2944
|
+
return await response.json();
|
|
2945
|
+
};
|
|
2946
|
+
var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {}) => {
|
|
2947
|
+
const listeners = new Set;
|
|
2948
|
+
let closed = false;
|
|
2949
|
+
let timer;
|
|
2950
|
+
let snapshot = {
|
|
2951
|
+
error: null,
|
|
2952
|
+
isLoading: false,
|
|
2953
|
+
providers: []
|
|
2954
|
+
};
|
|
2955
|
+
const emit = () => {
|
|
2956
|
+
for (const listener of listeners) {
|
|
2957
|
+
listener();
|
|
2958
|
+
}
|
|
2959
|
+
};
|
|
2960
|
+
const refresh = async () => {
|
|
2961
|
+
if (closed) {
|
|
2962
|
+
return snapshot.providers;
|
|
2963
|
+
}
|
|
2964
|
+
snapshot = {
|
|
2965
|
+
...snapshot,
|
|
2966
|
+
error: null,
|
|
2967
|
+
isLoading: true
|
|
2968
|
+
};
|
|
2969
|
+
emit();
|
|
2970
|
+
try {
|
|
2971
|
+
const providers = await fetchVoiceProviderStatus(path, options);
|
|
2972
|
+
snapshot = {
|
|
2973
|
+
error: null,
|
|
2974
|
+
isLoading: false,
|
|
2975
|
+
providers,
|
|
2976
|
+
updatedAt: Date.now()
|
|
2977
|
+
};
|
|
2978
|
+
emit();
|
|
2979
|
+
return providers;
|
|
2980
|
+
} catch (error) {
|
|
2981
|
+
snapshot = {
|
|
2982
|
+
...snapshot,
|
|
2983
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2984
|
+
isLoading: false
|
|
2985
|
+
};
|
|
2986
|
+
emit();
|
|
2987
|
+
throw error;
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
const close = () => {
|
|
2991
|
+
closed = true;
|
|
2992
|
+
if (timer) {
|
|
2993
|
+
clearInterval(timer);
|
|
2994
|
+
timer = undefined;
|
|
2995
|
+
}
|
|
2996
|
+
listeners.clear();
|
|
2997
|
+
};
|
|
2998
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
2999
|
+
timer = setInterval(() => {
|
|
3000
|
+
refresh().catch(() => {});
|
|
3001
|
+
}, options.intervalMs);
|
|
3002
|
+
}
|
|
3003
|
+
return {
|
|
3004
|
+
close,
|
|
3005
|
+
getServerSnapshot: () => snapshot,
|
|
3006
|
+
getSnapshot: () => snapshot,
|
|
3007
|
+
refresh,
|
|
3008
|
+
subscribe: (listener) => {
|
|
3009
|
+
listeners.add(listener);
|
|
3010
|
+
return () => {
|
|
3011
|
+
listeners.delete(listener);
|
|
3012
|
+
};
|
|
3013
|
+
}
|
|
3014
|
+
};
|
|
3015
|
+
};
|
|
3016
|
+
|
|
3017
|
+
// src/angular/voice-provider-status.service.ts
|
|
3018
|
+
var _dec = [
|
|
3019
|
+
Injectable13({ providedIn: "root" })
|
|
3020
|
+
];
|
|
3021
|
+
var _init = __decoratorStart(undefined);
|
|
3022
|
+
|
|
3023
|
+
class VoiceProviderStatusService {
|
|
3024
|
+
connect(path = "/api/provider-status", options = {}) {
|
|
3025
|
+
const store = createVoiceProviderStatusStore(path, options);
|
|
3026
|
+
const errorSignal = signal13(null);
|
|
3027
|
+
const isLoadingSignal = signal13(false);
|
|
3028
|
+
const providersSignal = signal13([]);
|
|
3029
|
+
const updatedAtSignal = signal13(undefined);
|
|
3030
|
+
const sync = () => {
|
|
3031
|
+
const snapshot = store.getSnapshot();
|
|
3032
|
+
errorSignal.set(snapshot.error);
|
|
3033
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3034
|
+
providersSignal.set([...snapshot.providers]);
|
|
3035
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3036
|
+
};
|
|
3037
|
+
const unsubscribe = store.subscribe(sync);
|
|
3038
|
+
sync();
|
|
3039
|
+
store.refresh().catch(() => {});
|
|
3040
|
+
return {
|
|
3041
|
+
close: () => {
|
|
3042
|
+
unsubscribe();
|
|
3043
|
+
store.close();
|
|
3044
|
+
},
|
|
3045
|
+
error: computed13(() => errorSignal()),
|
|
3046
|
+
isLoading: computed13(() => isLoadingSignal()),
|
|
3047
|
+
providers: computed13(() => providersSignal()),
|
|
3048
|
+
refresh: store.refresh,
|
|
3049
|
+
updatedAt: computed13(() => updatedAtSignal())
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
VoiceProviderStatusService = __decorateElement(_init, 0, "VoiceProviderStatusService", _dec, VoiceProviderStatusService);
|
|
3054
|
+
__runInitializers(_init, 1, VoiceProviderStatusService);
|
|
3055
|
+
__decoratorMetadata(_init, VoiceProviderStatusService);
|
|
3056
|
+
let _VoiceProviderStatusService = VoiceProviderStatusService;
|
|
3057
|
+
// src/angular/voice-routing-status.service.ts
|
|
3058
|
+
import { Injectable as Injectable14, signal as signal14 } from "@angular/core";
|
|
3059
|
+
|
|
3060
|
+
// src/client/routingStatus.ts
|
|
3061
|
+
var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
|
|
3062
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3063
|
+
const response = await fetchImpl(path);
|
|
3064
|
+
if (!response.ok) {
|
|
3065
|
+
throw new Error(`Voice routing status failed: HTTP ${response.status}`);
|
|
3066
|
+
}
|
|
3067
|
+
return await response.json();
|
|
3068
|
+
};
|
|
3069
|
+
var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {}) => {
|
|
3070
|
+
const listeners = new Set;
|
|
3071
|
+
let closed = false;
|
|
3072
|
+
let timer;
|
|
3073
|
+
let snapshot = {
|
|
3074
|
+
decision: null,
|
|
3075
|
+
error: null,
|
|
3076
|
+
isLoading: false
|
|
3077
|
+
};
|
|
3078
|
+
const emit = () => {
|
|
3079
|
+
for (const listener of listeners) {
|
|
3080
|
+
listener();
|
|
3081
|
+
}
|
|
3082
|
+
};
|
|
3083
|
+
const refresh = async () => {
|
|
3084
|
+
if (closed) {
|
|
3085
|
+
return snapshot.decision;
|
|
3086
|
+
}
|
|
3087
|
+
snapshot = {
|
|
3088
|
+
...snapshot,
|
|
3089
|
+
error: null,
|
|
3090
|
+
isLoading: true
|
|
3091
|
+
};
|
|
3092
|
+
emit();
|
|
3093
|
+
try {
|
|
3094
|
+
const decision = await fetchVoiceRoutingStatus(path, options);
|
|
3095
|
+
snapshot = {
|
|
3096
|
+
decision,
|
|
3097
|
+
error: null,
|
|
3098
|
+
isLoading: false,
|
|
3099
|
+
updatedAt: Date.now()
|
|
3100
|
+
};
|
|
3101
|
+
emit();
|
|
3102
|
+
return decision;
|
|
3103
|
+
} catch (error) {
|
|
3104
|
+
snapshot = {
|
|
3105
|
+
...snapshot,
|
|
3106
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3107
|
+
isLoading: false
|
|
3108
|
+
};
|
|
3109
|
+
emit();
|
|
3110
|
+
throw error;
|
|
3111
|
+
}
|
|
3112
|
+
};
|
|
3113
|
+
const close = () => {
|
|
3114
|
+
closed = true;
|
|
3115
|
+
if (timer) {
|
|
3116
|
+
clearInterval(timer);
|
|
3117
|
+
timer = undefined;
|
|
3118
|
+
}
|
|
3119
|
+
listeners.clear();
|
|
3120
|
+
};
|
|
3121
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3122
|
+
timer = setInterval(() => {
|
|
3123
|
+
refresh().catch(() => {});
|
|
3124
|
+
}, options.intervalMs);
|
|
3125
|
+
}
|
|
3126
|
+
return {
|
|
3127
|
+
close,
|
|
3128
|
+
getServerSnapshot: () => snapshot,
|
|
3129
|
+
getSnapshot: () => snapshot,
|
|
3130
|
+
refresh,
|
|
3131
|
+
subscribe: (listener) => {
|
|
3132
|
+
listeners.add(listener);
|
|
3133
|
+
return () => {
|
|
3134
|
+
listeners.delete(listener);
|
|
3135
|
+
};
|
|
3136
|
+
}
|
|
3137
|
+
};
|
|
3138
|
+
};
|
|
3139
|
+
|
|
3140
|
+
// src/angular/voice-routing-status.service.ts
|
|
3141
|
+
var _dec = [
|
|
3142
|
+
Injectable14({ providedIn: "root" })
|
|
3143
|
+
];
|
|
3144
|
+
var _init = __decoratorStart(undefined);
|
|
3145
|
+
|
|
3146
|
+
class VoiceRoutingStatusService {
|
|
3147
|
+
connect(path = "/api/routing/latest", options = {}) {
|
|
3148
|
+
const store = createVoiceRoutingStatusStore(path, options);
|
|
3149
|
+
const decisionSignal = signal14(null);
|
|
3150
|
+
const errorSignal = signal14(null);
|
|
3151
|
+
const isLoadingSignal = signal14(false);
|
|
3152
|
+
const updatedAtSignal = signal14(undefined);
|
|
3153
|
+
const sync = () => {
|
|
3154
|
+
const snapshot = store.getSnapshot();
|
|
3155
|
+
decisionSignal.set(snapshot.decision);
|
|
3156
|
+
errorSignal.set(snapshot.error);
|
|
3157
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3158
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3159
|
+
};
|
|
3160
|
+
const unsubscribe = store.subscribe(sync);
|
|
3161
|
+
sync();
|
|
3162
|
+
store.refresh().catch(() => {});
|
|
3163
|
+
return {
|
|
3164
|
+
close: () => {
|
|
3165
|
+
unsubscribe();
|
|
3166
|
+
store.close();
|
|
3167
|
+
},
|
|
3168
|
+
decision: decisionSignal.asReadonly(),
|
|
3169
|
+
error: errorSignal.asReadonly(),
|
|
3170
|
+
isLoading: isLoadingSignal.asReadonly(),
|
|
3171
|
+
refresh: store.refresh,
|
|
3172
|
+
updatedAt: updatedAtSignal.asReadonly()
|
|
3173
|
+
};
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
VoiceRoutingStatusService = __decorateElement(_init, 0, "VoiceRoutingStatusService", _dec, VoiceRoutingStatusService);
|
|
3177
|
+
__runInitializers(_init, 1, VoiceRoutingStatusService);
|
|
3178
|
+
__decoratorMetadata(_init, VoiceRoutingStatusService);
|
|
3179
|
+
let _VoiceRoutingStatusService = VoiceRoutingStatusService;
|
|
3180
|
+
// src/angular/voice-trace-timeline.service.ts
|
|
3181
|
+
import { computed as computed14, Injectable as Injectable15, signal as signal15 } from "@angular/core";
|
|
3182
|
+
|
|
3183
|
+
// src/client/traceTimeline.ts
|
|
3184
|
+
var fetchVoiceTraceTimeline = async (path = "/api/voice-traces", options = {}) => {
|
|
3185
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3186
|
+
const response = await fetchImpl(path);
|
|
3187
|
+
if (!response.ok) {
|
|
3188
|
+
throw new Error(`Voice trace timeline failed: HTTP ${response.status}`);
|
|
3189
|
+
}
|
|
3190
|
+
return await response.json();
|
|
3191
|
+
};
|
|
3192
|
+
var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) => {
|
|
3193
|
+
const listeners = new Set;
|
|
3194
|
+
let closed = false;
|
|
3195
|
+
let timer;
|
|
3196
|
+
let snapshot = {
|
|
3197
|
+
error: null,
|
|
3198
|
+
isLoading: false,
|
|
3199
|
+
report: null
|
|
3200
|
+
};
|
|
3201
|
+
const emit = () => {
|
|
3202
|
+
for (const listener of listeners) {
|
|
3203
|
+
listener();
|
|
3204
|
+
}
|
|
3205
|
+
};
|
|
3206
|
+
const refresh = async () => {
|
|
3207
|
+
if (closed) {
|
|
3208
|
+
return snapshot.report;
|
|
3209
|
+
}
|
|
3210
|
+
snapshot = {
|
|
3211
|
+
...snapshot,
|
|
3212
|
+
error: null,
|
|
3213
|
+
isLoading: true
|
|
3214
|
+
};
|
|
3215
|
+
emit();
|
|
3216
|
+
try {
|
|
3217
|
+
const report = await fetchVoiceTraceTimeline(path, options);
|
|
3218
|
+
snapshot = {
|
|
3219
|
+
error: null,
|
|
3220
|
+
isLoading: false,
|
|
3221
|
+
report,
|
|
3222
|
+
updatedAt: Date.now()
|
|
3223
|
+
};
|
|
3224
|
+
emit();
|
|
3225
|
+
return report;
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
snapshot = {
|
|
3228
|
+
...snapshot,
|
|
3229
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3230
|
+
isLoading: false
|
|
3231
|
+
};
|
|
3232
|
+
emit();
|
|
3233
|
+
throw error;
|
|
3234
|
+
}
|
|
3235
|
+
};
|
|
3236
|
+
const close = () => {
|
|
3237
|
+
closed = true;
|
|
3238
|
+
if (timer) {
|
|
3239
|
+
clearInterval(timer);
|
|
3240
|
+
timer = undefined;
|
|
3241
|
+
}
|
|
3242
|
+
listeners.clear();
|
|
3243
|
+
};
|
|
3244
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3245
|
+
timer = setInterval(() => {
|
|
3246
|
+
refresh().catch(() => {});
|
|
3247
|
+
}, options.intervalMs);
|
|
3248
|
+
}
|
|
3249
|
+
return {
|
|
3250
|
+
close,
|
|
3251
|
+
getServerSnapshot: () => snapshot,
|
|
3252
|
+
getSnapshot: () => snapshot,
|
|
3253
|
+
refresh,
|
|
3254
|
+
subscribe: (listener) => {
|
|
3255
|
+
listeners.add(listener);
|
|
3256
|
+
return () => {
|
|
3257
|
+
listeners.delete(listener);
|
|
3258
|
+
};
|
|
3259
|
+
}
|
|
3260
|
+
};
|
|
3261
|
+
};
|
|
3262
|
+
|
|
3263
|
+
// src/angular/voice-trace-timeline.service.ts
|
|
3264
|
+
var _dec = [
|
|
3265
|
+
Injectable15({ providedIn: "root" })
|
|
3266
|
+
];
|
|
3267
|
+
var _init = __decoratorStart(undefined);
|
|
3268
|
+
|
|
3269
|
+
class VoiceTraceTimelineService {
|
|
3270
|
+
connect(path = "/api/voice-traces", options = {}) {
|
|
3271
|
+
const store = createVoiceTraceTimelineStore(path, options);
|
|
3272
|
+
const errorSignal = signal15(null);
|
|
3273
|
+
const isLoadingSignal = signal15(false);
|
|
3274
|
+
const reportSignal = signal15(null);
|
|
3275
|
+
const updatedAtSignal = signal15(undefined);
|
|
3276
|
+
const sync = () => {
|
|
3277
|
+
const snapshot = store.getSnapshot();
|
|
3278
|
+
errorSignal.set(snapshot.error);
|
|
3279
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3280
|
+
reportSignal.set(snapshot.report);
|
|
3281
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3282
|
+
};
|
|
3283
|
+
const unsubscribe = store.subscribe(sync);
|
|
3284
|
+
sync();
|
|
3285
|
+
store.refresh().catch(() => {});
|
|
3286
|
+
return {
|
|
3287
|
+
close: () => {
|
|
3288
|
+
unsubscribe();
|
|
3289
|
+
store.close();
|
|
3290
|
+
},
|
|
3291
|
+
error: computed14(() => errorSignal()),
|
|
3292
|
+
isLoading: computed14(() => isLoadingSignal()),
|
|
3293
|
+
refresh: store.refresh,
|
|
3294
|
+
report: computed14(() => reportSignal()),
|
|
3295
|
+
updatedAt: computed14(() => updatedAtSignal())
|
|
3296
|
+
};
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
VoiceTraceTimelineService = __decorateElement(_init, 0, "VoiceTraceTimelineService", _dec, VoiceTraceTimelineService);
|
|
3300
|
+
__runInitializers(_init, 1, VoiceTraceTimelineService);
|
|
3301
|
+
__decoratorMetadata(_init, VoiceTraceTimelineService);
|
|
3302
|
+
let _VoiceTraceTimelineService = VoiceTraceTimelineService;
|
|
3303
|
+
// src/angular/voice-agent-squad-status.service.ts
|
|
3304
|
+
import { computed as computed15, Injectable as Injectable16, signal as signal16 } from "@angular/core";
|
|
3305
|
+
|
|
3306
|
+
// src/client/agentSquadStatus.ts
|
|
3307
|
+
var getString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
3308
|
+
var getPayloadString = (event, key) => getString(event.payload?.[key]);
|
|
3309
|
+
var eventStatus = (event) => {
|
|
3310
|
+
const status = getPayloadString(event, "status");
|
|
3311
|
+
if (status === "blocked")
|
|
3312
|
+
return "blocked";
|
|
3313
|
+
if (status === "unknown-target")
|
|
3314
|
+
return "unknown-target";
|
|
3315
|
+
if (status === "allowed")
|
|
3316
|
+
return "handoff";
|
|
3317
|
+
return event.type === "agent.result" ? "active" : "handoff";
|
|
3318
|
+
};
|
|
3319
|
+
var deriveSessionSpecialist = (session) => {
|
|
3320
|
+
const events = [...session.events].sort((left, right) => left.at - right.at);
|
|
3321
|
+
const agentEvents = events.filter((event) => event.type === "agent.handoff" || event.type === "agent.context" || event.type === "agent.result" || event.type === "agent.model");
|
|
3322
|
+
const latest = agentEvents.at(-1);
|
|
3323
|
+
if (!latest) {
|
|
3324
|
+
return {
|
|
3325
|
+
lastEventAt: session.lastEventAt,
|
|
3326
|
+
sessionId: session.sessionId,
|
|
3327
|
+
status: "idle"
|
|
3328
|
+
};
|
|
840
3329
|
}
|
|
3330
|
+
const handoffEvents = events.filter((event) => event.type === "agent.handoff");
|
|
3331
|
+
const lastHandoff = handoffEvents.at(-1);
|
|
3332
|
+
const latestAgentId = getPayloadString(latest, "agentId");
|
|
3333
|
+
const handoffStatus = lastHandoff ? eventStatus(lastHandoff) : undefined;
|
|
3334
|
+
const currentTarget = handoffStatus === "blocked" || handoffStatus === "unknown-target" ? getPayloadString(lastHandoff, "fromAgentId") ?? latestAgentId : getPayloadString(lastHandoff ?? latest, "targetAgentId") ?? latestAgentId;
|
|
3335
|
+
return {
|
|
3336
|
+
fromAgentId: getPayloadString(lastHandoff ?? latest, "fromAgentId"),
|
|
3337
|
+
lastEventAt: latest.at,
|
|
3338
|
+
reason: getPayloadString(lastHandoff ?? latest, "reason") ?? getPayloadString(latest, "handoffTarget"),
|
|
3339
|
+
sessionId: session.sessionId,
|
|
3340
|
+
status: lastHandoff ? eventStatus(lastHandoff) : "active",
|
|
3341
|
+
summary: getPayloadString(lastHandoff ?? latest, "summary"),
|
|
3342
|
+
targetAgentId: currentTarget,
|
|
3343
|
+
turnId: latest.turnId
|
|
3344
|
+
};
|
|
841
3345
|
};
|
|
842
|
-
var
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
const profile = config?.profile ?? DEFAULT_TURN_PROFILE;
|
|
846
|
-
const qualityProfile = config?.qualityProfile ?? DEFAULT_QUALITY_PROFILE;
|
|
847
|
-
const preset = TURN_PROFILE_DEFAULTS[profile];
|
|
848
|
-
const quality = QUALITY_PROFILE_DEFAULTS[qualityProfile];
|
|
3346
|
+
var buildVoiceAgentSquadStatusReport = (timeline, options = {}) => {
|
|
3347
|
+
const sessions = (timeline?.sessions ?? []).filter((session) => !options.sessionId || session.sessionId === options.sessionId).map(deriveSessionSpecialist).sort((left, right) => (right.lastEventAt ?? 0) - (left.lastEventAt ?? 0));
|
|
3348
|
+
const active = sessions.filter((session) => session.status !== "idle");
|
|
849
3349
|
return {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
3350
|
+
active,
|
|
3351
|
+
checkedAt: timeline?.checkedAt,
|
|
3352
|
+
current: active[0] ?? sessions[0],
|
|
3353
|
+
sessionCount: sessions.length,
|
|
3354
|
+
sessions
|
|
3355
|
+
};
|
|
3356
|
+
};
|
|
3357
|
+
var createVoiceAgentSquadStatusStore = (path = "/api/voice-traces", options = {}) => {
|
|
3358
|
+
const timelineStore = createVoiceTraceTimelineStore(path, options);
|
|
3359
|
+
const getReport = () => buildVoiceAgentSquadStatusReport(timelineStore.getSnapshot().report, {
|
|
3360
|
+
sessionId: options.sessionId
|
|
3361
|
+
});
|
|
3362
|
+
const getSnapshot = () => {
|
|
3363
|
+
const snapshot = timelineStore.getSnapshot();
|
|
3364
|
+
return {
|
|
3365
|
+
error: snapshot.error,
|
|
3366
|
+
isLoading: snapshot.isLoading,
|
|
3367
|
+
report: getReport(),
|
|
3368
|
+
updatedAt: snapshot.updatedAt
|
|
3369
|
+
};
|
|
3370
|
+
};
|
|
3371
|
+
return {
|
|
3372
|
+
close: timelineStore.close,
|
|
3373
|
+
getServerSnapshot: getSnapshot,
|
|
3374
|
+
getSnapshot,
|
|
3375
|
+
refresh: timelineStore.refresh,
|
|
3376
|
+
subscribe: timelineStore.subscribe
|
|
855
3377
|
};
|
|
856
3378
|
};
|
|
857
3379
|
|
|
858
|
-
// src/
|
|
859
|
-
var
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
capture: {
|
|
931
|
-
channelCount: 1,
|
|
932
|
-
sampleRateHz: 16000
|
|
933
|
-
},
|
|
934
|
-
connection: {
|
|
935
|
-
maxReconnectAttempts: 12,
|
|
936
|
-
pingInterval: 30000,
|
|
937
|
-
reconnect: true
|
|
938
|
-
},
|
|
939
|
-
sttLifecycle: "turn-scoped",
|
|
940
|
-
turnDetection: {
|
|
941
|
-
qualityProfile: "accent-heavy",
|
|
942
|
-
profile: "long-form"
|
|
943
|
-
}
|
|
944
|
-
},
|
|
945
|
-
"noisy-room": {
|
|
946
|
-
audioConditioning: {
|
|
947
|
-
enabled: true,
|
|
948
|
-
maxGain: 3,
|
|
949
|
-
noiseGateAttenuation: 0.12,
|
|
950
|
-
noiseGateThreshold: 0.006,
|
|
951
|
-
targetLevel: 0.085
|
|
952
|
-
},
|
|
953
|
-
capture: {
|
|
954
|
-
channelCount: 1,
|
|
955
|
-
sampleRateHz: 16000
|
|
956
|
-
},
|
|
957
|
-
connection: {
|
|
958
|
-
maxReconnectAttempts: 14,
|
|
959
|
-
pingInterval: 45000,
|
|
960
|
-
reconnect: true
|
|
961
|
-
},
|
|
962
|
-
sttLifecycle: "continuous",
|
|
963
|
-
turnDetection: {
|
|
964
|
-
qualityProfile: "noisy-room",
|
|
965
|
-
profile: "long-form",
|
|
966
|
-
silenceMs: 2100,
|
|
967
|
-
speechThreshold: 0.02,
|
|
968
|
-
transcriptStabilityMs: 1650
|
|
969
|
-
}
|
|
970
|
-
},
|
|
971
|
-
"pstn-balanced": {
|
|
972
|
-
audioConditioning: {
|
|
973
|
-
enabled: true,
|
|
974
|
-
maxGain: 2.8,
|
|
975
|
-
noiseGateAttenuation: 0.07,
|
|
976
|
-
noiseGateThreshold: 0.005,
|
|
977
|
-
targetLevel: 0.08
|
|
978
|
-
},
|
|
979
|
-
capture: {
|
|
980
|
-
channelCount: 1,
|
|
981
|
-
sampleRateHz: 16000
|
|
982
|
-
},
|
|
983
|
-
connection: {
|
|
984
|
-
maxReconnectAttempts: 14,
|
|
985
|
-
pingInterval: 45000,
|
|
986
|
-
reconnect: true
|
|
987
|
-
},
|
|
988
|
-
sttLifecycle: "continuous",
|
|
989
|
-
turnDetection: {
|
|
990
|
-
qualityProfile: "noisy-room",
|
|
991
|
-
profile: "long-form",
|
|
992
|
-
silenceMs: 660,
|
|
993
|
-
speechThreshold: 0.012,
|
|
994
|
-
transcriptStabilityMs: 300
|
|
3380
|
+
// src/angular/voice-agent-squad-status.service.ts
|
|
3381
|
+
var _dec = [
|
|
3382
|
+
Injectable16({ providedIn: "root" })
|
|
3383
|
+
];
|
|
3384
|
+
var _init = __decoratorStart(undefined);
|
|
3385
|
+
|
|
3386
|
+
class VoiceAgentSquadStatusService {
|
|
3387
|
+
connect(path = "/api/voice-traces", options = {}) {
|
|
3388
|
+
const store = createVoiceAgentSquadStatusStore(path, options);
|
|
3389
|
+
const errorSignal = signal16(null);
|
|
3390
|
+
const isLoadingSignal = signal16(false);
|
|
3391
|
+
const reportSignal = signal16(undefined);
|
|
3392
|
+
const updatedAtSignal = signal16(undefined);
|
|
3393
|
+
const sync = () => {
|
|
3394
|
+
const snapshot = store.getSnapshot();
|
|
3395
|
+
errorSignal.set(snapshot.error);
|
|
3396
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3397
|
+
reportSignal.set(snapshot.report);
|
|
3398
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3399
|
+
};
|
|
3400
|
+
const unsubscribe = store.subscribe(sync);
|
|
3401
|
+
sync();
|
|
3402
|
+
store.refresh().catch(() => {});
|
|
3403
|
+
return {
|
|
3404
|
+
close: () => {
|
|
3405
|
+
unsubscribe();
|
|
3406
|
+
store.close();
|
|
3407
|
+
},
|
|
3408
|
+
current: computed15(() => reportSignal()?.current),
|
|
3409
|
+
error: computed15(() => errorSignal()),
|
|
3410
|
+
isLoading: computed15(() => isLoadingSignal()),
|
|
3411
|
+
refresh: store.refresh,
|
|
3412
|
+
report: computed15(() => reportSignal()),
|
|
3413
|
+
updatedAt: computed15(() => updatedAtSignal())
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
VoiceAgentSquadStatusService = __decorateElement(_init, 0, "VoiceAgentSquadStatusService", _dec, VoiceAgentSquadStatusService);
|
|
3418
|
+
__runInitializers(_init, 1, VoiceAgentSquadStatusService);
|
|
3419
|
+
__decoratorMetadata(_init, VoiceAgentSquadStatusService);
|
|
3420
|
+
let _VoiceAgentSquadStatusService = VoiceAgentSquadStatusService;
|
|
3421
|
+
// src/angular/voice-turn-latency.service.ts
|
|
3422
|
+
import { computed as computed16, Injectable as Injectable17, signal as signal17 } from "@angular/core";
|
|
3423
|
+
|
|
3424
|
+
// src/client/turnLatency.ts
|
|
3425
|
+
var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) => {
|
|
3426
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3427
|
+
const response = await fetchImpl(path);
|
|
3428
|
+
if (!response.ok) {
|
|
3429
|
+
throw new Error(`Voice turn latency failed: HTTP ${response.status}`);
|
|
3430
|
+
}
|
|
3431
|
+
return await response.json();
|
|
3432
|
+
};
|
|
3433
|
+
var runVoiceTurnLatencyProof = async (path, options = {}) => {
|
|
3434
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3435
|
+
const response = await fetchImpl(path, { method: "POST" });
|
|
3436
|
+
if (!response.ok) {
|
|
3437
|
+
throw new Error(`Voice turn latency proof failed: HTTP ${response.status}`);
|
|
3438
|
+
}
|
|
3439
|
+
return response.json();
|
|
3440
|
+
};
|
|
3441
|
+
var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) => {
|
|
3442
|
+
const listeners = new Set;
|
|
3443
|
+
let closed = false;
|
|
3444
|
+
let timer;
|
|
3445
|
+
let snapshot = {
|
|
3446
|
+
error: null,
|
|
3447
|
+
isLoading: false
|
|
3448
|
+
};
|
|
3449
|
+
const emit = () => {
|
|
3450
|
+
for (const listener of listeners) {
|
|
3451
|
+
listener();
|
|
995
3452
|
}
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
maxGain: 2.75,
|
|
1001
|
-
noiseGateAttenuation: 0.06,
|
|
1002
|
-
noiseGateThreshold: 0.005,
|
|
1003
|
-
targetLevel: 0.08
|
|
1004
|
-
},
|
|
1005
|
-
capture: {
|
|
1006
|
-
channelCount: 1,
|
|
1007
|
-
sampleRateHz: 16000
|
|
1008
|
-
},
|
|
1009
|
-
connection: {
|
|
1010
|
-
maxReconnectAttempts: 14,
|
|
1011
|
-
pingInterval: 45000,
|
|
1012
|
-
reconnect: true
|
|
1013
|
-
},
|
|
1014
|
-
sttLifecycle: "continuous",
|
|
1015
|
-
turnDetection: {
|
|
1016
|
-
qualityProfile: "noisy-room",
|
|
1017
|
-
profile: "long-form",
|
|
1018
|
-
silenceMs: 620,
|
|
1019
|
-
speechThreshold: 0.012,
|
|
1020
|
-
transcriptStabilityMs: 280
|
|
3453
|
+
};
|
|
3454
|
+
const refresh = async () => {
|
|
3455
|
+
if (closed) {
|
|
3456
|
+
return snapshot.report;
|
|
1021
3457
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
3458
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
3459
|
+
emit();
|
|
3460
|
+
try {
|
|
3461
|
+
const report = await fetchVoiceTurnLatency(path, options);
|
|
3462
|
+
snapshot = {
|
|
3463
|
+
error: null,
|
|
3464
|
+
isLoading: false,
|
|
3465
|
+
report,
|
|
3466
|
+
updatedAt: Date.now()
|
|
3467
|
+
};
|
|
3468
|
+
emit();
|
|
3469
|
+
return report;
|
|
3470
|
+
} catch (error) {
|
|
3471
|
+
snapshot = {
|
|
3472
|
+
...snapshot,
|
|
3473
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3474
|
+
isLoading: false
|
|
3475
|
+
};
|
|
3476
|
+
emit();
|
|
3477
|
+
throw error;
|
|
3478
|
+
}
|
|
3479
|
+
};
|
|
3480
|
+
const runProof = async () => {
|
|
3481
|
+
if (!options.proofPath) {
|
|
3482
|
+
throw new Error("Voice turn latency proof path is not configured.");
|
|
3483
|
+
}
|
|
3484
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
3485
|
+
emit();
|
|
3486
|
+
try {
|
|
3487
|
+
await runVoiceTurnLatencyProof(options.proofPath, options);
|
|
3488
|
+
return await refresh();
|
|
3489
|
+
} catch (error) {
|
|
3490
|
+
snapshot = {
|
|
3491
|
+
...snapshot,
|
|
3492
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3493
|
+
isLoading: false
|
|
3494
|
+
};
|
|
3495
|
+
emit();
|
|
3496
|
+
throw error;
|
|
1044
3497
|
}
|
|
3498
|
+
};
|
|
3499
|
+
const close = () => {
|
|
3500
|
+
closed = true;
|
|
3501
|
+
if (timer) {
|
|
3502
|
+
clearInterval(timer);
|
|
3503
|
+
timer = undefined;
|
|
3504
|
+
}
|
|
3505
|
+
listeners.clear();
|
|
3506
|
+
};
|
|
3507
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3508
|
+
timer = setInterval(() => {
|
|
3509
|
+
refresh().catch(() => {});
|
|
3510
|
+
}, options.intervalMs);
|
|
1045
3511
|
}
|
|
1046
|
-
};
|
|
1047
|
-
var resolveVoiceRuntimePreset = (name = "default") => {
|
|
1048
|
-
const preset = PRESET_INPUTS[name];
|
|
1049
3512
|
return {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
3513
|
+
close,
|
|
3514
|
+
getServerSnapshot: () => snapshot,
|
|
3515
|
+
getSnapshot: () => snapshot,
|
|
3516
|
+
refresh,
|
|
3517
|
+
runProof,
|
|
3518
|
+
subscribe: (listener) => {
|
|
3519
|
+
listeners.add(listener);
|
|
3520
|
+
return () => {
|
|
3521
|
+
listeners.delete(listener);
|
|
3522
|
+
};
|
|
3523
|
+
}
|
|
1061
3524
|
};
|
|
1062
3525
|
};
|
|
1063
3526
|
|
|
1064
|
-
// src/
|
|
1065
|
-
var
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
3527
|
+
// src/angular/voice-turn-latency.service.ts
|
|
3528
|
+
var _dec = [
|
|
3529
|
+
Injectable17({ providedIn: "root" })
|
|
3530
|
+
];
|
|
3531
|
+
var _init = __decoratorStart(undefined);
|
|
3532
|
+
|
|
3533
|
+
class VoiceTurnLatencyService {
|
|
3534
|
+
connect(path = "/api/turn-latency", options = {}) {
|
|
3535
|
+
const store = createVoiceTurnLatencyStore(path, options);
|
|
3536
|
+
const errorSignal = signal17(null);
|
|
3537
|
+
const isLoadingSignal = signal17(false);
|
|
3538
|
+
const reportSignal = signal17(undefined);
|
|
3539
|
+
const updatedAtSignal = signal17(undefined);
|
|
3540
|
+
const sync = () => {
|
|
3541
|
+
const snapshot = store.getSnapshot();
|
|
3542
|
+
errorSignal.set(snapshot.error);
|
|
3543
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3544
|
+
reportSignal.set(snapshot.report);
|
|
3545
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3546
|
+
};
|
|
3547
|
+
const unsubscribe = store.subscribe(sync);
|
|
3548
|
+
sync();
|
|
3549
|
+
store.refresh().catch(() => {});
|
|
3550
|
+
return {
|
|
3551
|
+
close: () => {
|
|
3552
|
+
unsubscribe();
|
|
3553
|
+
store.close();
|
|
3554
|
+
},
|
|
3555
|
+
error: computed16(() => errorSignal()),
|
|
3556
|
+
isLoading: computed16(() => isLoadingSignal()),
|
|
3557
|
+
refresh: store.refresh,
|
|
3558
|
+
report: computed16(() => reportSignal()),
|
|
3559
|
+
runProof: store.runProof,
|
|
3560
|
+
updatedAt: computed16(() => updatedAtSignal())
|
|
3561
|
+
};
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
3564
|
+
VoiceTurnLatencyService = __decorateElement(_init, 0, "VoiceTurnLatencyService", _dec, VoiceTurnLatencyService);
|
|
3565
|
+
__runInitializers(_init, 1, VoiceTurnLatencyService);
|
|
3566
|
+
__decoratorMetadata(_init, VoiceTurnLatencyService);
|
|
3567
|
+
let _VoiceTurnLatencyService = VoiceTurnLatencyService;
|
|
3568
|
+
// src/angular/voice-turn-quality.service.ts
|
|
3569
|
+
import { computed as computed17, Injectable as Injectable18, signal as signal18 } from "@angular/core";
|
|
3570
|
+
|
|
3571
|
+
// src/client/turnQuality.ts
|
|
3572
|
+
var fetchVoiceTurnQuality = async (path = "/api/turn-quality", options = {}) => {
|
|
3573
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3574
|
+
const response = await fetchImpl(path);
|
|
3575
|
+
if (!response.ok) {
|
|
3576
|
+
throw new Error(`Voice turn quality failed: HTTP ${response.status}`);
|
|
3577
|
+
}
|
|
3578
|
+
return await response.json();
|
|
3579
|
+
};
|
|
3580
|
+
var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) => {
|
|
3581
|
+
const listeners = new Set;
|
|
3582
|
+
let closed = false;
|
|
3583
|
+
let timer;
|
|
3584
|
+
let snapshot = {
|
|
3585
|
+
error: null,
|
|
3586
|
+
isLoading: false
|
|
3587
|
+
};
|
|
3588
|
+
const emit = () => {
|
|
3589
|
+
for (const listener of listeners) {
|
|
3590
|
+
listener();
|
|
1090
3591
|
}
|
|
1091
3592
|
};
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
sessionId: stream.sessionId,
|
|
1101
|
-
scenarioId: stream.scenarioId,
|
|
1102
|
-
status: stream.status,
|
|
1103
|
-
turns: [...stream.turns]
|
|
3593
|
+
const refresh = async () => {
|
|
3594
|
+
if (closed) {
|
|
3595
|
+
return snapshot.report;
|
|
3596
|
+
}
|
|
3597
|
+
snapshot = {
|
|
3598
|
+
...snapshot,
|
|
3599
|
+
error: null,
|
|
3600
|
+
isLoading: true
|
|
1104
3601
|
};
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
3602
|
+
emit();
|
|
3603
|
+
try {
|
|
3604
|
+
const report = await fetchVoiceTurnQuality(path, options);
|
|
3605
|
+
snapshot = {
|
|
3606
|
+
error: null,
|
|
3607
|
+
isLoading: false,
|
|
3608
|
+
report,
|
|
3609
|
+
updatedAt: Date.now()
|
|
1111
3610
|
};
|
|
3611
|
+
emit();
|
|
3612
|
+
return report;
|
|
3613
|
+
} catch (error) {
|
|
3614
|
+
snapshot = {
|
|
3615
|
+
...snapshot,
|
|
3616
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3617
|
+
isLoading: false
|
|
3618
|
+
};
|
|
3619
|
+
emit();
|
|
3620
|
+
throw error;
|
|
1112
3621
|
}
|
|
1113
|
-
notify();
|
|
1114
3622
|
};
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
3623
|
+
const close = () => {
|
|
3624
|
+
closed = true;
|
|
3625
|
+
if (timer) {
|
|
3626
|
+
clearInterval(timer);
|
|
3627
|
+
timer = undefined;
|
|
1120
3628
|
}
|
|
1121
|
-
|
|
1122
|
-
channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
|
|
1123
|
-
onLevel: options.capture?.onLevel,
|
|
1124
|
-
onAudio: (audio) => stream.sendAudio(audio),
|
|
1125
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1126
|
-
});
|
|
1127
|
-
return capture;
|
|
3629
|
+
listeners.clear();
|
|
1128
3630
|
};
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
3631
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3632
|
+
timer = setInterval(() => {
|
|
3633
|
+
refresh().catch(() => {});
|
|
3634
|
+
}, options.intervalMs);
|
|
3635
|
+
}
|
|
3636
|
+
return {
|
|
3637
|
+
close,
|
|
3638
|
+
getServerSnapshot: () => snapshot,
|
|
3639
|
+
getSnapshot: () => snapshot,
|
|
3640
|
+
refresh,
|
|
3641
|
+
subscribe: (listener) => {
|
|
3642
|
+
listeners.add(listener);
|
|
3643
|
+
return () => {
|
|
3644
|
+
listeners.delete(listener);
|
|
3645
|
+
};
|
|
3646
|
+
}
|
|
3647
|
+
};
|
|
3648
|
+
};
|
|
3649
|
+
|
|
3650
|
+
// src/angular/voice-turn-quality.service.ts
|
|
3651
|
+
var _dec = [
|
|
3652
|
+
Injectable18({ providedIn: "root" })
|
|
3653
|
+
];
|
|
3654
|
+
var _init = __decoratorStart(undefined);
|
|
3655
|
+
|
|
3656
|
+
class VoiceTurnQualityService {
|
|
3657
|
+
connect(path = "/api/turn-quality", options = {}) {
|
|
3658
|
+
const store = createVoiceTurnQualityStore(path, options);
|
|
3659
|
+
const errorSignal = signal18(null);
|
|
3660
|
+
const isLoadingSignal = signal18(false);
|
|
3661
|
+
const reportSignal = signal18(undefined);
|
|
3662
|
+
const updatedAtSignal = signal18(undefined);
|
|
3663
|
+
const sync = () => {
|
|
3664
|
+
const snapshot = store.getSnapshot();
|
|
3665
|
+
errorSignal.set(snapshot.error);
|
|
3666
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3667
|
+
reportSignal.set(snapshot.report);
|
|
3668
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
1135
3669
|
};
|
|
1136
|
-
|
|
3670
|
+
const unsubscribe = store.subscribe(sync);
|
|
3671
|
+
sync();
|
|
3672
|
+
store.refresh().catch(() => {});
|
|
3673
|
+
return {
|
|
3674
|
+
close: () => {
|
|
3675
|
+
unsubscribe();
|
|
3676
|
+
store.close();
|
|
3677
|
+
},
|
|
3678
|
+
error: computed17(() => errorSignal()),
|
|
3679
|
+
isLoading: computed17(() => isLoadingSignal()),
|
|
3680
|
+
refresh: store.refresh,
|
|
3681
|
+
report: computed17(() => reportSignal()),
|
|
3682
|
+
updatedAt: computed17(() => updatedAtSignal())
|
|
3683
|
+
};
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
VoiceTurnQualityService = __decorateElement(_init, 0, "VoiceTurnQualityService", _dec, VoiceTurnQualityService);
|
|
3687
|
+
__runInitializers(_init, 1, VoiceTurnQualityService);
|
|
3688
|
+
__decoratorMetadata(_init, VoiceTurnQualityService);
|
|
3689
|
+
let _VoiceTurnQualityService = VoiceTurnQualityService;
|
|
3690
|
+
// src/angular/voice-workflow-status.service.ts
|
|
3691
|
+
import { computed as computed18, Injectable as Injectable19, signal as signal19 } from "@angular/core";
|
|
3692
|
+
|
|
3693
|
+
// src/client/workflowStatus.ts
|
|
3694
|
+
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
3695
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3696
|
+
const response = await fetchImpl(path);
|
|
3697
|
+
if (!response.ok) {
|
|
3698
|
+
throw new Error(`Voice workflow status failed: HTTP ${response.status}`);
|
|
3699
|
+
}
|
|
3700
|
+
return await response.json();
|
|
3701
|
+
};
|
|
3702
|
+
var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options = {}) => {
|
|
3703
|
+
const listeners = new Set;
|
|
3704
|
+
let closed = false;
|
|
3705
|
+
let timer;
|
|
3706
|
+
let snapshot = {
|
|
3707
|
+
error: null,
|
|
3708
|
+
isLoading: false
|
|
1137
3709
|
};
|
|
1138
|
-
const
|
|
1139
|
-
|
|
1140
|
-
|
|
3710
|
+
const emit = () => {
|
|
3711
|
+
for (const listener of listeners) {
|
|
3712
|
+
listener();
|
|
3713
|
+
}
|
|
3714
|
+
};
|
|
3715
|
+
const refresh = async () => {
|
|
3716
|
+
if (closed) {
|
|
3717
|
+
return snapshot.report;
|
|
1141
3718
|
}
|
|
3719
|
+
snapshot = {
|
|
3720
|
+
...snapshot,
|
|
3721
|
+
error: null,
|
|
3722
|
+
isLoading: true
|
|
3723
|
+
};
|
|
3724
|
+
emit();
|
|
1142
3725
|
try {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
state = {
|
|
1150
|
-
...state,
|
|
1151
|
-
isRecording: true
|
|
3726
|
+
const report = await fetchVoiceWorkflowStatus(path, options);
|
|
3727
|
+
snapshot = {
|
|
3728
|
+
error: null,
|
|
3729
|
+
isLoading: false,
|
|
3730
|
+
report,
|
|
3731
|
+
updatedAt: Date.now()
|
|
1152
3732
|
};
|
|
1153
|
-
|
|
3733
|
+
emit();
|
|
3734
|
+
return report;
|
|
1154
3735
|
} catch (error) {
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
recordingError: error instanceof Error ? error.message : String(error)
|
|
3736
|
+
snapshot = {
|
|
3737
|
+
...snapshot,
|
|
3738
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3739
|
+
isLoading: false
|
|
1160
3740
|
};
|
|
1161
|
-
|
|
3741
|
+
emit();
|
|
1162
3742
|
throw error;
|
|
1163
3743
|
}
|
|
1164
3744
|
};
|
|
1165
3745
|
const close = () => {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
3746
|
+
closed = true;
|
|
3747
|
+
if (timer) {
|
|
3748
|
+
clearInterval(timer);
|
|
3749
|
+
timer = undefined;
|
|
3750
|
+
}
|
|
3751
|
+
listeners.clear();
|
|
1169
3752
|
};
|
|
3753
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
3754
|
+
timer = setInterval(() => {
|
|
3755
|
+
refresh().catch(() => {});
|
|
3756
|
+
}, options.intervalMs);
|
|
3757
|
+
}
|
|
1170
3758
|
return {
|
|
1171
|
-
bindHTMX(bindingOptions) {
|
|
1172
|
-
return bindVoiceHTMX(stream, bindingOptions);
|
|
1173
|
-
},
|
|
1174
3759
|
close,
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
getSnapshot: () => state,
|
|
1181
|
-
get isConnected() {
|
|
1182
|
-
return state.isConnected;
|
|
1183
|
-
},
|
|
1184
|
-
get isRecording() {
|
|
1185
|
-
return state.isRecording;
|
|
1186
|
-
},
|
|
1187
|
-
get partial() {
|
|
1188
|
-
return state.partial;
|
|
1189
|
-
},
|
|
1190
|
-
get recordingError() {
|
|
1191
|
-
return state.recordingError;
|
|
1192
|
-
},
|
|
1193
|
-
sendAudio: (audio) => stream.sendAudio(audio),
|
|
1194
|
-
get sessionId() {
|
|
1195
|
-
return state.sessionId;
|
|
1196
|
-
},
|
|
1197
|
-
get scenarioId() {
|
|
1198
|
-
return state.scenarioId;
|
|
1199
|
-
},
|
|
1200
|
-
startRecording,
|
|
1201
|
-
get status() {
|
|
1202
|
-
return state.status;
|
|
1203
|
-
},
|
|
1204
|
-
stopRecording,
|
|
1205
|
-
subscribe: (subscriber) => {
|
|
1206
|
-
subscribers.add(subscriber);
|
|
3760
|
+
getServerSnapshot: () => snapshot,
|
|
3761
|
+
getSnapshot: () => snapshot,
|
|
3762
|
+
refresh,
|
|
3763
|
+
subscribe: (listener) => {
|
|
3764
|
+
listeners.add(listener);
|
|
1207
3765
|
return () => {
|
|
1208
|
-
|
|
3766
|
+
listeners.delete(listener);
|
|
1209
3767
|
};
|
|
1210
|
-
},
|
|
1211
|
-
toggleRecording: async () => {
|
|
1212
|
-
if (state.isRecording) {
|
|
1213
|
-
stopRecording();
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
await startRecording();
|
|
1217
|
-
},
|
|
1218
|
-
get turns() {
|
|
1219
|
-
return state.turns;
|
|
1220
|
-
},
|
|
1221
|
-
get assistantTexts() {
|
|
1222
|
-
return state.assistantTexts;
|
|
1223
|
-
},
|
|
1224
|
-
get assistantAudio() {
|
|
1225
|
-
return state.assistantAudio;
|
|
1226
3768
|
}
|
|
1227
3769
|
};
|
|
1228
3770
|
};
|
|
1229
3771
|
|
|
1230
|
-
// src/angular/voice-
|
|
3772
|
+
// src/angular/voice-workflow-status.service.ts
|
|
1231
3773
|
var _dec = [
|
|
1232
|
-
|
|
3774
|
+
Injectable19({ providedIn: "root" })
|
|
1233
3775
|
];
|
|
1234
3776
|
var _init = __decoratorStart(undefined);
|
|
1235
3777
|
|
|
1236
|
-
class
|
|
1237
|
-
connect(path, options = {}) {
|
|
1238
|
-
const
|
|
1239
|
-
const
|
|
1240
|
-
const
|
|
1241
|
-
const
|
|
1242
|
-
const
|
|
1243
|
-
const isRecordingSignal = signal2(false);
|
|
1244
|
-
const partialSignal = signal2("");
|
|
1245
|
-
const recordingErrorSignal = signal2(null);
|
|
1246
|
-
const sessionIdSignal = signal2(controller.sessionId);
|
|
1247
|
-
const statusSignal = signal2(controller.status);
|
|
1248
|
-
const turnsSignal = signal2([]);
|
|
3778
|
+
class VoiceWorkflowStatusService {
|
|
3779
|
+
connect(path = "/evals/scenarios/json", options = {}) {
|
|
3780
|
+
const store = createVoiceWorkflowStatusStore(path, options);
|
|
3781
|
+
const errorSignal = signal19(null);
|
|
3782
|
+
const isLoadingSignal = signal19(false);
|
|
3783
|
+
const reportSignal = signal19(undefined);
|
|
3784
|
+
const updatedAtSignal = signal19(undefined);
|
|
1249
3785
|
const sync = () => {
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
partialSignal.set(controller.partial);
|
|
1256
|
-
recordingErrorSignal.set(controller.recordingError);
|
|
1257
|
-
sessionIdSignal.set(controller.sessionId);
|
|
1258
|
-
statusSignal.set(controller.status);
|
|
1259
|
-
turnsSignal.set([...controller.turns]);
|
|
3786
|
+
const snapshot = store.getSnapshot();
|
|
3787
|
+
errorSignal.set(snapshot.error);
|
|
3788
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3789
|
+
reportSignal.set(snapshot.report);
|
|
3790
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
1260
3791
|
};
|
|
1261
|
-
const unsubscribe =
|
|
3792
|
+
const unsubscribe = store.subscribe(sync);
|
|
1262
3793
|
sync();
|
|
3794
|
+
if (typeof window !== "undefined") {
|
|
3795
|
+
store.refresh().catch(() => {});
|
|
3796
|
+
}
|
|
1263
3797
|
return {
|
|
1264
|
-
assistantAudio: computed2(() => assistantAudioSignal()),
|
|
1265
|
-
assistantTexts: computed2(() => assistantTextsSignal()),
|
|
1266
|
-
bindHTMX: controller.bindHTMX,
|
|
1267
3798
|
close: () => {
|
|
1268
3799
|
unsubscribe();
|
|
1269
|
-
|
|
3800
|
+
store.close();
|
|
1270
3801
|
},
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
recordingError: computed2(() => recordingErrorSignal()),
|
|
1277
|
-
sendAudio: (audio) => controller.sendAudio(audio),
|
|
1278
|
-
sessionId: computed2(() => sessionIdSignal()),
|
|
1279
|
-
startRecording: () => controller.startRecording(),
|
|
1280
|
-
status: computed2(() => statusSignal()),
|
|
1281
|
-
stopRecording: () => controller.stopRecording(),
|
|
1282
|
-
toggleRecording: () => controller.toggleRecording(),
|
|
1283
|
-
turns: computed2(() => turnsSignal())
|
|
3802
|
+
error: computed18(() => errorSignal()),
|
|
3803
|
+
isLoading: computed18(() => isLoadingSignal()),
|
|
3804
|
+
refresh: store.refresh,
|
|
3805
|
+
report: computed18(() => reportSignal()),
|
|
3806
|
+
updatedAt: computed18(() => updatedAtSignal())
|
|
1284
3807
|
};
|
|
1285
3808
|
}
|
|
1286
3809
|
}
|
|
1287
|
-
|
|
1288
|
-
__runInitializers(_init, 1,
|
|
1289
|
-
__decoratorMetadata(_init,
|
|
1290
|
-
let
|
|
3810
|
+
VoiceWorkflowStatusService = __decorateElement(_init, 0, "VoiceWorkflowStatusService", _dec, VoiceWorkflowStatusService);
|
|
3811
|
+
__runInitializers(_init, 1, VoiceWorkflowStatusService);
|
|
3812
|
+
__decoratorMetadata(_init, VoiceWorkflowStatusService);
|
|
3813
|
+
let _VoiceWorkflowStatusService = VoiceWorkflowStatusService;
|
|
1291
3814
|
export {
|
|
3815
|
+
VoiceWorkflowStatusService,
|
|
3816
|
+
VoiceTurnQualityService,
|
|
3817
|
+
VoiceTurnLatencyService,
|
|
3818
|
+
VoiceTraceTimelineService,
|
|
1292
3819
|
VoiceStreamService,
|
|
1293
|
-
|
|
3820
|
+
VoiceRoutingStatusService,
|
|
3821
|
+
VoiceReadinessFailuresService,
|
|
3822
|
+
VoiceProviderStatusService,
|
|
3823
|
+
VoiceProviderContractsService,
|
|
3824
|
+
VoiceProviderCapabilitiesService,
|
|
3825
|
+
VoiceProofTrendsService,
|
|
3826
|
+
VoicePlatformCoverageService,
|
|
3827
|
+
VoiceOpsStatusService,
|
|
3828
|
+
VoiceOpsActionCenterService,
|
|
3829
|
+
VoiceLiveOpsService,
|
|
3830
|
+
VoiceDeliveryRuntimeService,
|
|
3831
|
+
VoiceControllerService,
|
|
3832
|
+
VoiceCampaignDialerProofService,
|
|
3833
|
+
VoiceAgentSquadStatusService
|
|
1294
3834
|
};
|