@absolutejs/voice 0.0.22-beta.636 → 0.0.22-beta.637
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/index.js +56 -0
- package/dist/testing/benchmark.d.ts +3 -0
- package/dist/testing/index.js +56 -39
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49563,6 +49563,46 @@ var runSTTAdapterFixture = async (adapter, fixture, options = {}) => {
|
|
|
49563
49563
|
};
|
|
49564
49564
|
};
|
|
49565
49565
|
|
|
49566
|
+
// src/testing/confidenceCalibration.ts
|
|
49567
|
+
var clampConfidence2 = (value) => Math.max(0, Math.min(1, value));
|
|
49568
|
+
var calibrateVoiceConfidence = (samples, binCount = 10) => {
|
|
49569
|
+
const safeBinCount = Math.max(1, Math.round(binCount));
|
|
49570
|
+
const bins = Array.from({ length: safeBinCount }, (_, index) => {
|
|
49571
|
+
const lowerBound = index / safeBinCount;
|
|
49572
|
+
return {
|
|
49573
|
+
accuracy: 0,
|
|
49574
|
+
averageConfidence: 0,
|
|
49575
|
+
count: 0,
|
|
49576
|
+
lowerBound,
|
|
49577
|
+
upperBound: (index + 1) / safeBinCount
|
|
49578
|
+
};
|
|
49579
|
+
});
|
|
49580
|
+
let brierTotal = 0;
|
|
49581
|
+
for (const sample of samples) {
|
|
49582
|
+
const confidence = clampConfidence2(sample.confidence);
|
|
49583
|
+
const binIndex = Math.min(safeBinCount - 1, Math.floor(confidence * safeBinCount));
|
|
49584
|
+
const bin = bins[binIndex];
|
|
49585
|
+
bin.count += 1;
|
|
49586
|
+
bin.averageConfidence += confidence;
|
|
49587
|
+
bin.accuracy += sample.correct ? 1 : 0;
|
|
49588
|
+
brierTotal += (confidence - (sample.correct ? 1 : 0)) ** 2;
|
|
49589
|
+
}
|
|
49590
|
+
let expectedCalibrationError = 0;
|
|
49591
|
+
for (const bin of bins) {
|
|
49592
|
+
if (bin.count === 0)
|
|
49593
|
+
continue;
|
|
49594
|
+
bin.averageConfidence /= bin.count;
|
|
49595
|
+
bin.accuracy /= bin.count;
|
|
49596
|
+
expectedCalibrationError += bin.count / Math.max(1, samples.length) * Math.abs(bin.accuracy - bin.averageConfidence);
|
|
49597
|
+
}
|
|
49598
|
+
return {
|
|
49599
|
+
bins,
|
|
49600
|
+
brierScore: samples.length > 0 ? brierTotal / samples.length : 0,
|
|
49601
|
+
expectedCalibrationError,
|
|
49602
|
+
sampleCount: samples.length
|
|
49603
|
+
};
|
|
49604
|
+
};
|
|
49605
|
+
|
|
49566
49606
|
// src/testing/criticalFields.ts
|
|
49567
49607
|
var normalizeText4 = (value) => value.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}@.%+$'-]+/gu, " ").replace(/\s+/g, " ").trim();
|
|
49568
49608
|
var normalizeDigits = (value) => normalizeSpokenNumbers(value).replace(/\D/g, "");
|
|
@@ -49833,6 +49873,15 @@ var toFixtureBenchmarkResult = (fixture, result, elapsedMs) => {
|
|
|
49833
49873
|
const expectedTerms = scoreExpectedTerms(result.finalText, fixture.expectedTerms);
|
|
49834
49874
|
const criticalFields = scoreVoiceCriticalFields(result.finalText, fixture.expectedCriticalFields);
|
|
49835
49875
|
const speakerTurns = scoreSpeakerTurns(fixture, result);
|
|
49876
|
+
const transcriptConfidence = average2(result.finalEvents.map((event) => {
|
|
49877
|
+
if (typeof event.transcript.confidence === "number") {
|
|
49878
|
+
return event.transcript.confidence;
|
|
49879
|
+
}
|
|
49880
|
+
return average2([
|
|
49881
|
+
...(event.transcript.words ?? []).map((word) => word.confidence),
|
|
49882
|
+
...(event.transcript.tokens ?? []).map((token) => token.confidence)
|
|
49883
|
+
]);
|
|
49884
|
+
}));
|
|
49836
49885
|
return {
|
|
49837
49886
|
accuracy: result.accuracy,
|
|
49838
49887
|
closeCount: result.closeEvents.length,
|
|
@@ -49856,6 +49905,7 @@ var toFixtureBenchmarkResult = (fixture, result, elapsedMs) => {
|
|
|
49856
49905
|
timeToEndOfTurnMs,
|
|
49857
49906
|
timeToFirstFinalMs,
|
|
49858
49907
|
timeToFirstPartialMs,
|
|
49908
|
+
transcriptConfidence: roundMetric4(transcriptConfidence),
|
|
49859
49909
|
title: fixture.title
|
|
49860
49910
|
};
|
|
49861
49911
|
};
|
|
@@ -49969,6 +50019,12 @@ var summarizeSTTBenchmark = (adapterId, fixtures) => {
|
|
|
49969
50019
|
const passCount = fixtures.filter((fixture) => fixture.passes).length;
|
|
49970
50020
|
return {
|
|
49971
50021
|
adapterId,
|
|
50022
|
+
confidenceCalibration: calibrateVoiceConfidence(fixtures.flatMap((fixture) => typeof fixture.transcriptConfidence === "number" ? [
|
|
50023
|
+
{
|
|
50024
|
+
confidence: fixture.transcriptConfidence,
|
|
50025
|
+
correct: fixture.passes
|
|
50026
|
+
}
|
|
50027
|
+
] : [])),
|
|
49972
50028
|
averageCharErrorRate: roundMetric4(average2(fixtures.map((fixture) => fixture.accuracy.charErrorRate))) ?? 0,
|
|
49973
50029
|
averageElapsedMs: roundMetric4(average2(fixtures.map((fixture) => fixture.elapsedMs)), 2) ?? 0,
|
|
49974
50030
|
averageEndOfTurnCount: roundMetric4(average2(fixtures.map((fixture) => fixture.endOfTurnCount)), 2) ?? 0,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { STTAdapter, STTAdapterOpenOptions } from "../core/types";
|
|
2
2
|
import { type VoiceSTTAdapterHarnessOptions, type VoiceSTTAdapterHarnessResult } from "./stt";
|
|
3
3
|
import type { VoiceTestFixture } from "./fixtures";
|
|
4
|
+
import { type VoiceConfidenceCalibrationReport } from "./confidenceCalibration";
|
|
4
5
|
import { type VoiceCriticalFieldAccuracy } from "./criticalFields";
|
|
5
6
|
export type VoiceExpectedTermAccuracy = {
|
|
6
7
|
allMatched: boolean;
|
|
@@ -41,6 +42,7 @@ export type VoiceSTTBenchmarkFixtureResult = {
|
|
|
41
42
|
timeToEndOfTurnMs?: number;
|
|
42
43
|
timeToFirstFinalMs?: number;
|
|
43
44
|
timeToFirstPartialMs?: number;
|
|
45
|
+
transcriptConfidence?: number;
|
|
44
46
|
title: string;
|
|
45
47
|
};
|
|
46
48
|
export type VoiceSTTBenchmarkSummary = {
|
|
@@ -67,6 +69,7 @@ export type VoiceSTTBenchmarkSummary = {
|
|
|
67
69
|
totalErrorCount: number;
|
|
68
70
|
wordAccuracyRate: number;
|
|
69
71
|
groupSummaries: VoiceSTTBenchmarkFixtureSummary[];
|
|
72
|
+
confidenceCalibration: VoiceConfidenceCalibrationReport;
|
|
70
73
|
};
|
|
71
74
|
export type VoiceSTTBenchmarkFixtureSummary = {
|
|
72
75
|
group: VoiceSTTFixtureEnvironment;
|
package/dist/testing/index.js
CHANGED
|
@@ -367,6 +367,46 @@ var runSTTAdapterFixture = async (adapter, fixture, options = {}) => {
|
|
|
367
367
|
};
|
|
368
368
|
};
|
|
369
369
|
|
|
370
|
+
// src/testing/confidenceCalibration.ts
|
|
371
|
+
var clampConfidence = (value) => Math.max(0, Math.min(1, value));
|
|
372
|
+
var calibrateVoiceConfidence = (samples, binCount = 10) => {
|
|
373
|
+
const safeBinCount = Math.max(1, Math.round(binCount));
|
|
374
|
+
const bins = Array.from({ length: safeBinCount }, (_, index) => {
|
|
375
|
+
const lowerBound = index / safeBinCount;
|
|
376
|
+
return {
|
|
377
|
+
accuracy: 0,
|
|
378
|
+
averageConfidence: 0,
|
|
379
|
+
count: 0,
|
|
380
|
+
lowerBound,
|
|
381
|
+
upperBound: (index + 1) / safeBinCount
|
|
382
|
+
};
|
|
383
|
+
});
|
|
384
|
+
let brierTotal = 0;
|
|
385
|
+
for (const sample of samples) {
|
|
386
|
+
const confidence = clampConfidence(sample.confidence);
|
|
387
|
+
const binIndex = Math.min(safeBinCount - 1, Math.floor(confidence * safeBinCount));
|
|
388
|
+
const bin = bins[binIndex];
|
|
389
|
+
bin.count += 1;
|
|
390
|
+
bin.averageConfidence += confidence;
|
|
391
|
+
bin.accuracy += sample.correct ? 1 : 0;
|
|
392
|
+
brierTotal += (confidence - (sample.correct ? 1 : 0)) ** 2;
|
|
393
|
+
}
|
|
394
|
+
let expectedCalibrationError = 0;
|
|
395
|
+
for (const bin of bins) {
|
|
396
|
+
if (bin.count === 0)
|
|
397
|
+
continue;
|
|
398
|
+
bin.averageConfidence /= bin.count;
|
|
399
|
+
bin.accuracy /= bin.count;
|
|
400
|
+
expectedCalibrationError += bin.count / Math.max(1, samples.length) * Math.abs(bin.accuracy - bin.averageConfidence);
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
bins,
|
|
404
|
+
brierScore: samples.length > 0 ? brierTotal / samples.length : 0,
|
|
405
|
+
expectedCalibrationError,
|
|
406
|
+
sampleCount: samples.length
|
|
407
|
+
};
|
|
408
|
+
};
|
|
409
|
+
|
|
370
410
|
// src/core/numberNormalizer.ts
|
|
371
411
|
var ONES = {
|
|
372
412
|
eight: 8,
|
|
@@ -822,6 +862,15 @@ var toFixtureBenchmarkResult = (fixture, result, elapsedMs) => {
|
|
|
822
862
|
const expectedTerms = scoreExpectedTerms(result.finalText, fixture.expectedTerms);
|
|
823
863
|
const criticalFields = scoreVoiceCriticalFields(result.finalText, fixture.expectedCriticalFields);
|
|
824
864
|
const speakerTurns = scoreSpeakerTurns(fixture, result);
|
|
865
|
+
const transcriptConfidence = average(result.finalEvents.map((event) => {
|
|
866
|
+
if (typeof event.transcript.confidence === "number") {
|
|
867
|
+
return event.transcript.confidence;
|
|
868
|
+
}
|
|
869
|
+
return average([
|
|
870
|
+
...(event.transcript.words ?? []).map((word) => word.confidence),
|
|
871
|
+
...(event.transcript.tokens ?? []).map((token) => token.confidence)
|
|
872
|
+
]);
|
|
873
|
+
}));
|
|
825
874
|
return {
|
|
826
875
|
accuracy: result.accuracy,
|
|
827
876
|
closeCount: result.closeEvents.length,
|
|
@@ -845,6 +894,7 @@ var toFixtureBenchmarkResult = (fixture, result, elapsedMs) => {
|
|
|
845
894
|
timeToEndOfTurnMs,
|
|
846
895
|
timeToFirstFinalMs,
|
|
847
896
|
timeToFirstPartialMs,
|
|
897
|
+
transcriptConfidence: roundMetric(transcriptConfidence),
|
|
848
898
|
title: fixture.title
|
|
849
899
|
};
|
|
850
900
|
};
|
|
@@ -958,6 +1008,12 @@ var summarizeSTTBenchmark = (adapterId, fixtures) => {
|
|
|
958
1008
|
const passCount = fixtures.filter((fixture) => fixture.passes).length;
|
|
959
1009
|
return {
|
|
960
1010
|
adapterId,
|
|
1011
|
+
confidenceCalibration: calibrateVoiceConfidence(fixtures.flatMap((fixture) => typeof fixture.transcriptConfidence === "number" ? [
|
|
1012
|
+
{
|
|
1013
|
+
confidence: fixture.transcriptConfidence,
|
|
1014
|
+
correct: fixture.passes
|
|
1015
|
+
}
|
|
1016
|
+
] : [])),
|
|
961
1017
|
averageCharErrorRate: roundMetric(average(fixtures.map((fixture) => fixture.accuracy.charErrorRate))) ?? 0,
|
|
962
1018
|
averageElapsedMs: roundMetric(average(fixtures.map((fixture) => fixture.elapsedMs)), 2) ?? 0,
|
|
963
1019
|
averageEndOfTurnCount: roundMetric(average(fixtures.map((fixture) => fixture.endOfTurnCount)), 2) ?? 0,
|
|
@@ -1030,45 +1086,6 @@ var summarizeSTTBenchmarkSeries = (input) => {
|
|
|
1030
1086
|
}
|
|
1031
1087
|
};
|
|
1032
1088
|
};
|
|
1033
|
-
// src/testing/confidenceCalibration.ts
|
|
1034
|
-
var clampConfidence = (value) => Math.max(0, Math.min(1, value));
|
|
1035
|
-
var calibrateVoiceConfidence = (samples, binCount = 10) => {
|
|
1036
|
-
const safeBinCount = Math.max(1, Math.round(binCount));
|
|
1037
|
-
const bins = Array.from({ length: safeBinCount }, (_, index) => {
|
|
1038
|
-
const lowerBound = index / safeBinCount;
|
|
1039
|
-
return {
|
|
1040
|
-
accuracy: 0,
|
|
1041
|
-
averageConfidence: 0,
|
|
1042
|
-
count: 0,
|
|
1043
|
-
lowerBound,
|
|
1044
|
-
upperBound: (index + 1) / safeBinCount
|
|
1045
|
-
};
|
|
1046
|
-
});
|
|
1047
|
-
let brierTotal = 0;
|
|
1048
|
-
for (const sample of samples) {
|
|
1049
|
-
const confidence = clampConfidence(sample.confidence);
|
|
1050
|
-
const binIndex = Math.min(safeBinCount - 1, Math.floor(confidence * safeBinCount));
|
|
1051
|
-
const bin = bins[binIndex];
|
|
1052
|
-
bin.count += 1;
|
|
1053
|
-
bin.averageConfidence += confidence;
|
|
1054
|
-
bin.accuracy += sample.correct ? 1 : 0;
|
|
1055
|
-
brierTotal += (confidence - (sample.correct ? 1 : 0)) ** 2;
|
|
1056
|
-
}
|
|
1057
|
-
let expectedCalibrationError = 0;
|
|
1058
|
-
for (const bin of bins) {
|
|
1059
|
-
if (bin.count === 0)
|
|
1060
|
-
continue;
|
|
1061
|
-
bin.averageConfidence /= bin.count;
|
|
1062
|
-
bin.accuracy /= bin.count;
|
|
1063
|
-
expectedCalibrationError += bin.count / Math.max(1, samples.length) * Math.abs(bin.accuracy - bin.averageConfidence);
|
|
1064
|
-
}
|
|
1065
|
-
return {
|
|
1066
|
-
bins,
|
|
1067
|
-
brierScore: samples.length > 0 ? brierTotal / samples.length : 0,
|
|
1068
|
-
expectedCalibrationError,
|
|
1069
|
-
sampleCount: samples.length
|
|
1070
|
-
};
|
|
1071
|
-
};
|
|
1072
1089
|
// src/core/correction.ts
|
|
1073
1090
|
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1074
1091
|
var buildAliasMatcher = (alias) => new RegExp(`(?<![\\p{L}\\p{N}'])${escapeRegExp(alias)}(?![\\p{L}\\p{N}'])`, "giu");
|