react-voice-handler
Advanced tools
+3
-2
@@ -1,2 +0,3 @@ | ||
| export { default as useVoiceCommands } from './useVoiceCommand'; | ||
| export type { CommandAction } from './useVoiceCommand'; | ||
| export { default as useVoiceCommands } from "./useVoiceCommand"; | ||
| export type { CommandAction, VoiceCommandOptions, } from "./useVoiceCommand"; | ||
| export { LangEnum } from "./useVoiceCommand"; |
+1
-1
@@ -1,1 +0,1 @@ | ||
| !function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var r=t();for(var o in r)("object"==typeof exports?exports:e)[o]=r[o]}}(this,(()=>(()=>{"use strict";var e={d:(t,r)=>{for(var o in r)e.o(r,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:r[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{useVoiceCommands:()=>o});const r=require("react"),o=function(e,t){void 0===t&&(t=!1);var o=(0,r.useRef)(null);return(0,r.useEffect)((function(){var r=window.SpeechRecognition||window.webkitSpeechRecognition;if(r)return o.current=new r,o.current.continuous=t,o.current.lang="en-US",o.current.interimResults=!1,o.current.onresult=function(r){var n=r.results[r.results.length-1][0].transcript.trim().toLowerCase();e.forEach((function(e){var r,i=e.command,u=e.action;n.includes(i.toLowerCase())&&(u(),t||null===(r=o.current)||void 0===r||r.stop())}))},function(){o.current&&(o.current.stop(),o.current.onresult=null)};console.error("Browser does not support speech recognition.")}),[e,t]),{startRecognition:function(){var e;return null===(e=o.current)||void 0===e?void 0:e.start()},stopRecognition:function(){var e;return null===(e=o.current)||void 0===e?void 0:e.stop()}}};return t})())); | ||
| !function(e,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n();else if("function"==typeof define&&define.amd)define([],n);else{var r=n();for(var o in r)("object"==typeof exports?exports:e)[o]=r[o]}}(this,(()=>(()=>{"use strict";var e={d:(n,r)=>{for(var o in r)e.o(r,o)&&!e.o(n,o)&&Object.defineProperty(n,o,{enumerable:!0,get:r[o]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},n={};e.r(n),e.d(n,{LangEnum:()=>o,useVoiceCommands:()=>t});const r=require("react");var o;!function(e){e.EnglishUS="en-US",e.EnglishUK="en-GB",e.EnglishAustralia="en-AU",e.EnglishCanada="en-CA",e.EnglishIndia="en-IN",e.EnglishIreland="en-IE",e.EnglishNewZealand="en-NZ",e.EnglishSouthAfrica="en-ZA",e.SpanishSpain="es-ES",e.SpanishMexico="es-MX",e.SpanishArgentina="es-AR",e.SpanishColombia="es-CO",e.FrenchFrance="fr-FR",e.FrenchCanada="fr-CA",e.GermanGermany="de-DE",e.GermanSwitzerland="de-CH",e.ItalianItaly="it-IT",e.ItalianSwitzerland="it-CH",e.PortuguesePortugal="pt-PT",e.PortugueseBrazil="pt-BR",e.ChineseSimplified="zh-CN",e.ChineseHongKong="zh-HK",e.ChineseTaiwan="zh-TW",e.JapaneseJapan="ja-JP",e.KoreanSouthKorea="ko-KR",e.RussianRussia="ru-RU",e.ArabicSaudiArabia="ar-SA",e.ArabicEgypt="ar-EG",e.ArabicUAE="ar-AE",e.HindiIndia="hi-IN",e.DutchNetherlands="nl-NL",e.DutchBelgium="nl-BE",e.SwedishSweden="sv-SE",e.NorwegianNorway="no-NO",e.DanishDenmark="da-DK",e.FinnishFinland="fi-FI",e.GreekGreece="el-GR",e.TurkishTurkey="tr-TR",e.ThaiThailand="th-TH",e.HebrewIsrael="he-IL"}(o||(o={}));const t=function(e,n){var t=void 0===n?{}:n,i=t.continuous,a=void 0!==i&&i,s=t.onError,u=t.onNoMatch,c=t.lang,l=void 0===c?o.EnglishUS:c,d=(0,r.useRef)(null);return(0,r.useEffect)((function(){var n=window.SpeechRecognition||window.webkitSpeechRecognition;if(!n){var r="Browser does not support speech recognition.";return console.error(r),void(s&&s(r))}return d.current=new n,d.current.continuous=a,d.current.lang=l,d.current.interimResults=!1,d.current.onresult=function(n){var r=n.results[n.results.length-1][0].transcript.trim().toLowerCase();console.log("Transcript Language Text",r);var o=!1;e.forEach((function(e){var n,t=e.command,i=e.action;r.includes(t.toLowerCase())&&(i(),o=!0,a||null===(n=d.current)||void 0===n||n.stop())})),!o&&u&&u()},d.current.onerror=function(e){console.error("Speech recognition error:",e.error),s&&s(e.error)},function(){d.current&&(d.current.stop(),d.current.onresult=null,d.current.onerror=null)}}),[e,a,s,u,l]),{startRecognition:function(){var e;return null===(e=d.current)||void 0===e?void 0:e.start()},stopRecognition:function(){var e;return null===(e=d.current)||void 0===e?void 0:e.stop()}}};return n})())); |
@@ -0,1 +1,4 @@ | ||
| export interface SpeechRecognitionErrorEvent extends Event { | ||
| error: string; | ||
| } | ||
| export interface CommandAction { | ||
@@ -5,3 +8,51 @@ command: string; | ||
| } | ||
| declare const useVoiceCommands: (commands: CommandAction[], continuous?: boolean) => { | ||
| export declare enum LangEnum { | ||
| EnglishUS = "en-US", | ||
| EnglishUK = "en-GB", | ||
| EnglishAustralia = "en-AU", | ||
| EnglishCanada = "en-CA", | ||
| EnglishIndia = "en-IN", | ||
| EnglishIreland = "en-IE", | ||
| EnglishNewZealand = "en-NZ", | ||
| EnglishSouthAfrica = "en-ZA", | ||
| SpanishSpain = "es-ES", | ||
| SpanishMexico = "es-MX", | ||
| SpanishArgentina = "es-AR", | ||
| SpanishColombia = "es-CO", | ||
| FrenchFrance = "fr-FR", | ||
| FrenchCanada = "fr-CA", | ||
| GermanGermany = "de-DE", | ||
| GermanSwitzerland = "de-CH", | ||
| ItalianItaly = "it-IT", | ||
| ItalianSwitzerland = "it-CH", | ||
| PortuguesePortugal = "pt-PT", | ||
| PortugueseBrazil = "pt-BR", | ||
| ChineseSimplified = "zh-CN", | ||
| ChineseHongKong = "zh-HK", | ||
| ChineseTaiwan = "zh-TW", | ||
| JapaneseJapan = "ja-JP", | ||
| KoreanSouthKorea = "ko-KR", | ||
| RussianRussia = "ru-RU", | ||
| ArabicSaudiArabia = "ar-SA", | ||
| ArabicEgypt = "ar-EG", | ||
| ArabicUAE = "ar-AE", | ||
| HindiIndia = "hi-IN", | ||
| DutchNetherlands = "nl-NL", | ||
| DutchBelgium = "nl-BE", | ||
| SwedishSweden = "sv-SE", | ||
| NorwegianNorway = "no-NO", | ||
| DanishDenmark = "da-DK", | ||
| FinnishFinland = "fi-FI", | ||
| GreekGreece = "el-GR", | ||
| TurkishTurkey = "tr-TR", | ||
| ThaiThailand = "th-TH", | ||
| HebrewIsrael = "he-IL" | ||
| } | ||
| export interface VoiceCommandOptions { | ||
| continuous?: boolean; | ||
| onError?: (error: string) => void; | ||
| onNoMatch?: () => void; | ||
| lang?: LangEnum; | ||
| } | ||
| declare const useVoiceCommands: (commands: CommandAction[], { continuous, onError, onNoMatch, lang }?: VoiceCommandOptions) => { | ||
| startRecognition: () => void; | ||
@@ -8,0 +59,0 @@ stopRecognition: () => void; |
+3
-3
| { | ||
| "name": "react-voice-handler", | ||
| "version": "1.0.0", | ||
| "description": "A lightweight React hook for voice commands using the Web Speech API.", | ||
| "version": "1.1.0", | ||
| "description": "A lightweight React hook for voice commands using the Web Speech API with multi-language support and error handling.", | ||
| "main": "dist/index.js", | ||
@@ -10,3 +10,3 @@ "scripts": { | ||
| }, | ||
| "keywords": ["react", "voice", "commands", "speech-recognition", "hook"], | ||
| "keywords": ["react", "voice", "commands", "speech-recognition", "hook", "multi-language", "error-handling"], | ||
| "author": "NightDevilPT", | ||
@@ -13,0 +13,0 @@ "license": "ISC", |
+56
-18
@@ -16,2 +16,3 @@ <!DOCTYPE html> | ||
| <li>Handles both continuous and non-continuous recognition modes.</li> | ||
| <li>Supports multiple languages and dialects, with a wide selection of languages through the <code>LangEnum</code>.</li> | ||
| </ul> | ||
@@ -25,30 +26,53 @@ | ||
| <p>Here’s an example of how to use <code>useVoiceCommands</code> in your React application:</p> | ||
| <pre><code> | ||
| <code><pre> | ||
| import React from 'react'; | ||
| import { useVoiceCommands } from 'react-voice-handler'; | ||
| import { useVoiceCommands, LangEnum } from 'react-voice-handler'; | ||
| const App: React.FC = () => { | ||
| const commands = [ | ||
| { command: 'hello', action: () => alert('Hello there!') }, | ||
| { command: 'goodbye', action: () => alert('Goodbye!') }, | ||
| ]; | ||
| const commands = [ | ||
| { command: 'hello', action: () => alert('Hello there!') }, | ||
| { command: '안녕하세요', action: () => alert('hello') }, | ||
| { command: 'goodbye', action: () => alert('Goodbye!') }, | ||
| ]; | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, true); // Continuous mode | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, { continuous: true, lang: LangEnum.EnglishUS }); | ||
| return ( | ||
| <div> | ||
| <h1>Voice Command App</h1> | ||
| <button onClick={startRecognition}>Start Listening</button> | ||
| <button onClick={stopRecognition}>Stop Listening</button> | ||
| </div> | ||
| ); | ||
| return ( | ||
| <div> | ||
| <h1>Voice Command App</h1> | ||
| <button onClick={startRecognition}>Start Listening</button> | ||
| <button onClick={stopRecognition}>Stop Listening</button> | ||
| </div> | ||
| ); | ||
| }; | ||
| export default App; | ||
| </pre></code> | ||
| <h2>Language Support</h2> | ||
| <p>The <code>useVoiceCommands</code> hook supports a wide range of languages and dialects through the <code>LangEnum</code>. By default, it uses <code>LangEnum.EnglishUS</code>, but you can customize the language by passing the <code>lang</code> option in the configuration object.</p> | ||
| <p>For example, to use Spanish (Spain):</p> | ||
| <pre><code> | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, { lang: LangEnum.SpanishSpain }); | ||
| </code></pre> | ||
| <h3>Available Languages</h3> | ||
| <p>Here are some of the available languages in the <code>LangEnum</code>:</p> | ||
| <ul> | ||
| <li>English (US) - <code>LangEnum.EnglishUS</code></li> | ||
| <li>English (UK) - <code>LangEnum.EnglishUK</code></li> | ||
| <li>Spanish (Spain) - <code>LangEnum.SpanishSpain</code></li> | ||
| <li>French (France) - <code>LangEnum.FrenchFrance</code></li> | ||
| <li>German (Germany) - <code>LangEnum.GermanGermany</code></li> | ||
| <li>Chinese (Simplified) - <code>LangEnum.ChineseSimplified</code></li> | ||
| <li>Japanese (Japan) - <code>LangEnum.JapaneseJapan</code></li> | ||
| <li>Russian (Russia) - <code>LangEnum.RussianRussia</code></li> | ||
| <!-- List other languages as needed --> | ||
| </ul> | ||
| <h2>Continuous vs Non-Continuous Modes</h2> | ||
| <p><strong>Continuous Mode</strong> allows the voice recognition to keep listening after recognizing a command. Use this mode if you expect multiple commands over time without manually restarting the recognition.</p> | ||
| <pre><code> | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, true); // Continuous mode | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, { continuous: true }); | ||
| </code></pre> | ||
@@ -58,3 +82,3 @@ | ||
| <pre><code> | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, false); // Non-continuous mode | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, { continuous: false }); | ||
| </code></pre> | ||
@@ -69,4 +93,5 @@ | ||
| const commands = [ | ||
| { command: 'hello', action: () => alert('Hello there!') }, | ||
| { command: 'goodbye', action: () => alert('Goodbye!') }, | ||
| { command: 'hello', action: () => alert('Hello there!') }, | ||
| { command: '안녕하세요', action: () => alert('hello') }, | ||
| { command: 'goodbye', action: () => alert('Goodbye!') }, | ||
| ]; | ||
@@ -78,5 +103,18 @@ </code></pre> | ||
| </li> | ||
| <li> | ||
| <code>lang</code> (optional): A language variant from the <code>LangEnum</code> enum. Example: <code>LangEnum.EnglishUS</code>. Default is <code>LangEnum.EnglishUS</code>. | ||
| </li> | ||
| </ul> | ||
| <h2>Error Handling</h2> | ||
| <p>The hook allows error handling by passing a custom <code>onError</code> function in the options. For example:</p> | ||
| <pre><code> | ||
| const handleError = (error) => { | ||
| console.error('Speech recognition error:', error); | ||
| }; | ||
| const { startRecognition, stopRecognition } = useVoiceCommands(commands, { onError: handleError }); | ||
| </code></pre> | ||
| </body> | ||
| </html> |
+18
-18
@@ -7,6 +7,6 @@ // global.d.ts | ||
| webkitSpeechRecognition: typeof SpeechRecognition; | ||
| } | ||
| // Declare the SpeechRecognition class and its types | ||
| declare class SpeechRecognition { | ||
| } | ||
| // Declare the SpeechRecognition class and its types | ||
| declare class SpeechRecognition { | ||
| continuous: boolean; | ||
@@ -18,23 +18,23 @@ interimResults: boolean; | ||
| stop(): void; | ||
| } | ||
| interface SpeechRecognitionEvent { | ||
| onerror: (event: SpeechRecognitionErrorEvent) => void; // Add this line | ||
| } | ||
| interface SpeechRecognitionEvent { | ||
| results: SpeechRecognitionResultList; | ||
| } | ||
| interface SpeechRecognitionResultList { | ||
| } | ||
| interface SpeechRecognitionResultList { | ||
| length: number; | ||
| [index: number]: SpeechRecognitionResult; | ||
| } | ||
| interface SpeechRecognitionResult { | ||
| } | ||
| interface SpeechRecognitionResult { | ||
| isFinal: boolean; | ||
| length: number; | ||
| [index: number]: SpeechRecognitionAlternative; | ||
| } | ||
| interface SpeechRecognitionAlternative { | ||
| } | ||
| interface SpeechRecognitionAlternative { | ||
| transcript: string; | ||
| confidence: number; | ||
| } | ||
| } |
+6
-2
| // src/index.ts | ||
| export { default as useVoiceCommands } from './useVoiceCommand'; | ||
| export type { CommandAction } from './useVoiceCommand'; | ||
| export { default as useVoiceCommands } from "./useVoiceCommand"; | ||
| export type { | ||
| CommandAction, | ||
| VoiceCommandOptions, | ||
| } from "./useVoiceCommand"; | ||
| export { LangEnum } from "./useVoiceCommand"; // Corrected export for the LangEnum |
+120
-4
| import { useEffect, useRef } from "react"; | ||
| export interface SpeechRecognitionErrorEvent extends Event { | ||
| error: string; // Add more detailed error handling as needed | ||
| } | ||
| export interface CommandAction { | ||
@@ -8,3 +13,99 @@ command: string; | ||
| const useVoiceCommands = (commands: CommandAction[], continuous: boolean = false) => { | ||
| // src/langEnum.ts | ||
| export enum LangEnum { | ||
| // English Variants | ||
| EnglishUS = "en-US", | ||
| EnglishUK = "en-GB", | ||
| EnglishAustralia = "en-AU", | ||
| EnglishCanada = "en-CA", | ||
| EnglishIndia = "en-IN", | ||
| EnglishIreland = "en-IE", | ||
| EnglishNewZealand = "en-NZ", | ||
| EnglishSouthAfrica = "en-ZA", | ||
| // Spanish Variants | ||
| SpanishSpain = "es-ES", | ||
| SpanishMexico = "es-MX", | ||
| SpanishArgentina = "es-AR", | ||
| SpanishColombia = "es-CO", | ||
| // French Variants | ||
| FrenchFrance = "fr-FR", | ||
| FrenchCanada = "fr-CA", | ||
| // German | ||
| GermanGermany = "de-DE", | ||
| GermanSwitzerland = "de-CH", | ||
| // Italian | ||
| ItalianItaly = "it-IT", | ||
| ItalianSwitzerland = "it-CH", | ||
| // Portuguese Variants | ||
| PortuguesePortugal = "pt-PT", | ||
| PortugueseBrazil = "pt-BR", | ||
| // Chinese Variants | ||
| ChineseSimplified = "zh-CN", | ||
| ChineseHongKong = "zh-HK", | ||
| ChineseTaiwan = "zh-TW", | ||
| // Japanese | ||
| JapaneseJapan = "ja-JP", | ||
| // Korean | ||
| KoreanSouthKorea = "ko-KR", | ||
| // Russian | ||
| RussianRussia = "ru-RU", | ||
| // Arabic Variants | ||
| ArabicSaudiArabia = "ar-SA", | ||
| ArabicEgypt = "ar-EG", | ||
| ArabicUAE = "ar-AE", | ||
| // Hindi | ||
| HindiIndia = "hi-IN", | ||
| // Dutch | ||
| DutchNetherlands = "nl-NL", | ||
| DutchBelgium = "nl-BE", | ||
| // Swedish | ||
| SwedishSweden = "sv-SE", | ||
| // Norwegian | ||
| NorwegianNorway = "no-NO", | ||
| // Danish | ||
| DanishDenmark = "da-DK", | ||
| // Finnish | ||
| FinnishFinland = "fi-FI", | ||
| // Greek | ||
| GreekGreece = "el-GR", | ||
| // Turkish | ||
| TurkishTurkey = "tr-TR", | ||
| // Thai | ||
| ThaiThailand = "th-TH", | ||
| // Hebrew | ||
| HebrewIsrael = "he-IL" | ||
| } | ||
| export interface VoiceCommandOptions { | ||
| continuous?: boolean; | ||
| onError?: (error: string) => void; | ||
| onNoMatch?: () => void; | ||
| lang?: LangEnum; | ||
| } | ||
| const useVoiceCommands = ( | ||
| commands: CommandAction[], | ||
| { continuous = false, onError, onNoMatch, lang = LangEnum.EnglishUS }: VoiceCommandOptions = {} | ||
| ) => { | ||
| const recognitionRef = useRef<SpeechRecognition | null>(null); | ||
@@ -15,3 +116,5 @@ | ||
| if (!SpeechRecognition) { | ||
| console.error("Browser does not support speech recognition."); | ||
| const errorMsg = "Browser does not support speech recognition."; | ||
| console.error(errorMsg); | ||
| if (onError) onError(errorMsg); | ||
| return; | ||
@@ -22,3 +125,3 @@ } | ||
| recognitionRef.current.continuous = continuous; | ||
| recognitionRef.current.lang = "en-US"; | ||
| recognitionRef.current.lang = lang; | ||
| recognitionRef.current.interimResults = false; | ||
@@ -28,2 +131,4 @@ | ||
| const transcript = event.results[event.results.length - 1][0].transcript.trim().toLowerCase(); | ||
| console.log('Transcript Language Text',transcript) | ||
| let commandMatched = false; | ||
@@ -33,2 +138,3 @@ commands.forEach(({ command, action }) => { | ||
| action(); | ||
| commandMatched = true; | ||
| if (!continuous) { | ||
@@ -39,4 +145,13 @@ recognitionRef.current?.stop(); | ||
| }); | ||
| if (!commandMatched && onNoMatch) { | ||
| onNoMatch(); | ||
| } | ||
| }; | ||
| recognitionRef.current.onerror = (event: SpeechRecognitionErrorEvent) => { | ||
| console.error("Speech recognition error:", event.error); | ||
| if (onError) onError(event.error); | ||
| }; | ||
| return () => { | ||
@@ -46,5 +161,6 @@ if (recognitionRef.current) { | ||
| recognitionRef.current.onresult = null; | ||
| recognitionRef.current.onerror = null; | ||
| } | ||
| }; | ||
| }, [commands, continuous]); | ||
| }, [commands, continuous, onError, onNoMatch, lang]); | ||
@@ -51,0 +167,0 @@ return { |
17734
75.98%284
105.8%116
48.72%