Skip to content

Commit

Permalink
fix(voice recognition): added Voice Recognition component
Browse files Browse the repository at this point in the history
  • Loading branch information
opensrc0 committed Mar 18, 2024
1 parent c73d2cd commit f3d5bbd
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 73 deletions.
10 changes: 8 additions & 2 deletions __app/component/TextToSpeech/TextToSpeech.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import TextToSpeechInit from './TextToSpeechInit';
import TextToSpeechStart from './TextToSpeechStart';
import TextToSpeechStop from './TextToSpeechStop';
import TextToSpeechInit from './TextToSpeechInit';

export {
TextToSpeechInit,
TextToSpeechStart,
TextToSpeechStop,
TextToSpeechInit,
};

export default {
Init: TextToSpeechInit,
Start: TextToSpeechStart,
Stop: TextToSpeechStop,
};
10 changes: 8 additions & 2 deletions __app/component/VoiceRecognition/VoiceRecognition.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import VoiceRecognition from './VoiceRecognitionInit';
import VoiceRecognitionInit from './VoiceRecognitionInit';
import VoiceRecognitionIcon from './VoiceRecognitionIcon';
import VoiceRecognitionModal from './VoiceRecognitionModal';

export {
VoiceRecognition,
VoiceRecognitionInit,
VoiceRecognitionIcon,
VoiceRecognitionModal,
};

export default {
Init: VoiceRecognitionInit,
Icon: VoiceRecognitionIcon,
Modal: VoiceRecognitionModal,
};
4 changes: 2 additions & 2 deletions __app/component/VoiceRecognition/VoiceRecognitionIcon.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';

function VoiceRecognitionIcon({ children, onClick }) {
function VoiceRecognitionIcon({ children, listen }) {
return React.Children.map(children || 'Voice Recognition', (child) => React.cloneElement(typeof child === 'string' ? <span>{child}</span> : child, {
onClick,
onClick: listen,
}));
}

Expand Down
114 changes: 51 additions & 63 deletions __app/component/VoiceRecognition/VoiceRecognitionInit.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,71 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import Wrapper from '../Wrapper/Wrapper';
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

// import './voiceSearch.css';
// import Modal from '../../components/Modal/Modal';
// import VoiceLoader from './VoiceLoader';
// import LoadingDots from '../../components/LoadingDots/LoadingDots';
import { handleSuccess, handleError } from '../services/handlerService';

function VoiceRecognition({
disbaleToast,
successCb,
successMsg,
failureCb,
failureMsg,
cb,
children,
}) {
const [modalVisible, setModalVisible] = useState(false);
const [isModalVisible, setIsModalVisible] = useState(false);
const [isVoiceStarted, setIsVoiceStarted] = useState(false);
const [voiceText, setVoiceText] = useState('');
const [isLoadingDots, setIsLoadingDots] = useState(true);

const listen = () => {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SpeechRecognition();
if (VoiceRecognition.isBrowserSupport()) {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SpeechRecognition();

recognition.continuous = false;
recognition.lang = 'en-US';
recognition.interimResults = true;
recognition.maxAlternatives = 1;
recognition.onresult = (event) => {
const text = event.results[0][0].transcript;
setVoiceText(text);
if (event.results[0].isFinal) {
setTimeout(() => {
handleSuccess({ disbaleToast, msgType: 'SUCCESS', msg: successMsg, successCb, data: text });
setIsModalVisible(false);
setVoiceText('');
}, 1500);
}
};
recognition.start();
recognition.onsoundstart = () => {
setIsVoiceStarted(true);
};
recognition.onsoundend = () => {
setIsVoiceStarted(false);
};
recognition.onerror = () => {
setIsModalVisible(false);
return handleError({ disbaleToast, msgType: 'ERROR', msg: failureMsg.error, failureCb });
};
recognition.onend = () => {
recognition.abort();
recognition.onresult = () => {};
recognition.stop();
setTimeout(() => setIsModalVisible(false), 1500);
};
setIsModalVisible(true);
} else {
return handleError({ disbaleToast, msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb });
}

recognition.continuous = false;
recognition.lang = 'en-US';
recognition.interimResults = true;
recognition.maxAlternatives = 1;
recognition.onresult = (event) => {
const text = event.results[0][0].transcript;
setVoiceText(text);
if (event.results[0].isFinal) {
setTimeout(() => {
cb(text, true);
setModalVisible(false);
setVoiceText('');
}, 1500);
}
};
recognition.start();
recognition.onsoundstart = () => {
setIsLoadingDots(false);
};
recognition.onsoundend = () => {
setIsLoadingDots(true);
};
recognition.onerror = () => {
setModalVisible(false);
};
recognition.onend = () => {
recognition.abort();
recognition.onresult = () => {};
recognition.stop();
setTimeout(() => setModalVisible(false), 1500);
};
setModalVisible(true);
return true;
};

return React.Children.map(children, (child) => React.cloneElement(child, {
onClick: child.type.name === 'VoiceRecognitionIcon' ? listen : () => {},
listen,
isVoiceStarted,
isModalVisible,
voiceText,
onClose: () => setIsModalVisible(false),
disbaleToast,
successCb,
successMsg,
Expand All @@ -69,10 +74,8 @@ function VoiceRecognition({
}));
}

VoiceRecognition.isBrowserSupport = () => globalThis.speechSynthesis
&& globalThis.speechSynthesis?.cancel
&& globalThis.speechSynthesis?.speak
&& true;
VoiceRecognition.isBrowserSupport = () => window.SpeechRecognition
|| window.webkitSpeechRecognition;

VoiceRecognition.propTypes = {
disbaleToast: PropTypes.bool,
Expand All @@ -94,18 +97,3 @@ VoiceRecognition.defaultProps = {
};

export default Wrapper(VoiceRecognition);

// {
// <FontAwesomeIcon icon="fa-solid fa-microphone"
// size="xl" style={{ color: 'var(--secondary)' }} className="voiceIcon" onClick={listen} />

// modalVisible ? (
// <Modal modalTitle="Listening..." onClickCloseIcon={() =>
// setModalVisible(false)} titleClasses="listen" modalClass="voice-modal">
// <div className="voice-text">{voiceText}</div>
// <div className="loading-container">
// {isLoadingDots ? <LoadingDots /> : <VoiceLoader />}
// </div>
// </Modal>
// ) : null
// }
20 changes: 16 additions & 4 deletions __app/component/VoiceRecognition/VoiceRecognitionModal.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import React from 'react';

export default function VoiceRecognitionModal() {
return (
<div>VoiceRecognitionModal</div>
);
export default function VoiceRecognitionModal({
children,
isModalVisible,
isVoiceStarted,
onClose,
voiceText,
}) {
let isReactElement = true;
return isModalVisible && React.Children.map(children, (child) => {
isReactElement = child.type[0] === child.type[0].toUpperCase();
return React.cloneElement(typeof child === 'string' ? <span>{child}</span> : child, {
onClose,
[isReactElement ? 'voiceText' : 'voicetext']: voiceText,
[isReactElement ? 'isVoiceStarted' : 'isvoicestarted']: isVoiceStarted.toString(),
});
});
}

0 comments on commit f3d5bbd

Please sign in to comment.