bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/audio/captions/speech/component.jsx
2024-01-11 14:46:39 -03:00

161 lines
3.5 KiB
JavaScript

import { PureComponent } from 'react';
import PropTypes from 'prop-types';
import logger from '/imports/startup/client/logger';
import { throttle } from 'radash';
import Service from './service';
const THROTTLE_TIMEOUT = 200;
class Speech extends PureComponent {
constructor(props) {
super(props);
this.onEnd = this.onEnd.bind(this);
this.onError = this.onError.bind(this);
this.onResult = this.onResult.bind(this);
this.result = {
id: Service.generateId(),
transcript: '',
isFinal: true,
};
this.idle = true;
this.speechRecognition = Service.initSpeechRecognition(props.setUserSpeechLocale);
if (this.speechRecognition) {
this.speechRecognition.onend = () => this.onEnd();
this.speechRecognition.onerror = (event) => this.onError(event);
this.speechRecognition.onresult = (event) => this.onResult(event);
}
this.throttledTranscriptUpdate = throttle(
{ interval: THROTTLE_TIMEOUT },
props.captionSubmitText
);
}
componentDidUpdate(prevProps) {
const {
locale,
connected,
talking,
} = this.props;
// Connected
if (!prevProps.connected && connected) {
this.start(locale);
}
// Disconnected
if (prevProps.connected && !connected) {
this.stop();
}
// Switch locale
if (prevProps.locale !== locale) {
if (prevProps.connected && connected) {
this.stop();
this.start(locale);
}
}
// Recovery from idle
if (!prevProps.talking && talking) {
if (prevProps.connected && connected) {
if (this.idle) {
this.start(locale);
}
}
}
}
componentWillUnmount() {
this.stop();
}
onEnd() {
this.stop();
}
onError(event) {
this.stop();
logger.error({
logCode: 'captions_speech_recognition',
extraInfo: {
error: event.error,
message: event.message,
},
}, 'Captions speech recognition error');
}
onResult(event) {
const {
resultIndex,
results,
} = event;
const { id } = this.result;
const { transcript } = results[resultIndex][0];
const { isFinal } = results[resultIndex];
this.result.transcript = transcript;
this.result.isFinal = isFinal;
const { locale, captionSubmitText } = this.props;
if (isFinal) {
captionSubmitText(id, transcript, locale, true);
this.result.id = Service.generateId();
} else {
this.throttledTranscriptUpdate(id, transcript, locale, false);
}
}
start(locale) {
if (this.speechRecognition && Service.isLocaleValid(locale)) {
this.speechRecognition.lang = locale;
try {
this.result.id = Service.generateId();
this.speechRecognition.start();
this.idle = false;
} catch (event) {
this.onError(event);
}
}
}
stop() {
this.idle = true;
if (this.speechRecognition) {
const {
isFinal,
transcript,
} = this.result;
if (!isFinal) {
const { locale } = this.props;
const { id } = this.result;
Service.updateFinalTranscript(id, transcript, locale);
this.speechRecognition.abort();
} else {
this.speechRecognition.stop();
}
}
}
render() {
return null;
}
}
Speech.propTypes = {
locale: PropTypes.string.isRequired,
connected: PropTypes.bool.isRequired,
talking: PropTypes.bool.isRequired,
setUserSpeechLocale: PropTypes.func.isRequired,
};
export default Speech;