@absolutejs/voice 0.0.22-beta.598 → 0.0.22-beta.599
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 +6 -127
- package/dist/client/htmxBootstrap.js +6 -12
- package/dist/client/index.js +6 -127
- package/dist/core/turnDetection.d.ts +1 -1
- package/dist/core/types.d.ts +2 -4
- package/dist/embed/index.js +6 -12
- package/dist/embed/voice-widget.js +8 -8
- package/dist/index.js +158 -184
- package/dist/react/index.js +6 -127
- package/dist/svelte/index.js +6 -127
- package/dist/testing/index.js +29 -57
- package/dist/vue/index.js +6 -127
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -1227,146 +1227,25 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1227
1227
|
};
|
|
1228
1228
|
};
|
|
1229
1229
|
|
|
1230
|
-
// src/core/turnDetection.ts
|
|
1231
|
-
var DEFAULT_SILENCE_MS = 700;
|
|
1232
|
-
var DEFAULT_SPEECH_THRESHOLD = 0.015;
|
|
1233
|
-
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1234
|
-
var toUint8Array = (audio) => {
|
|
1235
|
-
if (audio instanceof ArrayBuffer) {
|
|
1236
|
-
return new Uint8Array(audio);
|
|
1237
|
-
}
|
|
1238
|
-
return new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
1239
|
-
};
|
|
1240
|
-
var measureAudioLevel = (audio) => {
|
|
1241
|
-
const bytes = toUint8Array(audio);
|
|
1242
|
-
if (bytes.byteLength < 2) {
|
|
1243
|
-
return 0;
|
|
1244
|
-
}
|
|
1245
|
-
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
1246
|
-
if (samples.length === 0) {
|
|
1247
|
-
return 0;
|
|
1248
|
-
}
|
|
1249
|
-
let sumSquares = 0;
|
|
1250
|
-
for (const sample of samples) {
|
|
1251
|
-
const normalized = sample / 32768;
|
|
1252
|
-
sumSquares += normalized * normalized;
|
|
1253
|
-
}
|
|
1254
|
-
return Math.sqrt(sumSquares / samples.length);
|
|
1255
|
-
};
|
|
1256
|
-
var normalizeText = (value) => value.trim().replace(/\s+/g, " ");
|
|
1257
|
-
var countWords = (value) => value.length > 0 ? value.split(" ").length : 0;
|
|
1258
|
-
var selectPreferredTranscriptText = (currentText, nextText) => {
|
|
1259
|
-
const current = normalizeText(currentText);
|
|
1260
|
-
const next = normalizeText(nextText);
|
|
1261
|
-
if (!current) {
|
|
1262
|
-
return next;
|
|
1263
|
-
}
|
|
1264
|
-
if (!next) {
|
|
1265
|
-
return current;
|
|
1266
|
-
}
|
|
1267
|
-
if (current === next || current.includes(next)) {
|
|
1268
|
-
return current;
|
|
1269
|
-
}
|
|
1270
|
-
if (next.includes(current)) {
|
|
1271
|
-
return next;
|
|
1272
|
-
}
|
|
1273
|
-
if (countWords(next) > countWords(current)) {
|
|
1274
|
-
return next;
|
|
1275
|
-
}
|
|
1276
|
-
if (countWords(next) === countWords(current) && next.length > current.length) {
|
|
1277
|
-
return next;
|
|
1278
|
-
}
|
|
1279
|
-
return current;
|
|
1280
|
-
};
|
|
1281
|
-
var mergeSequentialTranscriptText = (currentText, nextText) => {
|
|
1282
|
-
const current = normalizeText(currentText);
|
|
1283
|
-
const next = normalizeText(nextText);
|
|
1284
|
-
if (!current) {
|
|
1285
|
-
return next;
|
|
1286
|
-
}
|
|
1287
|
-
if (!next) {
|
|
1288
|
-
return current;
|
|
1289
|
-
}
|
|
1290
|
-
const currentWords = current.split(" ");
|
|
1291
|
-
const nextWords = next.split(" ");
|
|
1292
|
-
const maxOverlap = Math.min(currentWords.length, nextWords.length);
|
|
1293
|
-
for (let overlap = maxOverlap;overlap > 0; overlap -= 1) {
|
|
1294
|
-
const currentSuffix = currentWords.slice(-overlap).join(" ");
|
|
1295
|
-
const nextPrefix = nextWords.slice(0, overlap).join(" ");
|
|
1296
|
-
if (currentSuffix === nextPrefix) {
|
|
1297
|
-
return [...currentWords, ...nextWords.slice(overlap)].join(" ");
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
return `${current} ${next}`.trim();
|
|
1301
|
-
};
|
|
1302
|
-
var countCommonPrefixWords = (currentText, nextText) => {
|
|
1303
|
-
const currentWords = normalizeText(currentText).split(" ").filter(Boolean);
|
|
1304
|
-
const nextWords = normalizeText(nextText).split(" ").filter(Boolean);
|
|
1305
|
-
const maxWords = Math.min(currentWords.length, nextWords.length);
|
|
1306
|
-
let count = 0;
|
|
1307
|
-
for (let index = 0;index < maxWords; index += 1) {
|
|
1308
|
-
if (currentWords[index] !== nextWords[index]) {
|
|
1309
|
-
break;
|
|
1310
|
-
}
|
|
1311
|
-
count += 1;
|
|
1312
|
-
}
|
|
1313
|
-
return count;
|
|
1314
|
-
};
|
|
1315
|
-
var mergeTranscriptTexts = (transcripts) => {
|
|
1316
|
-
const merged = [];
|
|
1317
|
-
for (const transcript of transcripts) {
|
|
1318
|
-
const nextText = normalizeText(transcript.text);
|
|
1319
|
-
if (!nextText) {
|
|
1320
|
-
continue;
|
|
1321
|
-
}
|
|
1322
|
-
const previous = merged.at(-1);
|
|
1323
|
-
if (!previous) {
|
|
1324
|
-
merged.push(nextText);
|
|
1325
|
-
continue;
|
|
1326
|
-
}
|
|
1327
|
-
if (nextText === previous || previous.includes(nextText)) {
|
|
1328
|
-
continue;
|
|
1329
|
-
}
|
|
1330
|
-
if (nextText.includes(previous)) {
|
|
1331
|
-
merged[merged.length - 1] = nextText;
|
|
1332
|
-
continue;
|
|
1333
|
-
}
|
|
1334
|
-
merged.push(nextText);
|
|
1335
|
-
}
|
|
1336
|
-
return merged.join(" ").trim();
|
|
1337
|
-
};
|
|
1338
|
-
var buildTurnText = (transcripts, partialText, options = {}) => {
|
|
1339
|
-
const finalText = mergeTranscriptTexts(transcripts);
|
|
1340
|
-
const nextPartial = normalizeText(partialText);
|
|
1341
|
-
const lastFinalEndedAtMs = [...transcripts].reverse().find((transcript) => typeof transcript.endedAtMs === "number")?.endedAtMs;
|
|
1342
|
-
if (finalText && nextPartial && typeof lastFinalEndedAtMs === "number" && typeof options.partialStartedAtMs === "number" && options.partialStartedAtMs - lastFinalEndedAtMs >= 250 && countCommonPrefixWords(finalText, nextPartial) === 0) {
|
|
1343
|
-
return mergeSequentialTranscriptText(finalText, nextPartial);
|
|
1344
|
-
}
|
|
1345
|
-
return selectPreferredTranscriptText(finalText, nextPartial);
|
|
1346
|
-
};
|
|
1347
|
-
|
|
1348
1230
|
// src/core/turnProfiles.ts
|
|
1349
1231
|
var TURN_PROFILE_DEFAULTS = {
|
|
1350
1232
|
balanced: {
|
|
1351
1233
|
qualityProfile: "general",
|
|
1352
|
-
|
|
1353
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1234
|
+
minSilenceMs: 400,
|
|
1354
1235
|
silenceMs: 1400,
|
|
1355
1236
|
speechThreshold: 0.012,
|
|
1356
1237
|
transcriptStabilityMs: 1000
|
|
1357
1238
|
},
|
|
1358
1239
|
fast: {
|
|
1359
1240
|
qualityProfile: "general",
|
|
1360
|
-
|
|
1361
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1241
|
+
minSilenceMs: 300,
|
|
1362
1242
|
silenceMs: 700,
|
|
1363
1243
|
speechThreshold: 0.015,
|
|
1364
1244
|
transcriptStabilityMs: 450
|
|
1365
1245
|
},
|
|
1366
1246
|
"long-form": {
|
|
1367
1247
|
qualityProfile: "general",
|
|
1368
|
-
|
|
1369
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1248
|
+
minSilenceMs: 600,
|
|
1370
1249
|
silenceMs: 2200,
|
|
1371
1250
|
speechThreshold: 0.01,
|
|
1372
1251
|
transcriptStabilityMs: 1500
|
|
@@ -1397,12 +1276,12 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1397
1276
|
const qualityProfile = config?.qualityProfile ?? DEFAULT_QUALITY_PROFILE;
|
|
1398
1277
|
const preset = TURN_PROFILE_DEFAULTS[profile];
|
|
1399
1278
|
const quality = QUALITY_PROFILE_DEFAULTS[qualityProfile];
|
|
1279
|
+
const silenceMs = config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs;
|
|
1400
1280
|
return {
|
|
1401
1281
|
profile,
|
|
1402
1282
|
qualityProfile,
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1283
|
+
minSilenceMs: Math.min(silenceMs, config?.minSilenceMs ?? quality.minSilenceMs ?? preset.minSilenceMs),
|
|
1284
|
+
silenceMs,
|
|
1406
1285
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1407
1286
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
1408
1287
|
};
|
|
@@ -1107,31 +1107,25 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1107
1107
|
};
|
|
1108
1108
|
};
|
|
1109
1109
|
|
|
1110
|
-
// src/core/turnDetection.ts
|
|
1111
|
-
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1112
|
-
|
|
1113
1110
|
// src/core/turnProfiles.ts
|
|
1114
1111
|
var TURN_PROFILE_DEFAULTS = {
|
|
1115
1112
|
balanced: {
|
|
1116
1113
|
qualityProfile: "general",
|
|
1117
|
-
|
|
1118
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1114
|
+
minSilenceMs: 400,
|
|
1119
1115
|
silenceMs: 1400,
|
|
1120
1116
|
speechThreshold: 0.012,
|
|
1121
1117
|
transcriptStabilityMs: 1000
|
|
1122
1118
|
},
|
|
1123
1119
|
fast: {
|
|
1124
1120
|
qualityProfile: "general",
|
|
1125
|
-
|
|
1126
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1121
|
+
minSilenceMs: 300,
|
|
1127
1122
|
silenceMs: 700,
|
|
1128
1123
|
speechThreshold: 0.015,
|
|
1129
1124
|
transcriptStabilityMs: 450
|
|
1130
1125
|
},
|
|
1131
1126
|
"long-form": {
|
|
1132
1127
|
qualityProfile: "general",
|
|
1133
|
-
|
|
1134
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1128
|
+
minSilenceMs: 600,
|
|
1135
1129
|
silenceMs: 2200,
|
|
1136
1130
|
speechThreshold: 0.01,
|
|
1137
1131
|
transcriptStabilityMs: 1500
|
|
@@ -1162,12 +1156,12 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1162
1156
|
const qualityProfile = config?.qualityProfile ?? DEFAULT_QUALITY_PROFILE;
|
|
1163
1157
|
const preset = TURN_PROFILE_DEFAULTS[profile];
|
|
1164
1158
|
const quality = QUALITY_PROFILE_DEFAULTS[qualityProfile];
|
|
1159
|
+
const silenceMs = config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs;
|
|
1165
1160
|
return {
|
|
1166
1161
|
profile,
|
|
1167
1162
|
qualityProfile,
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1163
|
+
minSilenceMs: Math.min(silenceMs, config?.minSilenceMs ?? quality.minSilenceMs ?? preset.minSilenceMs),
|
|
1164
|
+
silenceMs,
|
|
1171
1165
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1172
1166
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
1173
1167
|
};
|
package/dist/client/index.js
CHANGED
|
@@ -1678,146 +1678,25 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1678
1678
|
};
|
|
1679
1679
|
};
|
|
1680
1680
|
|
|
1681
|
-
// src/core/turnDetection.ts
|
|
1682
|
-
var DEFAULT_SILENCE_MS = 700;
|
|
1683
|
-
var DEFAULT_SPEECH_THRESHOLD = 0.015;
|
|
1684
|
-
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1685
|
-
var toUint8Array = (audio) => {
|
|
1686
|
-
if (audio instanceof ArrayBuffer) {
|
|
1687
|
-
return new Uint8Array(audio);
|
|
1688
|
-
}
|
|
1689
|
-
return new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
1690
|
-
};
|
|
1691
|
-
var measureAudioLevel = (audio) => {
|
|
1692
|
-
const bytes = toUint8Array(audio);
|
|
1693
|
-
if (bytes.byteLength < 2) {
|
|
1694
|
-
return 0;
|
|
1695
|
-
}
|
|
1696
|
-
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
1697
|
-
if (samples.length === 0) {
|
|
1698
|
-
return 0;
|
|
1699
|
-
}
|
|
1700
|
-
let sumSquares = 0;
|
|
1701
|
-
for (const sample of samples) {
|
|
1702
|
-
const normalized = sample / 32768;
|
|
1703
|
-
sumSquares += normalized * normalized;
|
|
1704
|
-
}
|
|
1705
|
-
return Math.sqrt(sumSquares / samples.length);
|
|
1706
|
-
};
|
|
1707
|
-
var normalizeText = (value) => value.trim().replace(/\s+/g, " ");
|
|
1708
|
-
var countWords = (value) => value.length > 0 ? value.split(" ").length : 0;
|
|
1709
|
-
var selectPreferredTranscriptText = (currentText, nextText) => {
|
|
1710
|
-
const current = normalizeText(currentText);
|
|
1711
|
-
const next = normalizeText(nextText);
|
|
1712
|
-
if (!current) {
|
|
1713
|
-
return next;
|
|
1714
|
-
}
|
|
1715
|
-
if (!next) {
|
|
1716
|
-
return current;
|
|
1717
|
-
}
|
|
1718
|
-
if (current === next || current.includes(next)) {
|
|
1719
|
-
return current;
|
|
1720
|
-
}
|
|
1721
|
-
if (next.includes(current)) {
|
|
1722
|
-
return next;
|
|
1723
|
-
}
|
|
1724
|
-
if (countWords(next) > countWords(current)) {
|
|
1725
|
-
return next;
|
|
1726
|
-
}
|
|
1727
|
-
if (countWords(next) === countWords(current) && next.length > current.length) {
|
|
1728
|
-
return next;
|
|
1729
|
-
}
|
|
1730
|
-
return current;
|
|
1731
|
-
};
|
|
1732
|
-
var mergeSequentialTranscriptText = (currentText, nextText) => {
|
|
1733
|
-
const current = normalizeText(currentText);
|
|
1734
|
-
const next = normalizeText(nextText);
|
|
1735
|
-
if (!current) {
|
|
1736
|
-
return next;
|
|
1737
|
-
}
|
|
1738
|
-
if (!next) {
|
|
1739
|
-
return current;
|
|
1740
|
-
}
|
|
1741
|
-
const currentWords = current.split(" ");
|
|
1742
|
-
const nextWords = next.split(" ");
|
|
1743
|
-
const maxOverlap = Math.min(currentWords.length, nextWords.length);
|
|
1744
|
-
for (let overlap = maxOverlap;overlap > 0; overlap -= 1) {
|
|
1745
|
-
const currentSuffix = currentWords.slice(-overlap).join(" ");
|
|
1746
|
-
const nextPrefix = nextWords.slice(0, overlap).join(" ");
|
|
1747
|
-
if (currentSuffix === nextPrefix) {
|
|
1748
|
-
return [...currentWords, ...nextWords.slice(overlap)].join(" ");
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
return `${current} ${next}`.trim();
|
|
1752
|
-
};
|
|
1753
|
-
var countCommonPrefixWords = (currentText, nextText) => {
|
|
1754
|
-
const currentWords = normalizeText(currentText).split(" ").filter(Boolean);
|
|
1755
|
-
const nextWords = normalizeText(nextText).split(" ").filter(Boolean);
|
|
1756
|
-
const maxWords = Math.min(currentWords.length, nextWords.length);
|
|
1757
|
-
let count = 0;
|
|
1758
|
-
for (let index = 0;index < maxWords; index += 1) {
|
|
1759
|
-
if (currentWords[index] !== nextWords[index]) {
|
|
1760
|
-
break;
|
|
1761
|
-
}
|
|
1762
|
-
count += 1;
|
|
1763
|
-
}
|
|
1764
|
-
return count;
|
|
1765
|
-
};
|
|
1766
|
-
var mergeTranscriptTexts = (transcripts) => {
|
|
1767
|
-
const merged = [];
|
|
1768
|
-
for (const transcript of transcripts) {
|
|
1769
|
-
const nextText = normalizeText(transcript.text);
|
|
1770
|
-
if (!nextText) {
|
|
1771
|
-
continue;
|
|
1772
|
-
}
|
|
1773
|
-
const previous = merged.at(-1);
|
|
1774
|
-
if (!previous) {
|
|
1775
|
-
merged.push(nextText);
|
|
1776
|
-
continue;
|
|
1777
|
-
}
|
|
1778
|
-
if (nextText === previous || previous.includes(nextText)) {
|
|
1779
|
-
continue;
|
|
1780
|
-
}
|
|
1781
|
-
if (nextText.includes(previous)) {
|
|
1782
|
-
merged[merged.length - 1] = nextText;
|
|
1783
|
-
continue;
|
|
1784
|
-
}
|
|
1785
|
-
merged.push(nextText);
|
|
1786
|
-
}
|
|
1787
|
-
return merged.join(" ").trim();
|
|
1788
|
-
};
|
|
1789
|
-
var buildTurnText = (transcripts, partialText, options = {}) => {
|
|
1790
|
-
const finalText = mergeTranscriptTexts(transcripts);
|
|
1791
|
-
const nextPartial = normalizeText(partialText);
|
|
1792
|
-
const lastFinalEndedAtMs = [...transcripts].reverse().find((transcript) => typeof transcript.endedAtMs === "number")?.endedAtMs;
|
|
1793
|
-
if (finalText && nextPartial && typeof lastFinalEndedAtMs === "number" && typeof options.partialStartedAtMs === "number" && options.partialStartedAtMs - lastFinalEndedAtMs >= 250 && countCommonPrefixWords(finalText, nextPartial) === 0) {
|
|
1794
|
-
return mergeSequentialTranscriptText(finalText, nextPartial);
|
|
1795
|
-
}
|
|
1796
|
-
return selectPreferredTranscriptText(finalText, nextPartial);
|
|
1797
|
-
};
|
|
1798
|
-
|
|
1799
1681
|
// src/core/turnProfiles.ts
|
|
1800
1682
|
var TURN_PROFILE_DEFAULTS = {
|
|
1801
1683
|
balanced: {
|
|
1802
1684
|
qualityProfile: "general",
|
|
1803
|
-
|
|
1804
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1685
|
+
minSilenceMs: 400,
|
|
1805
1686
|
silenceMs: 1400,
|
|
1806
1687
|
speechThreshold: 0.012,
|
|
1807
1688
|
transcriptStabilityMs: 1000
|
|
1808
1689
|
},
|
|
1809
1690
|
fast: {
|
|
1810
1691
|
qualityProfile: "general",
|
|
1811
|
-
|
|
1812
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1692
|
+
minSilenceMs: 300,
|
|
1813
1693
|
silenceMs: 700,
|
|
1814
1694
|
speechThreshold: 0.015,
|
|
1815
1695
|
transcriptStabilityMs: 450
|
|
1816
1696
|
},
|
|
1817
1697
|
"long-form": {
|
|
1818
1698
|
qualityProfile: "general",
|
|
1819
|
-
|
|
1820
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1699
|
+
minSilenceMs: 600,
|
|
1821
1700
|
silenceMs: 2200,
|
|
1822
1701
|
speechThreshold: 0.01,
|
|
1823
1702
|
transcriptStabilityMs: 1500
|
|
@@ -1848,12 +1727,12 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1848
1727
|
const qualityProfile = config?.qualityProfile ?? DEFAULT_QUALITY_PROFILE;
|
|
1849
1728
|
const preset = TURN_PROFILE_DEFAULTS[profile];
|
|
1850
1729
|
const quality = QUALITY_PROFILE_DEFAULTS[qualityProfile];
|
|
1730
|
+
const silenceMs = config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs;
|
|
1851
1731
|
return {
|
|
1852
1732
|
profile,
|
|
1853
1733
|
qualityProfile,
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1734
|
+
minSilenceMs: Math.min(silenceMs, config?.minSilenceMs ?? quality.minSilenceMs ?? preset.minSilenceMs),
|
|
1735
|
+
silenceMs,
|
|
1857
1736
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1858
1737
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
1859
1738
|
};
|
|
@@ -1,7 +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
|
|
4
|
+
export declare const DEFAULT_MIN_SILENCE_MS = 400;
|
|
5
5
|
export declare const measureAudioLevel: (audio: AudioChunk) => number;
|
|
6
6
|
export declare const selectPreferredTranscriptText: (currentText: string, nextText: string) => string;
|
|
7
7
|
export declare const buildTurnText: (transcripts: Transcript[], partialText: string, options?: {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -436,19 +436,17 @@ export type VoiceTurnDetectionConfig = {
|
|
|
436
436
|
profile?: VoiceTurnProfile;
|
|
437
437
|
qualityProfile?: VoiceTurnQualityProfile;
|
|
438
438
|
silenceMs?: number;
|
|
439
|
+
minSilenceMs?: number;
|
|
439
440
|
speechThreshold?: number;
|
|
440
441
|
transcriptStabilityMs?: number;
|
|
441
|
-
semanticVetoMaxMs?: number;
|
|
442
|
-
semanticVetoRecheckMs?: number;
|
|
443
442
|
};
|
|
444
443
|
export type VoiceResolvedTurnDetectionConfig = {
|
|
445
444
|
qualityProfile: VoiceTurnQualityProfile;
|
|
446
445
|
profile: VoiceTurnProfile;
|
|
447
446
|
silenceMs: number;
|
|
447
|
+
minSilenceMs: number;
|
|
448
448
|
speechThreshold: number;
|
|
449
449
|
transcriptStabilityMs: number;
|
|
450
|
-
semanticVetoMaxMs: number;
|
|
451
|
-
semanticVetoRecheckMs: number;
|
|
452
450
|
};
|
|
453
451
|
export type VoiceAudioConditioningConfig = {
|
|
454
452
|
enabled?: boolean;
|
package/dist/embed/index.js
CHANGED
|
@@ -1104,31 +1104,25 @@ var resolveAudioConditioningConfig = (config) => {
|
|
|
1104
1104
|
};
|
|
1105
1105
|
};
|
|
1106
1106
|
|
|
1107
|
-
// src/core/turnDetection.ts
|
|
1108
|
-
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
1109
|
-
|
|
1110
1107
|
// src/core/turnProfiles.ts
|
|
1111
1108
|
var TURN_PROFILE_DEFAULTS = {
|
|
1112
1109
|
balanced: {
|
|
1113
1110
|
qualityProfile: "general",
|
|
1114
|
-
|
|
1115
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1111
|
+
minSilenceMs: 400,
|
|
1116
1112
|
silenceMs: 1400,
|
|
1117
1113
|
speechThreshold: 0.012,
|
|
1118
1114
|
transcriptStabilityMs: 1000
|
|
1119
1115
|
},
|
|
1120
1116
|
fast: {
|
|
1121
1117
|
qualityProfile: "general",
|
|
1122
|
-
|
|
1123
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1118
|
+
minSilenceMs: 300,
|
|
1124
1119
|
silenceMs: 700,
|
|
1125
1120
|
speechThreshold: 0.015,
|
|
1126
1121
|
transcriptStabilityMs: 450
|
|
1127
1122
|
},
|
|
1128
1123
|
"long-form": {
|
|
1129
1124
|
qualityProfile: "general",
|
|
1130
|
-
|
|
1131
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
1125
|
+
minSilenceMs: 600,
|
|
1132
1126
|
silenceMs: 2200,
|
|
1133
1127
|
speechThreshold: 0.01,
|
|
1134
1128
|
transcriptStabilityMs: 1500
|
|
@@ -1159,12 +1153,12 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
1159
1153
|
const qualityProfile = config?.qualityProfile ?? DEFAULT_QUALITY_PROFILE;
|
|
1160
1154
|
const preset = TURN_PROFILE_DEFAULTS[profile];
|
|
1161
1155
|
const quality = QUALITY_PROFILE_DEFAULTS[qualityProfile];
|
|
1156
|
+
const silenceMs = config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs;
|
|
1162
1157
|
return {
|
|
1163
1158
|
profile,
|
|
1164
1159
|
qualityProfile,
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
1160
|
+
minSilenceMs: Math.min(silenceMs, config?.minSilenceMs ?? quality.minSilenceMs ?? preset.minSilenceMs),
|
|
1161
|
+
silenceMs,
|
|
1168
1162
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
1169
1163
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
1170
1164
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(()=>{var{defineProperty:E,getOwnPropertyNames:I0,getOwnPropertyDescriptor:H0}=Object,_0=Object.prototype.hasOwnProperty;function G0(g){return this[g]}var L0=(g)=>{var A=(x??=new WeakMap).get(g),C;if(A)return A;if(A=E({},"__esModule",{value:!0}),g&&typeof g==="object"||typeof g==="function"){for(var V of I0(g))if(!_0.call(A,V))E(A,V,{get:G0.bind(g,V),enumerable:!(C=H0(g,V))||C.enumerable})}return x.set(g,A),A},x;var U0=(g)=>g;function w0(g,A){this[g]=U0.bind(null,A)}var y0=(g,A)=>{for(var C in A)E(g,C,{get:A[C],enumerable:!0,configurable:!0,set:w0.bind(A,C)})};var r0={};y0(r0,{mount:()=>V0,default:()=>s0,VOICE_EMBED_VERSION:()=>C0});var X0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},h0=(g,A,C,V)=>{let I=A??g.getAttribute("hx-get")??"";if(!I)return"";let R=new URL(I,window.location.origin);if(V)R.searchParams.set(C,V);else R.searchParams.delete(C);return`${R.pathname}${R.search}${R.hash}`},F=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=X0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",I=A.sessionQueryParam??"sessionId",R=()=>{let L=window,$=h0(C,A.route,I,g.sessionId);if($)C.setAttribute("hx-get",$);L.htmx?.process?.(C),L.htmx?.trigger?.(C,V)},w=g.subscribe(R);return R(),()=>{w()}};var D0=(g)=>Math.max(-1,Math.min(1,g)),J0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=D0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},Y0=(g)=>{let A=g instanceof Uint8Array?g:new Uint8Array(g);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let V=0;for(let I of C){let R=I/32768;V+=R*R}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},Z0=(g,A,C)=>{if(A===C)return g;let V=A/C,I=Math.round(g.length/V),R=new Float32Array(I),w=0,L=0;while(w<R.length){let $=Math.round((w+1)*V),X=0,G=0;for(let h=L;h<$&&h<g.length;h+=1)X+=g[h]??0,G+=1;R[w]=G>0?X/G:0,w+=1,L=$}return R},f=(g)=>{let A=null,C=null,V=null,I=null;return{start:async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let L=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!L)throw Error("Browser microphone capture requires AudioContext support.");if(I=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new L,A.state==="suspended")await A.resume();C=A.createMediaStreamSource(I),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=($)=>{let X=$.inputBuffer.getChannelData(0),G=Z0(X,A?.sampleRate??48000,g.sampleRateHz??16000),h=J0(G);g.onLevel?.(Y0(h)),g.onAudio(h)},C.connect(V),V.connect(A.destination)},stop:()=>{V?.disconnect(),C?.disconnect(),I?.getTracks().forEach((L)=>L.stop()),A?.close(),g.onLevel?.(0),A=null,I=null,V=null,C=null}}};var M=(g)=>{if(typeof g==="string"&&g.trim())return g;if(g instanceof Error&&g.message.trim())return g.message;if(g&&typeof g==="object"){let A=g;for(let C of["message","reason","description"]){let V=A[C];if(typeof V==="string"&&V.trim())return V}if("error"in A)return M(A.error);if("cause"in A)return M(A.cause);try{return JSON.stringify(g)}catch{}}return"Unexpected error"},l=(g)=>{switch(g.type){case"audio":return{chunk:Uint8Array.from(atob(g.chunkBase64),(A)=>A.charCodeAt(0)),format:g.format,receivedAt:g.receivedAt,turnId:g.turnId,type:"audio"};case"assistant":return{text:g.text,turnId:g.turnId,type:"assistant"};case"assistant_delta":return{delta:g.delta,turnId:g.turnId,type:"assistant_delta"};case"complete":return{sessionId:g.sessionId,type:"complete"};case"connection":return{reconnect:g.reconnect,type:"connection"};case"call_lifecycle":return{event:g.event,sessionId:g.sessionId,type:"call_lifecycle"};case"error":return{message:M(g.message),type:"error"};case"final":return{transcript:g.transcript,type:"final"};case"partial":return{transcript:g.transcript,type:"partial"};case"replay":return{assistantTexts:g.assistantTexts,call:g.call,partial:g.partial,scenarioId:g.scenarioId,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,status:g.status,turns:g.turns,type:"replay"};case"session":return{sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,type:"session"};case"turn":return{turn:g.turn,type:"turn"};default:return null}};var gg=Math.PI*2;var T=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var O0=(g)=>g.length===0?void 0:g.reduce((A,C)=>A+C,0)/g.length,z=(g)=>g.length===0?void 0:Math.max(...g);var D=(g,A)=>{let C=g[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},B=(g,A)=>{let C=g[A];return typeof C==="boolean"?C:void 0},Y=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},k=(g)=>String(g.id??Y(g,"ssrc")??D(g,"ssrc")??Y(g,"trackIdentifier")??Y(g,"mid")??"unknown"),d=(g)=>g===void 0?void 0:g*1000;var S0=(g)=>{let A={};for(let[C,V]of Object.entries(g))if(V===null||typeof V==="boolean"||typeof V==="number"||typeof V==="string")A[C]=V;return A};var v=(g={})=>{let A=g.stats??[],C=[],V=A.filter((H)=>H.type==="inbound-rtp"&&Y(H,"kind")!=="video"),I=A.filter((H)=>H.type==="outbound-rtp"&&Y(H,"kind")!=="video"),R=A.filter((H)=>H.type==="candidate-pair"),w=A.filter((H)=>(H.type==="track"||H.type==="media-source")&&Y(H,"kind")==="audio"),L=R.filter((H)=>B(H,"selected")===!0||B(H,"nominated")===!0||Y(H,"state")==="succeeded").length,$=w.filter((H)=>Y(H,"readyState")!=="ended"&&Y(H,"trackState")!=="ended"&&B(H,"ended")!==!0).length,X=w.filter((H)=>Y(H,"readyState")==="ended"||Y(H,"trackState")==="ended"||B(H,"ended")===!0).length,G=V.reduce((H,J)=>H+(D(J,"packetsReceived")??0),0),h=I.reduce((H,J)=>H+(D(J,"packetsSent")??0),0),_=[...V,...I].reduce((H,J)=>H+Math.max(0,D(J,"packetsLost")??0),0),Z=G+_,y=Z===0?0:_/Z,K=V.reduce((H,J)=>H+(D(J,"bytesReceived")??0),0),O=I.reduce((H,J)=>H+(D(J,"bytesSent")??0),0),S=z(R.map((H)=>d(D(H,"currentRoundTripTime")??D(H,"roundTripTime"))).filter((H)=>H!==void 0)),W=z([...V,...I].map((H)=>d(D(H,"jitter"))).filter((H)=>H!==void 0)),N=z(V.map((H)=>{let J=D(H,"jitterBufferDelay"),U=D(H,"jitterBufferEmittedCount");return J!==void 0&&U!==void 0&&U>0?J/U*1000:void 0}).filter((H)=>H!==void 0)),j=w.map((H)=>D(H,"audioLevel")).filter((H)=>H!==void 0);if(g.requireConnectedCandidatePair&&R.length>0&&L===0)T(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&$===0)T(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&y>g.maxPacketLossRatio)T(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(y)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&S!==void 0&&S>g.maxRoundTripTimeMs)T(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(S)}ms above ${String(g.maxRoundTripTimeMs)}ms.`);if(g.maxJitterMs!==void 0&&W!==void 0&&W>g.maxJitterMs)T(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(W)}ms above ${String(g.maxJitterMs)}ms.`);return{activeCandidatePairs:L,audioLevelAverage:O0(j),bytesReceived:K,bytesSent:O,checkedAt:Date.now(),endedAudioTracks:X,inboundPackets:G,issues:C,jitterBufferDelayMs:N,jitterMs:W,liveAudioTracks:$,outboundPackets:h,packetLossRatio:y,packetsLost:_,roundTripTimeMs:S,status:C.some((H)=>H.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},i=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(S0)};var o=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],I=new Map(C.map((_)=>[k(_),_])),w=A.filter((_)=>(_.type==="inbound-rtp"||_.type==="outbound-rtp")&&Y(_,"kind")!=="video"&&Y(_,"mediaType")!=="video").map((_)=>{let Z=_.type==="outbound-rtp"?"outbound":"inbound",y=Z==="outbound"?"packetsSent":"packetsReceived",K=Z==="outbound"?"bytesSent":"bytesReceived",O=I.get(k(_)),S=D(_,y),W=O?D(O,y):void 0,N=D(_,K),j=O?D(O,K):void 0,H=_.timestamp!==void 0&&O?.timestamp!==void 0?_.timestamp-O.timestamp:void 0;return{bytesDelta:N!==void 0&&j!==void 0?N-j:void 0,currentPackets:S,direction:Z,id:k(_),packetDelta:S!==void 0&&W!==void 0?S-W:void 0,previousPackets:W,timeDeltaMs:H}}),L=w.filter((_)=>_.direction==="inbound"),$=w.filter((_)=>_.direction==="outbound"),X=z(w.map((_)=>_.timeDeltaMs).filter((_)=>_!==void 0)),G=L.filter((_)=>g.maxInboundPacketStallMs!==void 0&&_.timeDeltaMs!==void 0&&_.timeDeltaMs>=g.maxInboundPacketStallMs&&_.packetDelta!==void 0&&_.packetDelta<=0).length,h=$.filter((_)=>g.maxOutboundPacketStallMs!==void 0&&_.timeDeltaMs!==void 0&&_.timeDeltaMs>=g.maxOutboundPacketStallMs&&_.packetDelta!==void 0&&_.packetDelta<=0).length;if(g.requireInboundAudio&&L.length===0)T(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&$.length===0)T(V,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(g.maxGapMs!==void 0&&X!==void 0&&X>g.maxGapMs)T(V,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(X)}ms above ${String(g.maxGapMs)}ms.`);if(G>0)T(V,"error","media.webrtc_inbound_stalled",`${String(G)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)T(V,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:L.length,issues:V,maxObservedGapMs:X,outboundAudioStreams:$.length,stalledInboundStreams:G,stalledOutboundStreams:h,status:V.some((_)=>_.severity==="error")?"fail":V.length>0?"warn":"pass",streams:w,totalStats:A.length}};var W0="/api/voice/browser-media",Q0=5000,T0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,c0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??W0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},n=(g)=>{let A=null,C=[],V=async()=>{let w=await T0(g);if(!w)return;let L=await i({peerConnection:w}),$=v({...g,stats:L}),X=g.continuity===!1?void 0:o({...g.continuity,previousStats:C,stats:L}),G={at:Date.now(),continuity:X,report:$,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=L,g.onReport?.(G),await c0(G,g),G},I=()=>{V().catch((w)=>{g.onError?.(w)})},R=()=>{if(A)clearInterval(A),A=null};return{close:R,reportOnce:V,stop:R,start:()=>{if(A)return;I(),A=setInterval(I,g.intervalMs??Q0)}}};var K0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));var q=()=>{},P0=()=>q,q0={callControl:q,close:q,endTurn:q,send:q,sendAudio:q,simulateDisconnect:q,subscribe:P0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},N0=()=>crypto.randomUUID(),j0=(g,A,C)=>{let{hostname:V,port:I,protocol:R}=window.location,w=R==="https:"?"wss:":"ws:",L=I?`:${I}`:"",$=new URL(`${w}//${V}${L}${g}`);if($.searchParams.set("sessionId",A),C)$.searchParams.set("scenarioId",C);return $.toString()},B0=(g)=>{if(!g||typeof g!=="object"||!("type"in g))return!1;switch(g.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}},z0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return B0(A)?A:null}catch{return null}},m=(g,A={})=>{if(typeof window>"u")return q0;let C=new Set,V=A.reconnect!==!1,I=A.maxReconnectAttempts??15,R=A.reconnectMaxDelayMs??8000,w=A.pingInterval??30000,L=(U)=>K0(U,500,R),$={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:A.sessionId??N0(),ws:null},X=(U)=>{C.forEach((Q)=>Q(U))},G=()=>{if($.pingInterval)clearInterval($.pingInterval),$.pingInterval=null;if($.reconnectTimeout)clearTimeout($.reconnectTimeout),$.reconnectTimeout=null},h=()=>{if($.ws?.readyState!==1)return;while($.pendingMessages.length>0){let U=$.pendingMessages.shift();if(U!==void 0)$.ws.send(U)}},_=()=>{$.reconnectAttempts+=1;let U=L($.reconnectAttempts),Q=Date.now()+U;X({reconnect:{attempts:$.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:I,nextAttemptAt:Q,status:"reconnecting"},type:"connection"}),$.reconnectTimeout=setTimeout(()=>{if($.reconnectAttempts>I){X({reconnect:{attempts:$.reconnectAttempts,maxAttempts:I,status:"exhausted"},type:"connection"});return}Z()},U)},Z=()=>{let U=new WebSocket(j0(g,$.sessionId,$.scenarioId));U.binaryType="arraybuffer",U.onopen=()=>{let Q=$.reconnectAttempts>0;if($.isConnected=!0,h(),Q)X({reconnect:{attempts:$.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:I,status:"resumed"},type:"connection"}),$.reconnectAttempts=0;C.forEach((P)=>P({scenarioId:$.scenarioId??void 0,sessionId:$.sessionId,status:"active",type:"session"})),$.pingInterval=setInterval(()=>{if(U.readyState===1)U.send(JSON.stringify({type:"ping"}))},w)},U.onmessage=(Q)=>{let P=z0(Q);if(!P)return;if(P.type==="session")$.sessionId=P.sessionId,$.scenarioId=P.scenarioId??$.scenarioId;C.forEach(($0)=>$0(P))},U.onclose=(Q)=>{if($.isConnected=!1,G(),V&&Q.code!==1000&&$.reconnectAttempts<I)_();else if(V&&Q.code!==1000)X({reconnect:{attempts:$.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:I,status:"exhausted"},type:"connection"})},$.ws=U},y=(U)=>{if($.ws?.readyState===1){$.ws.send(U);return}$.pendingMessages.push(U)},K=(U)=>{y(JSON.stringify(U))},O=(U={})=>{if(U.sessionId)$.sessionId=U.sessionId;if(U.scenarioId)$.scenarioId=U.scenarioId;K({scenarioId:$.scenarioId??void 0,sessionId:$.sessionId,type:"start"})},S=(U)=>{y(U)},W=()=>{K({type:"end_turn"})},N=(U)=>{K({...U,type:"call_control"})},j=()=>{if(G(),$.ws)$.ws.close(1000),$.ws=null;$.isConnected=!1,C.clear()},H=()=>{if($.ws?.readyState===1)$.ws.close(4000,"absolutejs-voice-reconnect-proof")},J=(U)=>{return C.add(U),()=>{C.delete(U)}};return Z(),{callControl:N,close:j,endTurn:W,send:K,sendAudio:S,simulateDisconnect:H,start:O,subscribe:J,getReadyState:()=>$.ws?.readyState??3,getScenarioId:()=>$.scenarioId??"",getSessionId:()=>$.sessionId}};var b0=()=>({attempts:0,maxAttempts:0,status:"idle"}),E0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return g;if(!g)return C;if(g===C||g.endsWith(C))return g;if(C.includes(g))return C;return`${g} ${C}`},M0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},k0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:b0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),u=()=>{let g=k0(),A="",C=new Set,V=()=>{C.forEach((R)=>R())};return{dispatch:(R)=>{switch(R.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:R.chunk,format:R.format,receivedAt:R.receivedAt,turnId:R.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,R.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${R.delta}`};break;case"complete":g={...g,sessionId:R.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:R.event.type==="end"?R.event.disposition:g.call?.disposition,endedAt:R.event.type==="end"?R.event.at:g.call?.endedAt,events:[...g.call?.events??[],R.event],lastEventAt:R.event.at,startedAt:g.call?.startedAt??R.event.at},sessionId:R.sessionId};break;case"connected":g={...g,isConnected:!0,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect};break;case"connection":g={...g,reconnect:R.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:R.message};break;case"final":A=E0(A,R.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:M0(A,R.transcript.text)};break;case"replay":A=R.partial,g={...g,assistantStreamingText:"",assistantTexts:[...R.assistantTexts],call:R.call??null,error:null,isConnected:R.status==="active",partial:R.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:R.scenarioId??g.scenarioId,sessionId:R.sessionId,sessionMetadata:R.sessionMetadata??g.sessionMetadata,status:R.status,turns:[...R.turns]};break;case"session":g={...g,error:null,scenarioId:R.scenarioId??g.scenarioId,isConnected:R.status==="active",sessionId:R.sessionId,sessionMetadata:R.sessionMetadata??g.sessionMetadata,status:R.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,R.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(R)=>{return C.add(R),()=>{C.delete(R)}}}};var r=(g,A={})=>{let C=m(g,A),V=u(),I=A.browserMedia&&typeof window<"u"?n({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,R=new Set,w=(G)=>Promise.resolve().then(()=>{if(!G?.sessionId&&!G?.scenarioId)return;C.start(G),I?.start()}),L=()=>{R.forEach((G)=>G())},$=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let G=V.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:G.reconnect,scenarioId:G.scenarioId,sessionId:C.getSessionId(),turnIds:G.turns.map((_)=>_.id)});fetch(A.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},X=C.subscribe((G)=>{let h=l(G);if(h){if(V.dispatch(h),G.type==="connection")$();L()}});return{start:w,get assistantAudio(){return V.getSnapshot().assistantAudio},get assistantTexts(){return V.getSnapshot().assistantTexts},get assistantStreamingText(){return V.getSnapshot().assistantStreamingText},get call(){return V.getSnapshot().call},callControl(G){C.callControl(G)},close(){X(),I?.close(),C.close(),V.dispatch({type:"disconnected"}),L()},endTurn(){C.endTurn()},get error(){return V.getSnapshot().error},getServerSnapshot(){return V.getServerSnapshot()},getSnapshot(){return V.getSnapshot()},get isConnected(){return V.getSnapshot().isConnected},get partial(){return V.getSnapshot().partial},get reconnect(){return V.getSnapshot().reconnect},get scenarioId(){return V.getSnapshot().scenarioId},sendAudio(G){C.sendAudio(G)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(G){return R.add(G),()=>{R.delete(G)}},get turns(){return V.getSnapshot().turns}}};var s=(g)=>{if(!g||g.enabled===!1)return;return{enabled:!0,maxGain:g.maxGain??3,noiseGateAttenuation:g.noiseGateAttenuation??0.15,noiseGateThreshold:g.noiseGateThreshold??0.006,targetLevel:g.targetLevel??0.08}};var b=1200;var x0={balanced:{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:b,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:b,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:b,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},F0={"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}},f0="fast",l0="general",a=(g)=>{let A=g?.profile??f0,C=g?.qualityProfile??l0,V=x0[A],I=F0[C];return{profile:A,qualityProfile:C,semanticVetoMaxMs:g?.semanticVetoMaxMs??V.semanticVetoMaxMs,semanticVetoRecheckMs:g?.semanticVetoRecheckMs??V.semanticVetoRecheckMs,silenceMs:g?.silenceMs??I.silenceMs??V.silenceMs,speechThreshold:g?.speechThreshold??I.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??I.transcriptStabilityMs??V.transcriptStabilityMs}};var d0={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"}}},p=(g="default")=>{let A=d0[g];return{audioConditioning:s(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:a(A.turnDetection)}};var v0=(g)=>({assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,isRecording:!1,partial:g.partial,reconnect:g.reconnect,recordingError:null,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]}),t=(g,A={})=>{let C=p(A.preset),V=r(g,{...C.connection,...A.connection}),I=null,R=v0(V),w=new Set,L=()=>{for(let y of w)y()},$=()=>{if(R={...R,assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,partial:V.partial,reconnect:V.reconnect,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]},A.autoStopOnComplete!==!1&&R.status==="completed"&&R.isRecording)I?.stop(),I=null,R={...R,isRecording:!1};L()},X=V.subscribe($);$();let G=()=>{if(I)return I;return I=f({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(y)=>{if(A.capture?.onAudio){A.capture.onAudio(y,V.sendAudio);return}V.sendAudio(y)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),I},h=()=>{I?.stop(),I=null,R={...R,isRecording:!1},L()},_=async()=>{if(R.isRecording)return;try{R={...R,recordingError:null},L(),await G().start(),R={...R,isRecording:!0},L()}catch(y){throw I=null,R={...R,isRecording:!1,recordingError:y instanceof Error?y.message:String(y)},L(),y}};return{close:()=>{X(),h(),V.close()},startRecording:_,stopRecording:h,get assistantAudio(){return R.assistantAudio},get assistantTexts(){return R.assistantTexts},get assistantStreamingText(){return R.assistantStreamingText},bindHTMX(y){return F(V,y)},get call(){return R.call},callControl:(y)=>V.callControl(y),endTurn:()=>V.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:(y)=>V.sendAudio(y),get sessionId(){return R.sessionId},get sessionMetadata(){return R.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return R.status},subscribe:(y)=>{return w.add(y),()=>{w.delete(y)}},toggleRecording:async()=>{if(R.isRecording){h();return}await _()},get turns(){return R.turns}}};var c=(g)=>String(g).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var e=(g)=>{if(!g.isConnected)return"idle";if(g.isPlaying)return"speaking";if(g.isRecording&&g.hasActivePartial)return"listening";if(g.isRecording)return"listening";if(g.lastTranscriptAt&&!g.lastAssistantAt)return"thinking";if(g.lastTranscriptAt&&g.lastAssistantAt&&g.lastTranscriptAt>g.lastAssistantAt)return"thinking";return"idle"};var i0={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},o0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},n0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},g0=(g)=>{let A={...i0,...g.theme},C={...o0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,I=g.state.turns.at(-1)?.committedAt,R=e({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:I}),w=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,L=g.state.error?"Error":w?C.connecting:g.state.status==="completed"?C.callEnded:n0(R,C);return{agentState:R,classes:{container:`absolute-voice-widget absolute-voice-widget--${R}`,dot:`absolute-voice-widget__dot${g.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:g.state.isConnected,canMute:g.state.isRecording,canStart:!g.state.isRecording&&g.state.status!=="completed"},errorMessage:g.state.error??void 0,labels:C,partial:g.state.partial||void 0,statusLabel:L,theme:A,title:g.title??"Voice"}},m0=(g)=>typeof g==="number"?`${g}px`:g,A0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${m0(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,V=`background:${g.errorMessage?A.errorAccent:g.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,I=[];if(g.controls.canStart)I.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${c(g.labels.startCall)}</button>`);if(g.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:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${c(g.labels.mute)}</button>`);if(g.controls.canEnd)I.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${c(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${c(g.classes.container)}" style="${C}">
|
|
1
|
+
(()=>{var{defineProperty:j,getOwnPropertyNames:_0,getOwnPropertyDescriptor:c0}=Object,R0=Object.prototype.hasOwnProperty;function $0(g){return this[g]}var I0=(g)=>{var A=(x??=new WeakMap).get(g),C;if(A)return A;if(A=j({},"__esModule",{value:!0}),g&&typeof g==="object"||typeof g==="function"){for(var V of _0(g))if(!R0.call(A,V))j(A,V,{get:$0.bind(g,V),enumerable:!(C=c0(g,V))||C.enumerable})}return x.set(g,A),A},x;var H0=(g)=>g;function U0(g,A){this[g]=H0.bind(null,A)}var L0=(g,A)=>{for(var C in A)j(g,C,{get:A[C],enumerable:!0,configurable:!0,set:U0.bind(A,C)})};var o0={};L0(o0,{mount:()=>A0,default:()=>m0,VOICE_EMBED_VERSION:()=>V0});var G0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},W0=(g,A,C,V)=>{let c=A??g.getAttribute("hx-get")??"";if(!c)return"";let T=new URL(c,window.location.origin);if(V)T.searchParams.set(C,V);else T.searchParams.delete(C);return`${T.pathname}${T.search}${T.hash}`},k=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=G0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",c=A.sessionQueryParam??"sessionId",T=()=>{let H=window,_=W0(C,A.route,c,g.sessionId);if(_)C.setAttribute("hx-get",_);H.htmx?.process?.(C),H.htmx?.trigger?.(C,V)},L=g.subscribe(T);return T(),()=>{L()}};var y0=(g)=>Math.max(-1,Math.min(1,g)),w0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=y0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},D0=(g)=>{let A=g instanceof Uint8Array?g:new Uint8Array(g);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let V=0;for(let c of C){let T=c/32768;V+=T*T}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},S0=(g,A,C)=>{if(A===C)return g;let V=A/C,c=Math.round(g.length/V),T=new Float32Array(c),L=0,H=0;while(L<T.length){let _=Math.round((L+1)*V),W=0,I=0;for(let y=H;y<_&&y<g.length;y+=1)W+=g[y]??0,I+=1;T[L]=I>0?W/I:0,L+=1,H=_}return T},F=(g)=>{let A=null,C=null,V=null,c=null;return{start:async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let H=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!H)throw Error("Browser microphone capture requires AudioContext support.");if(c=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new H,A.state==="suspended")await A.resume();C=A.createMediaStreamSource(c),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=(_)=>{let W=_.inputBuffer.getChannelData(0),I=S0(W,A?.sampleRate??48000,g.sampleRateHz??16000),y=w0(I);g.onLevel?.(D0(y)),g.onAudio(y)},C.connect(V),V.connect(A.destination)},stop:()=>{V?.disconnect(),C?.disconnect(),c?.getTracks().forEach((H)=>H.stop()),A?.close(),g.onLevel?.(0),A=null,c=null,V=null,C=null}}};var B=(g)=>{if(typeof g==="string"&&g.trim())return g;if(g instanceof Error&&g.message.trim())return g.message;if(g&&typeof g==="object"){let A=g;for(let C of["message","reason","description"]){let V=A[C];if(typeof V==="string"&&V.trim())return V}if("error"in A)return B(A.error);if("cause"in A)return B(A.cause);try{return JSON.stringify(g)}catch{}}return"Unexpected error"},l=(g)=>{switch(g.type){case"audio":return{chunk:Uint8Array.from(atob(g.chunkBase64),(A)=>A.charCodeAt(0)),format:g.format,receivedAt:g.receivedAt,turnId:g.turnId,type:"audio"};case"assistant":return{text:g.text,turnId:g.turnId,type:"assistant"};case"assistant_delta":return{delta:g.delta,turnId:g.turnId,type:"assistant_delta"};case"complete":return{sessionId:g.sessionId,type:"complete"};case"connection":return{reconnect:g.reconnect,type:"connection"};case"call_lifecycle":return{event:g.event,sessionId:g.sessionId,type:"call_lifecycle"};case"error":return{message:B(g.message),type:"error"};case"final":return{transcript:g.transcript,type:"final"};case"partial":return{transcript:g.transcript,type:"partial"};case"replay":return{assistantTexts:g.assistantTexts,call:g.call,partial:g.partial,scenarioId:g.scenarioId,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,status:g.status,turns:g.turns,type:"replay"};case"session":return{sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,type:"session"};case"turn":return{turn:g.turn,type:"turn"};default:return null}};var p0=Math.PI*2;var Z=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var X0=(g)=>g.length===0?void 0:g.reduce((A,C)=>A+C,0)/g.length,b=(g)=>g.length===0?void 0:Math.max(...g);var w=(g,A)=>{let C=g[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},z=(g,A)=>{let C=g[A];return typeof C==="boolean"?C:void 0},S=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},M=(g)=>String(g.id??S(g,"ssrc")??w(g,"ssrc")??S(g,"trackIdentifier")??S(g,"mid")??"unknown"),f=(g)=>g===void 0?void 0:g*1000;var h0=(g)=>{let A={};for(let[C,V]of Object.entries(g))if(V===null||typeof V==="boolean"||typeof V==="number"||typeof V==="string")A[C]=V;return A};var d=(g={})=>{let A=g.stats??[],C=[],V=A.filter((R)=>R.type==="inbound-rtp"&&S(R,"kind")!=="video"),c=A.filter((R)=>R.type==="outbound-rtp"&&S(R,"kind")!=="video"),T=A.filter((R)=>R.type==="candidate-pair"),L=A.filter((R)=>(R.type==="track"||R.type==="media-source")&&S(R,"kind")==="audio"),H=T.filter((R)=>z(R,"selected")===!0||z(R,"nominated")===!0||S(R,"state")==="succeeded").length,_=L.filter((R)=>S(R,"readyState")!=="ended"&&S(R,"trackState")!=="ended"&&z(R,"ended")!==!0).length,W=L.filter((R)=>S(R,"readyState")==="ended"||S(R,"trackState")==="ended"||z(R,"ended")===!0).length,I=V.reduce((R,D)=>R+(w(D,"packetsReceived")??0),0),y=c.reduce((R,D)=>R+(w(D,"packetsSent")??0),0),$=[...V,...c].reduce((R,D)=>R+Math.max(0,w(D,"packetsLost")??0),0),X=I+$,G=X===0?0:$/X,P=V.reduce((R,D)=>R+(w(D,"bytesReceived")??0),0),h=c.reduce((R,D)=>R+(w(D,"bytesSent")??0),0),O=b(T.map((R)=>f(w(R,"currentRoundTripTime")??w(R,"roundTripTime"))).filter((R)=>R!==void 0)),J=b([...V,...c].map((R)=>f(w(R,"jitter"))).filter((R)=>R!==void 0)),E=b(V.map((R)=>{let D=w(R,"jitterBufferDelay"),U=w(R,"jitterBufferEmittedCount");return D!==void 0&&U!==void 0&&U>0?D/U*1000:void 0}).filter((R)=>R!==void 0)),N=L.map((R)=>w(R,"audioLevel")).filter((R)=>R!==void 0);if(g.requireConnectedCandidatePair&&T.length>0&&H===0)Z(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&_===0)Z(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&G>g.maxPacketLossRatio)Z(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(G)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&O!==void 0&&O>g.maxRoundTripTimeMs)Z(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(O)}ms above ${String(g.maxRoundTripTimeMs)}ms.`);if(g.maxJitterMs!==void 0&&J!==void 0&&J>g.maxJitterMs)Z(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(J)}ms above ${String(g.maxJitterMs)}ms.`);return{activeCandidatePairs:H,audioLevelAverage:X0(N),bytesReceived:P,bytesSent:h,checkedAt:Date.now(),endedAudioTracks:W,inboundPackets:I,issues:C,jitterBufferDelayMs:E,jitterMs:J,liveAudioTracks:_,outboundPackets:y,packetLossRatio:G,packetsLost:$,roundTripTimeMs:O,status:C.some((R)=>R.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},v=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(h0)};var i=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],c=new Map(C.map(($)=>[M($),$])),L=A.filter(($)=>($.type==="inbound-rtp"||$.type==="outbound-rtp")&&S($,"kind")!=="video"&&S($,"mediaType")!=="video").map(($)=>{let X=$.type==="outbound-rtp"?"outbound":"inbound",G=X==="outbound"?"packetsSent":"packetsReceived",P=X==="outbound"?"bytesSent":"bytesReceived",h=c.get(M($)),O=w($,G),J=h?w(h,G):void 0,E=w($,P),N=h?w(h,P):void 0,R=$.timestamp!==void 0&&h?.timestamp!==void 0?$.timestamp-h.timestamp:void 0;return{bytesDelta:E!==void 0&&N!==void 0?E-N:void 0,currentPackets:O,direction:X,id:M($),packetDelta:O!==void 0&&J!==void 0?O-J:void 0,previousPackets:J,timeDeltaMs:R}}),H=L.filter(($)=>$.direction==="inbound"),_=L.filter(($)=>$.direction==="outbound"),W=b(L.map(($)=>$.timeDeltaMs).filter(($)=>$!==void 0)),I=H.filter(($)=>g.maxInboundPacketStallMs!==void 0&&$.timeDeltaMs!==void 0&&$.timeDeltaMs>=g.maxInboundPacketStallMs&&$.packetDelta!==void 0&&$.packetDelta<=0).length,y=_.filter(($)=>g.maxOutboundPacketStallMs!==void 0&&$.timeDeltaMs!==void 0&&$.timeDeltaMs>=g.maxOutboundPacketStallMs&&$.packetDelta!==void 0&&$.packetDelta<=0).length;if(g.requireInboundAudio&&H.length===0)Z(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&_.length===0)Z(V,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(g.maxGapMs!==void 0&&W!==void 0&&W>g.maxGapMs)Z(V,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(W)}ms above ${String(g.maxGapMs)}ms.`);if(I>0)Z(V,"error","media.webrtc_inbound_stalled",`${String(I)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(y>0)Z(V,"error","media.webrtc_outbound_stalled",`${String(y)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:H.length,issues:V,maxObservedGapMs:W,outboundAudioStreams:_.length,stalledInboundStreams:I,stalledOutboundStreams:y,status:V.some(($)=>$.severity==="error")?"fail":V.length>0?"warn":"pass",streams:L,totalStats:A.length}};var O0="/api/voice/browser-media",J0=5000,Y0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,Z0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??O0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},n=(g)=>{let A=null,C=[],V=async()=>{let L=await Y0(g);if(!L)return;let H=await v({peerConnection:L}),_=d({...g,stats:H}),W=g.continuity===!1?void 0:i({...g.continuity,previousStats:C,stats:H}),I={at:Date.now(),continuity:W,report:_,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=H,g.onReport?.(I),await Z0(I,g),I},c=()=>{V().catch((L)=>{g.onError?.(L)})},T=()=>{if(A)clearInterval(A),A=null};return{close:T,reportOnce:V,stop:T,start:()=>{if(A)return;c(),A=setInterval(c,g.intervalMs??J0)}}};var Q0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));var q=()=>{},P0=()=>q,K0={callControl:q,close:q,endTurn:q,send:q,sendAudio:q,simulateDisconnect:q,subscribe:P0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},q0=()=>crypto.randomUUID(),E0=(g,A,C)=>{let{hostname:V,port:c,protocol:T}=window.location,L=T==="https:"?"wss:":"ws:",H=c?`:${c}`:"",_=new URL(`${L}//${V}${H}${g}`);if(_.searchParams.set("sessionId",A),C)_.searchParams.set("scenarioId",C);return _.toString()},N0=(g)=>{if(!g||typeof g!=="object"||!("type"in g))return!1;switch(g.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}},z0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return N0(A)?A:null}catch{return null}},o=(g,A={})=>{if(typeof window>"u")return K0;let C=new Set,V=A.reconnect!==!1,c=A.maxReconnectAttempts??15,T=A.reconnectMaxDelayMs??8000,L=A.pingInterval??30000,H=(U)=>Q0(U,500,T),_={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:A.sessionId??q0(),ws:null},W=(U)=>{C.forEach((Y)=>Y(U))},I=()=>{if(_.pingInterval)clearInterval(_.pingInterval),_.pingInterval=null;if(_.reconnectTimeout)clearTimeout(_.reconnectTimeout),_.reconnectTimeout=null},y=()=>{if(_.ws?.readyState!==1)return;while(_.pendingMessages.length>0){let U=_.pendingMessages.shift();if(U!==void 0)_.ws.send(U)}},$=()=>{_.reconnectAttempts+=1;let U=H(_.reconnectAttempts),Y=Date.now()+U;W({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,nextAttemptAt:Y,status:"reconnecting"},type:"connection"}),_.reconnectTimeout=setTimeout(()=>{if(_.reconnectAttempts>c){W({reconnect:{attempts:_.reconnectAttempts,maxAttempts:c,status:"exhausted"},type:"connection"});return}X()},U)},X=()=>{let U=new WebSocket(E0(g,_.sessionId,_.scenarioId));U.binaryType="arraybuffer",U.onopen=()=>{let Y=_.reconnectAttempts>0;if(_.isConnected=!0,y(),Y)W({reconnect:{attempts:_.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:c,status:"resumed"},type:"connection"}),_.reconnectAttempts=0;C.forEach((K)=>K({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,status:"active",type:"session"})),_.pingInterval=setInterval(()=>{if(U.readyState===1)U.send(JSON.stringify({type:"ping"}))},L)},U.onmessage=(Y)=>{let K=z0(Y);if(!K)return;if(K.type==="session")_.sessionId=K.sessionId,_.scenarioId=K.scenarioId??_.scenarioId;C.forEach((T0)=>T0(K))},U.onclose=(Y)=>{if(_.isConnected=!1,I(),V&&Y.code!==1000&&_.reconnectAttempts<c)$();else if(V&&Y.code!==1000)W({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,status:"exhausted"},type:"connection"})},_.ws=U},G=(U)=>{if(_.ws?.readyState===1){_.ws.send(U);return}_.pendingMessages.push(U)},P=(U)=>{G(JSON.stringify(U))},h=(U={})=>{if(U.sessionId)_.sessionId=U.sessionId;if(U.scenarioId)_.scenarioId=U.scenarioId;P({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,type:"start"})},O=(U)=>{G(U)},J=()=>{P({type:"end_turn"})},E=(U)=>{P({...U,type:"call_control"})},N=()=>{if(I(),_.ws)_.ws.close(1000),_.ws=null;_.isConnected=!1,C.clear()},R=()=>{if(_.ws?.readyState===1)_.ws.close(4000,"absolutejs-voice-reconnect-proof")},D=(U)=>{return C.add(U),()=>{C.delete(U)}};return X(),{callControl:E,close:N,endTurn:J,send:P,sendAudio:O,simulateDisconnect:R,start:h,subscribe:D,getReadyState:()=>_.ws?.readyState??3,getScenarioId:()=>_.scenarioId??"",getSessionId:()=>_.sessionId}};var b0=()=>({attempts:0,maxAttempts:0,status:"idle"}),j0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return g;if(!g)return C;if(g===C||g.endsWith(C))return g;if(C.includes(g))return C;return`${g} ${C}`},B0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},M0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:b0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),m=()=>{let g=M0(),A="",C=new Set,V=()=>{C.forEach((T)=>T())};return{dispatch:(T)=>{switch(T.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:T.chunk,format:T.format,receivedAt:T.receivedAt,turnId:T.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,T.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${T.delta}`};break;case"complete":g={...g,sessionId:T.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:T.event.type==="end"?T.event.disposition:g.call?.disposition,endedAt:T.event.type==="end"?T.event.at:g.call?.endedAt,events:[...g.call?.events??[],T.event],lastEventAt:T.event.at,startedAt:g.call?.startedAt??T.event.at},sessionId:T.sessionId};break;case"connected":g={...g,isConnected:!0,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect};break;case"connection":g={...g,reconnect:T.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:T.message};break;case"final":A=j0(A,T.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:B0(A,T.transcript.text)};break;case"replay":A=T.partial,g={...g,assistantStreamingText:"",assistantTexts:[...T.assistantTexts],call:T.call??null,error:null,isConnected:T.status==="active",partial:T.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:T.scenarioId??g.scenarioId,sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??g.sessionMetadata,status:T.status,turns:[...T.turns]};break;case"session":g={...g,error:null,scenarioId:T.scenarioId??g.scenarioId,isConnected:T.status==="active",sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??g.sessionMetadata,status:T.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,T.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(T)=>{return C.add(T),()=>{C.delete(T)}}}};var r=(g,A={})=>{let C=o(g,A),V=m(),c=A.browserMedia&&typeof window<"u"?n({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,T=new Set,L=(I)=>Promise.resolve().then(()=>{if(!I?.sessionId&&!I?.scenarioId)return;C.start(I),c?.start()}),H=()=>{T.forEach((I)=>I())},_=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let I=V.getSnapshot(),y=JSON.stringify({at:Date.now(),reconnect:I.reconnect,scenarioId:I.scenarioId,sessionId:C.getSessionId(),turnIds:I.turns.map(($)=>$.id)});fetch(A.reconnectReportPath,{body:y,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},W=C.subscribe((I)=>{let y=l(I);if(y){if(V.dispatch(y),I.type==="connection")_();H()}});return{start:L,get assistantAudio(){return V.getSnapshot().assistantAudio},get assistantTexts(){return V.getSnapshot().assistantTexts},get assistantStreamingText(){return V.getSnapshot().assistantStreamingText},get call(){return V.getSnapshot().call},callControl(I){C.callControl(I)},close(){W(),c?.close(),C.close(),V.dispatch({type:"disconnected"}),H()},endTurn(){C.endTurn()},get error(){return V.getSnapshot().error},getServerSnapshot(){return V.getServerSnapshot()},getSnapshot(){return V.getSnapshot()},get isConnected(){return V.getSnapshot().isConnected},get partial(){return V.getSnapshot().partial},get reconnect(){return V.getSnapshot().reconnect},get scenarioId(){return V.getSnapshot().scenarioId},sendAudio(I){C.sendAudio(I)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(I){return T.add(I),()=>{T.delete(I)}},get turns(){return V.getSnapshot().turns}}};var u=(g)=>{if(!g||g.enabled===!1)return;return{enabled:!0,maxGain:g.maxGain??3,noiseGateAttenuation:g.noiseGateAttenuation??0.15,noiseGateThreshold:g.noiseGateThreshold??0.006,targetLevel:g.targetLevel??0.08}};var x0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},k0={"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 s=(g)=>{let A=g?.profile??"fast",C=g?.qualityProfile??"general",V=x0[A],c=k0[C],T=g?.silenceMs??c.silenceMs??V.silenceMs;return{profile:A,qualityProfile:C,minSilenceMs:Math.min(T,g?.minSilenceMs??c.minSilenceMs??V.minSilenceMs),silenceMs:T,speechThreshold:g?.speechThreshold??c.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??c.transcriptStabilityMs??V.transcriptStabilityMs}};var F0={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"}}},a=(g="default")=>{let A=F0[g];return{audioConditioning:u(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:s(A.turnDetection)}};var l0=(g)=>({assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,isRecording:!1,partial:g.partial,reconnect:g.reconnect,recordingError:null,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]}),p=(g,A={})=>{let C=a(A.preset),V=r(g,{...C.connection,...A.connection}),c=null,T=l0(V),L=new Set,H=()=>{for(let G of L)G()},_=()=>{if(T={...T,assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,partial:V.partial,reconnect:V.reconnect,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]},A.autoStopOnComplete!==!1&&T.status==="completed"&&T.isRecording)c?.stop(),c=null,T={...T,isRecording:!1};H()},W=V.subscribe(_);_();let I=()=>{if(c)return c;return c=F({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(G)=>{if(A.capture?.onAudio){A.capture.onAudio(G,V.sendAudio);return}V.sendAudio(G)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),c},y=()=>{c?.stop(),c=null,T={...T,isRecording:!1},H()},$=async()=>{if(T.isRecording)return;try{T={...T,recordingError:null},H(),await I().start(),T={...T,isRecording:!0},H()}catch(G){throw c=null,T={...T,isRecording:!1,recordingError:G instanceof Error?G.message:String(G)},H(),G}};return{close:()=>{W(),y(),V.close()},startRecording:$,stopRecording:y,get assistantAudio(){return T.assistantAudio},get assistantTexts(){return T.assistantTexts},get assistantStreamingText(){return T.assistantStreamingText},bindHTMX(G){return k(V,G)},get call(){return T.call},callControl:(G)=>V.callControl(G),endTurn:()=>V.endTurn(),get error(){return T.error},getServerSnapshot:()=>T,getSnapshot:()=>T,get isConnected(){return T.isConnected},get isRecording(){return T.isRecording},get partial(){return T.partial},get reconnect(){return T.reconnect},get recordingError(){return T.recordingError},get scenarioId(){return T.scenarioId},sendAudio:(G)=>V.sendAudio(G),get sessionId(){return T.sessionId},get sessionMetadata(){return T.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return T.status},subscribe:(G)=>{return L.add(G),()=>{L.delete(G)}},toggleRecording:async()=>{if(T.isRecording){y();return}await $()},get turns(){return T.turns}}};var Q=(g)=>String(g).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var t=(g)=>{if(!g.isConnected)return"idle";if(g.isPlaying)return"speaking";if(g.isRecording&&g.hasActivePartial)return"listening";if(g.isRecording)return"listening";if(g.lastTranscriptAt&&!g.lastAssistantAt)return"thinking";if(g.lastTranscriptAt&&g.lastAssistantAt&&g.lastTranscriptAt>g.lastAssistantAt)return"thinking";return"idle"};var f0={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},d0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},v0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},e=(g)=>{let A={...f0,...g.theme},C={...d0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,c=g.state.turns.at(-1)?.committedAt,T=t({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:c}),L=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,H=g.state.error?"Error":L?C.connecting:g.state.status==="completed"?C.callEnded:v0(T,C);return{agentState:T,classes:{container:`absolute-voice-widget absolute-voice-widget--${T}`,dot:`absolute-voice-widget__dot${g.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:g.state.isConnected,canMute:g.state.isRecording,canStart:!g.state.isRecording&&g.state.status!=="completed"},errorMessage:g.state.error??void 0,labels:C,partial:g.state.partial||void 0,statusLabel:H,theme:A,title:g.title??"Voice"}},i0=(g)=>typeof g==="number"?`${g}px`:g,g0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${i0(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,V=`background:${g.errorMessage?A.errorAccent:g.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,c=[];if(g.controls.canStart)c.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${Q(g.labels.startCall)}</button>`);if(g.controls.canMute)c.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${Q(g.labels.mute)}</button>`);if(g.controls.canEnd)c.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${Q(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${Q(g.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="${Q(g.classes.dot)}" style="${V}"></span>
|
|
4
|
+
<strong style="font-size:15px;">${Q(g.title)}</strong>
|
|
5
|
+
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${Q(g.statusLabel)}</span>
|
|
6
6
|
</div>
|
|
7
|
-
${g.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
|
-
${g.errorMessage?`<p style="color:${A.errorAccent};font-size:12px;margin-top:12px;">${
|
|
10
|
-
</div>`};var
|
|
7
|
+
${g.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${Q(g.partial)}”</p>`:""}
|
|
8
|
+
<div style="display:flex;gap:10px;">${c.join("")}</div>
|
|
9
|
+
${g.errorMessage?`<p style="color:${A.errorAccent};font-size:12px;margin-top:12px;">${Q(g.errorMessage)}</p>`:""}
|
|
10
|
+
</div>`};var n0=(g)=>{if(typeof g!=="string")return g;let A=document.querySelector(g);if(!A)throw Error(`AbsoluteVoice.mount: no element matches "${g}"`);return A},A0=(g,A={})=>{let C=n0(g),V=p(A.path??"/voice",A.controllerOptions),c=null,T=null,L=()=>{let _=e({...A.labels!==void 0?{labels:A.labels}:{},state:{assistantAudio:V.assistantAudio,error:V.error,isConnected:V.isConnected,isRecording:V.isRecording,partial:V.partial,status:V.status,turns:V.turns},...A.theme!==void 0?{theme:A.theme}:{},...A.title!==void 0?{title:A.title}:{}});C.innerHTML=g0(_);for(let W of C.querySelectorAll("button[data-action]")){let{action:I}=W.dataset;W.addEventListener("click",()=>{if(I==="start")V.startRecording();else if(I==="mute")V.stopRecording();else if(I==="end")V.close()})}if(V.error&&V.error!==c)c=V.error,A.onError?.(V.error);if(V.status!==T)T=V.status,A.onStatusChange?.(V.status)},H=V.subscribe(L);if(L(),A.autoStart)V.startRecording();return{controller:V,async end(){await V.close()},mute(){V.stopRecording()},async start(){await V.startRecording()},unmount(){H(),V.close(),C.innerHTML=""}}},V0="0.0.22-beta.516",C0={mount:A0,version:V0};if(typeof globalThis<"u")globalThis.AbsoluteVoice=C0;var m0=C0;})();
|