1

I am creating voice-controlled React app that will switch on and switch off a lamp using 'react-speech-recognition' module on voice command ON and OFF. Everything working as expected however there is one issue that I'm facing is, the App is listening my voice twice or more even I spoke my command once. Would be great if anybody share their suggestion on this. Here is my code,

//This component will listen my command (ON/OFF) and pass the corresponding command value 28/-28
// to the next component which is RetrieveCommand
// The problem is, even I'm saying 'ON/OFF' once, in the console log printing I can see the APP is 
// listening it twice or more

import React from 'react';
import { Button, Row,Col } from 'antd';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
import RetrieveCommand from './RetrieveCommand';



const StartApplication = () => {

const buttonDiv = {
   marginTop : '100px',
    marginLeft : '400px',
};

const lampOffDiv = {
    border: '5px solid #ffebcc',
    backgroundColor: '#666666',
    height : '300px',
    width : '60%',
    marginLeft: '200px',
};

const lampOnDiv = {
  border: '5px solid #ffebcc',
  backgroundColor: '#adebad',
  height : '300px',
  width : '60%',
  marginLeft: '200px',
};

enum BUTTON {
    START = "Start Application",
    STOP = "Stop Application"
};

enum LAMP_STATE{
  ON = 28,
  OFF = -28,
  INITIAL = 0
}

const [buttonName, setButtonName] = React.useState(BUTTON.START);
const [commandNumber, setCommandNumber] = React.useState(LAMP_STATE.INITIAL);


const [lightOnOnce, setLightOnOnce] = React.useState(false);
const [lightOffOnce, setLightOffOnce] = React.useState(false);

React.useEffect(() => {
  if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
    alert("Ups, your browser is not supported!");
  }  
}, []);

const onRegex = new RegExp('^on$','i');
const offRegex = new RegExp('^off$','i');


const commands = [
    {
      command: onRegex,
      callback: () => {
          console.log("on command");
        
          if(commandNumber === LAMP_STATE.ON){
            setLightOnOnce(false);
          }else{
            
            setCommandNumber(LAMP_STATE.ON);
            setLightOnOnce(true);
          }
          
        },
      
      matchInterim: true
    },
    {
      command: offRegex,
      callback: () => {
          
          if(lightOnOnce){
            
            if(commandNumber === LAMP_STATE.OFF){
              setLightOffOnce(false);
            }else{
              setCommandNumber(LAMP_STATE.OFF);
              setLightOffOnce(true);
            } 
          }
                       
          
        },
      matchInterim: true
    },
  ]

  const { transcript } = useSpeechRecognition({commands});
  //console.log("this is transcript :",transcript);



const handleListening = () => {
  if(buttonName === BUTTON.START){
    console.log("button start is clicked");
    setButtonName(BUTTON.STOP);
    SpeechRecognition.startListening({ continuous: true });
  }else if(buttonName === BUTTON.STOP){
    SpeechRecognition.stopListening();
    setCommandNumber(LAMP_STATE.OFF);
    setLightOnOnce(false);
    if(lightOffOnce){
      setLightOffOnce(false);
    }else{
      setLightOffOnce(true);
    }
    
    
    setButtonName(BUTTON.START);
    setCommandNumber(LAMP_STATE.INITIAL);
  }
}


return(
    <>
        <div style={commandNumber === LAMP_STATE.ON ? lampOnDiv : lampOffDiv}>
        {((commandNumber === LAMP_STATE.ON && lightOnOnce) || (commandNumber === LAMP_STATE.OFF && lightOffOnce)) && <RetrieveCommand commandNumber={commandNumber}/>}
        </div>
        <div style={buttonDiv}>
            <Button type="primary" size={'large'} onClick={handleListening}>{buttonName}</Button>
        </div>
        
    </>
);
}


export default StartApplication;

So, I've noticed that the callback for the 'on' command for example is called atleast twice even when I'm saying only once the 'ON'.

Could anyone help me on this ? Is it possible that I speak once and the command is taken once ?

Thanks much for stopping by !

sandy
  • 283
  • 1
  • 7
  • 27

1 Answers1

0

The issue is the setting matchInterim that you have set to true.

Change it to false and the command will be only recognised once as it should.

This is from the docs of react-speech-recognition:

  • matchInterim: Boolean that determines whether "interim" results should be matched against the command. This will make your component respond faster to commands, but also makes false positives more likely - i.e. the command may be detected when it is not spoken. This is false by default and should only be set for simple commands.

If you absolutely need the interim option set to true (because it responds faster) then you can check the transcript to see if a new command was indeed added and respond only in such cases.

Tiago Coelho
  • 5,023
  • 10
  • 17