@volley/recognition-client-sdk
Version:
Recognition Service TypeScript/Node.js Client SDK
203 lines (177 loc) • 6.23 kB
text/typescript
/**
* VGF Recognition Mapper
*
* Maps between the existing recognition client types and the simplified VGF state.
* This provides a clean abstraction layer for game developers.
*/
import {
RecognitionState,
RecordingStatus,
TranscriptionStatus,
createInitialRecognitionState
} from './vgf-recognition-state.js';
import {
ClientState,
IRecognitionClientConfig
} from './recognition-client.types.js';
import {
TranscriptionResultV1,
ErrorResultV1
} from '@recog/shared-types';
/**
* Maps ClientState to RecordingStatus for VGF state
*/
export function mapClientStateToRecordingStatus(clientState: ClientState): string {
switch (clientState) {
case ClientState.INITIAL:
case ClientState.CONNECTING:
case ClientState.CONNECTED:
return RecordingStatus.NOT_READY;
case ClientState.READY:
// Ready to record, but not recording yet
return RecordingStatus.READY;
case ClientState.STOPPING:
case ClientState.STOPPED:
case ClientState.FAILED:
return RecordingStatus.FINISHED;
default:
return RecordingStatus.NOT_READY;
}
}
/**
* Creates a VGF state from transcription result
*/
export function mapTranscriptionResultToState(
currentState: RecognitionState,
result: TranscriptionResultV1,
isRecording: boolean
): RecognitionState {
const newState = { ...currentState };
// Update recording status if actively recording
if (isRecording && currentState.startRecordingStatus !== RecordingStatus.FINISHED) {
newState.startRecordingStatus = RecordingStatus.RECORDING;
// Set start timestamp on first audio
if (!newState.startRecordingTimestamp) {
newState.startRecordingTimestamp = new Date().toISOString();
}
}
// Update transcription status
if (!result.is_finished) {
// Has pending transcript - STEP 2 support
newState.transcriptionStatus = TranscriptionStatus.IN_PROGRESS;
// Direct copy of pending transcript without any combination
newState.pendingTranscript = result.pendingTranscript || "";
// Direct copy of pending confidence
if (result.pendingTranscriptConfidence !== undefined) {
newState.pendingConfidence = result.pendingTranscriptConfidence;
}
// Also update final transcript if we have it (even if not finished)
if (result.finalTranscript) {
newState.finalTranscript = result.finalTranscript;
if (result.finalTranscriptConfidence !== undefined) {
newState.finalConfidence = result.finalTranscriptConfidence;
}
}
} else {
// Transcription is finished
newState.transcriptionStatus = TranscriptionStatus.FINALIZED;
newState.finalTranscript = result.finalTranscript || "";
if (result.finalTranscriptConfidence !== undefined) {
newState.finalConfidence = result.finalTranscriptConfidence;
}
newState.finalTranscriptionTimestamp = new Date().toISOString();
// Clear pending when we have final
newState.pendingTranscript = "";
newState.pendingConfidence = undefined;
}
return newState;
}
/**
* Maps error to state
*/
export function mapErrorToState(
currentState: RecognitionState,
error: ErrorResultV1
): RecognitionState {
return {
...currentState,
transcriptionStatus: TranscriptionStatus.ERROR,
startRecordingStatus: RecordingStatus.FINISHED,
finalRecordingTimestamp: new Date().toISOString()
};
}
/**
* Creates initial VGF state from client config
*/
export function createVGFStateFromConfig(config: IRecognitionClientConfig): RecognitionState {
const audioUtteranceId = config.audioUtteranceId || generateUUID();
const state = createInitialRecognitionState(audioUtteranceId);
// Store ASR config as JSON if provided
if (config.asrRequestConfig) {
state.asrConfig = JSON.stringify(config.asrRequestConfig);
}
return state;
}
/**
* Updates state when recording stops
*/
export function updateStateOnStop(currentState: RecognitionState): RecognitionState {
return {
...currentState,
startRecordingStatus: RecordingStatus.FINISHED,
finalRecordingTimestamp: new Date().toISOString()
};
}
/**
* Updates state when client becomes ready
*/
export function updateStateOnReady(currentState: RecognitionState): RecognitionState {
return {
...currentState,
startRecordingStatus: RecordingStatus.READY
};
}
/**
* Parses function call from transcript (STEP 3 support)
* This is a placeholder - actual implementation would use NLP/LLM
*/
export function extractFunctionCallFromTranscript(
transcript: string,
gameContext?: any
): { metadata?: string; confidence?: number } | null {
// This would be replaced with actual function call extraction logic
// For example, using an LLM to parse intent from the transcript
// and map it to game actions
// Example stub implementation:
const lowerTranscript = transcript.toLowerCase();
// Simple pattern matching for demo
if (lowerTranscript.includes("play") && lowerTranscript.includes("artist")) {
return {
metadata: JSON.stringify({ action: "play", target: "artist" }),
confidence: 0.8
};
}
return null;
}
/**
* Updates state with function call results (STEP 3)
*/
export function updateStateWithFunctionCall(
currentState: RecognitionState,
functionCall: { metadata?: string; confidence?: number }
): RecognitionState {
return {
...currentState,
functionCallMetadata: functionCall.metadata,
functionCallConfidence: functionCall.confidence,
finalFunctionCallTimestamp: new Date().toISOString()
};
}
// Helper function to generate UUID (simplified version)
function generateUUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}