@bitrix24/b24ui-nuxt
Version:
Bitrix24 UI-Kit for developing web applications REST API for NUXT & VUE
167 lines (166 loc) • 4.36 kB
JavaScript
import { ref, computed, onMounted, onBeforeUnmount, readonly } from "vue";
export function useSpeechRecognition(options = {}, events = {}) {
const {
lang = "en-US",
continuous = true,
interimResults = true,
maxAlternatives = 1
} = options;
const {
onStart,
onEnd,
onError,
onResult
} = events;
const state = ref({
isAvailable: false,
isListening: false,
lastRecognizedText: ""
});
let recognizer;
const isAvailable = computed(() => state.value.isAvailable);
const isListening = computed(() => state.value.isListening);
const init = () => {
if (typeof window === "undefined") {
onError?.("Speech recognition is not available in this environment");
return false;
}
const SpeechRecognition = window && (window.SpeechRecognition || window.webkitSpeechRecognition);
if (!SpeechRecognition) {
state.value.isAvailable = false;
onError?.("Speech recognition is not supported in this browser");
return false;
}
try {
recognizer = new SpeechRecognition();
recognizer.lang = lang;
recognizer.continuous = continuous;
recognizer.interimResults = interimResults;
recognizer.maxAlternatives = maxAlternatives;
setupEventHandlers();
state.value.isAvailable = true;
return true;
} catch (error) {
onError?.(error instanceof Error ? error.message : "Failed to initialize speech recognition");
state.value.isAvailable = false;
return false;
}
};
const setupEventHandlers = () => {
if (!recognizer) return;
recognizer.onstart = () => {
state.value.isListening = true;
onStart?.();
};
recognizer.onerror = (event) => {
state.value.isListening = false;
onError?.(event.error);
};
recognizer.onend = () => {
state.value.isListening = false;
onEnd?.();
};
recognizer.onresult = (event) => {
const recognizedText = _getRecognizedText(event);
const nextText = _getNewText(recognizedText);
if (nextText !== "") {
onResult?.({ text: nextText });
}
state.value.lastRecognizedText = recognizedText;
};
};
const _getRecognizedText = (event) => {
let recognizedChunk = "";
Object.values(event.results).forEach((result) => {
if (result.isFinal) {
return;
}
const [alternative] = result;
const { transcript } = alternative;
recognizedChunk += transcript;
});
return recognizedChunk;
};
const _getNewText = (fullText) => {
let additionalText = "";
const lastChunkLength = state.value.lastRecognizedText.length;
if (fullText.length > lastChunkLength) {
additionalText = fullText.slice(lastChunkLength);
}
return additionalText;
};
const start = async () => {
if (!state.value.isAvailable) {
return false;
}
if (state.value.isListening) {
return false;
}
if (!recognizer) {
if (!init()) {
return false;
}
}
try {
recognizer.start();
return true;
} catch (error) {
onError?.(error instanceof Error ? error.message : "Failed to start speech recognition");
return false;
}
};
const stop = async () => {
if (!state.value.isListening || !recognizer) {
return false;
}
try {
recognizer.stop();
return true;
} catch (error) {
onError?.(error instanceof Error ? error.message : "Failed to stop speech recognition");
return false;
}
};
const toggle = async () => {
if (state.value.isListening) {
return stop();
} else {
return start();
}
};
const setLanguage = (lang2) => {
if (!recognizer) {
return false;
}
try {
recognizer.lang = lang2;
return true;
} catch (error) {
onError?.(error instanceof Error ? error.message : "Failed to set language");
return false;
}
};
onMounted(() => {
init();
});
onBeforeUnmount(() => {
if (state.value.isListening) {
stop();
}
recognizer = void 0;
});
return {
// State (readonly)
state: readonly(state),
// Computed properties
isAvailable,
isListening,
// Controls
start,
stop,
toggle,
setLanguage,
// Recognizer instance (for advanced usage)
recognizer
};
}