@absolutejs/voice 0.0.22-beta.31 → 0.0.22-beta.310
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 +3250 -73
- package/dist/agent.d.ts +62 -0
- package/dist/agentSquadContract.d.ts +98 -0
- package/dist/angular/index.d.ts +16 -0
- package/dist/angular/index.js +3498 -1128
- 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-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 +1 -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/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 +83 -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/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 +703 -13
- package/dist/client/index.d.ts +70 -0
- package/dist/client/index.js +5257 -19
- 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/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/competitiveCoverage.d.ts +141 -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 +14 -2
- package/dist/guardrails.d.ts +128 -0
- package/dist/incidentBundle.d.ts +116 -0
- package/dist/index.d.ts +144 -13
- package/dist/index.js +28070 -5219
- package/dist/latencySlo.d.ts +56 -0
- package/dist/liveLatency.d.ts +78 -0
- package/dist/liveOps.d.ts +190 -0
- package/dist/mediaPipeline.d.ts +125 -0
- package/dist/modelAdapters.d.ts +60 -2
- package/dist/observabilityExport.d.ts +481 -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/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 +1 -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 +9 -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 +32 -0
- package/dist/react/index.js +5059 -31
- package/dist/react/useVoiceAgentSquadStatus.d.ts +8 -0
- package/dist/react/useVoiceCampaignDialerProof.d.ts +10 -0
- package/dist/react/useVoiceController.d.ts +1 -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/useVoiceReadinessFailures.d.ts +8 -0
- package/dist/react/useVoiceRoutingStatus.d.ts +8 -0
- package/dist/react/useVoiceStream.d.ts +1 -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/realtimeChannel.d.ts +136 -0
- package/dist/realtimeProviderContracts.d.ts +133 -0
- package/dist/reconnectContract.d.ts +88 -0
- package/dist/resilienceRoutes.d.ts +143 -0
- package/dist/sessionReplay.d.ts +12 -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 +4 -2
- 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 +17 -0
- package/dist/svelte/index.js +4924 -420
- 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 +1 -0
- package/dist/testing/index.js +1767 -44
- package/dist/testing/ioProviderSimulator.d.ts +41 -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 +97 -3
- 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 +30 -0
- package/dist/vue/index.js +4828 -56
- 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 +1 -1
- package/dist/vue/useVoiceReadinessFailures.d.ts +775 -0
- package/dist/vue/useVoiceRoutingStatus.d.ts +8 -0
- package/dist/vue/useVoiceStream.d.ts +2 -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,902 +69,2320 @@ 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 "call_lifecycle":
|
|
124
|
-
return {
|
|
125
|
-
event: message.event,
|
|
126
|
-
sessionId: message.sessionId,
|
|
127
|
-
type: "call_lifecycle"
|
|
128
|
-
};
|
|
129
|
-
case "error":
|
|
130
|
-
return {
|
|
131
|
-
message: normalizeErrorMessage(message.message),
|
|
132
|
-
type: "error"
|
|
133
|
-
};
|
|
134
|
-
case "final":
|
|
135
|
-
return {
|
|
136
|
-
transcript: message.transcript,
|
|
137
|
-
type: "final"
|
|
138
|
-
};
|
|
139
|
-
case "partial":
|
|
140
|
-
return {
|
|
141
|
-
transcript: message.transcript,
|
|
142
|
-
type: "partial"
|
|
143
|
-
};
|
|
144
|
-
case "session":
|
|
145
|
-
return {
|
|
146
|
-
sessionId: message.sessionId,
|
|
147
|
-
scenarioId: message.scenarioId,
|
|
148
|
-
status: message.status,
|
|
149
|
-
type: "session"
|
|
108
|
+
const report = await fetchVoiceOpsStatus(path, options);
|
|
109
|
+
snapshot = {
|
|
110
|
+
error: null,
|
|
111
|
+
isLoading: false,
|
|
112
|
+
report,
|
|
113
|
+
updatedAt: Date.now()
|
|
150
114
|
};
|
|
151
|
-
|
|
152
|
-
return
|
|
153
|
-
|
|
154
|
-
|
|
115
|
+
emit();
|
|
116
|
+
return report;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
snapshot = {
|
|
119
|
+
...snapshot,
|
|
120
|
+
error: error instanceof Error ? error.message : String(error),
|
|
121
|
+
isLoading: false
|
|
155
122
|
};
|
|
156
|
-
|
|
157
|
-
|
|
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);
|
|
158
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
|
+
};
|
|
159
152
|
};
|
|
160
153
|
|
|
161
|
-
// src/
|
|
162
|
-
var
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
var
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
switch (value.type) {
|
|
200
|
-
case "audio":
|
|
201
|
-
case "assistant":
|
|
202
|
-
case "call_lifecycle":
|
|
203
|
-
case "complete":
|
|
204
|
-
case "error":
|
|
205
|
-
case "final":
|
|
206
|
-
case "partial":
|
|
207
|
-
case "pong":
|
|
208
|
-
case "session":
|
|
209
|
-
case "turn":
|
|
210
|
-
return true;
|
|
211
|
-
default:
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
var parseServerMessage = (event) => {
|
|
216
|
-
if (typeof event.data !== "string") {
|
|
217
|
-
return null;
|
|
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
|
+
};
|
|
218
190
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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}`);
|
|
224
205
|
}
|
|
206
|
+
return await response.json();
|
|
225
207
|
};
|
|
226
|
-
var
|
|
227
|
-
if (typeof window === "undefined") {
|
|
228
|
-
return NOOP_CONNECTION;
|
|
229
|
-
}
|
|
208
|
+
var createVoicePlatformCoverageStore = (path = "/api/voice/platform-coverage", options = {}) => {
|
|
230
209
|
const listeners = new Set;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
pendingMessages: [],
|
|
237
|
-
scenarioId: options.scenarioId ?? null,
|
|
238
|
-
pingInterval: null,
|
|
239
|
-
reconnectAttempts: 0,
|
|
240
|
-
reconnectTimeout: null,
|
|
241
|
-
sessionId: options.sessionId ?? createSessionId(),
|
|
242
|
-
ws: null
|
|
210
|
+
let closed = false;
|
|
211
|
+
let timer;
|
|
212
|
+
let snapshot = {
|
|
213
|
+
error: null,
|
|
214
|
+
isLoading: false
|
|
243
215
|
};
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
state.pingInterval = null;
|
|
248
|
-
}
|
|
249
|
-
if (state.reconnectTimeout) {
|
|
250
|
-
clearTimeout(state.reconnectTimeout);
|
|
251
|
-
state.reconnectTimeout = null;
|
|
216
|
+
const emit = () => {
|
|
217
|
+
for (const listener of listeners) {
|
|
218
|
+
listener();
|
|
252
219
|
}
|
|
253
220
|
};
|
|
254
|
-
const
|
|
255
|
-
if (
|
|
256
|
-
return;
|
|
221
|
+
const refresh = async () => {
|
|
222
|
+
if (closed) {
|
|
223
|
+
return snapshot.report;
|
|
257
224
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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;
|
|
263
249
|
}
|
|
264
250
|
};
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}, RECONNECT_DELAY_MS);
|
|
251
|
+
const close = () => {
|
|
252
|
+
closed = true;
|
|
253
|
+
if (timer) {
|
|
254
|
+
clearInterval(timer);
|
|
255
|
+
timer = undefined;
|
|
256
|
+
}
|
|
257
|
+
listeners.clear();
|
|
273
258
|
};
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
259
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
260
|
+
timer = setInterval(() => {
|
|
261
|
+
refresh().catch(() => {});
|
|
262
|
+
}, options.intervalMs);
|
|
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
|
+
};
|
|
276
|
+
};
|
|
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);
|
|
303
297
|
};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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())
|
|
311
313
|
};
|
|
312
|
-
|
|
314
|
+
}
|
|
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}`);
|
|
329
|
+
}
|
|
330
|
+
return await response.json();
|
|
331
|
+
};
|
|
332
|
+
var createVoiceProofTrendsStore = (path = "/api/voice/proof-trends", options = {}) => {
|
|
333
|
+
const listeners = new Set;
|
|
334
|
+
let closed = false;
|
|
335
|
+
let timer;
|
|
336
|
+
let snapshot = {
|
|
337
|
+
error: null,
|
|
338
|
+
isLoading: false
|
|
313
339
|
};
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
return;
|
|
340
|
+
const emit = () => {
|
|
341
|
+
for (const listener of listeners) {
|
|
342
|
+
listener();
|
|
318
343
|
}
|
|
319
|
-
state.pendingMessages.push(value);
|
|
320
|
-
};
|
|
321
|
-
const send = (message) => {
|
|
322
|
-
sendSerialized(JSON.stringify(message));
|
|
323
344
|
};
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
326
|
-
|
|
345
|
+
const refresh = async () => {
|
|
346
|
+
if (closed) {
|
|
347
|
+
return snapshot.report;
|
|
327
348
|
}
|
|
328
|
-
|
|
329
|
-
|
|
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;
|
|
330
373
|
}
|
|
331
|
-
send({
|
|
332
|
-
type: "start",
|
|
333
|
-
sessionId: state.sessionId,
|
|
334
|
-
scenarioId: state.scenarioId ?? undefined
|
|
335
|
-
});
|
|
336
|
-
};
|
|
337
|
-
const sendAudio = (audio) => {
|
|
338
|
-
sendSerialized(audio);
|
|
339
|
-
};
|
|
340
|
-
const endTurn = () => {
|
|
341
|
-
send({ type: "end_turn" });
|
|
342
|
-
};
|
|
343
|
-
const callControl = (message) => {
|
|
344
|
-
send({
|
|
345
|
-
...message,
|
|
346
|
-
type: "call_control"
|
|
347
|
-
});
|
|
348
374
|
};
|
|
349
375
|
const close = () => {
|
|
350
|
-
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
|
|
376
|
+
closed = true;
|
|
377
|
+
if (timer) {
|
|
378
|
+
clearInterval(timer);
|
|
379
|
+
timer = undefined;
|
|
354
380
|
}
|
|
355
|
-
state.isConnected = false;
|
|
356
381
|
listeners.clear();
|
|
357
382
|
};
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
};
|
|
364
|
-
connect();
|
|
383
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
384
|
+
timer = setInterval(() => {
|
|
385
|
+
refresh().catch(() => {});
|
|
386
|
+
}, options.intervalMs);
|
|
387
|
+
}
|
|
365
388
|
return {
|
|
366
|
-
callControl,
|
|
367
389
|
close,
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
390
|
+
getServerSnapshot: () => snapshot,
|
|
391
|
+
getSnapshot: () => snapshot,
|
|
392
|
+
refresh,
|
|
393
|
+
subscribe: (listener) => {
|
|
394
|
+
listeners.add(listener);
|
|
395
|
+
return () => {
|
|
396
|
+
listeners.delete(listener);
|
|
397
|
+
};
|
|
398
|
+
}
|
|
376
399
|
};
|
|
377
400
|
};
|
|
378
401
|
|
|
379
|
-
// src/
|
|
380
|
-
var
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
assistantAudio: [
|
|
404
|
-
...state.assistantAudio,
|
|
405
|
-
{
|
|
406
|
-
chunk: action.chunk,
|
|
407
|
-
format: action.format,
|
|
408
|
-
receivedAt: action.receivedAt,
|
|
409
|
-
turnId: action.turnId
|
|
410
|
-
}
|
|
411
|
-
]
|
|
412
|
-
};
|
|
413
|
-
break;
|
|
414
|
-
case "assistant":
|
|
415
|
-
state = {
|
|
416
|
-
...state,
|
|
417
|
-
assistantTexts: [...state.assistantTexts, action.text]
|
|
418
|
-
};
|
|
419
|
-
break;
|
|
420
|
-
case "complete":
|
|
421
|
-
state = {
|
|
422
|
-
...state,
|
|
423
|
-
sessionId: action.sessionId,
|
|
424
|
-
status: "completed"
|
|
425
|
-
};
|
|
426
|
-
break;
|
|
427
|
-
case "call_lifecycle":
|
|
428
|
-
state = {
|
|
429
|
-
...state,
|
|
430
|
-
call: {
|
|
431
|
-
...state.call,
|
|
432
|
-
disposition: action.event.type === "end" ? action.event.disposition : state.call?.disposition,
|
|
433
|
-
endedAt: action.event.type === "end" ? action.event.at : state.call?.endedAt,
|
|
434
|
-
events: [...state.call?.events ?? [], action.event],
|
|
435
|
-
lastEventAt: action.event.at,
|
|
436
|
-
startedAt: state.call?.startedAt ?? action.event.at
|
|
437
|
-
},
|
|
438
|
-
sessionId: action.sessionId
|
|
439
|
-
};
|
|
440
|
-
break;
|
|
441
|
-
case "connected":
|
|
442
|
-
state = {
|
|
443
|
-
...state,
|
|
444
|
-
isConnected: true
|
|
445
|
-
};
|
|
446
|
-
break;
|
|
447
|
-
case "disconnected":
|
|
448
|
-
state = {
|
|
449
|
-
...state,
|
|
450
|
-
isConnected: false
|
|
451
|
-
};
|
|
452
|
-
break;
|
|
453
|
-
case "error":
|
|
454
|
-
state = {
|
|
455
|
-
...state,
|
|
456
|
-
error: action.message
|
|
457
|
-
};
|
|
458
|
-
break;
|
|
459
|
-
case "final":
|
|
460
|
-
state = {
|
|
461
|
-
...state,
|
|
462
|
-
partial: action.transcript.text,
|
|
463
|
-
turns: state.turns.map((turn) => turn)
|
|
464
|
-
};
|
|
465
|
-
break;
|
|
466
|
-
case "partial":
|
|
467
|
-
state = {
|
|
468
|
-
...state,
|
|
469
|
-
partial: action.transcript.text
|
|
470
|
-
};
|
|
471
|
-
break;
|
|
472
|
-
case "session":
|
|
473
|
-
state = {
|
|
474
|
-
...state,
|
|
475
|
-
error: null,
|
|
476
|
-
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
477
|
-
isConnected: action.status === "active",
|
|
478
|
-
sessionId: action.sessionId,
|
|
479
|
-
status: action.status
|
|
480
|
-
};
|
|
481
|
-
break;
|
|
482
|
-
case "turn":
|
|
483
|
-
state = {
|
|
484
|
-
...state,
|
|
485
|
-
partial: "",
|
|
486
|
-
turns: [...state.turns, action.turn]
|
|
487
|
-
};
|
|
488
|
-
break;
|
|
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);
|
|
421
|
+
};
|
|
422
|
+
const unsubscribe = store.subscribe(sync);
|
|
423
|
+
sync();
|
|
424
|
+
if (typeof window !== "undefined") {
|
|
425
|
+
store.refresh().catch(() => {});
|
|
489
426
|
}
|
|
490
|
-
|
|
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())
|
|
437
|
+
};
|
|
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
|
|
491
463
|
};
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
getSnapshot: () => state,
|
|
496
|
-
subscribe: (subscriber) => {
|
|
497
|
-
subscribers.add(subscriber);
|
|
498
|
-
return () => {
|
|
499
|
-
subscribers.delete(subscriber);
|
|
500
|
-
};
|
|
464
|
+
const emit = () => {
|
|
465
|
+
for (const listener of listeners) {
|
|
466
|
+
listener();
|
|
501
467
|
}
|
|
502
468
|
};
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
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;
|
|
513
493
|
}
|
|
514
|
-
connection.start(input);
|
|
515
|
-
});
|
|
516
|
-
const notify = () => {
|
|
517
|
-
subscribers.forEach((subscriber) => subscriber());
|
|
518
494
|
};
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
if (
|
|
522
|
-
|
|
523
|
-
|
|
495
|
+
const close = () => {
|
|
496
|
+
closed = true;
|
|
497
|
+
if (timer) {
|
|
498
|
+
clearInterval(timer);
|
|
499
|
+
timer = undefined;
|
|
524
500
|
}
|
|
525
|
-
|
|
501
|
+
listeners.clear();
|
|
502
|
+
};
|
|
503
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
504
|
+
timer = setInterval(() => {
|
|
505
|
+
refresh().catch(() => {});
|
|
506
|
+
}, options.intervalMs);
|
|
507
|
+
}
|
|
526
508
|
return {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
store.dispatch({ type: "disconnected" });
|
|
534
|
-
notify();
|
|
535
|
-
},
|
|
536
|
-
endTurn() {
|
|
537
|
-
connection.endTurn();
|
|
538
|
-
},
|
|
539
|
-
get error() {
|
|
540
|
-
return store.getSnapshot().error;
|
|
541
|
-
},
|
|
542
|
-
getServerSnapshot() {
|
|
543
|
-
return store.getServerSnapshot();
|
|
544
|
-
},
|
|
545
|
-
getSnapshot() {
|
|
546
|
-
return store.getSnapshot();
|
|
547
|
-
},
|
|
548
|
-
get isConnected() {
|
|
549
|
-
return store.getSnapshot().isConnected;
|
|
550
|
-
},
|
|
551
|
-
get scenarioId() {
|
|
552
|
-
return store.getSnapshot().scenarioId;
|
|
553
|
-
},
|
|
554
|
-
start,
|
|
555
|
-
get partial() {
|
|
556
|
-
return store.getSnapshot().partial;
|
|
557
|
-
},
|
|
558
|
-
get sessionId() {
|
|
559
|
-
return connection.getSessionId();
|
|
560
|
-
},
|
|
561
|
-
get status() {
|
|
562
|
-
return store.getSnapshot().status;
|
|
563
|
-
},
|
|
564
|
-
get turns() {
|
|
565
|
-
return store.getSnapshot().turns;
|
|
566
|
-
},
|
|
567
|
-
get assistantTexts() {
|
|
568
|
-
return store.getSnapshot().assistantTexts;
|
|
569
|
-
},
|
|
570
|
-
get assistantAudio() {
|
|
571
|
-
return store.getSnapshot().assistantAudio;
|
|
572
|
-
},
|
|
573
|
-
get call() {
|
|
574
|
-
return store.getSnapshot().call;
|
|
575
|
-
},
|
|
576
|
-
sendAudio(audio) {
|
|
577
|
-
connection.sendAudio(audio);
|
|
578
|
-
},
|
|
579
|
-
subscribe(subscriber) {
|
|
580
|
-
subscribers.add(subscriber);
|
|
509
|
+
close,
|
|
510
|
+
getServerSnapshot: () => snapshot,
|
|
511
|
+
getSnapshot: () => snapshot,
|
|
512
|
+
refresh,
|
|
513
|
+
subscribe: (listener) => {
|
|
514
|
+
listeners.add(listener);
|
|
581
515
|
return () => {
|
|
582
|
-
|
|
516
|
+
listeners.delete(listener);
|
|
583
517
|
};
|
|
584
518
|
}
|
|
585
519
|
};
|
|
586
520
|
};
|
|
587
521
|
|
|
588
|
-
// src/angular/voice-
|
|
522
|
+
// src/angular/voice-readiness-failures.service.ts
|
|
589
523
|
var _dec = [
|
|
590
|
-
|
|
524
|
+
Injectable4({ providedIn: "root" })
|
|
591
525
|
];
|
|
592
526
|
var _init = __decoratorStart(undefined);
|
|
593
527
|
|
|
594
|
-
class
|
|
595
|
-
connect(path, options = {}) {
|
|
596
|
-
const
|
|
597
|
-
const
|
|
598
|
-
const
|
|
599
|
-
const
|
|
600
|
-
const
|
|
601
|
-
const isConnectedSignal = signal(false);
|
|
602
|
-
const partialSignal = signal("");
|
|
603
|
-
const sessionIdSignal = signal(stream.sessionId);
|
|
604
|
-
const statusSignal = signal(stream.status);
|
|
605
|
-
const turnsSignal = signal([]);
|
|
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);
|
|
606
535
|
const sync = () => {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
partialSignal.set(stream.partial);
|
|
613
|
-
sessionIdSignal.set(stream.sessionId);
|
|
614
|
-
statusSignal.set(stream.status);
|
|
615
|
-
turnsSignal.set([...stream.turns]);
|
|
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);
|
|
616
541
|
};
|
|
617
|
-
const unsubscribe =
|
|
542
|
+
const unsubscribe = store.subscribe(sync);
|
|
618
543
|
sync();
|
|
544
|
+
if (typeof window !== "undefined") {
|
|
545
|
+
store.refresh().catch(() => {});
|
|
546
|
+
}
|
|
619
547
|
return {
|
|
620
|
-
assistantAudio: computed(() => assistantAudioSignal()),
|
|
621
|
-
assistantTexts: computed(() => assistantTextsSignal()),
|
|
622
|
-
call: computed(() => callSignal()),
|
|
623
|
-
callControl: (message) => stream.callControl(message),
|
|
624
548
|
close: () => {
|
|
625
549
|
unsubscribe();
|
|
626
|
-
|
|
550
|
+
store.close();
|
|
627
551
|
},
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
status: computed(() => statusSignal()),
|
|
635
|
-
turns: computed(() => turnsSignal())
|
|
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())
|
|
636
558
|
};
|
|
637
559
|
}
|
|
638
560
|
}
|
|
639
|
-
|
|
640
|
-
__runInitializers(_init, 1,
|
|
641
|
-
__decoratorMetadata(_init,
|
|
642
|
-
let
|
|
643
|
-
// src/angular/voice-
|
|
644
|
-
import { computed as
|
|
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";
|
|
645
567
|
|
|
646
|
-
// src/client/
|
|
647
|
-
var
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (typeof input !== "string") {
|
|
651
|
-
return input;
|
|
652
|
-
}
|
|
653
|
-
return document.querySelector(input);
|
|
654
|
-
};
|
|
655
|
-
var buildRoute = (element, route, queryParam, sessionId) => {
|
|
656
|
-
const baseRoute = route ?? element.getAttribute("hx-get") ?? "";
|
|
657
|
-
if (!baseRoute) {
|
|
658
|
-
return "";
|
|
568
|
+
// src/client/opsActionCenter.ts
|
|
569
|
+
var recordVoiceOpsActionResult = async (result, options = {}) => {
|
|
570
|
+
if (options.auditPath === false) {
|
|
571
|
+
return;
|
|
659
572
|
}
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
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}`);
|
|
665
584
|
}
|
|
666
|
-
return `${url.pathname}${url.search}${url.hash}`;
|
|
667
585
|
};
|
|
668
|
-
var
|
|
669
|
-
|
|
670
|
-
|
|
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"
|
|
596
|
+
});
|
|
671
597
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
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
|
+
});
|
|
675
612
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
+
});
|
|
683
638
|
}
|
|
684
|
-
htmxWindow.htmx?.process?.(element);
|
|
685
|
-
htmxWindow.htmx?.trigger?.(element, eventName);
|
|
686
|
-
};
|
|
687
|
-
const unsubscribe = stream.subscribe(sync);
|
|
688
|
-
sync();
|
|
689
|
-
return () => {
|
|
690
|
-
unsubscribe();
|
|
691
|
-
};
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
// src/client/microphone.ts
|
|
695
|
-
var clampSample = (value) => Math.max(-1, Math.min(1, value));
|
|
696
|
-
var floatTo16BitPCM = (input) => {
|
|
697
|
-
const output = new Int16Array(input.length);
|
|
698
|
-
for (let index = 0;index < input.length; index += 1) {
|
|
699
|
-
const sample = clampSample(input[index] ?? 0);
|
|
700
|
-
output[index] = sample < 0 ? sample * 32768 : sample * 32767;
|
|
701
639
|
}
|
|
702
|
-
return
|
|
640
|
+
return actions;
|
|
703
641
|
};
|
|
704
|
-
var
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
}
|
|
709
|
-
const
|
|
710
|
-
if (
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
let sumSquares = 0;
|
|
714
|
-
for (const sample of samples) {
|
|
715
|
-
const normalized = sample / 32768;
|
|
716
|
-
sumSquares += normalized * normalized;
|
|
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);
|
|
717
651
|
}
|
|
718
|
-
return
|
|
652
|
+
return {
|
|
653
|
+
actionId: action.id,
|
|
654
|
+
body,
|
|
655
|
+
ok: response.ok,
|
|
656
|
+
ranAt: Date.now(),
|
|
657
|
+
status: response.status
|
|
658
|
+
};
|
|
719
659
|
};
|
|
720
|
-
var
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
let count = 0;
|
|
733
|
-
for (let index = offsetBuffer;index < nextOffsetBuffer && index < input.length; index += 1) {
|
|
734
|
-
accum += input[index] ?? 0;
|
|
735
|
-
count += 1;
|
|
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
|
|
668
|
+
};
|
|
669
|
+
const emit = () => {
|
|
670
|
+
for (const listener of listeners) {
|
|
671
|
+
listener();
|
|
736
672
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
let sourceNode = null;
|
|
746
|
-
let processorNode = null;
|
|
747
|
-
let mediaStream = null;
|
|
748
|
-
const start = async () => {
|
|
749
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
750
|
-
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
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;
|
|
751
681
|
}
|
|
752
|
-
const
|
|
753
|
-
if (!
|
|
754
|
-
throw new Error(
|
|
682
|
+
const action = snapshot.actions.find((item) => item.id === actionId);
|
|
683
|
+
if (!action) {
|
|
684
|
+
throw new Error(`Voice ops action "${actionId}" is not configured.`);
|
|
755
685
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
processorNode.onaudioprocess = (event) => {
|
|
765
|
-
const channel = event.inputBuffer.getChannelData(0);
|
|
766
|
-
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
767
|
-
const pcm = floatTo16BitPCM(downsampled);
|
|
768
|
-
options.onLevel?.(getPcmLevel(pcm));
|
|
769
|
-
options.onAudio(pcm);
|
|
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
|
|
770
694
|
};
|
|
771
|
-
|
|
772
|
-
|
|
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
|
+
}
|
|
773
730
|
};
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
731
|
+
const close = () => {
|
|
732
|
+
closed = true;
|
|
733
|
+
if (timer) {
|
|
734
|
+
clearInterval(timer);
|
|
735
|
+
timer = undefined;
|
|
736
|
+
}
|
|
737
|
+
listeners.clear();
|
|
738
|
+
};
|
|
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
|
+
}
|
|
784
756
|
};
|
|
785
|
-
return { start, stop };
|
|
786
757
|
};
|
|
787
758
|
|
|
788
|
-
// src/
|
|
789
|
-
var
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
var
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
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
|
|
795
|
+
};
|
|
796
796
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
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.");
|
|
802
809
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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);
|
|
807
822
|
}
|
|
808
|
-
return
|
|
823
|
+
return payload;
|
|
809
824
|
};
|
|
810
|
-
var
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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();
|
|
876
|
+
};
|
|
814
877
|
return {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
878
|
+
close,
|
|
879
|
+
getServerSnapshot: () => snapshot,
|
|
880
|
+
getSnapshot: () => snapshot,
|
|
881
|
+
run,
|
|
882
|
+
subscribe: (listener) => {
|
|
883
|
+
listeners.add(listener);
|
|
884
|
+
return () => {
|
|
885
|
+
listeners.delete(listener);
|
|
886
|
+
};
|
|
887
|
+
}
|
|
820
888
|
};
|
|
821
889
|
};
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
890
|
+
|
|
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
|
+
};
|
|
839
924
|
}
|
|
840
|
-
|
|
841
|
-
|
|
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";
|
|
842
932
|
|
|
843
|
-
// src/
|
|
844
|
-
var
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
silenceMs: 1400,
|
|
848
|
-
speechThreshold: 0.012,
|
|
849
|
-
transcriptStabilityMs: 1000
|
|
850
|
-
},
|
|
851
|
-
fast: {
|
|
852
|
-
qualityProfile: "general",
|
|
853
|
-
silenceMs: 700,
|
|
854
|
-
speechThreshold: 0.015,
|
|
855
|
-
transcriptStabilityMs: 450
|
|
856
|
-
},
|
|
857
|
-
"long-form": {
|
|
858
|
-
qualityProfile: "general",
|
|
859
|
-
silenceMs: 2200,
|
|
860
|
-
speechThreshold: 0.01,
|
|
861
|
-
transcriptStabilityMs: 1500
|
|
933
|
+
// src/client/deliveryRuntime.ts
|
|
934
|
+
var getDefaultActionPath = (path, action, options) => {
|
|
935
|
+
if (action === "tick") {
|
|
936
|
+
return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
|
|
862
937
|
}
|
|
938
|
+
return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
|
|
863
939
|
};
|
|
864
|
-
var
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
transcriptStabilityMs: 1200
|
|
870
|
-
},
|
|
871
|
-
"noisy-room": {
|
|
872
|
-
silenceMs: 2000,
|
|
873
|
-
speechThreshold: 0.02,
|
|
874
|
-
transcriptStabilityMs: 1600
|
|
875
|
-
},
|
|
876
|
-
"short-command": {
|
|
877
|
-
silenceMs: 500,
|
|
878
|
-
speechThreshold: 0.016,
|
|
879
|
-
transcriptStabilityMs: 420
|
|
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}`);
|
|
880
945
|
}
|
|
946
|
+
return await response.json();
|
|
881
947
|
};
|
|
882
|
-
var
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
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();
|
|
889
957
|
return {
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
958
|
+
action,
|
|
959
|
+
result: body.result,
|
|
960
|
+
summary: body.summary,
|
|
961
|
+
updatedAt: Date.now()
|
|
895
962
|
};
|
|
896
963
|
};
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
sampleRateHz: 16000
|
|
911
|
-
},
|
|
912
|
-
connection: {
|
|
913
|
-
maxReconnectAttempts: 10,
|
|
914
|
-
pingInterval: 30000,
|
|
915
|
-
reconnect: true
|
|
916
|
-
},
|
|
917
|
-
sttLifecycle: "continuous",
|
|
918
|
-
turnDetection: {
|
|
919
|
-
qualityProfile: "short-command",
|
|
920
|
-
profile: "balanced"
|
|
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();
|
|
921
977
|
}
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
sampleRateHz: 16000
|
|
927
|
-
},
|
|
928
|
-
connection: {
|
|
929
|
-
maxReconnectAttempts: 10,
|
|
930
|
-
pingInterval: 30000,
|
|
931
|
-
reconnect: true
|
|
932
|
-
},
|
|
933
|
-
sttLifecycle: "continuous",
|
|
934
|
-
turnDetection: {
|
|
935
|
-
qualityProfile: "general",
|
|
936
|
-
profile: "fast"
|
|
978
|
+
};
|
|
979
|
+
const refresh = async () => {
|
|
980
|
+
if (closed) {
|
|
981
|
+
return snapshot.report;
|
|
937
982
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
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
|
|
1005
|
+
};
|
|
1006
|
+
emit();
|
|
1007
|
+
throw error;
|
|
960
1008
|
}
|
|
961
|
-
}
|
|
962
|
-
|
|
1009
|
+
};
|
|
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;
|
|
1039
|
+
}
|
|
1040
|
+
};
|
|
1041
|
+
const close = () => {
|
|
1042
|
+
closed = true;
|
|
1043
|
+
if (timer) {
|
|
1044
|
+
clearInterval(timer);
|
|
1045
|
+
timer = undefined;
|
|
1046
|
+
}
|
|
1047
|
+
listeners.clear();
|
|
1048
|
+
};
|
|
1049
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
1050
|
+
timer = setInterval(() => {
|
|
1051
|
+
refresh().catch(() => {});
|
|
1052
|
+
}, options.intervalMs);
|
|
1053
|
+
}
|
|
1054
|
+
return {
|
|
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);
|
|
1063
|
+
return () => {
|
|
1064
|
+
listeners.delete(listener);
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
};
|
|
1069
|
+
|
|
1070
|
+
// src/angular/voice-delivery-runtime.service.ts
|
|
1071
|
+
var _dec = [
|
|
1072
|
+
Injectable7({ providedIn: "root" })
|
|
1073
|
+
];
|
|
1074
|
+
var _init = __decoratorStart(undefined);
|
|
1075
|
+
|
|
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);
|
|
1085
|
+
const sync = () => {
|
|
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);
|
|
1093
|
+
};
|
|
1094
|
+
const unsubscribe = store.subscribe(sync);
|
|
1095
|
+
sync();
|
|
1096
|
+
if (typeof window !== "undefined") {
|
|
1097
|
+
store.refresh().catch(() => {});
|
|
1098
|
+
}
|
|
1099
|
+
return {
|
|
1100
|
+
close: () => {
|
|
1101
|
+
unsubscribe();
|
|
1102
|
+
store.close();
|
|
1103
|
+
},
|
|
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())
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
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";
|
|
1122
|
+
|
|
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}`);
|
|
1129
|
+
}
|
|
1130
|
+
return await response.json();
|
|
1131
|
+
};
|
|
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}`);
|
|
1137
|
+
}
|
|
1138
|
+
return await response.json();
|
|
1139
|
+
};
|
|
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();
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
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
|
+
}
|
|
1179
|
+
};
|
|
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;
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
const close = () => {
|
|
1214
|
+
closed = true;
|
|
1215
|
+
if (timer) {
|
|
1216
|
+
clearInterval(timer);
|
|
1217
|
+
timer = undefined;
|
|
1218
|
+
}
|
|
1219
|
+
listeners.clear();
|
|
1220
|
+
};
|
|
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
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
};
|
|
1240
|
+
|
|
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
|
+
};
|
|
1279
|
+
}
|
|
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;
|
|
1292
|
+
}
|
|
1293
|
+
if (value instanceof Error && value.message.trim()) {
|
|
1294
|
+
return value.message;
|
|
1295
|
+
}
|
|
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 {}
|
|
1313
|
+
}
|
|
1314
|
+
return "Unexpected error";
|
|
1315
|
+
};
|
|
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;
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
|
|
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",
|
|
2202
|
+
silenceMs: 2200,
|
|
2203
|
+
speechThreshold: 0.01,
|
|
2204
|
+
transcriptStabilityMs: 1500
|
|
2205
|
+
}
|
|
2206
|
+
};
|
|
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": {
|
|
963
2381
|
audioConditioning: {
|
|
964
2382
|
enabled: true,
|
|
965
|
-
maxGain: 2.
|
|
966
|
-
noiseGateAttenuation: 0,
|
|
967
|
-
noiseGateThreshold: 0.
|
|
2383
|
+
maxGain: 2.75,
|
|
2384
|
+
noiseGateAttenuation: 0.06,
|
|
2385
|
+
noiseGateThreshold: 0.005,
|
|
968
2386
|
targetLevel: 0.08
|
|
969
2387
|
},
|
|
970
2388
|
capture: {
|
|
@@ -972,388 +2390,1322 @@ var PRESET_INPUTS = {
|
|
|
972
2390
|
sampleRateHz: 16000
|
|
973
2391
|
},
|
|
974
2392
|
connection: {
|
|
975
|
-
maxReconnectAttempts:
|
|
976
|
-
pingInterval:
|
|
2393
|
+
maxReconnectAttempts: 14,
|
|
2394
|
+
pingInterval: 45000,
|
|
977
2395
|
reconnect: true
|
|
978
2396
|
},
|
|
979
|
-
sttLifecycle: "
|
|
2397
|
+
sttLifecycle: "continuous",
|
|
980
2398
|
turnDetection: {
|
|
981
|
-
qualityProfile: "
|
|
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",
|
|
982
2426
|
profile: "long-form"
|
|
983
2427
|
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
},
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
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;
|
|
1009
2995
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
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;
|
|
1035
3234
|
}
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
noiseGateThreshold: 0.005,
|
|
1043
|
-
targetLevel: 0.08
|
|
1044
|
-
},
|
|
1045
|
-
capture: {
|
|
1046
|
-
channelCount: 1,
|
|
1047
|
-
sampleRateHz: 16000
|
|
1048
|
-
},
|
|
1049
|
-
connection: {
|
|
1050
|
-
maxReconnectAttempts: 14,
|
|
1051
|
-
pingInterval: 45000,
|
|
1052
|
-
reconnect: true
|
|
1053
|
-
},
|
|
1054
|
-
sttLifecycle: "continuous",
|
|
1055
|
-
turnDetection: {
|
|
1056
|
-
qualityProfile: "noisy-room",
|
|
1057
|
-
profile: "long-form",
|
|
1058
|
-
silenceMs: 620,
|
|
1059
|
-
speechThreshold: 0.012,
|
|
1060
|
-
transcriptStabilityMs: 280
|
|
3235
|
+
};
|
|
3236
|
+
const close = () => {
|
|
3237
|
+
closed = true;
|
|
3238
|
+
if (timer) {
|
|
3239
|
+
clearInterval(timer);
|
|
3240
|
+
timer = undefined;
|
|
1061
3241
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
},
|
|
1080
|
-
sttLifecycle: "continuous",
|
|
1081
|
-
turnDetection: {
|
|
1082
|
-
qualityProfile: "noisy-room",
|
|
1083
|
-
profile: "long-form"
|
|
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
|
+
};
|
|
1084
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
|
+
};
|
|
1085
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";
|
|
1086
3318
|
};
|
|
1087
|
-
var
|
|
1088
|
-
const
|
|
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
|
+
};
|
|
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;
|
|
1089
3335
|
return {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
name,
|
|
1099
|
-
sttLifecycle: preset.sttLifecycle ?? "continuous",
|
|
1100
|
-
turnDetection: resolveTurnDetectionConfig(preset.turnDetection)
|
|
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
|
|
1101
3344
|
};
|
|
1102
3345
|
};
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
});
|
|
1119
|
-
var createVoiceController = (path, options = {}) => {
|
|
1120
|
-
const preset = resolveVoiceRuntimePreset(options.preset);
|
|
1121
|
-
const stream = createVoiceStream(path, {
|
|
1122
|
-
...preset.connection,
|
|
1123
|
-
...options.connection
|
|
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");
|
|
3349
|
+
return {
|
|
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
|
|
1124
3361
|
});
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
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
|
+
};
|
|
1132
3370
|
};
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
3371
|
+
return {
|
|
3372
|
+
close: timelineStore.close,
|
|
3373
|
+
getServerSnapshot: getSnapshot,
|
|
3374
|
+
getSnapshot,
|
|
3375
|
+
refresh: timelineStore.refresh,
|
|
3376
|
+
subscribe: timelineStore.subscribe
|
|
3377
|
+
};
|
|
3378
|
+
};
|
|
3379
|
+
|
|
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);
|
|
1146
3399
|
};
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
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();
|
|
3452
|
+
}
|
|
3453
|
+
};
|
|
3454
|
+
const refresh = async () => {
|
|
3455
|
+
if (closed) {
|
|
3456
|
+
return snapshot.report;
|
|
3457
|
+
}
|
|
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
|
|
1153
3494
|
};
|
|
3495
|
+
emit();
|
|
3496
|
+
throw error;
|
|
3497
|
+
}
|
|
3498
|
+
};
|
|
3499
|
+
const close = () => {
|
|
3500
|
+
closed = true;
|
|
3501
|
+
if (timer) {
|
|
3502
|
+
clearInterval(timer);
|
|
3503
|
+
timer = undefined;
|
|
1154
3504
|
}
|
|
1155
|
-
|
|
3505
|
+
listeners.clear();
|
|
1156
3506
|
};
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
3507
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3508
|
+
timer = setInterval(() => {
|
|
3509
|
+
refresh().catch(() => {});
|
|
3510
|
+
}, options.intervalMs);
|
|
3511
|
+
}
|
|
3512
|
+
return {
|
|
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
|
+
};
|
|
1162
3523
|
}
|
|
1163
|
-
capture = createMicrophoneCapture({
|
|
1164
|
-
channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
|
|
1165
|
-
onLevel: options.capture?.onLevel,
|
|
1166
|
-
onAudio: (audio) => stream.sendAudio(audio),
|
|
1167
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1168
|
-
});
|
|
1169
|
-
return capture;
|
|
1170
3524
|
};
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
3525
|
+
};
|
|
3526
|
+
|
|
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);
|
|
1177
3546
|
};
|
|
1178
|
-
|
|
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
|
|
1179
3587
|
};
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
|
|
3588
|
+
const emit = () => {
|
|
3589
|
+
for (const listener of listeners) {
|
|
3590
|
+
listener();
|
|
3591
|
+
}
|
|
3592
|
+
};
|
|
3593
|
+
const refresh = async () => {
|
|
3594
|
+
if (closed) {
|
|
3595
|
+
return snapshot.report;
|
|
1183
3596
|
}
|
|
3597
|
+
snapshot = {
|
|
3598
|
+
...snapshot,
|
|
3599
|
+
error: null,
|
|
3600
|
+
isLoading: true
|
|
3601
|
+
};
|
|
3602
|
+
emit();
|
|
1184
3603
|
try {
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
state = {
|
|
1192
|
-
...state,
|
|
1193
|
-
isRecording: true
|
|
3604
|
+
const report = await fetchVoiceTurnQuality(path, options);
|
|
3605
|
+
snapshot = {
|
|
3606
|
+
error: null,
|
|
3607
|
+
isLoading: false,
|
|
3608
|
+
report,
|
|
3609
|
+
updatedAt: Date.now()
|
|
1194
3610
|
};
|
|
1195
|
-
|
|
3611
|
+
emit();
|
|
3612
|
+
return report;
|
|
1196
3613
|
} catch (error) {
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
recordingError: error instanceof Error ? error.message : String(error)
|
|
3614
|
+
snapshot = {
|
|
3615
|
+
...snapshot,
|
|
3616
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3617
|
+
isLoading: false
|
|
1202
3618
|
};
|
|
1203
|
-
|
|
3619
|
+
emit();
|
|
1204
3620
|
throw error;
|
|
1205
3621
|
}
|
|
1206
3622
|
};
|
|
1207
3623
|
const close = () => {
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
3624
|
+
closed = true;
|
|
3625
|
+
if (timer) {
|
|
3626
|
+
clearInterval(timer);
|
|
3627
|
+
timer = undefined;
|
|
3628
|
+
}
|
|
3629
|
+
listeners.clear();
|
|
1211
3630
|
};
|
|
3631
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3632
|
+
timer = setInterval(() => {
|
|
3633
|
+
refresh().catch(() => {});
|
|
3634
|
+
}, options.intervalMs);
|
|
3635
|
+
}
|
|
1212
3636
|
return {
|
|
1213
|
-
bindHTMX(bindingOptions) {
|
|
1214
|
-
return bindVoiceHTMX(stream, bindingOptions);
|
|
1215
|
-
},
|
|
1216
|
-
callControl: (message) => stream.callControl(message),
|
|
1217
3637
|
close,
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
getSnapshot: () => state,
|
|
1224
|
-
get isConnected() {
|
|
1225
|
-
return state.isConnected;
|
|
1226
|
-
},
|
|
1227
|
-
get isRecording() {
|
|
1228
|
-
return state.isRecording;
|
|
1229
|
-
},
|
|
1230
|
-
get partial() {
|
|
1231
|
-
return state.partial;
|
|
1232
|
-
},
|
|
1233
|
-
get recordingError() {
|
|
1234
|
-
return state.recordingError;
|
|
1235
|
-
},
|
|
1236
|
-
sendAudio: (audio) => stream.sendAudio(audio),
|
|
1237
|
-
get sessionId() {
|
|
1238
|
-
return state.sessionId;
|
|
1239
|
-
},
|
|
1240
|
-
get scenarioId() {
|
|
1241
|
-
return state.scenarioId;
|
|
1242
|
-
},
|
|
1243
|
-
startRecording,
|
|
1244
|
-
get status() {
|
|
1245
|
-
return state.status;
|
|
1246
|
-
},
|
|
1247
|
-
stopRecording,
|
|
1248
|
-
subscribe: (subscriber) => {
|
|
1249
|
-
subscribers.add(subscriber);
|
|
3638
|
+
getServerSnapshot: () => snapshot,
|
|
3639
|
+
getSnapshot: () => snapshot,
|
|
3640
|
+
refresh,
|
|
3641
|
+
subscribe: (listener) => {
|
|
3642
|
+
listeners.add(listener);
|
|
1250
3643
|
return () => {
|
|
1251
|
-
|
|
3644
|
+
listeners.delete(listener);
|
|
1252
3645
|
};
|
|
1253
|
-
},
|
|
1254
|
-
toggleRecording: async () => {
|
|
1255
|
-
if (state.isRecording) {
|
|
1256
|
-
stopRecording();
|
|
1257
|
-
return;
|
|
1258
|
-
}
|
|
1259
|
-
await startRecording();
|
|
1260
|
-
},
|
|
1261
|
-
get turns() {
|
|
1262
|
-
return state.turns;
|
|
1263
|
-
},
|
|
1264
|
-
get assistantTexts() {
|
|
1265
|
-
return state.assistantTexts;
|
|
1266
|
-
},
|
|
1267
|
-
get assistantAudio() {
|
|
1268
|
-
return state.assistantAudio;
|
|
1269
|
-
},
|
|
1270
|
-
get call() {
|
|
1271
|
-
return state.call;
|
|
1272
3646
|
}
|
|
1273
3647
|
};
|
|
1274
3648
|
};
|
|
1275
3649
|
|
|
1276
|
-
// src/angular/voice-
|
|
3650
|
+
// src/angular/voice-turn-quality.service.ts
|
|
1277
3651
|
var _dec = [
|
|
1278
|
-
|
|
3652
|
+
Injectable18({ providedIn: "root" })
|
|
1279
3653
|
];
|
|
1280
3654
|
var _init = __decoratorStart(undefined);
|
|
1281
3655
|
|
|
1282
|
-
class
|
|
1283
|
-
connect(path, options = {}) {
|
|
1284
|
-
const
|
|
1285
|
-
const
|
|
1286
|
-
const
|
|
1287
|
-
const
|
|
1288
|
-
const
|
|
1289
|
-
const isRecordingSignal = signal2(false);
|
|
1290
|
-
const partialSignal = signal2("");
|
|
1291
|
-
const recordingErrorSignal = signal2(null);
|
|
1292
|
-
const sessionIdSignal = signal2(controller.sessionId);
|
|
1293
|
-
const statusSignal = signal2(controller.status);
|
|
1294
|
-
const turnsSignal = signal2([]);
|
|
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);
|
|
1295
3663
|
const sync = () => {
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
partialSignal.set(controller.partial);
|
|
1302
|
-
recordingErrorSignal.set(controller.recordingError);
|
|
1303
|
-
sessionIdSignal.set(controller.sessionId);
|
|
1304
|
-
statusSignal.set(controller.status);
|
|
1305
|
-
turnsSignal.set([...controller.turns]);
|
|
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);
|
|
1306
3669
|
};
|
|
1307
|
-
const unsubscribe =
|
|
3670
|
+
const unsubscribe = store.subscribe(sync);
|
|
1308
3671
|
sync();
|
|
3672
|
+
store.refresh().catch(() => {});
|
|
1309
3673
|
return {
|
|
1310
|
-
assistantAudio: computed2(() => assistantAudioSignal()),
|
|
1311
|
-
assistantTexts: computed2(() => assistantTextsSignal()),
|
|
1312
|
-
bindHTMX: controller.bindHTMX,
|
|
1313
3674
|
close: () => {
|
|
1314
3675
|
unsubscribe();
|
|
1315
|
-
|
|
3676
|
+
store.close();
|
|
1316
3677
|
},
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
recordingError: computed2(() => recordingErrorSignal()),
|
|
1323
|
-
sendAudio: (audio) => controller.sendAudio(audio),
|
|
1324
|
-
sessionId: computed2(() => sessionIdSignal()),
|
|
1325
|
-
startRecording: () => controller.startRecording(),
|
|
1326
|
-
status: computed2(() => statusSignal()),
|
|
1327
|
-
stopRecording: () => controller.stopRecording(),
|
|
1328
|
-
toggleRecording: () => controller.toggleRecording(),
|
|
1329
|
-
turns: computed2(() => turnsSignal())
|
|
3678
|
+
error: computed17(() => errorSignal()),
|
|
3679
|
+
isLoading: computed17(() => isLoadingSignal()),
|
|
3680
|
+
refresh: store.refresh,
|
|
3681
|
+
report: computed17(() => reportSignal()),
|
|
3682
|
+
updatedAt: computed17(() => updatedAtSignal())
|
|
1330
3683
|
};
|
|
1331
3684
|
}
|
|
1332
3685
|
}
|
|
1333
|
-
|
|
1334
|
-
__runInitializers(_init, 1,
|
|
1335
|
-
__decoratorMetadata(_init,
|
|
1336
|
-
let
|
|
1337
|
-
// src/angular/voice-
|
|
1338
|
-
import { computed as
|
|
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";
|
|
1339
3692
|
|
|
1340
|
-
// src/client/
|
|
1341
|
-
var
|
|
3693
|
+
// src/client/workflowStatus.ts
|
|
3694
|
+
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
1342
3695
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1343
3696
|
const response = await fetchImpl(path);
|
|
1344
3697
|
if (!response.ok) {
|
|
1345
|
-
throw new Error(`Voice
|
|
3698
|
+
throw new Error(`Voice workflow status failed: HTTP ${response.status}`);
|
|
1346
3699
|
}
|
|
1347
3700
|
return await response.json();
|
|
1348
3701
|
};
|
|
1349
|
-
var
|
|
3702
|
+
var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options = {}) => {
|
|
1350
3703
|
const listeners = new Set;
|
|
1351
3704
|
let closed = false;
|
|
1352
3705
|
let timer;
|
|
1353
3706
|
let snapshot = {
|
|
1354
3707
|
error: null,
|
|
1355
|
-
isLoading: false
|
|
1356
|
-
providers: []
|
|
3708
|
+
isLoading: false
|
|
1357
3709
|
};
|
|
1358
3710
|
const emit = () => {
|
|
1359
3711
|
for (const listener of listeners) {
|
|
@@ -1362,7 +3714,7 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1362
3714
|
};
|
|
1363
3715
|
const refresh = async () => {
|
|
1364
3716
|
if (closed) {
|
|
1365
|
-
return snapshot.
|
|
3717
|
+
return snapshot.report;
|
|
1366
3718
|
}
|
|
1367
3719
|
snapshot = {
|
|
1368
3720
|
...snapshot,
|
|
@@ -1371,15 +3723,15 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1371
3723
|
};
|
|
1372
3724
|
emit();
|
|
1373
3725
|
try {
|
|
1374
|
-
const
|
|
3726
|
+
const report = await fetchVoiceWorkflowStatus(path, options);
|
|
1375
3727
|
snapshot = {
|
|
1376
3728
|
error: null,
|
|
1377
3729
|
isLoading: false,
|
|
1378
|
-
|
|
3730
|
+
report,
|
|
1379
3731
|
updatedAt: Date.now()
|
|
1380
3732
|
};
|
|
1381
3733
|
emit();
|
|
1382
|
-
return
|
|
3734
|
+
return report;
|
|
1383
3735
|
} catch (error) {
|
|
1384
3736
|
snapshot = {
|
|
1385
3737
|
...snapshot,
|
|
@@ -1398,7 +3750,7 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1398
3750
|
}
|
|
1399
3751
|
listeners.clear();
|
|
1400
3752
|
};
|
|
1401
|
-
if (options.intervalMs && options.intervalMs > 0) {
|
|
3753
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
1402
3754
|
timer = setInterval(() => {
|
|
1403
3755
|
refresh().catch(() => {});
|
|
1404
3756
|
}, options.intervalMs);
|
|
@@ -1417,48 +3769,66 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1417
3769
|
};
|
|
1418
3770
|
};
|
|
1419
3771
|
|
|
1420
|
-
// src/angular/voice-
|
|
3772
|
+
// src/angular/voice-workflow-status.service.ts
|
|
1421
3773
|
var _dec = [
|
|
1422
|
-
|
|
3774
|
+
Injectable19({ providedIn: "root" })
|
|
1423
3775
|
];
|
|
1424
3776
|
var _init = __decoratorStart(undefined);
|
|
1425
3777
|
|
|
1426
|
-
class
|
|
1427
|
-
connect(path = "/
|
|
1428
|
-
const store =
|
|
1429
|
-
const errorSignal =
|
|
1430
|
-
const isLoadingSignal =
|
|
1431
|
-
const
|
|
1432
|
-
const updatedAtSignal =
|
|
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);
|
|
1433
3785
|
const sync = () => {
|
|
1434
3786
|
const snapshot = store.getSnapshot();
|
|
1435
3787
|
errorSignal.set(snapshot.error);
|
|
1436
3788
|
isLoadingSignal.set(snapshot.isLoading);
|
|
1437
|
-
|
|
3789
|
+
reportSignal.set(snapshot.report);
|
|
1438
3790
|
updatedAtSignal.set(snapshot.updatedAt);
|
|
1439
3791
|
};
|
|
1440
3792
|
const unsubscribe = store.subscribe(sync);
|
|
1441
3793
|
sync();
|
|
1442
|
-
|
|
3794
|
+
if (typeof window !== "undefined") {
|
|
3795
|
+
store.refresh().catch(() => {});
|
|
3796
|
+
}
|
|
1443
3797
|
return {
|
|
1444
3798
|
close: () => {
|
|
1445
3799
|
unsubscribe();
|
|
1446
3800
|
store.close();
|
|
1447
3801
|
},
|
|
1448
|
-
error:
|
|
1449
|
-
isLoading:
|
|
1450
|
-
providers: computed3(() => providersSignal()),
|
|
3802
|
+
error: computed18(() => errorSignal()),
|
|
3803
|
+
isLoading: computed18(() => isLoadingSignal()),
|
|
1451
3804
|
refresh: store.refresh,
|
|
1452
|
-
|
|
3805
|
+
report: computed18(() => reportSignal()),
|
|
3806
|
+
updatedAt: computed18(() => updatedAtSignal())
|
|
1453
3807
|
};
|
|
1454
3808
|
}
|
|
1455
3809
|
}
|
|
1456
|
-
|
|
1457
|
-
__runInitializers(_init, 1,
|
|
1458
|
-
__decoratorMetadata(_init,
|
|
1459
|
-
let
|
|
3810
|
+
VoiceWorkflowStatusService = __decorateElement(_init, 0, "VoiceWorkflowStatusService", _dec, VoiceWorkflowStatusService);
|
|
3811
|
+
__runInitializers(_init, 1, VoiceWorkflowStatusService);
|
|
3812
|
+
__decoratorMetadata(_init, VoiceWorkflowStatusService);
|
|
3813
|
+
let _VoiceWorkflowStatusService = VoiceWorkflowStatusService;
|
|
1460
3814
|
export {
|
|
3815
|
+
VoiceWorkflowStatusService,
|
|
3816
|
+
VoiceTurnQualityService,
|
|
3817
|
+
VoiceTurnLatencyService,
|
|
3818
|
+
VoiceTraceTimelineService,
|
|
1461
3819
|
VoiceStreamService,
|
|
3820
|
+
VoiceRoutingStatusService,
|
|
3821
|
+
VoiceReadinessFailuresService,
|
|
1462
3822
|
VoiceProviderStatusService,
|
|
1463
|
-
|
|
3823
|
+
VoiceProviderContractsService,
|
|
3824
|
+
VoiceProviderCapabilitiesService,
|
|
3825
|
+
VoiceProofTrendsService,
|
|
3826
|
+
VoicePlatformCoverageService,
|
|
3827
|
+
VoiceOpsStatusService,
|
|
3828
|
+
VoiceOpsActionCenterService,
|
|
3829
|
+
VoiceLiveOpsService,
|
|
3830
|
+
VoiceDeliveryRuntimeService,
|
|
3831
|
+
VoiceControllerService,
|
|
3832
|
+
VoiceCampaignDialerProofService,
|
|
3833
|
+
VoiceAgentSquadStatusService
|
|
1464
3834
|
};
|