2022-03-25 03:05:20 +08:00
|
|
|
import _ from 'lodash';
|
|
|
|
import { Session } from 'meteor/session';
|
2022-04-01 03:40:07 +08:00
|
|
|
import Auth from '/imports/ui/services/auth';
|
2022-03-25 03:05:20 +08:00
|
|
|
import { makeCall } from '/imports/ui/services/api';
|
|
|
|
import AudioService from '/imports/ui/components/audio/service';
|
|
|
|
|
2022-04-12 04:48:01 +08:00
|
|
|
const LANGUAGES = [
|
|
|
|
'en-US',
|
|
|
|
'es-ES',
|
|
|
|
'pt-BR',
|
|
|
|
];
|
2022-04-11 21:45:09 +08:00
|
|
|
|
2022-04-12 21:53:53 +08:00
|
|
|
const THROTTLE_TIMEOUT = 1000;
|
|
|
|
|
2022-04-12 04:48:01 +08:00
|
|
|
const CONFIG = Meteor.settings.public.app.audioCaptions;
|
|
|
|
const ENABLED = CONFIG.enabled;
|
2022-04-11 21:45:09 +08:00
|
|
|
|
2022-03-25 03:05:20 +08:00
|
|
|
const SpeechRecognitionAPI = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
|
|
|
2022-04-12 04:48:01 +08:00
|
|
|
const hasSpeechRecognitionSupport = () => typeof SpeechRecognitionAPI !== 'undefined';
|
2022-03-25 03:05:20 +08:00
|
|
|
|
2022-04-12 21:53:53 +08:00
|
|
|
const setSpeechLocale = (value) => {
|
|
|
|
if (LANGUAGES.includes(value) || value === '') {
|
|
|
|
Session.set('speechLocale', value);
|
|
|
|
} else {
|
|
|
|
// TODO: ERROR
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const setSpeechVoices = () => {
|
|
|
|
if (typeof window.speechSynthesis === 'undefined') return;
|
|
|
|
|
|
|
|
Session.set('speechVoices', window.speechSynthesis.getVoices().map((v) => v.lang));
|
|
|
|
};
|
|
|
|
|
|
|
|
// Trigger getVoices
|
|
|
|
setSpeechVoices();
|
|
|
|
|
|
|
|
const getSpeechVoices = () => {
|
|
|
|
const voices = Session.get('speechVoices') || [];
|
|
|
|
|
|
|
|
return voices.filter((v) => LANGUAGES.includes(v));
|
|
|
|
};
|
|
|
|
|
|
|
|
const setDefault = () => {
|
|
|
|
const voices = getSpeechVoices();
|
|
|
|
if (voices.includes(CONFIG.language.locale)) {
|
|
|
|
setSpeechLocale(CONFIG.language.locale);
|
|
|
|
} else {
|
|
|
|
// TODO: ERROR
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const useDefault = () => ENABLED && CONFIG.language.default;
|
|
|
|
|
2022-04-12 04:48:01 +08:00
|
|
|
const initSpeechRecognition = () => {
|
2022-03-25 03:05:20 +08:00
|
|
|
if (hasSpeechRecognitionSupport()) {
|
2022-04-12 21:53:53 +08:00
|
|
|
// Effectivate getVoices
|
|
|
|
setSpeechVoices();
|
2022-03-25 03:05:20 +08:00
|
|
|
const speechRecognition = new SpeechRecognitionAPI();
|
|
|
|
speechRecognition.continuous = true;
|
|
|
|
speechRecognition.interimResults = true;
|
|
|
|
|
2022-04-12 21:53:53 +08:00
|
|
|
if (useDefault()) setDefault();
|
|
|
|
|
2022-03-25 03:05:20 +08:00
|
|
|
return speechRecognition;
|
|
|
|
}
|
|
|
|
|
2022-04-12 21:53:53 +08:00
|
|
|
// TODO: WARN
|
|
|
|
|
2022-03-25 03:05:20 +08:00
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
2022-04-01 03:40:07 +08:00
|
|
|
const updateTranscript = (id, transcript, locale) => makeCall('updateTranscript', id, transcript, locale);
|
2022-03-25 03:05:20 +08:00
|
|
|
|
2022-04-01 03:40:07 +08:00
|
|
|
const throttledTranscriptUpdate = _.throttle(updateTranscript, THROTTLE_TIMEOUT, {
|
2022-03-25 03:05:20 +08:00
|
|
|
leading: false,
|
|
|
|
trailing: true,
|
|
|
|
});
|
|
|
|
|
2022-04-01 03:40:07 +08:00
|
|
|
const updateInterimTranscript = (id, transcript, locale) => {
|
|
|
|
throttledTranscriptUpdate(id, transcript, locale);
|
|
|
|
};
|
2022-03-25 03:05:20 +08:00
|
|
|
|
2022-04-01 03:40:07 +08:00
|
|
|
const updateFinalTranscript = (id, transcript, locale) => {
|
|
|
|
throttledTranscriptUpdate.cancel();
|
|
|
|
updateTranscript(id, transcript, locale);
|
2022-03-25 03:05:20 +08:00
|
|
|
};
|
|
|
|
|
2022-04-12 04:48:01 +08:00
|
|
|
const getSpeechLocale = () => Session.get('speechLocale') || '';
|
2022-03-25 03:05:20 +08:00
|
|
|
|
2022-04-12 21:53:53 +08:00
|
|
|
const hasSpeechLocale = () => getSpeechLocale() !== '';
|
2022-03-25 03:05:20 +08:00
|
|
|
|
2022-04-12 21:53:53 +08:00
|
|
|
const isLocaleValid = (locale) => LANGUAGES.includes(locale);
|
2022-03-25 03:05:20 +08:00
|
|
|
|
2022-04-12 21:53:53 +08:00
|
|
|
const isEnabled = () => ENABLED && hasSpeechRecognitionSupport();
|
2022-04-12 04:48:01 +08:00
|
|
|
|
|
|
|
const isActive = () => isEnabled() && hasSpeechLocale();
|
2022-03-25 03:05:20 +08:00
|
|
|
|
|
|
|
const getStatus = () => {
|
|
|
|
const active = isActive();
|
2022-04-12 04:48:01 +08:00
|
|
|
const locale = getSpeechLocale();
|
2022-03-25 03:05:20 +08:00
|
|
|
const audio = AudioService.isConnected() && !AudioService.isEchoTest() && !AudioService.isMuted();
|
2022-03-29 03:23:46 +08:00
|
|
|
const connected = Meteor.status().connected && active && audio;
|
|
|
|
const talking = AudioService.isTalking();
|
2022-03-25 03:05:20 +08:00
|
|
|
|
|
|
|
return {
|
2022-04-12 04:48:01 +08:00
|
|
|
locale,
|
2022-03-29 03:23:46 +08:00
|
|
|
connected,
|
|
|
|
talking,
|
2022-03-25 03:05:20 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-04-01 03:40:07 +08:00
|
|
|
const generateId = () => `${Auth.userID}-${Date.now()}`;
|
|
|
|
|
2022-03-25 03:05:20 +08:00
|
|
|
export default {
|
2022-04-12 04:48:01 +08:00
|
|
|
LANGUAGES,
|
2022-03-25 03:05:20 +08:00
|
|
|
hasSpeechRecognitionSupport,
|
|
|
|
initSpeechRecognition,
|
2022-04-01 03:40:07 +08:00
|
|
|
updateInterimTranscript,
|
|
|
|
updateFinalTranscript,
|
2022-04-12 21:53:53 +08:00
|
|
|
getSpeechVoices,
|
2022-04-12 04:48:01 +08:00
|
|
|
getSpeechLocale,
|
|
|
|
setSpeechLocale,
|
2022-04-12 21:53:53 +08:00
|
|
|
isLocaleValid,
|
2022-03-25 03:05:20 +08:00
|
|
|
isEnabled,
|
|
|
|
isActive,
|
|
|
|
getStatus,
|
2022-04-01 03:40:07 +08:00
|
|
|
generateId,
|
2022-04-12 04:48:01 +08:00
|
|
|
useDefault,
|
2022-03-25 03:05:20 +08:00
|
|
|
};
|