@volley/recognition-client-sdk 0.1.295 → 0.1.296
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simplified-vgf-recognition-client.d.ts","sourceRoot":"","sources":["../src/simplified-vgf-recognition-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,gBAAgB,EAGnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEH,wBAAwB,EACxB,WAAW,EACd,MAAM,+BAA+B,CAAC;AAWvC;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACvE;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAElD;;;OAGG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,+BAA+B;IAE5C;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IAEjE;;;OAGG;IACH,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,IAAI,IAAI,CAAC;IAGvB;;;OAGG;IACH,WAAW,IAAI,gBAAgB,CAAC;IAGhC;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC;IAEvB;;OAEG;IACH,YAAY,IAAI,OAAO,CAAC;IAExB;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC;IAEtB;;OAEG;IACH,uBAAuB,IAAI,OAAO,CAAC;IAEnC;;OAEG;IACH,mBAAmB,IAAI,OAAO,CAAC;IAG/B;;OAEG;IACH,mBAAmB,IAAI,MAAM,CAAC;IAE9B;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,IAAI,WAAW,CAAC;CAE3B;AAED;;;GAGG;AACH,qBAAa,8BAA+B,YAAW,+BAA+B;IAClF,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,mBAAmB,CAAkD;gBAEjE,MAAM,EAAE,yBAAyB;
|
|
1
|
+
{"version":3,"file":"simplified-vgf-recognition-client.d.ts","sourceRoot":"","sources":["../src/simplified-vgf-recognition-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,gBAAgB,EAGnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEH,wBAAwB,EACxB,WAAW,EACd,MAAM,+BAA+B,CAAC;AAWvC;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACvE;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAElD;;;OAGG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,+BAA+B;IAE5C;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IAEjE;;;OAGG;IACH,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,IAAI,IAAI,CAAC;IAGvB;;;OAGG;IACH,WAAW,IAAI,gBAAgB,CAAC;IAGhC;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC;IAEvB;;OAEG;IACH,YAAY,IAAI,OAAO,CAAC;IAExB;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC;IAEtB;;OAEG;IACH,uBAAuB,IAAI,OAAO,CAAC;IAEnC;;OAEG;IACH,mBAAmB,IAAI,OAAO,CAAC;IAG/B;;OAEG;IACH,mBAAmB,IAAI,MAAM,CAAC;IAE9B;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,IAAI,WAAW,CAAC;CAE3B;AAED;;;GAGG;AACH,qBAAa,8BAA+B,YAAW,+BAA+B;IAClF,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,mBAAmB,CAAkD;gBAEjE,MAAM,EAAE,yBAAyB;IAqIvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI;IAc1D,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC,cAAc,IAAI,IAAI;IAiCtB,mBAAmB,IAAI,MAAM;IAI7B,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,WAAW;IAIvB,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,OAAO;IAIvB,UAAU,IAAI,OAAO;IAIrB,uBAAuB,IAAI,OAAO;IAIlC,mBAAmB,IAAI,OAAO;IAM9B,WAAW,IAAI,gBAAgB;IAI/B,OAAO,CAAC,iBAAiB;CAK5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,GAAG,+BAA+B,CAE5G"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volley/recognition-client-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.296",
|
|
4
4
|
"description": "Recognition Service TypeScript/Node.js Client SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"semantic-release": "^25.0.1",
|
|
53
53
|
"ts-jest": "^29.4.5",
|
|
54
54
|
"typescript": "^5.1.6",
|
|
55
|
-
"@recog/shared-config": "1.0.0",
|
|
56
|
-
"@recog/shared-types": "1.0.0",
|
|
57
55
|
"@recog/shared-utils": "1.0.0",
|
|
56
|
+
"@recog/shared-types": "1.0.0",
|
|
57
|
+
"@recog/shared-config": "1.0.0",
|
|
58
58
|
"@recog/websocket": "1.0.0"
|
|
59
59
|
},
|
|
60
60
|
"keywords": [
|
|
@@ -80,12 +80,18 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
const state = simplifiedClient.getVGFState();
|
|
83
|
-
|
|
83
|
+
// FINALIZED session gets new UUID to prevent server session reuse
|
|
84
|
+
expect(state.audioUtteranceId).not.toBe('existing-session-id');
|
|
85
|
+
expect(state.audioUtteranceId).toBeDefined();
|
|
86
|
+
// Other state preserved
|
|
84
87
|
expect(state.finalTranscript).toBe('Previous transcript');
|
|
88
|
+
// Status reset to NOT_STARTED
|
|
89
|
+
expect(state.transcriptionStatus).toBe(TranscriptionStatus.NOT_STARTED);
|
|
85
90
|
|
|
86
|
-
// Verify audioUtteranceId was passed to underlying client
|
|
91
|
+
// Verify NEW audioUtteranceId was passed to underlying client
|
|
87
92
|
const constructorCalls = (RealTimeTwoWayWebSocketRecognitionClient as jest.MockedClass<typeof RealTimeTwoWayWebSocketRecognitionClient>).mock.calls;
|
|
88
|
-
expect(constructorCalls[0]?.[0]?.audioUtteranceId).toBe('existing-session-id');
|
|
93
|
+
expect(constructorCalls[0]?.[0]?.audioUtteranceId).not.toBe('existing-session-id');
|
|
94
|
+
expect(constructorCalls[0]?.[0]?.audioUtteranceId).toBe(state.audioUtteranceId);
|
|
89
95
|
});
|
|
90
96
|
|
|
91
97
|
it('should store ASR config as JSON string', () => {
|
|
@@ -528,6 +534,101 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
528
534
|
expect(client.getVGFState).toBeDefined();
|
|
529
535
|
expect(client.connect).toBeDefined();
|
|
530
536
|
});
|
|
537
|
+
|
|
538
|
+
it('should auto-generate new UUID for ABORTED session and reset fields', () => {
|
|
539
|
+
const stateChangeCallback = jest.fn();
|
|
540
|
+
const abortedState: RecognitionState = {
|
|
541
|
+
audioUtteranceId: 'old-aborted-uuid',
|
|
542
|
+
transcriptionStatus: TranscriptionStatus.ABORTED,
|
|
543
|
+
startRecordingStatus: RecordingStatus.FINISHED,
|
|
544
|
+
pendingTranscript: '',
|
|
545
|
+
finalTranscript: 'old transcript from aborted session'
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
const client = createSimplifiedVGFClient({
|
|
549
|
+
initialState: abortedState,
|
|
550
|
+
onStateChange: stateChangeCallback,
|
|
551
|
+
asrRequestConfig: {
|
|
552
|
+
provider: 'deepgram',
|
|
553
|
+
language: 'en',
|
|
554
|
+
sampleRate: 16000,
|
|
555
|
+
encoding: AudioEncoding.LINEAR16
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// Should have called callback with new UUID
|
|
560
|
+
expect(stateChangeCallback).toHaveBeenCalledTimes(1);
|
|
561
|
+
const newState = stateChangeCallback.mock.calls[0][0];
|
|
562
|
+
|
|
563
|
+
// New UUID should be different
|
|
564
|
+
expect(newState.audioUtteranceId).not.toBe('old-aborted-uuid');
|
|
565
|
+
expect(newState.audioUtteranceId).toBeDefined();
|
|
566
|
+
|
|
567
|
+
// Status fields should be reset for fresh session
|
|
568
|
+
expect(newState.transcriptionStatus).toBe(TranscriptionStatus.NOT_STARTED);
|
|
569
|
+
expect(newState.startRecordingStatus).toBe(RecordingStatus.READY);
|
|
570
|
+
|
|
571
|
+
// Previous transcript should be cleared
|
|
572
|
+
expect(newState.finalTranscript).toBeUndefined();
|
|
573
|
+
|
|
574
|
+
// Client should use the new UUID
|
|
575
|
+
expect(client.getVGFState().audioUtteranceId).toBe(newState.audioUtteranceId);
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
it('should auto-generate new UUID for FINALIZED session', () => {
|
|
579
|
+
const stateChangeCallback = jest.fn();
|
|
580
|
+
const finalizedState: RecognitionState = {
|
|
581
|
+
audioUtteranceId: 'old-finalized-uuid',
|
|
582
|
+
transcriptionStatus: TranscriptionStatus.FINALIZED,
|
|
583
|
+
startRecordingStatus: RecordingStatus.FINISHED,
|
|
584
|
+
pendingTranscript: '',
|
|
585
|
+
finalTranscript: 'completed transcript'
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
const client = createSimplifiedVGFClient({
|
|
589
|
+
initialState: finalizedState,
|
|
590
|
+
onStateChange: stateChangeCallback,
|
|
591
|
+
asrRequestConfig: {
|
|
592
|
+
provider: 'deepgram',
|
|
593
|
+
language: 'en',
|
|
594
|
+
sampleRate: 16000,
|
|
595
|
+
encoding: AudioEncoding.LINEAR16
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
// Should have generated new UUID
|
|
600
|
+
expect(stateChangeCallback).toHaveBeenCalledTimes(1);
|
|
601
|
+
const newState = stateChangeCallback.mock.calls[0][0];
|
|
602
|
+
|
|
603
|
+
expect(newState.audioUtteranceId).not.toBe('old-finalized-uuid');
|
|
604
|
+
expect(newState.transcriptionStatus).toBe(TranscriptionStatus.NOT_STARTED);
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
it('should preserve UUID for IN_PROGRESS session (valid resumption)', () => {
|
|
608
|
+
const stateChangeCallback = jest.fn();
|
|
609
|
+
const inProgressState: RecognitionState = {
|
|
610
|
+
audioUtteranceId: 'in-progress-uuid',
|
|
611
|
+
transcriptionStatus: TranscriptionStatus.IN_PROGRESS,
|
|
612
|
+
startRecordingStatus: RecordingStatus.RECORDING,
|
|
613
|
+
pendingTranscript: 'partial text'
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const client = createSimplifiedVGFClient({
|
|
617
|
+
initialState: inProgressState,
|
|
618
|
+
onStateChange: stateChangeCallback,
|
|
619
|
+
asrRequestConfig: {
|
|
620
|
+
provider: 'deepgram',
|
|
621
|
+
language: 'en',
|
|
622
|
+
sampleRate: 16000,
|
|
623
|
+
encoding: AudioEncoding.LINEAR16
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// Should NOT generate new UUID (valid reconnection)
|
|
628
|
+
const currentState = client.getVGFState();
|
|
629
|
+
expect(currentState.audioUtteranceId).toBe('in-progress-uuid');
|
|
630
|
+
expect(currentState.transcriptionStatus).toBe(TranscriptionStatus.IN_PROGRESS);
|
|
631
|
+
});
|
|
531
632
|
});
|
|
532
633
|
|
|
533
634
|
describe('PromptSlotMap Integration', () => {
|
|
@@ -734,6 +835,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
734
835
|
expect(stateChangeCallback).toHaveBeenCalledTimes(1);
|
|
735
836
|
|
|
736
837
|
const firstCallState = stateChangeCallback.mock.calls[0][0];
|
|
838
|
+
const firstTranscript = firstCallState.finalTranscript;
|
|
737
839
|
jest.clearAllMocks();
|
|
738
840
|
|
|
739
841
|
// Call stopAbnormally second time
|
|
@@ -744,7 +846,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
744
846
|
|
|
745
847
|
const currentState = simplifiedClient.getVGFState();
|
|
746
848
|
expect(currentState.transcriptionStatus).toBe(TranscriptionStatus.ABORTED);
|
|
747
|
-
expect(currentState.finalTranscript).toBe(
|
|
849
|
+
expect(currentState.finalTranscript).toBe(firstTranscript); // Unchanged
|
|
748
850
|
});
|
|
749
851
|
|
|
750
852
|
it('should work even if called before any recording', () => {
|
|
@@ -753,7 +855,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
753
855
|
|
|
754
856
|
const state = simplifiedClient.getVGFState();
|
|
755
857
|
expect(state.transcriptionStatus).toBe(TranscriptionStatus.ABORTED);
|
|
756
|
-
expect(state.finalTranscript).
|
|
858
|
+
expect(state.finalTranscript).toBeUndefined(); // No transcript was ever received
|
|
757
859
|
expect(state.startRecordingStatus).toBe(RecordingStatus.FINISHED);
|
|
758
860
|
});
|
|
759
861
|
|
|
@@ -853,7 +955,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
853
955
|
// Verify ABORTED is used (not FINALIZED)
|
|
854
956
|
expect(abortedState.transcriptionStatus).toBe(TranscriptionStatus.ABORTED);
|
|
855
957
|
expect(abortedState.transcriptionStatus).not.toBe(TranscriptionStatus.FINALIZED);
|
|
856
|
-
|
|
958
|
+
// finalTranscript is preserved (whatever partial transcript was received)
|
|
857
959
|
|
|
858
960
|
// ABORTED clearly indicates user cancelled, vs FINALIZED which means completed normally
|
|
859
961
|
});
|
|
@@ -157,10 +157,43 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
157
157
|
|
|
158
158
|
// Use provided initial state or create from config
|
|
159
159
|
if (initialState) {
|
|
160
|
-
|
|
161
|
-
//
|
|
162
|
-
if (initialState.
|
|
163
|
-
|
|
160
|
+
// If previous session is in terminal state (ABORTED/FINALIZED), force new UUID
|
|
161
|
+
// This prevents server from attaching to completed session which silently drops audio
|
|
162
|
+
if (initialState.transcriptionStatus === TranscriptionStatus.ABORTED ||
|
|
163
|
+
initialState.transcriptionStatus === TranscriptionStatus.FINALIZED) {
|
|
164
|
+
|
|
165
|
+
// Generate new UUID for fresh session
|
|
166
|
+
const newUUID = crypto.randomUUID();
|
|
167
|
+
|
|
168
|
+
if (clientConfig.logger) {
|
|
169
|
+
clientConfig.logger('info', `Terminal session detected (${initialState.transcriptionStatus}), generating new UUID: ${newUUID}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Update state with new UUID and reset session-specific fields
|
|
173
|
+
this.state = {
|
|
174
|
+
...initialState,
|
|
175
|
+
audioUtteranceId: newUUID,
|
|
176
|
+
// Reset status fields for fresh session
|
|
177
|
+
transcriptionStatus: TranscriptionStatus.NOT_STARTED,
|
|
178
|
+
startRecordingStatus: RecordingStatus.READY,
|
|
179
|
+
// Clear previous session's transcript
|
|
180
|
+
finalTranscript: undefined
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// Use new UUID in client config
|
|
184
|
+
clientConfig.audioUtteranceId = newUUID;
|
|
185
|
+
|
|
186
|
+
// Notify state change immediately so app can update
|
|
187
|
+
if (onStateChange) {
|
|
188
|
+
onStateChange(this.state);
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
// Non-terminal state - safe to reuse UUID (e.g., reconnecting to IN_PROGRESS session)
|
|
192
|
+
this.state = initialState;
|
|
193
|
+
// Override audioUtteranceId in config if state has one
|
|
194
|
+
if (initialState.audioUtteranceId && !clientConfig.audioUtteranceId) {
|
|
195
|
+
clientConfig.audioUtteranceId = initialState.audioUtteranceId;
|
|
196
|
+
}
|
|
164
197
|
}
|
|
165
198
|
} else {
|
|
166
199
|
// Initialize VGF state from config
|