@absolutejs/voice 0.0.22-beta.584 → 0.0.22-beta.586
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/index.js +126 -0
- package/dist/client/htmxBootstrap.js +11 -0
- package/dist/client/index.js +126 -0
- package/dist/core/turnDetection.d.ts +1 -0
- package/dist/core/types.d.ts +4 -0
- package/dist/embed/index.js +11 -0
- package/dist/embed/voice-widget.js +8 -8
- package/dist/index.js +203 -119
- package/dist/react/index.js +126 -0
- package/dist/svelte/index.js +126 -0
- package/dist/testing/index.js +83 -2
- package/dist/vue/index.js +126 -0
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -1198,22 +1198,146 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1198
1198
|
};
|
|
1199
1199
|
};
|
|
1200
1200
|
|
|
1201
|
+
// src/core/turnDetection.ts
|
|
1202
|
+
var DEFAULT_SILENCE_MS = 700;
|
|
1203
|
+
var DEFAULT_SPEECH_THRESHOLD = 0.015;
|
|
1204
|
+
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1205
|
+
var toUint8Array = (audio) => {
|
|
1206
|
+
if (audio instanceof ArrayBuffer) {
|
|
1207
|
+
return new Uint8Array(audio);
|
|
1208
|
+
}
|
|
1209
|
+
return new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
1210
|
+
};
|
|
1211
|
+
var measureAudioLevel = (audio) => {
|
|
1212
|
+
const bytes = toUint8Array(audio);
|
|
1213
|
+
if (bytes.byteLength < 2) {
|
|
1214
|
+
return 0;
|
|
1215
|
+
}
|
|
1216
|
+
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
1217
|
+
if (samples.length === 0) {
|
|
1218
|
+
return 0;
|
|
1219
|
+
}
|
|
1220
|
+
let sumSquares = 0;
|
|
1221
|
+
for (const sample of samples) {
|
|
1222
|
+
const normalized = sample / 32768;
|
|
1223
|
+
sumSquares += normalized * normalized;
|
|
1224
|
+
}
|
|
1225
|
+
return Math.sqrt(sumSquares / samples.length);
|
|
1226
|
+
};
|
|
1227
|
+
var normalizeText = (value) => value.trim().replace(/\s+/g, " ");
|
|
1228
|
+
var countWords = (value) => value.length > 0 ? value.split(" ").length : 0;
|
|
1229
|
+
var selectPreferredTranscriptText = (currentText, nextText) => {
|
|
1230
|
+
const current = normalizeText(currentText);
|
|
1231
|
+
const next = normalizeText(nextText);
|
|
1232
|
+
if (!current) {
|
|
1233
|
+
return next;
|
|
1234
|
+
}
|
|
1235
|
+
if (!next) {
|
|
1236
|
+
return current;
|
|
1237
|
+
}
|
|
1238
|
+
if (current === next || current.includes(next)) {
|
|
1239
|
+
return current;
|
|
1240
|
+
}
|
|
1241
|
+
if (next.includes(current)) {
|
|
1242
|
+
return next;
|
|
1243
|
+
}
|
|
1244
|
+
if (countWords(next) > countWords(current)) {
|
|
1245
|
+
return next;
|
|
1246
|
+
}
|
|
1247
|
+
if (countWords(next) === countWords(current) && next.length > current.length) {
|
|
1248
|
+
return next;
|
|
1249
|
+
}
|
|
1250
|
+
return current;
|
|
1251
|
+
};
|
|
1252
|
+
var mergeSequentialTranscriptText = (currentText, nextText) => {
|
|
1253
|
+
const current = normalizeText(currentText);
|
|
1254
|
+
const next = normalizeText(nextText);
|
|
1255
|
+
if (!current) {
|
|
1256
|
+
return next;
|
|
1257
|
+
}
|
|
1258
|
+
if (!next) {
|
|
1259
|
+
return current;
|
|
1260
|
+
}
|
|
1261
|
+
const currentWords = current.split(" ");
|
|
1262
|
+
const nextWords = next.split(" ");
|
|
1263
|
+
const maxOverlap = Math.min(currentWords.length, nextWords.length);
|
|
1264
|
+
for (let overlap = maxOverlap;overlap > 0; overlap -= 1) {
|
|
1265
|
+
const currentSuffix = currentWords.slice(-overlap).join(" ");
|
|
1266
|
+
const nextPrefix = nextWords.slice(0, overlap).join(" ");
|
|
1267
|
+
if (currentSuffix === nextPrefix) {
|
|
1268
|
+
return [...currentWords, ...nextWords.slice(overlap)].join(" ");
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
return `${current} ${next}`.trim();
|
|
1272
|
+
};
|
|
1273
|
+
var countCommonPrefixWords = (currentText, nextText) => {
|
|
1274
|
+
const currentWords = normalizeText(currentText).split(" ").filter(Boolean);
|
|
1275
|
+
const nextWords = normalizeText(nextText).split(" ").filter(Boolean);
|
|
1276
|
+
const maxWords = Math.min(currentWords.length, nextWords.length);
|
|
1277
|
+
let count = 0;
|
|
1278
|
+
for (let index = 0;index < maxWords; index += 1) {
|
|
1279
|
+
if (currentWords[index] !== nextWords[index]) {
|
|
1280
|
+
break;
|
|
1281
|
+
}
|
|
1282
|
+
count += 1;
|
|
1283
|
+
}
|
|
1284
|
+
return count;
|
|
1285
|
+
};
|
|
1286
|
+
var mergeTranscriptTexts = (transcripts) => {
|
|
1287
|
+
const merged = [];
|
|
1288
|
+
for (const transcript of transcripts) {
|
|
1289
|
+
const nextText = normalizeText(transcript.text);
|
|
1290
|
+
if (!nextText) {
|
|
1291
|
+
continue;
|
|
1292
|
+
}
|
|
1293
|
+
const previous = merged.at(-1);
|
|
1294
|
+
if (!previous) {
|
|
1295
|
+
merged.push(nextText);
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
if (nextText === previous || previous.includes(nextText)) {
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
if (nextText.includes(previous)) {
|
|
1302
|
+
merged[merged.length - 1] = nextText;
|
|
1303
|
+
continue;
|
|
1304
|
+
}
|
|
1305
|
+
merged.push(nextText);
|
|
1306
|
+
}
|
|
1307
|
+
return merged.join(" ").trim();
|
|
1308
|
+
};
|
|
1309
|
+
var buildTurnText = (transcripts, partialText, options = {}) => {
|
|
1310
|
+
const finalText = mergeTranscriptTexts(transcripts);
|
|
1311
|
+
const nextPartial = normalizeText(partialText);
|
|
1312
|
+
const lastFinalEndedAtMs = [...transcripts].reverse().find((transcript) => typeof transcript.endedAtMs === "number")?.endedAtMs;
|
|
1313
|
+
if (finalText && nextPartial && typeof lastFinalEndedAtMs === "number" && typeof options.partialStartedAtMs === "number" && options.partialStartedAtMs - lastFinalEndedAtMs >= 250 && countCommonPrefixWords(finalText, nextPartial) === 0) {
|
|
1314
|
+
return mergeSequentialTranscriptText(finalText, nextPartial);
|
|
1315
|
+
}
|
|
1316
|
+
return selectPreferredTranscriptText(finalText, nextPartial);
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1201
1319
|
// src/core/turnProfiles.ts
|
|
1202
1320
|
var TURN_PROFILE_DEFAULTS = {
|
|
1203
1321
|
balanced: {
|
|
1204
1322
|
qualityProfile: "general",
|
|
1323
|
+
semanticVetoMaxMs: 0,
|
|
1324
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1205
1325
|
silenceMs: 1400,
|
|
1206
1326
|
speechThreshold: 0.012,
|
|
1207
1327
|
transcriptStabilityMs: 1000
|
|
1208
1328
|
},
|
|
1209
1329
|
fast: {
|
|
1210
1330
|
qualityProfile: "general",
|
|
1331
|
+
semanticVetoMaxMs: 0,
|
|
1332
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1211
1333
|
silenceMs: 700,
|
|
1212
1334
|
speechThreshold: 0.015,
|
|
1213
1335
|
transcriptStabilityMs: 450
|
|
1214
1336
|
},
|
|
1215
1337
|
"long-form": {
|
|
1216
1338
|
qualityProfile: "general",
|
|
1339
|
+
semanticVetoMaxMs: 0,
|
|
1340
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1217
1341
|
silenceMs: 2200,
|
|
1218
1342
|
speechThreshold: 0.01,
|
|
1219
1343
|
transcriptStabilityMs: 1500
|
|
@@ -1247,6 +1371,8 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1247
1371
|
return {
|
|
1248
1372
|
profile,
|
|
1249
1373
|
qualityProfile,
|
|
1374
|
+
semanticVetoMaxMs: config?.semanticVetoMaxMs ?? preset.semanticVetoMaxMs,
|
|
1375
|
+
semanticVetoRecheckMs: config?.semanticVetoRecheckMs ?? preset.semanticVetoRecheckMs,
|
|
1250
1376
|
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1251
1377
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1252
1378
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
@@ -1078,22 +1078,31 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1078
1078
|
};
|
|
1079
1079
|
};
|
|
1080
1080
|
|
|
1081
|
+
// src/core/turnDetection.ts
|
|
1082
|
+
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1083
|
+
|
|
1081
1084
|
// src/core/turnProfiles.ts
|
|
1082
1085
|
var TURN_PROFILE_DEFAULTS = {
|
|
1083
1086
|
balanced: {
|
|
1084
1087
|
qualityProfile: "general",
|
|
1088
|
+
semanticVetoMaxMs: 0,
|
|
1089
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1085
1090
|
silenceMs: 1400,
|
|
1086
1091
|
speechThreshold: 0.012,
|
|
1087
1092
|
transcriptStabilityMs: 1000
|
|
1088
1093
|
},
|
|
1089
1094
|
fast: {
|
|
1090
1095
|
qualityProfile: "general",
|
|
1096
|
+
semanticVetoMaxMs: 0,
|
|
1097
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1091
1098
|
silenceMs: 700,
|
|
1092
1099
|
speechThreshold: 0.015,
|
|
1093
1100
|
transcriptStabilityMs: 450
|
|
1094
1101
|
},
|
|
1095
1102
|
"long-form": {
|
|
1096
1103
|
qualityProfile: "general",
|
|
1104
|
+
semanticVetoMaxMs: 0,
|
|
1105
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1097
1106
|
silenceMs: 2200,
|
|
1098
1107
|
speechThreshold: 0.01,
|
|
1099
1108
|
transcriptStabilityMs: 1500
|
|
@@ -1127,6 +1136,8 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1127
1136
|
return {
|
|
1128
1137
|
profile,
|
|
1129
1138
|
qualityProfile,
|
|
1139
|
+
semanticVetoMaxMs: config?.semanticVetoMaxMs ?? preset.semanticVetoMaxMs,
|
|
1140
|
+
semanticVetoRecheckMs: config?.semanticVetoRecheckMs ?? preset.semanticVetoRecheckMs,
|
|
1130
1141
|
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1131
1142
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1132
1143
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
package/dist/client/index.js
CHANGED
|
@@ -1649,22 +1649,146 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1649
1649
|
};
|
|
1650
1650
|
};
|
|
1651
1651
|
|
|
1652
|
+
// src/core/turnDetection.ts
|
|
1653
|
+
var DEFAULT_SILENCE_MS = 700;
|
|
1654
|
+
var DEFAULT_SPEECH_THRESHOLD = 0.015;
|
|
1655
|
+
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1656
|
+
var toUint8Array = (audio) => {
|
|
1657
|
+
if (audio instanceof ArrayBuffer) {
|
|
1658
|
+
return new Uint8Array(audio);
|
|
1659
|
+
}
|
|
1660
|
+
return new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
1661
|
+
};
|
|
1662
|
+
var measureAudioLevel = (audio) => {
|
|
1663
|
+
const bytes = toUint8Array(audio);
|
|
1664
|
+
if (bytes.byteLength < 2) {
|
|
1665
|
+
return 0;
|
|
1666
|
+
}
|
|
1667
|
+
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
1668
|
+
if (samples.length === 0) {
|
|
1669
|
+
return 0;
|
|
1670
|
+
}
|
|
1671
|
+
let sumSquares = 0;
|
|
1672
|
+
for (const sample of samples) {
|
|
1673
|
+
const normalized = sample / 32768;
|
|
1674
|
+
sumSquares += normalized * normalized;
|
|
1675
|
+
}
|
|
1676
|
+
return Math.sqrt(sumSquares / samples.length);
|
|
1677
|
+
};
|
|
1678
|
+
var normalizeText = (value) => value.trim().replace(/\s+/g, " ");
|
|
1679
|
+
var countWords = (value) => value.length > 0 ? value.split(" ").length : 0;
|
|
1680
|
+
var selectPreferredTranscriptText = (currentText, nextText) => {
|
|
1681
|
+
const current = normalizeText(currentText);
|
|
1682
|
+
const next = normalizeText(nextText);
|
|
1683
|
+
if (!current) {
|
|
1684
|
+
return next;
|
|
1685
|
+
}
|
|
1686
|
+
if (!next) {
|
|
1687
|
+
return current;
|
|
1688
|
+
}
|
|
1689
|
+
if (current === next || current.includes(next)) {
|
|
1690
|
+
return current;
|
|
1691
|
+
}
|
|
1692
|
+
if (next.includes(current)) {
|
|
1693
|
+
return next;
|
|
1694
|
+
}
|
|
1695
|
+
if (countWords(next) > countWords(current)) {
|
|
1696
|
+
return next;
|
|
1697
|
+
}
|
|
1698
|
+
if (countWords(next) === countWords(current) && next.length > current.length) {
|
|
1699
|
+
return next;
|
|
1700
|
+
}
|
|
1701
|
+
return current;
|
|
1702
|
+
};
|
|
1703
|
+
var mergeSequentialTranscriptText = (currentText, nextText) => {
|
|
1704
|
+
const current = normalizeText(currentText);
|
|
1705
|
+
const next = normalizeText(nextText);
|
|
1706
|
+
if (!current) {
|
|
1707
|
+
return next;
|
|
1708
|
+
}
|
|
1709
|
+
if (!next) {
|
|
1710
|
+
return current;
|
|
1711
|
+
}
|
|
1712
|
+
const currentWords = current.split(" ");
|
|
1713
|
+
const nextWords = next.split(" ");
|
|
1714
|
+
const maxOverlap = Math.min(currentWords.length, nextWords.length);
|
|
1715
|
+
for (let overlap = maxOverlap;overlap > 0; overlap -= 1) {
|
|
1716
|
+
const currentSuffix = currentWords.slice(-overlap).join(" ");
|
|
1717
|
+
const nextPrefix = nextWords.slice(0, overlap).join(" ");
|
|
1718
|
+
if (currentSuffix === nextPrefix) {
|
|
1719
|
+
return [...currentWords, ...nextWords.slice(overlap)].join(" ");
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
return `${current} ${next}`.trim();
|
|
1723
|
+
};
|
|
1724
|
+
var countCommonPrefixWords = (currentText, nextText) => {
|
|
1725
|
+
const currentWords = normalizeText(currentText).split(" ").filter(Boolean);
|
|
1726
|
+
const nextWords = normalizeText(nextText).split(" ").filter(Boolean);
|
|
1727
|
+
const maxWords = Math.min(currentWords.length, nextWords.length);
|
|
1728
|
+
let count = 0;
|
|
1729
|
+
for (let index = 0;index < maxWords; index += 1) {
|
|
1730
|
+
if (currentWords[index] !== nextWords[index]) {
|
|
1731
|
+
break;
|
|
1732
|
+
}
|
|
1733
|
+
count += 1;
|
|
1734
|
+
}
|
|
1735
|
+
return count;
|
|
1736
|
+
};
|
|
1737
|
+
var mergeTranscriptTexts = (transcripts) => {
|
|
1738
|
+
const merged = [];
|
|
1739
|
+
for (const transcript of transcripts) {
|
|
1740
|
+
const nextText = normalizeText(transcript.text);
|
|
1741
|
+
if (!nextText) {
|
|
1742
|
+
continue;
|
|
1743
|
+
}
|
|
1744
|
+
const previous = merged.at(-1);
|
|
1745
|
+
if (!previous) {
|
|
1746
|
+
merged.push(nextText);
|
|
1747
|
+
continue;
|
|
1748
|
+
}
|
|
1749
|
+
if (nextText === previous || previous.includes(nextText)) {
|
|
1750
|
+
continue;
|
|
1751
|
+
}
|
|
1752
|
+
if (nextText.includes(previous)) {
|
|
1753
|
+
merged[merged.length - 1] = nextText;
|
|
1754
|
+
continue;
|
|
1755
|
+
}
|
|
1756
|
+
merged.push(nextText);
|
|
1757
|
+
}
|
|
1758
|
+
return merged.join(" ").trim();
|
|
1759
|
+
};
|
|
1760
|
+
var buildTurnText = (transcripts, partialText, options = {}) => {
|
|
1761
|
+
const finalText = mergeTranscriptTexts(transcripts);
|
|
1762
|
+
const nextPartial = normalizeText(partialText);
|
|
1763
|
+
const lastFinalEndedAtMs = [...transcripts].reverse().find((transcript) => typeof transcript.endedAtMs === "number")?.endedAtMs;
|
|
1764
|
+
if (finalText && nextPartial && typeof lastFinalEndedAtMs === "number" && typeof options.partialStartedAtMs === "number" && options.partialStartedAtMs - lastFinalEndedAtMs >= 250 && countCommonPrefixWords(finalText, nextPartial) === 0) {
|
|
1765
|
+
return mergeSequentialTranscriptText(finalText, nextPartial);
|
|
1766
|
+
}
|
|
1767
|
+
return selectPreferredTranscriptText(finalText, nextPartial);
|
|
1768
|
+
};
|
|
1769
|
+
|
|
1652
1770
|
// src/core/turnProfiles.ts
|
|
1653
1771
|
var TURN_PROFILE_DEFAULTS = {
|
|
1654
1772
|
balanced: {
|
|
1655
1773
|
qualityProfile: "general",
|
|
1774
|
+
semanticVetoMaxMs: 0,
|
|
1775
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1656
1776
|
silenceMs: 1400,
|
|
1657
1777
|
speechThreshold: 0.012,
|
|
1658
1778
|
transcriptStabilityMs: 1000
|
|
1659
1779
|
},
|
|
1660
1780
|
fast: {
|
|
1661
1781
|
qualityProfile: "general",
|
|
1782
|
+
semanticVetoMaxMs: 0,
|
|
1783
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1662
1784
|
silenceMs: 700,
|
|
1663
1785
|
speechThreshold: 0.015,
|
|
1664
1786
|
transcriptStabilityMs: 450
|
|
1665
1787
|
},
|
|
1666
1788
|
"long-form": {
|
|
1667
1789
|
qualityProfile: "general",
|
|
1790
|
+
semanticVetoMaxMs: 0,
|
|
1791
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1668
1792
|
silenceMs: 2200,
|
|
1669
1793
|
speechThreshold: 0.01,
|
|
1670
1794
|
transcriptStabilityMs: 1500
|
|
@@ -1698,6 +1822,8 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1698
1822
|
return {
|
|
1699
1823
|
profile,
|
|
1700
1824
|
qualityProfile,
|
|
1825
|
+
semanticVetoMaxMs: config?.semanticVetoMaxMs ?? preset.semanticVetoMaxMs,
|
|
1826
|
+
semanticVetoRecheckMs: config?.semanticVetoRecheckMs ?? preset.semanticVetoRecheckMs,
|
|
1701
1827
|
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1702
1828
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1703
1829
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AudioChunk, Transcript } from "./types";
|
|
2
2
|
export declare const DEFAULT_SILENCE_MS = 700;
|
|
3
3
|
export declare const DEFAULT_SPEECH_THRESHOLD = 0.015;
|
|
4
|
+
export declare const DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
4
5
|
export declare const measureAudioLevel: (audio: AudioChunk) => number;
|
|
5
6
|
export declare const selectPreferredTranscriptText: (currentText: string, nextText: string) => string;
|
|
6
7
|
export declare const buildTurnText: (transcripts: Transcript[], partialText: string, options?: {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -438,6 +438,8 @@ export type VoiceTurnDetectionConfig = {
|
|
|
438
438
|
silenceMs?: number;
|
|
439
439
|
speechThreshold?: number;
|
|
440
440
|
transcriptStabilityMs?: number;
|
|
441
|
+
semanticVetoMaxMs?: number;
|
|
442
|
+
semanticVetoRecheckMs?: number;
|
|
441
443
|
};
|
|
442
444
|
export type VoiceResolvedTurnDetectionConfig = {
|
|
443
445
|
qualityProfile: VoiceTurnQualityProfile;
|
|
@@ -445,6 +447,8 @@ export type VoiceResolvedTurnDetectionConfig = {
|
|
|
445
447
|
silenceMs: number;
|
|
446
448
|
speechThreshold: number;
|
|
447
449
|
transcriptStabilityMs: number;
|
|
450
|
+
semanticVetoMaxMs: number;
|
|
451
|
+
semanticVetoRecheckMs: number;
|
|
448
452
|
};
|
|
449
453
|
export type VoiceAudioConditioningConfig = {
|
|
450
454
|
enabled?: boolean;
|
package/dist/embed/index.js
CHANGED
|
@@ -1075,22 +1075,31 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1075
1075
|
};
|
|
1076
1076
|
};
|
|
1077
1077
|
|
|
1078
|
+
// src/core/turnDetection.ts
|
|
1079
|
+
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1080
|
+
|
|
1078
1081
|
// src/core/turnProfiles.ts
|
|
1079
1082
|
var TURN_PROFILE_DEFAULTS = {
|
|
1080
1083
|
balanced: {
|
|
1081
1084
|
qualityProfile: "general",
|
|
1085
|
+
semanticVetoMaxMs: 0,
|
|
1086
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1082
1087
|
silenceMs: 1400,
|
|
1083
1088
|
speechThreshold: 0.012,
|
|
1084
1089
|
transcriptStabilityMs: 1000
|
|
1085
1090
|
},
|
|
1086
1091
|
fast: {
|
|
1087
1092
|
qualityProfile: "general",
|
|
1093
|
+
semanticVetoMaxMs: 0,
|
|
1094
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1088
1095
|
silenceMs: 700,
|
|
1089
1096
|
speechThreshold: 0.015,
|
|
1090
1097
|
transcriptStabilityMs: 450
|
|
1091
1098
|
},
|
|
1092
1099
|
"long-form": {
|
|
1093
1100
|
qualityProfile: "general",
|
|
1101
|
+
semanticVetoMaxMs: 0,
|
|
1102
|
+
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1094
1103
|
silenceMs: 2200,
|
|
1095
1104
|
speechThreshold: 0.01,
|
|
1096
1105
|
transcriptStabilityMs: 1500
|
|
@@ -1124,6 +1133,8 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1124
1133
|
return {
|
|
1125
1134
|
profile,
|
|
1126
1135
|
qualityProfile,
|
|
1136
|
+
semanticVetoMaxMs: config?.semanticVetoMaxMs ?? preset.semanticVetoMaxMs,
|
|
1137
|
+
semanticVetoRecheckMs: config?.semanticVetoRecheckMs ?? preset.semanticVetoRecheckMs,
|
|
1127
1138
|
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1128
1139
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1129
1140
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(()=>{var{defineProperty:X,getOwnPropertyNames:Ac,getOwnPropertyDescriptor:Tc}=Object,Cc=Object.prototype.hasOwnProperty;function Ic(c){return this[c]}var Vc=(c)=>{var g=(J??=new WeakMap).get(c),A;if(g)return g;if(g=X({},"__esModule",{value:!0}),c&&typeof c==="object"||typeof c==="function"){for(var n of Ac(c))if(!Cc.call(g,n))X(g,n,{get:Ic.bind(c,n),enumerable:!(A=Tc(c,n))||A.enumerable})}return J.set(c,g),g},J;var lc=(c)=>c;function Sc(c,g){this[c]=lc.bind(null,g)}var yc=(c,g)=>{for(var A in g)X(c,A,{get:g[A],enumerable:!0,configurable:!0,set:Sc.bind(g,A)})};var jc={};yc(jc,{mount:()=>p,default:()=>oc,VOICE_EMBED_VERSION:()=>cc});var _c=(c)=>{if(typeof c!=="string")return c;return document.querySelector(c)},Rc=(c,g,A,n)=>{let T=g??c.getAttribute("hx-get")??"";if(!T)return"";let V=new URL(T,window.location.origin);if(n)V.searchParams.set(A,n);else V.searchParams.delete(A);return`${V.pathname}${V.search}${V.hash}`},Z=(c,g)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let A=_c(g.element);if(!A)return()=>{};let n=g.eventName??"voice-refresh",T=g.sessionQueryParam??"sessionId",V=()=>{let y=window,_=Rc(A,g.route,T,c.sessionId);if(_)A.setAttribute("hx-get",_);y.htmx?.process?.(A),y.htmx?.trigger?.(A,n)},I=c.subscribe(V);return V(),()=>{I()}};var hc=(c)=>Math.max(-1,Math.min(1,c)),Lc=(c)=>{let g=new Int16Array(c.length);for(let A=0;A<c.length;A+=1){let n=hc(c[A]??0);g[A]=n<0?n*32768:n*32767}return new Uint8Array(g.buffer)},Uc=(c)=>{let g=c instanceof Uint8Array?c:new Uint8Array(c);if(g.byteLength<2)return 0;let A=new Int16Array(g.buffer,g.byteOffset,Math.floor(g.byteLength/2));if(A.length===0)return 0;let n=0;for(let T of A){let V=T/32768;n+=V*V}return Math.min(1,Math.max(0,Math.sqrt(n/A.length)*5.5))},wc=(c,g,A)=>{if(g===A)return c;let n=g/A,T=Math.round(c.length/n),V=new Float32Array(T),I=0,y=0;while(I<V.length){let _=Math.round((I+1)*n),L=0,S=0;for(let h=y;h<_&&h<c.length;h+=1)L+=c[h]??0,S+=1;V[I]=S>0?L/S:0,I+=1,y=_}return V},q=(c)=>{let g=null,A=null,n=null,T=null;return{start:async()=>{if(!c.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let y=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!y)throw Error("Browser microphone capture requires AudioContext support.");if(T=c.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:c.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),g=new y,g.state==="suspended")await g.resume();A=g.createMediaStreamSource(T),n=g.createScriptProcessor(4096,1,1),n.onaudioprocess=(_)=>{let L=_.inputBuffer.getChannelData(0),S=wc(L,g?.sampleRate??48000,c.sampleRateHz??16000),h=Lc(S);c.onLevel?.(Uc(h)),c.onAudio(h)},A.connect(n),n.connect(g.destination)},stop:()=>{n?.disconnect(),A?.disconnect(),T?.getTracks().forEach((y)=>y.stop()),g?.close(),c.onLevel?.(0),g=null,T=null,n=null,A=null}}};var Y=(c)=>{if(typeof c==="string"&&c.trim())return c;if(c instanceof Error&&c.message.trim())return c.message;if(c&&typeof c==="object"){let g=c;for(let A of["message","reason","description"]){let n=g[A];if(typeof n==="string"&&n.trim())return n}if("error"in g)return Y(g.error);if("cause"in g)return Y(g.cause);try{return JSON.stringify(c)}catch{}}return"Unexpected error"},z=(c)=>{switch(c.type){case"audio":return{chunk:Uint8Array.from(atob(c.chunkBase64),(g)=>g.charCodeAt(0)),format:c.format,receivedAt:c.receivedAt,turnId:c.turnId,type:"audio"};case"assistant":return{text:c.text,turnId:c.turnId,type:"assistant"};case"assistant_delta":return{delta:c.delta,turnId:c.turnId,type:"assistant_delta"};case"complete":return{sessionId:c.sessionId,type:"complete"};case"connection":return{reconnect:c.reconnect,type:"connection"};case"call_lifecycle":return{event:c.event,sessionId:c.sessionId,type:"call_lifecycle"};case"error":return{message:Y(c.message),type:"error"};case"final":return{transcript:c.transcript,type:"final"};case"partial":return{transcript:c.transcript,type:"partial"};case"replay":return{assistantTexts:c.assistantTexts,call:c.call,partial:c.partial,scenarioId:c.scenarioId,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,status:c.status,turns:c.turns,type:"replay"};case"session":return{sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,type:"session"};case"turn":return{turn:c.turn,type:"turn"};default:return null}};var ec=Math.PI*2;var P=(c,g,A,n)=>{c.push({code:A,message:n,severity:g})};var Dc=(c)=>c.length===0?void 0:c.reduce((g,A)=>g+A,0)/c.length,G=(c)=>c.length===0?void 0:Math.max(...c);var w=(c,g)=>{let A=c[g];return typeof A==="number"&&Number.isFinite(A)?A:void 0},x=(c,g)=>{let A=c[g];return typeof A==="boolean"?A:void 0},D=(c,g)=>{let A=c[g];return typeof A==="string"?A:void 0},Q=(c)=>String(c.id??D(c,"ssrc")??w(c,"ssrc")??D(c,"trackIdentifier")??D(c,"mid")??"unknown"),K=(c)=>c===void 0?void 0:c*1000;var bc=(c)=>{let g={};for(let[A,n]of Object.entries(c))if(n===null||typeof n==="boolean"||typeof n==="number"||typeof n==="string")g[A]=n;return g};var B=(c={})=>{let g=c.stats??[],A=[],n=g.filter((C)=>C.type==="inbound-rtp"&&D(C,"kind")!=="video"),T=g.filter((C)=>C.type==="outbound-rtp"&&D(C,"kind")!=="video"),V=g.filter((C)=>C.type==="candidate-pair"),I=g.filter((C)=>(C.type==="track"||C.type==="media-source")&&D(C,"kind")==="audio"),y=V.filter((C)=>x(C,"selected")===!0||x(C,"nominated")===!0||D(C,"state")==="succeeded").length,_=I.filter((C)=>D(C,"readyState")!=="ended"&&D(C,"trackState")!=="ended"&&x(C,"ended")!==!0).length,L=I.filter((C)=>D(C,"readyState")==="ended"||D(C,"trackState")==="ended"||x(C,"ended")===!0).length,S=n.reduce((C,U)=>C+(w(U,"packetsReceived")??0),0),h=T.reduce((C,U)=>C+(w(U,"packetsSent")??0),0),l=[...n,...T].reduce((C,U)=>C+Math.max(0,w(U,"packetsLost")??0),0),b=S+l,R=b===0?0:l/b,W=n.reduce((C,U)=>C+(w(U,"bytesReceived")??0),0),E=T.reduce((C,U)=>C+(w(U,"bytesSent")??0),0),M=G(V.map((C)=>K(w(C,"currentRoundTripTime")??w(C,"roundTripTime"))).filter((C)=>C!==void 0)),$=G([...n,...T].map((C)=>K(w(C,"jitter"))).filter((C)=>C!==void 0)),d=G(n.map((C)=>{let U=w(C,"jitterBufferDelay"),O=w(C,"jitterBufferEmittedCount");return U!==void 0&&O!==void 0&&O>0?U/O*1000:void 0}).filter((C)=>C!==void 0)),N=I.map((C)=>w(C,"audioLevel")).filter((C)=>C!==void 0);if(c.requireConnectedCandidatePair&&V.length>0&&y===0)P(A,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(c.requireLiveAudioTrack&&_===0)P(A,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(c.maxPacketLossRatio!==void 0&&R>c.maxPacketLossRatio)P(A,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(R)} above ${String(c.maxPacketLossRatio)}.`);if(c.maxRoundTripTimeMs!==void 0&&M!==void 0&&M>c.maxRoundTripTimeMs)P(A,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(M)}ms above ${String(c.maxRoundTripTimeMs)}ms.`);if(c.maxJitterMs!==void 0&&$!==void 0&&$>c.maxJitterMs)P(A,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String($)}ms above ${String(c.maxJitterMs)}ms.`);return{activeCandidatePairs:y,audioLevelAverage:Dc(N),bytesReceived:W,bytesSent:E,checkedAt:Date.now(),endedAudioTracks:L,inboundPackets:S,issues:A,jitterBufferDelayMs:d,jitterMs:$,liveAudioTracks:_,outboundPackets:h,packetLossRatio:R,packetsLost:l,roundTripTimeMs:M,status:A.some((C)=>C.severity==="error")?"fail":A.length>0?"warn":"pass",totalStats:g.length}},j=async(c)=>{return[...(await c.peerConnection.getStats(c.selector??null)).values()].map(bc)};var o=(c={})=>{let g=c.stats??[],A=c.previousStats??[],n=[],T=new Map(A.map((l)=>[Q(l),l])),I=g.filter((l)=>(l.type==="inbound-rtp"||l.type==="outbound-rtp")&&D(l,"kind")!=="video"&&D(l,"mediaType")!=="video").map((l)=>{let b=l.type==="outbound-rtp"?"outbound":"inbound",R=b==="outbound"?"packetsSent":"packetsReceived",W=b==="outbound"?"bytesSent":"bytesReceived",E=T.get(Q(l)),M=w(l,R),$=E?w(E,R):void 0,d=w(l,W),N=E?w(E,W):void 0,C=l.timestamp!==void 0&&E?.timestamp!==void 0?l.timestamp-E.timestamp:void 0;return{bytesDelta:d!==void 0&&N!==void 0?d-N:void 0,currentPackets:M,direction:b,id:Q(l),packetDelta:M!==void 0&&$!==void 0?M-$:void 0,previousPackets:$,timeDeltaMs:C}}),y=I.filter((l)=>l.direction==="inbound"),_=I.filter((l)=>l.direction==="outbound"),L=G(I.map((l)=>l.timeDeltaMs).filter((l)=>l!==void 0)),S=y.filter((l)=>c.maxInboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=c.maxInboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length,h=_.filter((l)=>c.maxOutboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=c.maxOutboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length;if(c.requireInboundAudio&&y.length===0)P(n,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(c.requireOutboundAudio&&_.length===0)P(n,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(c.maxGapMs!==void 0&&L!==void 0&&L>c.maxGapMs)P(n,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(L)}ms above ${String(c.maxGapMs)}ms.`);if(S>0)P(n,"error","media.webrtc_inbound_stalled",`${String(S)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)P(n,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:y.length,issues:n,maxObservedGapMs:L,outboundAudioStreams:_.length,stalledInboundStreams:S,stalledOutboundStreams:h,status:n.some((l)=>l.severity==="error")?"fail":n.length>0?"warn":"pass",streams:I,totalStats:g.length}};var Oc="/api/voice/browser-media",Ec=5000,Mc=async(c)=>c.peerConnection??await c.getPeerConnection?.()??null,$c=async(c,g)=>{let A=g.fetch??globalThis.fetch;if(!A)return;await A(g.path??Oc,{body:JSON.stringify(c),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},s=(c)=>{let g=null,A=[],n=async()=>{let I=await Mc(c);if(!I)return;let y=await j({peerConnection:I}),_=B({...c,stats:y}),L=c.continuity===!1?void 0:o({...c.continuity,previousStats:A,stats:y}),S={at:Date.now(),continuity:L,report:_,scenarioId:c.getScenarioId?.()??null,sessionId:c.getSessionId?.()??null};return A=y,c.onReport?.(S),await $c(S,c),S},T=()=>{n().catch((I)=>{c.onError?.(I)})},V=()=>{if(g)clearInterval(g),g=null};return{close:V,reportOnce:n,stop:V,start:()=>{if(g)return;T(),g=setInterval(T,c.intervalMs??Ec)}}};var H=()=>{},Pc=()=>H,ic={callControl:H,close:H,endTurn:H,send:H,sendAudio:H,simulateDisconnect:H,subscribe:Pc,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},Hc=()=>crypto.randomUUID(),Wc=(c,g,A)=>{let{hostname:n,port:T,protocol:V}=window.location,I=V==="https:"?"wss:":"ws:",y=T?`:${T}`:"",_=new URL(`${I}//${n}${y}${c}`);if(_.searchParams.set("sessionId",g),A)_.searchParams.set("scenarioId",A);return _.toString()},dc=(c)=>{if(!c||typeof c!=="object"||!("type"in c))return!1;switch(c.type){case"audio":case"assistant":case"call_lifecycle":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},Nc=(c)=>{if(typeof c.data!=="string")return null;try{let g=JSON.parse(c.data);return dc(g)?g:null}catch{return null}},k=(c,g={})=>{if(typeof window>"u")return ic;let A=new Set,n=g.reconnect!==!1,T=g.maxReconnectAttempts??10,V=g.pingInterval??30000,I={isConnected:!1,pendingMessages:[],scenarioId:g.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:g.sessionId??Hc(),ws:null},y=(C)=>{A.forEach((U)=>U(C))},_=()=>{if(I.pingInterval)clearInterval(I.pingInterval),I.pingInterval=null;if(I.reconnectTimeout)clearTimeout(I.reconnectTimeout),I.reconnectTimeout=null},L=()=>{if(I.ws?.readyState!==1)return;while(I.pendingMessages.length>0){let C=I.pendingMessages.shift();if(C!==void 0)I.ws.send(C)}},S=()=>{let C=Date.now()+500;I.reconnectAttempts+=1,y({reconnect:{attempts:I.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,nextAttemptAt:C,status:"reconnecting"},type:"connection"}),I.reconnectTimeout=setTimeout(()=>{if(I.reconnectAttempts>T){y({reconnect:{attempts:I.reconnectAttempts,maxAttempts:T,status:"exhausted"},type:"connection"});return}h()},500)},h=()=>{let C=new WebSocket(Wc(c,I.sessionId,I.scenarioId));C.binaryType="arraybuffer",C.onopen=()=>{let U=I.reconnectAttempts>0;if(I.isConnected=!0,L(),U)y({reconnect:{attempts:I.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:T,status:"resumed"},type:"connection"}),I.reconnectAttempts=0;A.forEach((O)=>O({scenarioId:I.scenarioId??void 0,sessionId:I.sessionId,status:"active",type:"session"})),I.pingInterval=setInterval(()=>{if(C.readyState===1)C.send(JSON.stringify({type:"ping"}))},V)},C.onmessage=(U)=>{let O=Nc(U);if(!O)return;if(O.type==="session")I.sessionId=O.sessionId,I.scenarioId=O.scenarioId??I.scenarioId;A.forEach((nc)=>nc(O))},C.onclose=(U)=>{if(I.isConnected=!1,_(),n&&U.code!==1000&&I.reconnectAttempts<T)S();else if(n&&U.code!==1000)y({reconnect:{attempts:I.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,status:"exhausted"},type:"connection"})},I.ws=C},l=(C)=>{if(I.ws?.readyState===1){I.ws.send(C);return}I.pendingMessages.push(C)},b=(C)=>{l(JSON.stringify(C))},R=(C={})=>{if(C.sessionId)I.sessionId=C.sessionId;if(C.scenarioId)I.scenarioId=C.scenarioId;b({scenarioId:I.scenarioId??void 0,sessionId:I.sessionId,type:"start"})},W=(C)=>{l(C)},E=()=>{b({type:"end_turn"})},M=(C)=>{b({...C,type:"call_control"})},$=()=>{if(_(),I.ws)I.ws.close(1000),I.ws=null;I.isConnected=!1,A.clear()},d=()=>{if(I.ws?.readyState===1)I.ws.close(4000,"absolutejs-voice-reconnect-proof")},N=(C)=>{return A.add(C),()=>{A.delete(C)}};return h(),{callControl:M,close:$,endTurn:E,send:b,sendAudio:W,simulateDisconnect:d,start:R,subscribe:N,getReadyState:()=>I.ws?.readyState??3,getScenarioId:()=>I.scenarioId??"",getSessionId:()=>I.sessionId}};var xc=()=>({attempts:0,maxAttempts:0,status:"idle"}),Gc=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:xc(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),f=()=>{let c=Gc(),g=new Set,A=()=>{g.forEach((T)=>T())};return{dispatch:(T)=>{switch(T.type){case"audio":c={...c,assistantAudio:[...c.assistantAudio,{chunk:T.chunk,format:T.format,receivedAt:T.receivedAt,turnId:T.turnId}]};break;case"assistant":c={...c,assistantStreamingText:"",assistantTexts:[...c.assistantTexts,T.text]};break;case"assistant_delta":c={...c,assistantStreamingText:`${c.assistantStreamingText}${T.delta}`};break;case"complete":c={...c,sessionId:T.sessionId,status:"completed"};break;case"call_lifecycle":c={...c,call:{...c.call,disposition:T.event.type==="end"?T.event.disposition:c.call?.disposition,endedAt:T.event.type==="end"?T.event.at:c.call?.endedAt,events:[...c.call?.events??[],T.event],lastEventAt:T.event.at,startedAt:c.call?.startedAt??T.event.at},sessionId:T.sessionId};break;case"connected":c={...c,isConnected:!0,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect};break;case"connection":c={...c,reconnect:T.reconnect};break;case"disconnected":c={...c,isConnected:!1};break;case"error":c={...c,error:T.message};break;case"final":c={...c,partial:T.transcript.text,turns:c.turns.map((V)=>V)};break;case"partial":c={...c,partial:T.transcript.text};break;case"replay":c={...c,assistantStreamingText:"",assistantTexts:[...T.assistantTexts],call:T.call??null,error:null,isConnected:T.status==="active",partial:T.partial,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect,scenarioId:T.scenarioId??c.scenarioId,sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??c.sessionMetadata,status:T.status,turns:[...T.turns]};break;case"session":c={...c,error:null,scenarioId:T.scenarioId??c.scenarioId,isConnected:T.status==="active",sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??c.sessionMetadata,status:T.status};break;case"turn":c={...c,partial:"",turns:[...c.turns,T.turn]};break}A()},getServerSnapshot:()=>c,getSnapshot:()=>c,subscribe:(T)=>{return g.add(T),()=>{g.delete(T)}}}};var F=(c,g={})=>{let A=k(c,g),n=f(),T=g.browserMedia&&typeof window<"u"?s({...g.browserMedia,getScenarioId:()=>g.browserMedia?g.browserMedia.getScenarioId?.()??A.getScenarioId():A.getScenarioId(),getSessionId:()=>g.browserMedia?g.browserMedia.getSessionId?.()??A.getSessionId():A.getSessionId()}):null,V=new Set,I=(S)=>Promise.resolve().then(()=>{if(!S?.sessionId&&!S?.scenarioId)return;A.start(S),T?.start()}),y=()=>{V.forEach((S)=>S())},_=()=>{if(!g.reconnectReportPath||typeof fetch>"u")return;let S=n.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:S.reconnect,scenarioId:S.scenarioId,sessionId:A.getSessionId(),turnIds:S.turns.map((l)=>l.id)});fetch(g.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=A.subscribe((S)=>{let h=z(S);if(h){if(n.dispatch(h),S.type==="connection")_();y()}});return{start:I,get assistantAudio(){return n.getSnapshot().assistantAudio},get assistantTexts(){return n.getSnapshot().assistantTexts},get assistantStreamingText(){return n.getSnapshot().assistantStreamingText},get call(){return n.getSnapshot().call},callControl(S){A.callControl(S)},close(){L(),T?.close(),A.close(),n.dispatch({type:"disconnected"}),y()},endTurn(){A.endTurn()},get error(){return n.getSnapshot().error},getServerSnapshot(){return n.getServerSnapshot()},getSnapshot(){return n.getSnapshot()},get isConnected(){return n.getSnapshot().isConnected},get partial(){return n.getSnapshot().partial},get reconnect(){return n.getSnapshot().reconnect},get scenarioId(){return n.getSnapshot().scenarioId},sendAudio(S){A.sendAudio(S)},get sessionId(){return A.getSessionId()},get sessionMetadata(){return n.getSnapshot().sessionMetadata},simulateDisconnect(){A.simulateDisconnect()},get status(){return n.getSnapshot().status},subscribe(S){return V.add(S),()=>{V.delete(S)}},get turns(){return n.getSnapshot().turns}}};var e=(c)=>{if(!c||c.enabled===!1)return;return{enabled:!0,maxGain:c.maxGain??3,noiseGateAttenuation:c.noiseGateAttenuation??0.15,noiseGateThreshold:c.noiseGateThreshold??0.006,targetLevel:c.targetLevel??0.08}};var Xc={balanced:{qualityProfile:"general",silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},Yc={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var t=(c)=>{let g=c?.profile??"fast",A=c?.qualityProfile??"general",n=Xc[g],T=Yc[A];return{profile:g,qualityProfile:A,silenceMs:c?.silenceMs??T.silenceMs??n.silenceMs,speechThreshold:c?.speechThreshold??T.speechThreshold??n.speechThreshold,transcriptStabilityMs:c?.transcriptStabilityMs??T.transcriptStabilityMs??n.transcriptStabilityMs}};var Qc={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},r=(c="default")=>{let g=Qc[c];return{audioConditioning:e(g.audioConditioning),capture:{channelCount:g.capture?.channelCount??1,sampleRateHz:g.capture?.sampleRateHz??16000},connection:{...g.connection},name:c,sttLifecycle:g.sttLifecycle??"continuous",turnDetection:t(g.turnDetection)}};var Jc=(c)=>({assistantAudio:[...c.assistantAudio],assistantStreamingText:c.assistantStreamingText,assistantTexts:[...c.assistantTexts],call:c.call,error:c.error,isConnected:c.isConnected,isRecording:!1,partial:c.partial,reconnect:c.reconnect,recordingError:null,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,turns:[...c.turns]}),a=(c,g={})=>{let A=r(g.preset),n=F(c,{...A.connection,...g.connection}),T=null,V=Jc(n),I=new Set,y=()=>{for(let R of I)R()},_=()=>{if(V={...V,assistantAudio:[...n.assistantAudio],assistantStreamingText:n.assistantStreamingText,assistantTexts:[...n.assistantTexts],call:n.call,error:n.error,isConnected:n.isConnected,partial:n.partial,reconnect:n.reconnect,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,turns:[...n.turns]},g.autoStopOnComplete!==!1&&V.status==="completed"&&V.isRecording)T?.stop(),T=null,V={...V,isRecording:!1};y()},L=n.subscribe(_);_();let S=()=>{if(T)return T;return T=q({channelCount:g.capture?.channelCount??A.capture.channelCount,onLevel:g.capture?.onLevel,onAudio:(R)=>{if(g.capture?.onAudio){g.capture.onAudio(R,n.sendAudio);return}n.sendAudio(R)},sampleRateHz:g.capture?.sampleRateHz??A.capture.sampleRateHz,...g.capture?.stream?{stream:g.capture.stream}:{}}),T},h=()=>{T?.stop(),T=null,V={...V,isRecording:!1},y()},l=async()=>{if(V.isRecording)return;try{V={...V,recordingError:null},y(),await S().start(),V={...V,isRecording:!0},y()}catch(R){throw T=null,V={...V,isRecording:!1,recordingError:R instanceof Error?R.message:String(R)},y(),R}};return{close:()=>{L(),h(),n.close()},startRecording:l,stopRecording:h,get assistantAudio(){return V.assistantAudio},get assistantTexts(){return V.assistantTexts},get assistantStreamingText(){return V.assistantStreamingText},bindHTMX(R){return Z(n,R)},get call(){return V.call},callControl:(R)=>n.callControl(R),endTurn:()=>n.endTurn(),get error(){return V.error},getServerSnapshot:()=>V,getSnapshot:()=>V,get isConnected(){return V.isConnected},get isRecording(){return V.isRecording},get partial(){return V.partial},get reconnect(){return V.reconnect},get recordingError(){return V.recordingError},get scenarioId(){return V.scenarioId},sendAudio:(R)=>n.sendAudio(R),get sessionId(){return V.sessionId},get sessionMetadata(){return V.sessionMetadata},simulateDisconnect:()=>n.simulateDisconnect(),get status(){return V.status},subscribe:(R)=>{return I.add(R),()=>{I.delete(R)}},toggleRecording:async()=>{if(V.isRecording){h();return}await l()},get turns(){return V.turns}}};var i=(c)=>String(c).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var v=(c)=>{if(!c.isConnected)return"idle";if(c.isPlaying)return"speaking";if(c.isRecording&&c.hasActivePartial)return"listening";if(c.isRecording)return"listening";if(c.lastTranscriptAt&&!c.lastAssistantAt)return"thinking";if(c.lastTranscriptAt&&c.lastAssistantAt&&c.lastTranscriptAt>c.lastAssistantAt)return"thinking";return"idle"};var Zc={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},qc={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},zc=(c,g)=>{switch(c){case"listening":return g.listening;case"speaking":return g.speaking;case"thinking":return g.thinking;case"idle":return g.idle}},m=(c)=>{let g={...Zc,...c.theme},A={...qc,...c.labels},n=c.state.assistantAudio.at(-1)?.receivedAt,T=c.state.turns.at(-1)?.committedAt,V=v({hasActivePartial:c.state.partial.length>0,isConnected:c.state.isConnected,isPlaying:!1,isRecording:c.state.isRecording,lastAssistantAt:n,lastTranscriptAt:T}),I=!c.state.isConnected&&c.state.status!=="idle"&&!c.state.error,y=c.state.error?"Error":I?A.connecting:c.state.status==="completed"?A.callEnded:zc(V,A);return{agentState:V,classes:{container:`absolute-voice-widget absolute-voice-widget--${V}`,dot:`absolute-voice-widget__dot${c.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:c.state.isConnected,canMute:c.state.isRecording,canStart:!c.state.isRecording&&c.state.status!=="completed"},errorMessage:c.state.error??void 0,labels:A,partial:c.state.partial||void 0,statusLabel:y,theme:g,title:c.title??"Voice"}},Kc=(c)=>typeof c==="number"?`${c}px`:c,u=(c)=>{let g=c.theme,A=`background:${g.background};border-radius:${Kc(g.radius)};color:${g.foreground};font-family:${g.fontFamily};min-width:240px;padding:20px 22px;`,n=`background:${c.errorMessage?g.errorAccent:c.agentState==="idle"?"rgba(148,163,184,0.6)":g.accent};border-radius:50%;height:10px;width:10px;`,T=[];if(c.controls.canStart)T.push(`<button type="button" data-action="start" style="background:${g.accent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${i(c.labels.startCall)}</button>`);if(c.controls.canMute)T.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${i(c.labels.mute)}</button>`);if(c.controls.canEnd)T.push(`<button type="button" data-action="end" style="background:${g.errorAccent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${i(c.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${c.agentState}" class="${i(c.classes.container)}" style="${A}">
|
|
1
|
+
(()=>{var{defineProperty:Q,getOwnPropertyNames:Ic,getOwnPropertyDescriptor:Vc}=Object,Sc=Object.prototype.hasOwnProperty;function Rc(c){return this[c]}var yc=(c)=>{var g=(z??=new WeakMap).get(c),C;if(g)return g;if(g=Q({},"__esModule",{value:!0}),c&&typeof c==="object"||typeof c==="function"){for(var A of Ic(c))if(!Sc.call(g,A))Q(g,A,{get:Rc.bind(c,A),enumerable:!(C=Vc(c,A))||C.enumerable})}return z.set(c,g),g},z;var _c=(c)=>c;function Tc(c,g){this[c]=_c.bind(null,g)}var wc=(c,g)=>{for(var C in g)Q(c,C,{get:g[C],enumerable:!0,configurable:!0,set:Tc.bind(g,C)})};var Fc={};wc(Fc,{mount:()=>cc,default:()=>oc,VOICE_EMBED_VERSION:()=>gc});var hc=(c)=>{if(typeof c!=="string")return c;return document.querySelector(c)},Lc=(c,g,C,A)=>{let I=g??c.getAttribute("hx-get")??"";if(!I)return"";let R=new URL(I,window.location.origin);if(A)R.searchParams.set(C,A);else R.searchParams.delete(C);return`${R.pathname}${R.search}${R.hash}`},B=(c,g)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=hc(g.element);if(!C)return()=>{};let A=g.eventName??"voice-refresh",I=g.sessionQueryParam??"sessionId",R=()=>{let T=window,w=Lc(C,g.route,I,c.sessionId);if(w)C.setAttribute("hx-get",w);T.htmx?.process?.(C),T.htmx?.trigger?.(C,A)},S=c.subscribe(R);return R(),()=>{S()}};var Uc=(c)=>Math.max(-1,Math.min(1,c)),$c=(c)=>{let g=new Int16Array(c.length);for(let C=0;C<c.length;C+=1){let A=Uc(c[C]??0);g[C]=A<0?A*32768:A*32767}return new Uint8Array(g.buffer)},nc=(c)=>{let g=c instanceof Uint8Array?c:new Uint8Array(c);if(g.byteLength<2)return 0;let C=new Int16Array(g.buffer,g.byteOffset,Math.floor(g.byteLength/2));if(C.length===0)return 0;let A=0;for(let I of C){let R=I/32768;A+=R*R}return Math.min(1,Math.max(0,Math.sqrt(A/C.length)*5.5))},Oc=(c,g,C)=>{if(g===C)return c;let A=g/C,I=Math.round(c.length/A),R=new Float32Array(I),S=0,T=0;while(S<R.length){let w=Math.round((S+1)*A),U=0,_=0;for(let L=T;L<w&&L<c.length;L+=1)U+=c[L]??0,_+=1;R[S]=_>0?U/_:0,S+=1,T=w}return R},j=(c)=>{let g=null,C=null,A=null,I=null;return{start:async()=>{if(!c.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let T=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!T)throw Error("Browser microphone capture requires AudioContext support.");if(I=c.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:c.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),g=new T,g.state==="suspended")await g.resume();C=g.createMediaStreamSource(I),A=g.createScriptProcessor(4096,1,1),A.onaudioprocess=(w)=>{let U=w.inputBuffer.getChannelData(0),_=Oc(U,g?.sampleRate??48000,c.sampleRateHz??16000),L=$c(_);c.onLevel?.(nc(L)),c.onAudio(L)},C.connect(A),A.connect(g.destination)},stop:()=>{A?.disconnect(),C?.disconnect(),I?.getTracks().forEach((T)=>T.stop()),g?.close(),c.onLevel?.(0),g=null,I=null,A=null,C=null}}};var K=(c)=>{if(typeof c==="string"&&c.trim())return c;if(c instanceof Error&&c.message.trim())return c.message;if(c&&typeof c==="object"){let g=c;for(let C of["message","reason","description"]){let A=g[C];if(typeof A==="string"&&A.trim())return A}if("error"in g)return K(g.error);if("cause"in g)return K(g.cause);try{return JSON.stringify(c)}catch{}}return"Unexpected error"},d=(c)=>{switch(c.type){case"audio":return{chunk:Uint8Array.from(atob(c.chunkBase64),(g)=>g.charCodeAt(0)),format:c.format,receivedAt:c.receivedAt,turnId:c.turnId,type:"audio"};case"assistant":return{text:c.text,turnId:c.turnId,type:"assistant"};case"assistant_delta":return{delta:c.delta,turnId:c.turnId,type:"assistant_delta"};case"complete":return{sessionId:c.sessionId,type:"complete"};case"connection":return{reconnect:c.reconnect,type:"connection"};case"call_lifecycle":return{event:c.event,sessionId:c.sessionId,type:"call_lifecycle"};case"error":return{message:K(c.message),type:"error"};case"final":return{transcript:c.transcript,type:"final"};case"partial":return{transcript:c.transcript,type:"partial"};case"replay":return{assistantTexts:c.assistantTexts,call:c.call,partial:c.partial,scenarioId:c.scenarioId,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,status:c.status,turns:c.turns,type:"replay"};case"session":return{sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,type:"session"};case"turn":return{turn:c.turn,type:"turn"};default:return null}};var tc=Math.PI*2;var N=(c,g,C,A)=>{c.push({code:C,message:A,severity:g})};var bc=(c)=>c.length===0?void 0:c.reduce((g,C)=>g+C,0)/c.length,J=(c)=>c.length===0?void 0:Math.max(...c);var n=(c,g)=>{let C=c[g];return typeof C==="number"&&Number.isFinite(C)?C:void 0},Y=(c,g)=>{let C=c[g];return typeof C==="boolean"?C:void 0},O=(c,g)=>{let C=c[g];return typeof C==="string"?C:void 0},q=(c)=>String(c.id??O(c,"ssrc")??n(c,"ssrc")??O(c,"trackIdentifier")??O(c,"mid")??"unknown"),k=(c)=>c===void 0?void 0:c*1000;var Dc=(c)=>{let g={};for(let[C,A]of Object.entries(c))if(A===null||typeof A==="boolean"||typeof A==="number"||typeof A==="string")g[C]=A;return g};var x=(c={})=>{let g=c.stats??[],C=[],A=g.filter((V)=>V.type==="inbound-rtp"&&O(V,"kind")!=="video"),I=g.filter((V)=>V.type==="outbound-rtp"&&O(V,"kind")!=="video"),R=g.filter((V)=>V.type==="candidate-pair"),S=g.filter((V)=>(V.type==="track"||V.type==="media-source")&&O(V,"kind")==="audio"),T=R.filter((V)=>Y(V,"selected")===!0||Y(V,"nominated")===!0||O(V,"state")==="succeeded").length,w=S.filter((V)=>O(V,"readyState")!=="ended"&&O(V,"trackState")!=="ended"&&Y(V,"ended")!==!0).length,U=S.filter((V)=>O(V,"readyState")==="ended"||O(V,"trackState")==="ended"||Y(V,"ended")===!0).length,_=A.reduce((V,$)=>V+(n($,"packetsReceived")??0),0),L=I.reduce((V,$)=>V+(n($,"packetsSent")??0),0),y=[...A,...I].reduce((V,$)=>V+Math.max(0,n($,"packetsLost")??0),0),b=_+y,h=b===0?0:y/b,E=A.reduce((V,$)=>V+(n($,"bytesReceived")??0),0),H=I.reduce((V,$)=>V+(n($,"bytesSent")??0),0),G=J(R.map((V)=>k(n(V,"currentRoundTripTime")??n(V,"roundTripTime"))).filter((V)=>V!==void 0)),M=J([...A,...I].map((V)=>k(n(V,"jitter"))).filter((V)=>V!==void 0)),X=J(A.map((V)=>{let $=n(V,"jitterBufferDelay"),D=n(V,"jitterBufferEmittedCount");return $!==void 0&&D!==void 0&&D>0?$/D*1000:void 0}).filter((V)=>V!==void 0)),P=S.map((V)=>n(V,"audioLevel")).filter((V)=>V!==void 0);if(c.requireConnectedCandidatePair&&R.length>0&&T===0)N(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(c.requireLiveAudioTrack&&w===0)N(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(c.maxPacketLossRatio!==void 0&&h>c.maxPacketLossRatio)N(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(h)} above ${String(c.maxPacketLossRatio)}.`);if(c.maxRoundTripTimeMs!==void 0&&G!==void 0&&G>c.maxRoundTripTimeMs)N(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(G)}ms above ${String(c.maxRoundTripTimeMs)}ms.`);if(c.maxJitterMs!==void 0&&M!==void 0&&M>c.maxJitterMs)N(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(M)}ms above ${String(c.maxJitterMs)}ms.`);return{activeCandidatePairs:T,audioLevelAverage:bc(P),bytesReceived:E,bytesSent:H,checkedAt:Date.now(),endedAudioTracks:U,inboundPackets:_,issues:C,jitterBufferDelayMs:X,jitterMs:M,liveAudioTracks:w,outboundPackets:L,packetLossRatio:h,packetsLost:y,roundTripTimeMs:G,status:C.some((V)=>V.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:g.length}},i=async(c)=>{return[...(await c.peerConnection.getStats(c.selector??null)).values()].map(Dc)};var f=(c={})=>{let g=c.stats??[],C=c.previousStats??[],A=[],I=new Map(C.map((y)=>[q(y),y])),S=g.filter((y)=>(y.type==="inbound-rtp"||y.type==="outbound-rtp")&&O(y,"kind")!=="video"&&O(y,"mediaType")!=="video").map((y)=>{let b=y.type==="outbound-rtp"?"outbound":"inbound",h=b==="outbound"?"packetsSent":"packetsReceived",E=b==="outbound"?"bytesSent":"bytesReceived",H=I.get(q(y)),G=n(y,h),M=H?n(H,h):void 0,X=n(y,E),P=H?n(H,E):void 0,V=y.timestamp!==void 0&&H?.timestamp!==void 0?y.timestamp-H.timestamp:void 0;return{bytesDelta:X!==void 0&&P!==void 0?X-P:void 0,currentPackets:G,direction:b,id:q(y),packetDelta:G!==void 0&&M!==void 0?G-M:void 0,previousPackets:M,timeDeltaMs:V}}),T=S.filter((y)=>y.direction==="inbound"),w=S.filter((y)=>y.direction==="outbound"),U=J(S.map((y)=>y.timeDeltaMs).filter((y)=>y!==void 0)),_=T.filter((y)=>c.maxInboundPacketStallMs!==void 0&&y.timeDeltaMs!==void 0&&y.timeDeltaMs>=c.maxInboundPacketStallMs&&y.packetDelta!==void 0&&y.packetDelta<=0).length,L=w.filter((y)=>c.maxOutboundPacketStallMs!==void 0&&y.timeDeltaMs!==void 0&&y.timeDeltaMs>=c.maxOutboundPacketStallMs&&y.packetDelta!==void 0&&y.packetDelta<=0).length;if(c.requireInboundAudio&&T.length===0)N(A,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(c.requireOutboundAudio&&w.length===0)N(A,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(c.maxGapMs!==void 0&&U!==void 0&&U>c.maxGapMs)N(A,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(U)}ms above ${String(c.maxGapMs)}ms.`);if(_>0)N(A,"error","media.webrtc_inbound_stalled",`${String(_)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(L>0)N(A,"error","media.webrtc_outbound_stalled",`${String(L)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:T.length,issues:A,maxObservedGapMs:U,outboundAudioStreams:w.length,stalledInboundStreams:_,stalledOutboundStreams:L,status:A.some((y)=>y.severity==="error")?"fail":A.length>0?"warn":"pass",streams:S,totalStats:g.length}};var Hc="/api/voice/browser-media",Gc=5000,Mc=async(c)=>c.peerConnection??await c.getPeerConnection?.()??null,Nc=async(c,g)=>{let C=g.fetch??globalThis.fetch;if(!C)return;await C(g.path??Hc,{body:JSON.stringify(c),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},F=(c)=>{let g=null,C=[],A=async()=>{let S=await Mc(c);if(!S)return;let T=await i({peerConnection:S}),w=x({...c,stats:T}),U=c.continuity===!1?void 0:f({...c.continuity,previousStats:C,stats:T}),_={at:Date.now(),continuity:U,report:w,scenarioId:c.getScenarioId?.()??null,sessionId:c.getSessionId?.()??null};return C=T,c.onReport?.(_),await Nc(_,c),_},I=()=>{A().catch((S)=>{c.onError?.(S)})},R=()=>{if(g)clearInterval(g),g=null};return{close:R,reportOnce:A,stop:R,start:()=>{if(g)return;I(),g=setInterval(I,c.intervalMs??Gc)}}};var W=()=>{},lc=()=>W,Wc={callControl:W,close:W,endTurn:W,send:W,sendAudio:W,simulateDisconnect:W,subscribe:lc,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},Ec=()=>crypto.randomUUID(),Xc=(c,g,C)=>{let{hostname:A,port:I,protocol:R}=window.location,S=R==="https:"?"wss:":"ws:",T=I?`:${I}`:"",w=new URL(`${S}//${A}${T}${c}`);if(w.searchParams.set("sessionId",g),C)w.searchParams.set("scenarioId",C);return w.toString()},Pc=(c)=>{if(!c||typeof c!=="object"||!("type"in c))return!1;switch(c.type){case"audio":case"assistant":case"call_lifecycle":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},Yc=(c)=>{if(typeof c.data!=="string")return null;try{let g=JSON.parse(c.data);return Pc(g)?g:null}catch{return null}},o=(c,g={})=>{if(typeof window>"u")return Wc;let C=new Set,A=g.reconnect!==!1,I=g.maxReconnectAttempts??10,R=g.pingInterval??30000,S={isConnected:!1,pendingMessages:[],scenarioId:g.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:g.sessionId??Ec(),ws:null},T=(V)=>{C.forEach(($)=>$(V))},w=()=>{if(S.pingInterval)clearInterval(S.pingInterval),S.pingInterval=null;if(S.reconnectTimeout)clearTimeout(S.reconnectTimeout),S.reconnectTimeout=null},U=()=>{if(S.ws?.readyState!==1)return;while(S.pendingMessages.length>0){let V=S.pendingMessages.shift();if(V!==void 0)S.ws.send(V)}},_=()=>{let V=Date.now()+500;S.reconnectAttempts+=1,T({reconnect:{attempts:S.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:I,nextAttemptAt:V,status:"reconnecting"},type:"connection"}),S.reconnectTimeout=setTimeout(()=>{if(S.reconnectAttempts>I){T({reconnect:{attempts:S.reconnectAttempts,maxAttempts:I,status:"exhausted"},type:"connection"});return}L()},500)},L=()=>{let V=new WebSocket(Xc(c,S.sessionId,S.scenarioId));V.binaryType="arraybuffer",V.onopen=()=>{let $=S.reconnectAttempts>0;if(S.isConnected=!0,U(),$)T({reconnect:{attempts:S.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:I,status:"resumed"},type:"connection"}),S.reconnectAttempts=0;C.forEach((D)=>D({scenarioId:S.scenarioId??void 0,sessionId:S.sessionId,status:"active",type:"session"})),S.pingInterval=setInterval(()=>{if(V.readyState===1)V.send(JSON.stringify({type:"ping"}))},R)},V.onmessage=($)=>{let D=Yc($);if(!D)return;if(D.type==="session")S.sessionId=D.sessionId,S.scenarioId=D.scenarioId??S.scenarioId;C.forEach((Cc)=>Cc(D))},V.onclose=($)=>{if(S.isConnected=!1,w(),A&&$.code!==1000&&S.reconnectAttempts<I)_();else if(A&&$.code!==1000)T({reconnect:{attempts:S.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:I,status:"exhausted"},type:"connection"})},S.ws=V},y=(V)=>{if(S.ws?.readyState===1){S.ws.send(V);return}S.pendingMessages.push(V)},b=(V)=>{y(JSON.stringify(V))},h=(V={})=>{if(V.sessionId)S.sessionId=V.sessionId;if(V.scenarioId)S.scenarioId=V.scenarioId;b({scenarioId:S.scenarioId??void 0,sessionId:S.sessionId,type:"start"})},E=(V)=>{y(V)},H=()=>{b({type:"end_turn"})},G=(V)=>{b({...V,type:"call_control"})},M=()=>{if(w(),S.ws)S.ws.close(1000),S.ws=null;S.isConnected=!1,C.clear()},X=()=>{if(S.ws?.readyState===1)S.ws.close(4000,"absolutejs-voice-reconnect-proof")},P=(V)=>{return C.add(V),()=>{C.delete(V)}};return L(),{callControl:G,close:M,endTurn:H,send:b,sendAudio:E,simulateDisconnect:X,start:h,subscribe:P,getReadyState:()=>S.ws?.readyState??3,getScenarioId:()=>S.scenarioId??"",getSessionId:()=>S.sessionId}};var Jc=()=>({attempts:0,maxAttempts:0,status:"idle"}),Zc=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:Jc(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),s=()=>{let c=Zc(),g=new Set,C=()=>{g.forEach((I)=>I())};return{dispatch:(I)=>{switch(I.type){case"audio":c={...c,assistantAudio:[...c.assistantAudio,{chunk:I.chunk,format:I.format,receivedAt:I.receivedAt,turnId:I.turnId}]};break;case"assistant":c={...c,assistantStreamingText:"",assistantTexts:[...c.assistantTexts,I.text]};break;case"assistant_delta":c={...c,assistantStreamingText:`${c.assistantStreamingText}${I.delta}`};break;case"complete":c={...c,sessionId:I.sessionId,status:"completed"};break;case"call_lifecycle":c={...c,call:{...c.call,disposition:I.event.type==="end"?I.event.disposition:c.call?.disposition,endedAt:I.event.type==="end"?I.event.at:c.call?.endedAt,events:[...c.call?.events??[],I.event],lastEventAt:I.event.at,startedAt:c.call?.startedAt??I.event.at},sessionId:I.sessionId};break;case"connected":c={...c,isConnected:!0,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect};break;case"connection":c={...c,reconnect:I.reconnect};break;case"disconnected":c={...c,isConnected:!1};break;case"error":c={...c,error:I.message};break;case"final":c={...c,partial:I.transcript.text,turns:c.turns.map((R)=>R)};break;case"partial":c={...c,partial:I.transcript.text};break;case"replay":c={...c,assistantStreamingText:"",assistantTexts:[...I.assistantTexts],call:I.call??null,error:null,isConnected:I.status==="active",partial:I.partial,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect,scenarioId:I.scenarioId??c.scenarioId,sessionId:I.sessionId,sessionMetadata:I.sessionMetadata??c.sessionMetadata,status:I.status,turns:[...I.turns]};break;case"session":c={...c,error:null,scenarioId:I.scenarioId??c.scenarioId,isConnected:I.status==="active",sessionId:I.sessionId,sessionMetadata:I.sessionMetadata??c.sessionMetadata,status:I.status};break;case"turn":c={...c,partial:"",turns:[...c.turns,I.turn]};break}C()},getServerSnapshot:()=>c,getSnapshot:()=>c,subscribe:(I)=>{return g.add(I),()=>{g.delete(I)}}}};var v=(c,g={})=>{let C=o(c,g),A=s(),I=g.browserMedia&&typeof window<"u"?F({...g.browserMedia,getScenarioId:()=>g.browserMedia?g.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>g.browserMedia?g.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,R=new Set,S=(_)=>Promise.resolve().then(()=>{if(!_?.sessionId&&!_?.scenarioId)return;C.start(_),I?.start()}),T=()=>{R.forEach((_)=>_())},w=()=>{if(!g.reconnectReportPath||typeof fetch>"u")return;let _=A.getSnapshot(),L=JSON.stringify({at:Date.now(),reconnect:_.reconnect,scenarioId:_.scenarioId,sessionId:C.getSessionId(),turnIds:_.turns.map((y)=>y.id)});fetch(g.reconnectReportPath,{body:L,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},U=C.subscribe((_)=>{let L=d(_);if(L){if(A.dispatch(L),_.type==="connection")w();T()}});return{start:S,get assistantAudio(){return A.getSnapshot().assistantAudio},get assistantTexts(){return A.getSnapshot().assistantTexts},get assistantStreamingText(){return A.getSnapshot().assistantStreamingText},get call(){return A.getSnapshot().call},callControl(_){C.callControl(_)},close(){U(),I?.close(),C.close(),A.dispatch({type:"disconnected"}),T()},endTurn(){C.endTurn()},get error(){return A.getSnapshot().error},getServerSnapshot(){return A.getServerSnapshot()},getSnapshot(){return A.getSnapshot()},get isConnected(){return A.getSnapshot().isConnected},get partial(){return A.getSnapshot().partial},get reconnect(){return A.getSnapshot().reconnect},get scenarioId(){return A.getSnapshot().scenarioId},sendAudio(_){C.sendAudio(_)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return A.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return A.getSnapshot().status},subscribe(_){return R.add(_),()=>{R.delete(_)}},get turns(){return A.getSnapshot().turns}}};var a=(c)=>{if(!c||c.enabled===!1)return;return{enabled:!0,maxGain:c.maxGain??3,noiseGateAttenuation:c.noiseGateAttenuation??0.15,noiseGateThreshold:c.noiseGateThreshold??0.006,targetLevel:c.targetLevel??0.08}};var Z=1200;var Qc={balanced:{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:Z,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:Z,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:Z,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},Kc={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}},qc="fast",zc="general",r=(c)=>{let g=c?.profile??qc,C=c?.qualityProfile??zc,A=Qc[g],I=Kc[C];return{profile:g,qualityProfile:C,semanticVetoMaxMs:c?.semanticVetoMaxMs??A.semanticVetoMaxMs,semanticVetoRecheckMs:c?.semanticVetoRecheckMs??A.semanticVetoRecheckMs,silenceMs:c?.silenceMs??I.silenceMs??A.silenceMs,speechThreshold:c?.speechThreshold??I.speechThreshold??A.speechThreshold,transcriptStabilityMs:c?.transcriptStabilityMs??I.transcriptStabilityMs??A.transcriptStabilityMs}};var Bc={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},t=(c="default")=>{let g=Bc[c];return{audioConditioning:a(g.audioConditioning),capture:{channelCount:g.capture?.channelCount??1,sampleRateHz:g.capture?.sampleRateHz??16000},connection:{...g.connection},name:c,sttLifecycle:g.sttLifecycle??"continuous",turnDetection:r(g.turnDetection)}};var jc=(c)=>({assistantAudio:[...c.assistantAudio],assistantStreamingText:c.assistantStreamingText,assistantTexts:[...c.assistantTexts],call:c.call,error:c.error,isConnected:c.isConnected,isRecording:!1,partial:c.partial,reconnect:c.reconnect,recordingError:null,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,turns:[...c.turns]}),e=(c,g={})=>{let C=t(g.preset),A=v(c,{...C.connection,...g.connection}),I=null,R=jc(A),S=new Set,T=()=>{for(let h of S)h()},w=()=>{if(R={...R,assistantAudio:[...A.assistantAudio],assistantStreamingText:A.assistantStreamingText,assistantTexts:[...A.assistantTexts],call:A.call,error:A.error,isConnected:A.isConnected,partial:A.partial,reconnect:A.reconnect,sessionId:A.sessionId,sessionMetadata:A.sessionMetadata,scenarioId:A.scenarioId,status:A.status,turns:[...A.turns]},g.autoStopOnComplete!==!1&&R.status==="completed"&&R.isRecording)I?.stop(),I=null,R={...R,isRecording:!1};T()},U=A.subscribe(w);w();let _=()=>{if(I)return I;return I=j({channelCount:g.capture?.channelCount??C.capture.channelCount,onLevel:g.capture?.onLevel,onAudio:(h)=>{if(g.capture?.onAudio){g.capture.onAudio(h,A.sendAudio);return}A.sendAudio(h)},sampleRateHz:g.capture?.sampleRateHz??C.capture.sampleRateHz,...g.capture?.stream?{stream:g.capture.stream}:{}}),I},L=()=>{I?.stop(),I=null,R={...R,isRecording:!1},T()},y=async()=>{if(R.isRecording)return;try{R={...R,recordingError:null},T(),await _().start(),R={...R,isRecording:!0},T()}catch(h){throw I=null,R={...R,isRecording:!1,recordingError:h instanceof Error?h.message:String(h)},T(),h}};return{close:()=>{U(),L(),A.close()},startRecording:y,stopRecording:L,get assistantAudio(){return R.assistantAudio},get assistantTexts(){return R.assistantTexts},get assistantStreamingText(){return R.assistantStreamingText},bindHTMX(h){return B(A,h)},get call(){return R.call},callControl:(h)=>A.callControl(h),endTurn:()=>A.endTurn(),get error(){return R.error},getServerSnapshot:()=>R,getSnapshot:()=>R,get isConnected(){return R.isConnected},get isRecording(){return R.isRecording},get partial(){return R.partial},get reconnect(){return R.reconnect},get recordingError(){return R.recordingError},get scenarioId(){return R.scenarioId},sendAudio:(h)=>A.sendAudio(h),get sessionId(){return R.sessionId},get sessionMetadata(){return R.sessionMetadata},simulateDisconnect:()=>A.simulateDisconnect(),get status(){return R.status},subscribe:(h)=>{return S.add(h),()=>{S.delete(h)}},toggleRecording:async()=>{if(R.isRecording){L();return}await y()},get turns(){return R.turns}}};var l=(c)=>String(c).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var m=(c)=>{if(!c.isConnected)return"idle";if(c.isPlaying)return"speaking";if(c.isRecording&&c.hasActivePartial)return"listening";if(c.isRecording)return"listening";if(c.lastTranscriptAt&&!c.lastAssistantAt)return"thinking";if(c.lastTranscriptAt&&c.lastAssistantAt&&c.lastTranscriptAt>c.lastAssistantAt)return"thinking";return"idle"};var dc={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},kc={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},xc=(c,g)=>{switch(c){case"listening":return g.listening;case"speaking":return g.speaking;case"thinking":return g.thinking;case"idle":return g.idle}},u=(c)=>{let g={...dc,...c.theme},C={...kc,...c.labels},A=c.state.assistantAudio.at(-1)?.receivedAt,I=c.state.turns.at(-1)?.committedAt,R=m({hasActivePartial:c.state.partial.length>0,isConnected:c.state.isConnected,isPlaying:!1,isRecording:c.state.isRecording,lastAssistantAt:A,lastTranscriptAt:I}),S=!c.state.isConnected&&c.state.status!=="idle"&&!c.state.error,T=c.state.error?"Error":S?C.connecting:c.state.status==="completed"?C.callEnded:xc(R,C);return{agentState:R,classes:{container:`absolute-voice-widget absolute-voice-widget--${R}`,dot:`absolute-voice-widget__dot${c.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:c.state.isConnected,canMute:c.state.isRecording,canStart:!c.state.isRecording&&c.state.status!=="completed"},errorMessage:c.state.error??void 0,labels:C,partial:c.state.partial||void 0,statusLabel:T,theme:g,title:c.title??"Voice"}},ic=(c)=>typeof c==="number"?`${c}px`:c,p=(c)=>{let g=c.theme,C=`background:${g.background};border-radius:${ic(g.radius)};color:${g.foreground};font-family:${g.fontFamily};min-width:240px;padding:20px 22px;`,A=`background:${c.errorMessage?g.errorAccent:c.agentState==="idle"?"rgba(148,163,184,0.6)":g.accent};border-radius:50%;height:10px;width:10px;`,I=[];if(c.controls.canStart)I.push(`<button type="button" data-action="start" style="background:${g.accent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${l(c.labels.startCall)}</button>`);if(c.controls.canMute)I.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${l(c.labels.mute)}</button>`);if(c.controls.canEnd)I.push(`<button type="button" data-action="end" style="background:${g.errorAccent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${l(c.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${c.agentState}" class="${l(c.classes.container)}" style="${C}">
|
|
2
2
|
<div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
|
|
3
|
-
<span aria-hidden="true" class="${
|
|
4
|
-
<strong style="font-size:15px;">${
|
|
5
|
-
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${
|
|
3
|
+
<span aria-hidden="true" class="${l(c.classes.dot)}" style="${A}"></span>
|
|
4
|
+
<strong style="font-size:15px;">${l(c.title)}</strong>
|
|
5
|
+
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${l(c.statusLabel)}</span>
|
|
6
6
|
</div>
|
|
7
|
-
${c.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${
|
|
8
|
-
<div style="display:flex;gap:10px;">${
|
|
9
|
-
${c.errorMessage?`<p style="color:${g.errorAccent};font-size:12px;margin-top:12px;">${
|
|
10
|
-
</div>`};var
|
|
7
|
+
${c.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${l(c.partial)}”</p>`:""}
|
|
8
|
+
<div style="display:flex;gap:10px;">${I.join("")}</div>
|
|
9
|
+
${c.errorMessage?`<p style="color:${g.errorAccent};font-size:12px;margin-top:12px;">${l(c.errorMessage)}</p>`:""}
|
|
10
|
+
</div>`};var fc=(c)=>{if(typeof c!=="string")return c;let g=document.querySelector(c);if(!g)throw Error(`AbsoluteVoice.mount: no element matches "${c}"`);return g},cc=(c,g={})=>{let C=fc(c),A=e(g.path??"/voice",g.controllerOptions),I=null,R=null,S=()=>{let w=u({...g.labels!==void 0?{labels:g.labels}:{},state:{assistantAudio:A.assistantAudio,error:A.error,isConnected:A.isConnected,isRecording:A.isRecording,partial:A.partial,status:A.status,turns:A.turns},...g.theme!==void 0?{theme:g.theme}:{},...g.title!==void 0?{title:g.title}:{}});C.innerHTML=p(w);for(let U of C.querySelectorAll("button[data-action]")){let{action:_}=U.dataset;U.addEventListener("click",()=>{if(_==="start")A.startRecording();else if(_==="mute")A.stopRecording();else if(_==="end")A.close()})}if(A.error&&A.error!==I)I=A.error,g.onError?.(A.error);if(A.status!==R)R=A.status,g.onStatusChange?.(A.status)},T=A.subscribe(S);if(S(),g.autoStart)A.startRecording();return{controller:A,async end(){await A.close()},mute(){A.stopRecording()},async start(){await A.startRecording()},unmount(){T(),A.close(),C.innerHTML=""}}},gc="0.0.22-beta.516",Ac={mount:cc,version:gc};if(typeof globalThis<"u")globalThis.AbsoluteVoice=Ac;var oc=Ac;})();
|