@kuralle-syrinx/pipecat-smart-turn 4.4.0 → 4.5.0
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/eos-plugin.d.ts +59 -0
- package/dist/eos-plugin.d.ts.map +1 -0
- package/dist/eos-plugin.js +504 -0
- package/dist/eos-plugin.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction-policy.d.ts +41 -0
- package/dist/interaction-policy.d.ts.map +1 -0
- package/dist/interaction-policy.js +233 -0
- package/dist/interaction-policy.js.map +1 -0
- package/dist/predictor.d.ts +12 -0
- package/dist/predictor.d.ts.map +1 -0
- package/dist/predictor.js +57 -0
- package/dist/predictor.js.map +1 -0
- package/dist/semantic-completeness.d.ts +24 -0
- package/dist/semantic-completeness.d.ts.map +1 -0
- package/dist/semantic-completeness.js +116 -0
- package/dist/semantic-completeness.js.map +1 -0
- package/dist/semantic-fixtures.d.ts +7 -0
- package/dist/semantic-fixtures.d.ts.map +1 -0
- package/dist/semantic-fixtures.js +15 -0
- package/dist/semantic-fixtures.js.map +1 -0
- package/dist/smart-turn-types.d.ts +8 -0
- package/dist/smart-turn-types.d.ts.map +1 -0
- package/dist/smart-turn-types.js +3 -0
- package/dist/smart-turn-types.js.map +1 -0
- package/package.json +20 -7
- package/src/index.test.ts +1033 -0
- package/src/interaction-policy.test.ts +161 -0
- package/src/semantic-completeness.test.ts +207 -0
- package/models/README.md +0 -10
- package/models/smart-turn-v3.2-cpu.onnx +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type InteractionDecision, type InteractionObservation, type LifecycleInteractionPolicy, type PluginConfig } from "@kuralle-syrinx/core";
|
|
2
|
+
import { type SmartTurnPredictor } from "./predictor.js";
|
|
3
|
+
export interface SmartTurnInteractionPolicyConfig {
|
|
4
|
+
readonly probability_threshold?: number;
|
|
5
|
+
readonly semantic_endpointing_enabled?: boolean;
|
|
6
|
+
readonly finalize_delay_ms?: number;
|
|
7
|
+
readonly semantic_shortcut_delay_ms?: number;
|
|
8
|
+
readonly incomplete_fallback_ms?: number;
|
|
9
|
+
readonly semantic_defer_fallback_ms?: number;
|
|
10
|
+
readonly min_speech_ms?: number;
|
|
11
|
+
readonly max_audio_samples?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class SmartTurnInteractionPolicy implements LifecycleInteractionPolicy {
|
|
14
|
+
private readonly predictor;
|
|
15
|
+
private readonly states;
|
|
16
|
+
private probabilityThreshold;
|
|
17
|
+
private semanticEndpointingEnabled;
|
|
18
|
+
private finalizeDelayMs;
|
|
19
|
+
private semanticShortcutDelayMs;
|
|
20
|
+
private incompleteFallbackMs;
|
|
21
|
+
private semanticDeferFallbackMs;
|
|
22
|
+
private minSpeechMs;
|
|
23
|
+
private maxAudioSamples;
|
|
24
|
+
private initialized;
|
|
25
|
+
constructor(predictor?: SmartTurnPredictor);
|
|
26
|
+
initialize(config?: PluginConfig): Promise<void>;
|
|
27
|
+
observe(observation: InteractionObservation): readonly InteractionDecision[];
|
|
28
|
+
reset(contextId: string): void;
|
|
29
|
+
close(): Promise<void>;
|
|
30
|
+
private stateFor;
|
|
31
|
+
private beginSpeech;
|
|
32
|
+
private appendAudio;
|
|
33
|
+
private analyzeBoundary;
|
|
34
|
+
private evaluateBoundary;
|
|
35
|
+
private issueTakeTurn;
|
|
36
|
+
private scheduleFallback;
|
|
37
|
+
private clearFallback;
|
|
38
|
+
private drainDecisions;
|
|
39
|
+
private fusionConfig;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=interaction-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-policy.d.ts","sourceRoot":"","sources":["../src/interaction-policy.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAA6B,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAoBpF,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IAChD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,qBAAa,0BAA2B,YAAW,0BAA0B;IAY/D,OAAO,CAAC,QAAQ,CAAC,SAAS;IAXtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,oBAAoB,CAAO;IACnC,OAAO,CAAC,0BAA0B,CAAQ;IAC1C,OAAO,CAAC,eAAe,CAAO;IAC9B,OAAO,CAAC,uBAAuB,CAAM;IACrC,OAAO,CAAC,oBAAoB,CAAQ;IACpC,OAAO,CAAC,uBAAuB,CAAQ;IACvC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,WAAW,CAAS;gBAEC,SAAS,GAAE,kBAAoD;IAEtF,UAAU,CAAC,MAAM,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAa1D,OAAO,CAAC,WAAW,EAAE,sBAAsB,GAAG,SAAS,mBAAmB,EAAE;IA8B5E,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAQxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,OAAO,CAAC,QAAQ;IAqBhB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,YAAY;CASrB"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { confidenceToWaitMs, } from "@kuralle-syrinx/core";
|
|
3
|
+
import { fuseEndpointDecision, latestTranscript, scoreSemanticCompleteness, } from "./semantic-completeness.js";
|
|
4
|
+
import { LocalSmartTurnV3Predictor } from "./predictor.js";
|
|
5
|
+
const SAMPLE_RATE = 16000;
|
|
6
|
+
const DEFAULT_MAX_AUDIO_SAMPLES = SAMPLE_RATE * 8;
|
|
7
|
+
export class SmartTurnInteractionPolicy {
|
|
8
|
+
predictor;
|
|
9
|
+
states = new Map();
|
|
10
|
+
probabilityThreshold = 0.5;
|
|
11
|
+
semanticEndpointingEnabled = true;
|
|
12
|
+
finalizeDelayMs = 250;
|
|
13
|
+
semanticShortcutDelayMs = 50;
|
|
14
|
+
incompleteFallbackMs = 2000;
|
|
15
|
+
semanticDeferFallbackMs = 4000;
|
|
16
|
+
minSpeechMs = 0;
|
|
17
|
+
maxAudioSamples = DEFAULT_MAX_AUDIO_SAMPLES;
|
|
18
|
+
initialized = false;
|
|
19
|
+
constructor(predictor = new LocalSmartTurnV3Predictor()) {
|
|
20
|
+
this.predictor = predictor;
|
|
21
|
+
}
|
|
22
|
+
async initialize(config = {}) {
|
|
23
|
+
this.probabilityThreshold = readProbability(config["probability_threshold"], 0.5);
|
|
24
|
+
this.semanticEndpointingEnabled = readBoolean(config["semantic_endpointing_enabled"], true);
|
|
25
|
+
this.finalizeDelayMs = readNonNegativeNumber(config["finalize_delay_ms"], 250);
|
|
26
|
+
this.semanticShortcutDelayMs = readNonNegativeNumber(config["semantic_shortcut_delay_ms"], 50);
|
|
27
|
+
this.incompleteFallbackMs = readNonNegativeNumber(config["incomplete_fallback_ms"], 2000);
|
|
28
|
+
this.semanticDeferFallbackMs = readNonNegativeNumber(config["semantic_defer_fallback_ms"], 4000);
|
|
29
|
+
this.minSpeechMs = readNonNegativeNumber(config["min_speech_ms"], 0);
|
|
30
|
+
this.maxAudioSamples = readPositiveNumber(config["max_audio_samples"], DEFAULT_MAX_AUDIO_SAMPLES);
|
|
31
|
+
await this.predictor.initialize(config);
|
|
32
|
+
this.initialized = true;
|
|
33
|
+
}
|
|
34
|
+
observe(observation) {
|
|
35
|
+
const state = this.stateFor(observation.contextId);
|
|
36
|
+
switch (observation.kind) {
|
|
37
|
+
case "audio_frame":
|
|
38
|
+
this.appendAudio(state, observation.audio, observation.sampleRateHz);
|
|
39
|
+
break;
|
|
40
|
+
case "stt_partial":
|
|
41
|
+
if (observation.text.trim())
|
|
42
|
+
state.latestInterim = observation.text.trim();
|
|
43
|
+
this.evaluateBoundary(state);
|
|
44
|
+
break;
|
|
45
|
+
case "stt_final": {
|
|
46
|
+
const text = observation.text.trim();
|
|
47
|
+
if (text && state.finalSegments.at(-1) !== text)
|
|
48
|
+
state.finalSegments.push(text);
|
|
49
|
+
state.latestInterim = "";
|
|
50
|
+
this.evaluateBoundary(state);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case "vad_speech_started":
|
|
54
|
+
this.beginSpeech(state);
|
|
55
|
+
break;
|
|
56
|
+
case "vad_speech_ended":
|
|
57
|
+
state.speechActive = false;
|
|
58
|
+
this.analyzeBoundary(state);
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
return this.drainDecisions(state);
|
|
64
|
+
}
|
|
65
|
+
reset(contextId) {
|
|
66
|
+
const state = this.states.get(contextId);
|
|
67
|
+
if (!state)
|
|
68
|
+
return;
|
|
69
|
+
this.clearFallback(state);
|
|
70
|
+
state.boundarySequence += 1;
|
|
71
|
+
this.states.delete(contextId);
|
|
72
|
+
}
|
|
73
|
+
async close() {
|
|
74
|
+
this.initialized = false;
|
|
75
|
+
for (const contextId of [...this.states.keys()])
|
|
76
|
+
this.reset(contextId);
|
|
77
|
+
await this.predictor.close();
|
|
78
|
+
}
|
|
79
|
+
stateFor(contextId) {
|
|
80
|
+
const existing = this.states.get(contextId);
|
|
81
|
+
if (existing)
|
|
82
|
+
return existing;
|
|
83
|
+
const state = {
|
|
84
|
+
contextId,
|
|
85
|
+
audio: [],
|
|
86
|
+
speechMs: 0,
|
|
87
|
+
finalSegments: [],
|
|
88
|
+
latestInterim: "",
|
|
89
|
+
speechActive: false,
|
|
90
|
+
boundarySequence: 0,
|
|
91
|
+
boundaryAnalyzed: false,
|
|
92
|
+
probability: 0,
|
|
93
|
+
decisionIssued: false,
|
|
94
|
+
pendingDecisions: [],
|
|
95
|
+
fallbackTimer: null,
|
|
96
|
+
};
|
|
97
|
+
this.states.set(contextId, state);
|
|
98
|
+
return state;
|
|
99
|
+
}
|
|
100
|
+
beginSpeech(state) {
|
|
101
|
+
this.clearFallback(state);
|
|
102
|
+
state.audio = [];
|
|
103
|
+
state.speechMs = 0;
|
|
104
|
+
state.finalSegments = [];
|
|
105
|
+
state.latestInterim = "";
|
|
106
|
+
state.speechActive = true;
|
|
107
|
+
state.boundarySequence += 1;
|
|
108
|
+
state.boundaryAnalyzed = false;
|
|
109
|
+
state.probability = 0;
|
|
110
|
+
state.decisionIssued = false;
|
|
111
|
+
state.pendingDecisions = [];
|
|
112
|
+
}
|
|
113
|
+
appendAudio(state, audio, sampleRateHz = SAMPLE_RATE) {
|
|
114
|
+
if (!audio?.length)
|
|
115
|
+
return;
|
|
116
|
+
for (const sample of audio)
|
|
117
|
+
state.audio.push(sample / 32768);
|
|
118
|
+
if (state.speechActive && sampleRateHz > 0) {
|
|
119
|
+
state.speechMs += (audio.length / sampleRateHz) * 1000;
|
|
120
|
+
}
|
|
121
|
+
const overflow = state.audio.length - this.maxAudioSamples;
|
|
122
|
+
if (overflow > 0)
|
|
123
|
+
state.audio.splice(0, overflow);
|
|
124
|
+
}
|
|
125
|
+
analyzeBoundary(state) {
|
|
126
|
+
if (!this.initialized || state.decisionIssued)
|
|
127
|
+
return;
|
|
128
|
+
const sequence = ++state.boundarySequence;
|
|
129
|
+
const audio = Float32Array.from(state.audio);
|
|
130
|
+
void this.predictor.predict(audio).then((probability) => {
|
|
131
|
+
if (!this.initialized || state.boundarySequence !== sequence || !this.states.has(state.contextId))
|
|
132
|
+
return;
|
|
133
|
+
state.probability = clampProbability(probability);
|
|
134
|
+
state.boundaryAnalyzed = true;
|
|
135
|
+
this.evaluateBoundary(state);
|
|
136
|
+
}, () => {
|
|
137
|
+
if (!this.initialized || state.boundarySequence !== sequence || !this.states.has(state.contextId))
|
|
138
|
+
return;
|
|
139
|
+
state.boundaryAnalyzed = true;
|
|
140
|
+
state.probability = 0;
|
|
141
|
+
this.scheduleFallback(state, this.incompleteFallbackMs);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
evaluateBoundary(state) {
|
|
145
|
+
if (!state.boundaryAnalyzed || state.speechActive || state.decisionIssued)
|
|
146
|
+
return;
|
|
147
|
+
const smartTurnComplete = state.probability > this.probabilityThreshold;
|
|
148
|
+
const transcript = latestTranscript(state.finalSegments, state.latestInterim);
|
|
149
|
+
if (!transcript) {
|
|
150
|
+
if (smartTurnComplete && state.speechMs >= this.minSpeechMs) {
|
|
151
|
+
this.issueTakeTurn(state, state.probability);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
this.scheduleFallback(state, this.incompleteFallbackMs);
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const semantic = scoreSemanticCompleteness(transcript);
|
|
159
|
+
const fusion = fuseEndpointDecision(smartTurnComplete, semantic, state.speechMs, this.fusionConfig());
|
|
160
|
+
if (fusion.release) {
|
|
161
|
+
const confidence = smartTurnComplete ? Math.max(state.probability, semantic.confidence) : semantic.confidence;
|
|
162
|
+
this.issueTakeTurn(state, confidence);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!state.pendingDecisions.some((decision) => decision.kind === "hold")) {
|
|
166
|
+
state.pendingDecisions.push({ kind: "hold" });
|
|
167
|
+
}
|
|
168
|
+
this.scheduleFallback(state, fusion.deferReason ? this.semanticDeferFallbackMs : fusion.finalizeDelayMs);
|
|
169
|
+
}
|
|
170
|
+
issueTakeTurn(state, confidence) {
|
|
171
|
+
if (state.decisionIssued)
|
|
172
|
+
return;
|
|
173
|
+
this.clearFallback(state);
|
|
174
|
+
state.decisionIssued = true;
|
|
175
|
+
state.pendingDecisions.push({
|
|
176
|
+
kind: "take_turn",
|
|
177
|
+
confidence,
|
|
178
|
+
waitMs: confidenceToWaitMs(confidence),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
scheduleFallback(state, delayMs) {
|
|
182
|
+
if (state.fallbackTimer || state.decisionIssued)
|
|
183
|
+
return;
|
|
184
|
+
state.fallbackTimer = setTimeout(() => {
|
|
185
|
+
state.fallbackTimer = null;
|
|
186
|
+
if (!this.initialized || state.speechActive || state.decisionIssued || !this.states.has(state.contextId))
|
|
187
|
+
return;
|
|
188
|
+
state.decisionIssued = true;
|
|
189
|
+
state.pendingDecisions.push({ kind: "take_turn", confidence: 0, waitMs: 0 });
|
|
190
|
+
}, delayMs);
|
|
191
|
+
}
|
|
192
|
+
clearFallback(state) {
|
|
193
|
+
if (!state.fallbackTimer)
|
|
194
|
+
return;
|
|
195
|
+
clearTimeout(state.fallbackTimer);
|
|
196
|
+
state.fallbackTimer = null;
|
|
197
|
+
}
|
|
198
|
+
drainDecisions(state) {
|
|
199
|
+
if (state.pendingDecisions.length === 0)
|
|
200
|
+
return [];
|
|
201
|
+
return state.pendingDecisions.splice(0);
|
|
202
|
+
}
|
|
203
|
+
fusionConfig() {
|
|
204
|
+
return {
|
|
205
|
+
enabled: this.semanticEndpointingEnabled,
|
|
206
|
+
finalizeDelayMs: this.finalizeDelayMs,
|
|
207
|
+
semanticShortcutDelayMs: this.semanticShortcutDelayMs,
|
|
208
|
+
incompleteFallbackMs: this.incompleteFallbackMs,
|
|
209
|
+
minSpeechMs: this.minSpeechMs,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function clampProbability(value) {
|
|
214
|
+
if (!Number.isFinite(value))
|
|
215
|
+
return 0;
|
|
216
|
+
return Math.min(1, Math.max(0, value));
|
|
217
|
+
}
|
|
218
|
+
function readBoolean(value, fallback) {
|
|
219
|
+
return typeof value === "boolean" ? value : fallback;
|
|
220
|
+
}
|
|
221
|
+
function readNonNegativeNumber(value, fallback) {
|
|
222
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
223
|
+
return fallback;
|
|
224
|
+
return Math.max(0, Math.floor(value));
|
|
225
|
+
}
|
|
226
|
+
function readPositiveNumber(value, fallback) {
|
|
227
|
+
const parsed = readNonNegativeNumber(value, fallback);
|
|
228
|
+
return parsed > 0 ? parsed : fallback;
|
|
229
|
+
}
|
|
230
|
+
function readProbability(value, fallback) {
|
|
231
|
+
return typeof value === "number" ? clampProbability(value) : fallback;
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=interaction-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-policy.js","sourceRoot":"","sources":["../src/interaction-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type PluginConfig } from "@kuralle-syrinx/core";
|
|
2
|
+
import type { SmartTurnPredictor } from "./smart-turn-types.js";
|
|
3
|
+
export type { SmartTurnPredictor } from "./smart-turn-types.js";
|
|
4
|
+
export declare class LocalSmartTurnV3Predictor implements SmartTurnPredictor {
|
|
5
|
+
private ort;
|
|
6
|
+
private session;
|
|
7
|
+
private featureExtractor;
|
|
8
|
+
initialize(config: PluginConfig): Promise<void>;
|
|
9
|
+
predict(audio: Float32Array): Promise<number>;
|
|
10
|
+
close(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=predictor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predictor.d.ts","sourceRoot":"","sources":["../src/predictor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAahE,qBAAa,yBAA0B,YAAW,kBAAkB;IAClE,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,gBAAgB,CAAiC;IAEnD,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB/C,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAe7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { optionalStringConfig } from "@kuralle-syrinx/core";
|
|
4
|
+
const SAMPLE_RATE = 16000;
|
|
5
|
+
const MAX_AUDIO_SAMPLES = SAMPLE_RATE * 8;
|
|
6
|
+
const DEFAULT_MODEL_PATH = fileURLToPath(new URL("../models/smart-turn-v3.2-cpu.onnx", import.meta.url));
|
|
7
|
+
export class LocalSmartTurnV3Predictor {
|
|
8
|
+
ort = null;
|
|
9
|
+
session = null;
|
|
10
|
+
featureExtractor = null;
|
|
11
|
+
async initialize(config) {
|
|
12
|
+
const sampleRate = readNonNegativeNumber(config["sample_rate"], SAMPLE_RATE);
|
|
13
|
+
if (sampleRate !== SAMPLE_RATE) {
|
|
14
|
+
throw new Error(`Smart Turn requires 16 kHz PCM input, got ${String(sampleRate)} Hz`);
|
|
15
|
+
}
|
|
16
|
+
const modelPath = optionalStringConfig(config, "model_path") ?? DEFAULT_MODEL_PATH;
|
|
17
|
+
const { WhisperFeatureExtractor } = await import("@huggingface/transformers");
|
|
18
|
+
this.featureExtractor = new WhisperFeatureExtractor({
|
|
19
|
+
feature_size: 80,
|
|
20
|
+
sampling_rate: SAMPLE_RATE,
|
|
21
|
+
hop_length: 160,
|
|
22
|
+
n_fft: 400,
|
|
23
|
+
n_samples: MAX_AUDIO_SAMPLES,
|
|
24
|
+
nb_max_frames: 800,
|
|
25
|
+
});
|
|
26
|
+
this.ort = await import("onnxruntime-node");
|
|
27
|
+
this.session = await this.ort.InferenceSession.create(modelPath, {
|
|
28
|
+
executionProviders: ["cpu"],
|
|
29
|
+
interOpNumThreads: 1,
|
|
30
|
+
intraOpNumThreads: 1,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async predict(audio) {
|
|
34
|
+
if (!this.ort || !this.session || !this.featureExtractor) {
|
|
35
|
+
throw new Error("Smart Turn predictor is not initialized");
|
|
36
|
+
}
|
|
37
|
+
const modelAudio = new Float32Array(MAX_AUDIO_SAMPLES);
|
|
38
|
+
const tail = audio.length > MAX_AUDIO_SAMPLES ? audio.slice(-MAX_AUDIO_SAMPLES) : audio;
|
|
39
|
+
modelAudio.set(tail, MAX_AUDIO_SAMPLES - tail.length);
|
|
40
|
+
const features = await this.featureExtractor._extract_fbank_features(modelAudio);
|
|
41
|
+
const input = new this.ort.Tensor("float32", features.data, [1, 80, 800]);
|
|
42
|
+
const outputs = await this.session.run({ input_features: input });
|
|
43
|
+
const value = outputs["logits"]?.data[0];
|
|
44
|
+
return typeof value === "number" ? value : 0;
|
|
45
|
+
}
|
|
46
|
+
async close() {
|
|
47
|
+
this.session = null;
|
|
48
|
+
this.ort = null;
|
|
49
|
+
this.featureExtractor = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function readNonNegativeNumber(value, fallback) {
|
|
53
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
54
|
+
return fallback;
|
|
55
|
+
return Math.max(0, Math.floor(value));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=predictor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predictor.js","sourceRoot":"","sources":["../src/predictor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type SemanticCompletenessLabel = "complete" | "incomplete" | "backchannel";
|
|
2
|
+
export interface SemanticCompletenessScore {
|
|
3
|
+
readonly complete: boolean;
|
|
4
|
+
readonly label: SemanticCompletenessLabel;
|
|
5
|
+
readonly confidence: number;
|
|
6
|
+
}
|
|
7
|
+
export interface SemanticEndpointFusionConfig {
|
|
8
|
+
readonly enabled: boolean;
|
|
9
|
+
readonly finalizeDelayMs: number;
|
|
10
|
+
readonly semanticShortcutDelayMs: number;
|
|
11
|
+
readonly incompleteFallbackMs: number;
|
|
12
|
+
readonly minSpeechMs?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface EndpointFusionDecision {
|
|
15
|
+
readonly release: boolean;
|
|
16
|
+
readonly requestFinalize: boolean;
|
|
17
|
+
readonly finalizeDelayMs: number;
|
|
18
|
+
readonly deferReason?: "semantic_incomplete";
|
|
19
|
+
readonly shortcutReason?: "semantic_complete";
|
|
20
|
+
}
|
|
21
|
+
export declare function scoreSemanticCompleteness(text: string): SemanticCompletenessScore;
|
|
22
|
+
export declare function fuseEndpointDecision(smartTurnComplete: boolean, semantic: SemanticCompletenessScore, speechMs: number, config: SemanticEndpointFusionConfig): EndpointFusionDecision;
|
|
23
|
+
export declare function latestTranscript(finalSegments: readonly string[], interimText: string): string;
|
|
24
|
+
//# sourceMappingURL=semantic-completeness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-completeness.d.ts","sourceRoot":"","sources":["../src/semantic-completeness.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG,UAAU,GAAG,YAAY,GAAG,aAAa,CAAC;AAElF,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IAC7C,QAAQ,CAAC,cAAc,CAAC,EAAE,mBAAmB,CAAC;CAC/C;AAkCD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,yBAAyB,CAqDjF;AAED,wBAAgB,oBAAoB,CAClC,iBAAiB,EAAE,OAAO,EAC1B,QAAQ,EAAE,yBAAyB,EACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,4BAA4B,GACnC,sBAAsB,CAwCxB;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAS9F"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const TRAILING_INCOMPLETE = /\b(and|but|or|so|because|if|when|while|although|though|since|unless|until|as|that|which|who|where|how|what|why|the|a|an|to|for|of|in|on|at|with|about|from|by|into|through|after|before|during|without|within|between|among|over|under|around|against|toward|towards|upon|like|than|not|please|just|also|then|well|um|uh|er|hmm|i|we|you|he|she|they|my|your|our|their|this|these|those)\s*$/i;
|
|
2
|
+
const EXACT_INCOMPLETE = [
|
|
3
|
+
/^i need to know$/i,
|
|
4
|
+
/^i want to know$/i,
|
|
5
|
+
/^can you tell me$/i,
|
|
6
|
+
/^how do i$/i,
|
|
7
|
+
/^what is the$/i,
|
|
8
|
+
];
|
|
9
|
+
const INCOMPLETE_PREFIXES = [
|
|
10
|
+
/^i need to\b/i,
|
|
11
|
+
/^i want to\b/i,
|
|
12
|
+
/^can you tell me about\b/i,
|
|
13
|
+
/^what is the\b/i,
|
|
14
|
+
/^how do i\b/i,
|
|
15
|
+
/^i'm trying to\b/i,
|
|
16
|
+
/^i am trying to\b/i,
|
|
17
|
+
/^could you help me with\b/i,
|
|
18
|
+
/^tell me about the\b/i,
|
|
19
|
+
];
|
|
20
|
+
const OPEN_ENDED_PREFIXES = [
|
|
21
|
+
/^i was wondering if\b/i,
|
|
22
|
+
];
|
|
23
|
+
const BACKCHANNEL = /^(yeah|yes|yep|yup|uh-?huh|mm-?hmm|mhm|right|okay|ok|sure|got it|thank you|thanks|no|nope|nah)\.?$/i;
|
|
24
|
+
const SENTENCE_END = /[.!?]["')]*\s*$/;
|
|
25
|
+
export function scoreSemanticCompleteness(text) {
|
|
26
|
+
const normalized = text.trim().replace(/\s+/g, " ");
|
|
27
|
+
if (!normalized) {
|
|
28
|
+
return { complete: false, label: "incomplete", confidence: 0 };
|
|
29
|
+
}
|
|
30
|
+
if (BACKCHANNEL.test(normalized)) {
|
|
31
|
+
return { complete: true, label: "backchannel", confidence: 0.95 };
|
|
32
|
+
}
|
|
33
|
+
if (SENTENCE_END.test(normalized)) {
|
|
34
|
+
return { complete: true, label: "complete", confidence: 0.9 };
|
|
35
|
+
}
|
|
36
|
+
if (TRAILING_INCOMPLETE.test(normalized)) {
|
|
37
|
+
return { complete: false, label: "incomplete", confidence: 0.85 };
|
|
38
|
+
}
|
|
39
|
+
for (const phrase of EXACT_INCOMPLETE) {
|
|
40
|
+
if (phrase.test(normalized)) {
|
|
41
|
+
return { complete: false, label: "incomplete", confidence: 0.85 };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const prefix of INCOMPLETE_PREFIXES) {
|
|
45
|
+
if (!prefix.test(normalized))
|
|
46
|
+
continue;
|
|
47
|
+
const remainder = normalized.replace(prefix, "").trim();
|
|
48
|
+
if (!remainder) {
|
|
49
|
+
return { complete: false, label: "incomplete", confidence: 0.8 };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const prefix of OPEN_ENDED_PREFIXES) {
|
|
53
|
+
if (prefix.test(normalized)) {
|
|
54
|
+
return { complete: false, label: "incomplete", confidence: 0.75 };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (/,\s*$/.test(normalized)) {
|
|
58
|
+
return { complete: false, label: "incomplete", confidence: 0.75 };
|
|
59
|
+
}
|
|
60
|
+
const words = normalized.split(/\s+/);
|
|
61
|
+
if (/^(what|where|when|why|how|who|which|is|are|do|does|did|can|could|would|will|should|have|has|had)\b/i.test(normalized) &&
|
|
62
|
+
words.length >= 4) {
|
|
63
|
+
return { complete: true, label: "complete", confidence: 0.7 };
|
|
64
|
+
}
|
|
65
|
+
return { complete: true, label: "complete", confidence: 0.55 };
|
|
66
|
+
}
|
|
67
|
+
export function fuseEndpointDecision(smartTurnComplete, semantic, speechMs, config) {
|
|
68
|
+
if (!config.enabled) {
|
|
69
|
+
return {
|
|
70
|
+
release: smartTurnComplete,
|
|
71
|
+
requestFinalize: smartTurnComplete,
|
|
72
|
+
finalizeDelayMs: config.finalizeDelayMs,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (smartTurnComplete && semantic.complete && speechMs >= (config.minSpeechMs ?? 0)) {
|
|
76
|
+
return {
|
|
77
|
+
release: true,
|
|
78
|
+
requestFinalize: true,
|
|
79
|
+
finalizeDelayMs: config.finalizeDelayMs,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (smartTurnComplete && !semantic.complete) {
|
|
83
|
+
return {
|
|
84
|
+
release: false,
|
|
85
|
+
requestFinalize: false,
|
|
86
|
+
finalizeDelayMs: config.finalizeDelayMs,
|
|
87
|
+
deferReason: "semantic_incomplete",
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (!smartTurnComplete && semantic.complete && semantic.confidence >= 0.85 && config.semanticShortcutDelayMs > 0) {
|
|
91
|
+
return {
|
|
92
|
+
release: true,
|
|
93
|
+
requestFinalize: true,
|
|
94
|
+
finalizeDelayMs: config.semanticShortcutDelayMs,
|
|
95
|
+
shortcutReason: "semantic_complete",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
release: false,
|
|
100
|
+
requestFinalize: false,
|
|
101
|
+
finalizeDelayMs: config.incompleteFallbackMs,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function latestTranscript(finalSegments, interimText) {
|
|
105
|
+
const finals = finalSegments.join(" ").replace(/\s+/g, " ").trim();
|
|
106
|
+
const interim = interimText.trim();
|
|
107
|
+
if (!interim)
|
|
108
|
+
return finals;
|
|
109
|
+
if (!finals)
|
|
110
|
+
return interim;
|
|
111
|
+
if (interim.startsWith(finals) || finals.startsWith(interim)) {
|
|
112
|
+
return interim.length >= finals.length ? interim : finals;
|
|
113
|
+
}
|
|
114
|
+
return `${finals} ${interim}`.replace(/\s+/g, " ").trim();
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=semantic-completeness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-completeness.js","sourceRoot":"","sources":["../src/semantic-completeness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface SemanticLabeledUtterance {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly text: string;
|
|
4
|
+
readonly category: "complete" | "mid_thought_pause" | "backchannel";
|
|
5
|
+
}
|
|
6
|
+
export declare const SEMANTIC_LABELED_UTTERANCES: readonly SemanticLabeledUtterance[];
|
|
7
|
+
//# sourceMappingURL=semantic-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-fixtures.d.ts","sourceRoot":"","sources":["../src/semantic-fixtures.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,mBAAmB,GAAG,aAAa,CAAC;CACrE;AAED,eAAO,MAAM,2BAA2B,EAAE,SAAS,wBAAwB,EAa1E,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const SEMANTIC_LABELED_UTTERANCES = [
|
|
2
|
+
{ id: "complete-question", text: "What are your office hours?", category: "complete" },
|
|
3
|
+
{ id: "complete-statement", text: "I would like to schedule an appointment.", category: "complete" },
|
|
4
|
+
{ id: "complete-imperative", text: "Please send me the enrollment form.", category: "complete" },
|
|
5
|
+
{ id: "complete-multi-clause", text: "I applied last week, and I still have not heard back.", category: "complete" },
|
|
6
|
+
{ id: "mid-thought-conjunction", text: "I need to know whether the petition is approved and", category: "mid_thought_pause" },
|
|
7
|
+
{ id: "mid-thought-prefix", text: "I need to know", category: "mid_thought_pause" },
|
|
8
|
+
{ id: "mid-thought-comma", text: "Before I submit the form,", category: "mid_thought_pause" },
|
|
9
|
+
{ id: "mid-thought-article", text: "Can you tell me about the", category: "mid_thought_pause" },
|
|
10
|
+
{ id: "backchannel-yeah", text: "yeah", category: "backchannel" },
|
|
11
|
+
{ id: "backchannel-uh-huh", text: "uh-huh", category: "backchannel" },
|
|
12
|
+
{ id: "backchannel-okay", text: "okay", category: "backchannel" },
|
|
13
|
+
{ id: "backchannel-thanks", text: "thank you", category: "backchannel" },
|
|
14
|
+
];
|
|
15
|
+
//# sourceMappingURL=semantic-fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-fixtures.js","sourceRoot":"","sources":["../src/semantic-fixtures.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,2BAA2B,GAAwC;IAC9E,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,6BAA6B,EAAE,QAAQ,EAAE,UAAU,EAAE;IACtF,EAAE,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,0CAA0C,EAAE,QAAQ,EAAE,UAAU,EAAE;IACpG,EAAE,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,qCAAqC,EAAE,QAAQ,EAAE,UAAU,EAAE;IAChG,EAAE,EAAE,EAAE,uBAAuB,EAAE,IAAI,EAAE,uDAAuD,EAAE,QAAQ,EAAE,UAAU,EAAE;IACpH,EAAE,EAAE,EAAE,yBAAyB,EAAE,IAAI,EAAE,qDAAqD,EAAE,QAAQ,EAAE,mBAAmB,EAAE;IAC7H,EAAE,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,mBAAmB,EAAE;IACnF,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,2BAA2B,EAAE,QAAQ,EAAE,mBAAmB,EAAE;IAC7F,EAAE,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,2BAA2B,EAAE,QAAQ,EAAE,mBAAmB,EAAE;IAC/F,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE;IACjE,EAAE,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE;IACrE,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE;IACjE,EAAE,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE;CACzE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PluginConfig } from "@kuralle-syrinx/core";
|
|
2
|
+
/** Host- or model-agnostic Smart Turn probability scorer. */
|
|
3
|
+
export interface SmartTurnPredictor {
|
|
4
|
+
initialize(config: PluginConfig): Promise<void>;
|
|
5
|
+
predict(audio: Float32Array): Promise<number>;
|
|
6
|
+
close(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=smart-turn-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-turn-types.d.ts","sourceRoot":"","sources":["../src/smart-turn-types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,6DAA6D;AAC7D,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-turn-types.js","sourceRoot":"","sources":["../src/smart-turn-types.ts"],"names":[],"mappings":"AAAA,+BAA+B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kuralle-syrinx/pipecat-smart-turn",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Pipecat Smart Turn v3 semantic endpointing for Syrinx — local ONNX end-of-turn analysis",
|
|
6
6
|
"keywords": [
|
|
@@ -24,23 +24,36 @@
|
|
|
24
24
|
"url": "https://github.com/kuralle/syrinx/issues"
|
|
25
25
|
},
|
|
26
26
|
"type": "module",
|
|
27
|
-
"main": "./
|
|
28
|
-
"types": "./
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
29
|
"exports": {
|
|
30
|
-
".":
|
|
31
|
-
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./eos": {
|
|
35
|
+
"types": "./dist/eos-plugin.d.ts",
|
|
36
|
+
"default": "./dist/eos-plugin.js"
|
|
37
|
+
}
|
|
32
38
|
},
|
|
33
39
|
"dependencies": {
|
|
34
40
|
"@huggingface/transformers": "^4.2.0",
|
|
35
41
|
"onnxruntime-node": "1.24.3",
|
|
36
|
-
"@kuralle-syrinx/core": "4.
|
|
42
|
+
"@kuralle-syrinx/core": "4.5.0"
|
|
37
43
|
},
|
|
38
44
|
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.0.0",
|
|
39
46
|
"typescript": "^5.7.0",
|
|
40
47
|
"vitest": "^3.2.6"
|
|
41
48
|
},
|
|
49
|
+
"files": [
|
|
50
|
+
"dist",
|
|
51
|
+
"src",
|
|
52
|
+
"README.md"
|
|
53
|
+
],
|
|
42
54
|
"scripts": {
|
|
43
55
|
"typecheck": "tsc --noEmit",
|
|
44
|
-
"test": "vitest run"
|
|
56
|
+
"test": "vitest run",
|
|
57
|
+
"build": "tsc -p tsconfig.build.json"
|
|
45
58
|
}
|
|
46
59
|
}
|