annyang 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/annyang.cjs +10 -3
- package/dist/annyang.cjs.map +1 -1
- package/dist/annyang.iife.min.js +1 -1
- package/dist/annyang.js +10 -3
- package/dist/annyang.js.map +1 -1
- package/package.json +28 -22
package/README.md
CHANGED
|
@@ -64,8 +64,8 @@ const annyang = require('annyang');
|
|
|
64
64
|
|
|
65
65
|
### Script tag (IIFE)
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
<script src="dist/annyang.iife.min.js"></script>
|
|
67
|
+
```html
|
|
68
|
+
<script src="https://cdn.jsdelivr.net/npm/annyang@3/dist/annyang.iife.min.js"></script>
|
|
69
69
|
<script>
|
|
70
70
|
if (annyang.isSpeechRecognitionSupported()) {
|
|
71
71
|
// Let's define a command.
|
package/dist/annyang.cjs
CHANGED
|
@@ -66,12 +66,19 @@ var optionalParam = /\s*\((.*?)\)\s*/g;
|
|
|
66
66
|
var optionalRegex = /(\(\?:[^)]+\))\?/g;
|
|
67
67
|
var namedParam = /(\(\?)?:\w+/g;
|
|
68
68
|
var splatParam = /\*\w+/g;
|
|
69
|
-
var escapeRegExp = /[
|
|
69
|
+
var escapeRegExp = /[{}[\]+?.\\^$|]/g;
|
|
70
70
|
var commandToRegExp = (command) => {
|
|
71
|
-
const
|
|
71
|
+
const parts = command.split(/([:*]\w+)/);
|
|
72
|
+
const last = parts.length - 1;
|
|
73
|
+
const ending = parts[last].replace(/[.!?]+$/, "");
|
|
74
|
+
const literalEnding = /\S/.test(ending) && (last === 0 || !ending.trimEnd().endsWith(")"));
|
|
75
|
+
if (literalEnding) parts[last] = ending;
|
|
76
|
+
const parsedCommand = parts.map(
|
|
77
|
+
(part, index) => index % 2 ? part : part.replace(escapeRegExp, "\\$&").replace(/([\p{L}\p{N}]),?(?=\s+[\p{L}\p{N}])/gu, "$1,?")
|
|
78
|
+
).join("").replace(optionalParam, "(?:$1)?").replace(namedParam, (match, optional) => {
|
|
72
79
|
return optional ? match : "([^\\s]+)";
|
|
73
80
|
}).replace(splatParam, "(.*?)").replace(optionalRegex, "\\s*$1?\\s*");
|
|
74
|
-
return new RegExp(`^${parsedCommand}$`, "
|
|
81
|
+
return new RegExp(`^${parsedCommand}${literalEnding ? "[.!?]*" : ""}$`, "iu");
|
|
75
82
|
};
|
|
76
83
|
var getSpeechRecognition = () => globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition;
|
|
77
84
|
var isInitialized = () => {
|
package/dist/annyang.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/annyang.ts"],"sourcesContent":["const MIN_RESTART_INTERVAL_MS = 1000;\nconst RESTART_WARNING_INTERVAL = 10;\n\nlet recognition: SpeechRecognition;\nlet listening: boolean = false;\nlet autoRestart: boolean = true;\nlet debugState: boolean = false;\nconst debugStyle: string = 'font-weight: bold; color: #00f;';\n\nexport interface CallbackMap {\n start: () => void;\n end: () => void;\n soundstart: () => void;\n result: (phrases: string[]) => void;\n resultMatch: (userSaid: string, commandText: string, phrases: string[]) => void;\n resultNoMatch: (phrases: string[]) => void;\n error: (event: SpeechRecognitionErrorEvent) => void;\n errorNetwork: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionBlocked: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionDenied: (event: SpeechRecognitionErrorEvent) => void;\n}\n\nexport type CallbackType = keyof CallbackMap;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyFunction = (...args: any[]) => void;\n\ninterface StoredCallback {\n callback: AnyFunction;\n context: object | undefined;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst commandsList: Map<string, { command: RegExp; callback: (...args: any[]) => void }> = new Map();\nconst callbacks: Map<CallbackType, StoredCallback[]> = new Map([\n ['start', []],\n ['error', []],\n ['end', []],\n ['soundstart', []],\n ['result', []],\n ['resultMatch', []],\n ['resultNoMatch', []],\n ['errorNetwork', []],\n ['errorPermissionBlocked', []],\n ['errorPermissionDenied', []],\n]);\nlet lastStartedAt: number = 0;\nlet autoRestartCount: number = 0;\nlet pauseListening: boolean = false;\n\n// The command matching code is a modified version of Backbone.Router by Jeremy Ashkenas, under the MIT license.\nconst optionalParam = /\\s*\\((.*?)\\)\\s*/g;\nconst optionalRegex = /(\\(\\?:[^)]+\\))\\?/g;\nconst namedParam = /(\\(\\?)?:\\w+/g;\nconst splatParam = /\\*\\w+/g;\nconst escapeRegExp = /[-{}[\\]+?.,\\\\^$|#]/g;\nconst commandToRegExp = (command: string) => {\n const parsedCommand = command\n .replace(escapeRegExp, '\\\\$&')\n .replace(optionalParam, '(?:$1)?')\n .replace(namedParam, (match, optional) => {\n return optional ? match : '([^\\\\s]+)';\n })\n .replace(splatParam, '(.*?)')\n .replace(optionalRegex, '\\\\s*$1?\\\\s*');\n return new RegExp(`^${parsedCommand}$`, 'i');\n};\n\n// Get the SpeechRecognition object, accounting for possible browser prefixes\nconst getSpeechRecognition = () => globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition;\n\n// Check if annyang is already initialized\nconst isInitialized = () => {\n return recognition !== undefined;\n};\n\n// Method for logging to the console when debug mode is on\nconst logMessage = (text: string, extraParameters?: string | string[]) => {\n if (debugState) {\n if (text.indexOf('%c') === -1 && !extraParameters) {\n console.log(text);\n } else {\n console.log(text, extraParameters || debugStyle);\n }\n }\n};\n\n// Add a command to the commands list\nconst registerCommand = (command: RegExp, callback: AnyFunction, originalPhrase: string) => {\n commandsList.set(originalPhrase, { command, callback });\n logMessage(`Command successfully loaded: %c${originalPhrase}`, debugStyle);\n};\n\n// This method receives an array of callbacks and invokes each of them\nconst invokeCallbacks = (callbacksArr: StoredCallback[] = [], ...args: unknown[]) => {\n callbacksArr.forEach(cb => {\n cb.callback.apply(cb.context, args);\n });\n};\n\n// Initialize annyang\nconst init = () => {\n if (!getSpeechRecognition()) {\n return;\n }\n\n // Abort previous instances of recognition already running\n if (recognition && recognition.abort) {\n recognition.abort();\n }\n\n // initiate SpeechRecognition\n recognition = new (getSpeechRecognition())();\n\n // Set the max number of alternative transcripts to try and match with a command\n recognition.maxAlternatives = 5;\n\n // In HTTPS, turn off continuous mode for faster results.\n // In HTTP, turn on continuous mode for much slower results, but no repeating security notices\n recognition.continuous = globalThis.location.protocol === 'http:';\n\n // Sets the language to the default 'en-US'. This can be changed with annyang.setLanguage()\n recognition.lang = 'en-US';\n\n recognition.onstart = () => {\n listening = true;\n invokeCallbacks(callbacks.get('start'));\n };\n\n recognition.onsoundstart = () => {\n invokeCallbacks(callbacks.get('soundstart'));\n };\n\n recognition.onerror = event => {\n invokeCallbacks(callbacks.get('error'), event);\n switch (event.error) {\n case 'network':\n invokeCallbacks(callbacks.get('errorNetwork'), event);\n break;\n case 'not-allowed':\n case 'service-not-allowed':\n // if permission to use the mic is denied, turn off auto-restart\n autoRestart = false;\n // determine if permission was denied by user or automatically.\n if (new Date().getTime() - lastStartedAt < 200) {\n invokeCallbacks(callbacks.get('errorPermissionBlocked'), event);\n } else {\n invokeCallbacks(callbacks.get('errorPermissionDenied'), event);\n }\n break;\n default:\n break;\n }\n };\n\n recognition.onend = () => {\n listening = false;\n invokeCallbacks(callbacks.get('end'));\n // annyang will auto restart if it is closed automatically and not by user action.\n if (autoRestart) {\n // play nicely with the browser, and never restart annyang automatically more than once per second\n const timeSinceLastStart = new Date().getTime() - lastStartedAt;\n autoRestartCount += 1;\n if (autoRestartCount % RESTART_WARNING_INTERVAL === 0) {\n logMessage(\n 'Speech Recognition is repeatedly stopping and starting. See http://is.gd/annyang_restarts for tips.'\n );\n }\n if (timeSinceLastStart < MIN_RESTART_INTERVAL_MS) {\n setTimeout(() => {\n start({ paused: pauseListening });\n }, MIN_RESTART_INTERVAL_MS - timeSinceLastStart);\n } else {\n start({ paused: pauseListening });\n }\n }\n };\n\n recognition.onresult = (event: SpeechRecognitionEvent) => {\n if (pauseListening) {\n logMessage('Speech heard, but annyang is paused');\n return;\n }\n\n // Map the results to an array\n const SpeechRecognitionResults = event.results[event.resultIndex];\n const results = Array.from(SpeechRecognitionResults, result => result.transcript);\n parseResults(results);\n };\n};\n\n// If annyang isn't initialized, initialize it\nconst initIfNeeded = () => {\n if (!isInitialized()) {\n init();\n }\n};\n\nconst parseResults = (recognitionResults: string[]) => {\n invokeCallbacks(callbacks.get('result'), recognitionResults);\n\n // Log all recognition alternatives for debugging, regardless of match\n for (const rawText of recognitionResults) {\n logMessage(`Speech recognized: %c${rawText.trim()}`, debugStyle);\n }\n\n // Try to match each alternative to a command\n for (const rawText of recognitionResults) {\n const commandText = rawText.trim();\n for (const [originalPhrase, currentCommand] of commandsList) {\n const matchedCommand = currentCommand.command.exec(commandText);\n if (matchedCommand) {\n const parameters = matchedCommand.slice(1);\n logMessage(`command matched: %c${originalPhrase}`, debugStyle);\n if (parameters.length) {\n logMessage('with parameters', parameters);\n }\n currentCommand.callback(...parameters);\n invokeCallbacks(callbacks.get('resultMatch'), commandText, originalPhrase, recognitionResults);\n return;\n }\n }\n }\n invokeCallbacks(callbacks.get('resultNoMatch'), recognitionResults);\n};\n\n/**\n * Is SpeechRecognition supported in this environment?\n *\n * @returns {boolean} true if SpeechRecognition is supported by the browser\n */\nconst isSpeechRecognitionSupported = () => !!getSpeechRecognition();\n\nexport type CommandCallback = (...args: string[]) => void;\n\nexport interface CommandsList {\n [key: string]:\n | CommandCallback\n | {\n regexp: RegExp;\n callback: CommandCallback;\n };\n}\n\n/**\n * Add commands that annyang will respond to.\n * By default this will add to the existing commands. Pass `true` as the second parameter to remove all existing commands first.\n *\n * #### Examples:\n * ````javascript\n * const commands1 = {'hello :name': helloFunction, 'howdy': helloFunction};\n * const commands2 = {'hi': helloFunction};\n *\n * annyang.addCommands(commands1);\n * annyang.addCommands(commands2);\n * // annyang will now listen for all three commands defined in commands1 and commands2\n *\n * annyang.addCommands(commands2, true);\n * // annyang will now only listen for the command in commands2\n * ````\n *\n * @param {Object} commands - Commands that annyang should listen for\n * @param {boolean} [resetCommands=false] - Remove all existing commands before adding new commands? * @see [Commands Object](#commands-object)\n */\nconst addCommands = (commands: CommandsList, resetCommands = false) => {\n if (resetCommands) {\n commandsList.clear();\n }\n\n for (const phrase of Object.keys(commands)) {\n const cb = commands[phrase];\n\n if (typeof cb === 'function') {\n // convert command to regex then register the command\n registerCommand(commandToRegExp(phrase), cb, phrase);\n } else if (typeof cb === 'object' && cb.regexp instanceof RegExp) {\n // register the command\n registerCommand(new RegExp(cb.regexp.source, 'i'), cb.callback, phrase);\n } else {\n logMessage(`Can not register command: %c${phrase}`, debugStyle);\n }\n }\n};\n\n/**\n * Remove existing commands. Called with a single phrase, an array of phrases, or with no params to remove all commands.\n *\n * #### Examples:\n * ````javascript\n * const commands = {'hello': helloFunction, 'howdy': helloFunction, 'hi': helloFunction};\n *\n * // Remove all existing commands\n * annyang.removeCommands();\n *\n * // Add some commands\n * annyang.addCommands(commands);\n *\n * // Don't respond to hello\n * annyang.removeCommands('hello');\n *\n * // Don't respond to howdy or hi\n * annyang.removeCommands(['howdy', 'hi']);\n * ````\n * @param {string|string[]|undefined} [commandsToRemove] - Commands to remove\n */\nconst removeCommands = (commandsToRemove?: string | string[] | undefined) => {\n if (commandsToRemove === undefined) {\n commandsList.clear();\n } else {\n const commandsToRemoveArray = Array.isArray(commandsToRemove) ? commandsToRemove : [commandsToRemove];\n commandsToRemoveArray.forEach(command => commandsList.delete(command));\n }\n};\n\nexport interface StartOptions {\n autoRestart?: boolean;\n continuous?: boolean;\n paused?: boolean;\n}\n\n/**\n * Start listening.\n * It's a good idea to call this after adding some commands first (but not mandatory)\n *\n * Receives an optional options object which supports the following options:\n *\n * - `autoRestart` (boolean) Should annyang restart itself if it is closed indirectly (e.g. because of silence or window conflicts)?\n * - `continuous` (boolean) Allow forcing continuous mode on or off. annyang is pretty smart about this, so only set this if you know what you're doing.\n * - `paused` (boolean) Start annyang in paused mode.\n *\n * #### Examples:\n * ````javascript\n * // Start listening, don't restart automatically\n * annyang.start({ autoRestart: false });\n * // Start listening, don't restart automatically, stop recognition after first phrase recognized\n * annyang.start({ autoRestart: false, continuous: false });\n * ````\n * @param {Object} [options] - Optional options.\n */\nconst start = (options: StartOptions = {}) => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n pauseListening = !!options.paused;\n if (options.autoRestart !== undefined) {\n autoRestart = !!options.autoRestart;\n } else {\n autoRestart = true;\n }\n if (options.continuous !== undefined) {\n recognition.continuous = !!options.continuous;\n }\n\n lastStartedAt = new Date().getTime();\n try {\n recognition.start();\n } catch (e: unknown) {\n logMessage(e instanceof Error ? e.message : String(e));\n }\n};\n\n/**\n * Stop listening and turn off the mic.\n *\n * Alternatively, to only temporarily pause annyang responding to commands without stopping the SpeechRecognition engine or closing the mic, use pause() instead.\n * @see [pause()](#pause)\n */\nconst abort = () => {\n autoRestart = false;\n autoRestartCount = 0;\n if (isInitialized()) {\n recognition.abort();\n }\n};\n\n/**\n * Pause listening. annyang will stop responding to commands (until the resume or start methods are called), without turning off the browser's SpeechRecognition engine or the mic.\n *\n * Alternatively, to stop the SpeechRecognition engine and close the mic, use abort() instead.\n * @see [abort()](#abort)\n */\nconst pause = () => {\n pauseListening = true;\n};\n\n/**\n * Resumes listening and restore command callback execution when a command is matched.\n * If SpeechRecognition was aborted (stopped), start it.\n */\nconst resume = () => {\n start();\n};\n\n/**\n * Add a callback function to be called in case one of the following events happens:\n *\n * * `start` - Fired as soon as the browser's Speech Recognition engine starts listening.\n *\n * * `soundstart` - Fired as soon as any sound (possibly speech) has been detected.\n *\n * This will fire once per Speech Recognition starting. See https://is.gd/annyang_sound_start.\n *\n * * `error` - Fired when the browser's Speech Recognition engine returns an error, this generic error callback will be followed by more accurate error callbacks (both will fire if both are defined).\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorNetwork` - Fired when Speech Recognition fails because of a network error.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionBlocked` - Fired when the browser blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionDenied` - Fired when the user blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `end` - Fired when the browser's Speech Recognition engine stops.\n *\n * * `result` - Fired as soon as some speech was identified. This generic callback will be followed by either the `resultMatch` or `resultNoMatch` callbacks.\n *\n * The Callback functions for this event will be called with an array of possible phrases the user said as the first argument.\n *\n * * `resultMatch` - Fired when annyang was able to match between what the user said and a registered command.\n *\n * The Callback functions for this event will be called with three arguments in the following order:\n *\n * * The phrase the user said that matched a command.\n * * The command that was matched.\n * * An array of possible alternative phrases the user might have said.\n *\n * * `resultNoMatch` - Fired when what the user said didn't match any of the registered commands.\n *\n * Callback functions for this event will be called with an array of possible phrases the user might have said as the first argument.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('resultMatch', (userSaid, commandText, phrases) => {\n * console.log(userSaid); // sample output: 'hello'\n * console.log(commandText); // sample output: 'hello (there)'\n * console.log(phrases); // sample output: ['hello', 'halo', 'yellow', 'polo', 'hello kitty']\n * });\n *\n * // Returns an unsubscribe function\n * const unsubscribe = annyang.addCallback('error', () => {\n * console.log('There was an error!');\n * });\n * unsubscribe(); // removes the callback\n * ````\n * @param {string} type - Name of event that will trigger this callback\n * @param {function} callback - The function to call when event is triggered\n * @param {Object} [context] - Optional context for the callback function\n * @returns {function} A function that removes this callback when called\n */\nconst addCallback = <T extends CallbackType>(\n type: T,\n callback: CallbackMap[T],\n context: object | undefined = undefined\n): (() => void) => {\n const callbacksOfType = callbacks.get(type);\n if (typeof callback === 'function' && callbacksOfType) {\n const entry: StoredCallback = {\n callback: callback as AnyFunction,\n context,\n };\n callbacksOfType.push(entry);\n return () => {\n const arr = callbacks.get(type);\n if (arr) {\n const idx = arr.indexOf(entry);\n if (idx !== -1) arr.splice(idx, 1);\n }\n };\n }\n return () => {};\n};\n\n/**\n * Remove callbacks from events.\n *\n * - Pass an event name and a callback command to remove that callback command from that event type.\n * - Pass just an event name to remove all callback commands from that event type.\n * - Pass undefined as event name and a callback command to remove that callback command from all event types.\n * - Pass no params to remove all callback commands from all event types.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('start', myFunction1);\n * annyang.addCallback('start', myFunction2);\n * annyang.addCallback('end', myFunction1);\n * annyang.addCallback('end', myFunction2);\n *\n * // Remove all callbacks from all events:\n * annyang.removeCallback();\n *\n * // Remove all callbacks attached to end event:\n * annyang.removeCallback('end');\n *\n * // Remove myFunction2 from being called on start:\n * annyang.removeCallback('start', myFunction2);\n *\n * // Remove myFunction1 from being called on all events:\n * annyang.removeCallback(undefined, myFunction1);\n * ````\n *\n * @param type Name of event type to remove callback from\n * @param callback The callback function to remove\n * @returns undefined\n */\nconst removeCallback = (type?: CallbackType, callback?: CallbackMap[CallbackType]) => {\n callbacks.forEach((callbacksArray, callbackType) => {\n if (type === undefined || type === callbackType) {\n if (callback === undefined) {\n callbacks.get(callbackType)!.length = 0;\n } else {\n callbacks.set(\n callbackType,\n callbacksArray.filter(cb => cb.callback !== callback)\n );\n }\n }\n });\n};\n\n/**\n * Returns true if speech recognition is currently on.\n * Returns false if speech recognition is off or annyang is paused.\n *\n * @returns true if SpeechRecognition is on and annyang is not paused\n */\nconst isListening = () => {\n return listening && !pauseListening;\n};\n\nexport type AnnyangState = 'idle' | 'listening' | 'paused';\n\n/**\n * Returns the current state of annyang.\n *\n * @returns {'idle' | 'listening' | 'paused'} The current state\n */\nconst getState = (): AnnyangState => {\n if (!listening) return 'idle';\n if (pauseListening) return 'paused';\n return 'listening';\n};\n\n/**\n * Set the language the user will speak in. If this method is not called, annyang defaults to 'en-US'.\n *\n * @param {string} language - The language (locale)\n * @see [Languages](https://github.com/TalAter/annyang/blob/master/docs/FAQ.md#what-languages-are-supported)\n */\nconst setLanguage = (language: string): void => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n recognition.lang = language;\n};\n\n/**\n * Turn on the output of debug messages to the console.\n *\n * @param {boolean} [newState=true] - Turn debug messages on or off\n */\nconst debug = (newState: boolean = true): void => {\n debugState = !!newState;\n};\n\n/**\n * Match text against registered commands and fire the corresponding callbacks.\n * Works independently of the speech recognition engine — does not require `start()`, and works even in\n * environments where SpeechRecognition is not supported.\n *\n * Can accept either a string containing a single sentence or an array containing multiple sentences to be checked\n * in order until one of them matches a command (similar to the way Speech Recognition Alternatives are parsed)\n *\n * #### Examples:\n * ````javascript\n * annyang.trigger('Time for some thrilling heroics');\n * annyang.trigger(\n * ['Time for some thrilling heroics', 'Time for some thrilling aerobics']\n * );\n * ````\n *\n * @param sentences - A sentence as a string or an array of strings of possible sentences\n */\nconst trigger = (sentences: string | string[] = []) => {\n parseResults(Array.isArray(sentences) ? sentences : [sentences]);\n};\n\n/**\n * Returns the instance of the browser's SpeechRecognition object used by annyang.\n * Useful in case you want direct access to the browser's Speech Recognition engine.\n *\n * @returns SpeechRecognition The browser's Speech Recognizer instance currently used by annyang\n */\nconst getSpeechRecognizer = (): SpeechRecognition | undefined => {\n return recognition;\n};\n\n/**\n * @deprecated annyang no longer requires manual initialization. It initializes automatically on `start()` or `addCommands()`. Remove any calls to `init()`.\n */\nconst initDeprecated = () => {\n console.warn(\n 'annyang.init() is deprecated and no longer needed. ' +\n 'annyang initializes automatically on start() or addCommands(). Remove this call.'\n );\n};\n\nexport {\n abort,\n addCallback,\n addCommands,\n debug,\n getSpeechRecognizer,\n getState,\n initDeprecated as init,\n isListening,\n isSpeechRecognitionSupported,\n pause,\n removeCallback,\n removeCommands,\n resume,\n setLanguage,\n start,\n trigger,\n};\n\nconst annyang = {\n isSpeechRecognitionSupported,\n addCommands,\n removeCommands,\n start,\n abort,\n pause,\n resume,\n addCallback,\n removeCallback,\n isListening,\n setLanguage,\n trigger,\n debug,\n getSpeechRecognizer,\n getState,\n init: initDeprecated,\n get state() {\n return getState();\n },\n} as const;\n\nexport default annyang;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/annyang.ts"],"sourcesContent":["const MIN_RESTART_INTERVAL_MS = 1000;\nconst RESTART_WARNING_INTERVAL = 10;\n\nlet recognition: SpeechRecognition;\nlet listening: boolean = false;\nlet autoRestart: boolean = true;\nlet debugState: boolean = false;\nconst debugStyle: string = 'font-weight: bold; color: #00f;';\n\nexport interface CallbackMap {\n start: () => void;\n end: () => void;\n soundstart: () => void;\n result: (phrases: string[]) => void;\n resultMatch: (userSaid: string, commandText: string, phrases: string[]) => void;\n resultNoMatch: (phrases: string[]) => void;\n error: (event: SpeechRecognitionErrorEvent) => void;\n errorNetwork: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionBlocked: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionDenied: (event: SpeechRecognitionErrorEvent) => void;\n}\n\nexport type CallbackType = keyof CallbackMap;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyFunction = (...args: any[]) => void;\n\ninterface StoredCallback {\n callback: AnyFunction;\n context: object | undefined;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst commandsList: Map<string, { command: RegExp; callback: (...args: any[]) => void }> = new Map();\nconst callbacks: Map<CallbackType, StoredCallback[]> = new Map([\n ['start', []],\n ['error', []],\n ['end', []],\n ['soundstart', []],\n ['result', []],\n ['resultMatch', []],\n ['resultNoMatch', []],\n ['errorNetwork', []],\n ['errorPermissionBlocked', []],\n ['errorPermissionDenied', []],\n]);\nlet lastStartedAt: number = 0;\nlet autoRestartCount: number = 0;\nlet pauseListening: boolean = false;\n\n// The command matching code is a modified version of Backbone.Router by Jeremy Ashkenas, under the MIT license.\nconst optionalParam = /\\s*\\((.*?)\\)\\s*/g;\nconst optionalRegex = /(\\(\\?:[^)]+\\))\\?/g;\nconst namedParam = /(\\(\\?)?:\\w+/g;\nconst splatParam = /\\*\\w+/g;\nconst escapeRegExp = /[{}[\\]+?.\\\\^$|]/g;\nconst commandToRegExp = (command: string) => {\n const parts = command.split(/([:*]\\w+)/);\n const last = parts.length - 1;\n const ending = parts[last].replace(/[.!?]+$/, '');\n // Only relax sentence endings after literal text, never after a captured value\n // or an optional suffix that could disappear and expose a capture.\n const literalEnding = /\\S/.test(ending) && (last === 0 || !ending.trimEnd().endsWith(')'));\n if (literalEnding) parts[last] = ending;\n const parsedCommand = parts\n .map((part, index) =>\n index % 2 ? part : part.replace(escapeRegExp, '\\\\$&').replace(/([\\p{L}\\p{N}]),?(?=\\s+[\\p{L}\\p{N}])/gu, '$1,?')\n )\n .join('')\n .replace(optionalParam, '(?:$1)?')\n .replace(namedParam, (match, optional) => {\n return optional ? match : '([^\\\\s]+)';\n })\n .replace(splatParam, '(.*?)')\n .replace(optionalRegex, '\\\\s*$1?\\\\s*');\n return new RegExp(`^${parsedCommand}${literalEnding ? '[.!?]*' : ''}$`, 'iu');\n};\n\n// Get the SpeechRecognition object, accounting for possible browser prefixes\nconst getSpeechRecognition = () => globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition;\n\n// Check if annyang is already initialized\nconst isInitialized = () => {\n return recognition !== undefined;\n};\n\n// Method for logging to the console when debug mode is on\nconst logMessage = (text: string, extraParameters?: string | string[]) => {\n if (debugState) {\n if (text.indexOf('%c') === -1 && !extraParameters) {\n console.log(text);\n } else {\n console.log(text, extraParameters || debugStyle);\n }\n }\n};\n\n// Add a command to the commands list\nconst registerCommand = (command: RegExp, callback: AnyFunction, originalPhrase: string) => {\n commandsList.set(originalPhrase, { command, callback });\n logMessage(`Command successfully loaded: %c${originalPhrase}`, debugStyle);\n};\n\n// This method receives an array of callbacks and invokes each of them\nconst invokeCallbacks = (callbacksArr: StoredCallback[] = [], ...args: unknown[]) => {\n callbacksArr.forEach(cb => {\n cb.callback.apply(cb.context, args);\n });\n};\n\n// Initialize annyang\nconst init = () => {\n if (!getSpeechRecognition()) {\n return;\n }\n\n // Abort previous instances of recognition already running\n if (recognition && recognition.abort) {\n recognition.abort();\n }\n\n // initiate SpeechRecognition\n recognition = new (getSpeechRecognition())();\n\n // Set the max number of alternative transcripts to try and match with a command\n recognition.maxAlternatives = 5;\n\n // In HTTPS, turn off continuous mode for faster results.\n // In HTTP, turn on continuous mode for much slower results, but no repeating security notices\n recognition.continuous = globalThis.location.protocol === 'http:';\n\n // Sets the language to the default 'en-US'. This can be changed with annyang.setLanguage()\n recognition.lang = 'en-US';\n\n recognition.onstart = () => {\n listening = true;\n invokeCallbacks(callbacks.get('start'));\n };\n\n recognition.onsoundstart = () => {\n invokeCallbacks(callbacks.get('soundstart'));\n };\n\n recognition.onerror = event => {\n invokeCallbacks(callbacks.get('error'), event);\n switch (event.error) {\n case 'network':\n invokeCallbacks(callbacks.get('errorNetwork'), event);\n break;\n case 'not-allowed':\n case 'service-not-allowed':\n // if permission to use the mic is denied, turn off auto-restart\n autoRestart = false;\n // determine if permission was denied by user or automatically.\n if (new Date().getTime() - lastStartedAt < 200) {\n invokeCallbacks(callbacks.get('errorPermissionBlocked'), event);\n } else {\n invokeCallbacks(callbacks.get('errorPermissionDenied'), event);\n }\n break;\n default:\n break;\n }\n };\n\n recognition.onend = () => {\n listening = false;\n invokeCallbacks(callbacks.get('end'));\n // annyang will auto restart if it is closed automatically and not by user action.\n if (autoRestart) {\n // play nicely with the browser, and never restart annyang automatically more than once per second\n const timeSinceLastStart = new Date().getTime() - lastStartedAt;\n autoRestartCount += 1;\n if (autoRestartCount % RESTART_WARNING_INTERVAL === 0) {\n logMessage(\n 'Speech Recognition is repeatedly stopping and starting. See http://is.gd/annyang_restarts for tips.'\n );\n }\n if (timeSinceLastStart < MIN_RESTART_INTERVAL_MS) {\n setTimeout(() => {\n start({ paused: pauseListening });\n }, MIN_RESTART_INTERVAL_MS - timeSinceLastStart);\n } else {\n start({ paused: pauseListening });\n }\n }\n };\n\n recognition.onresult = (event: SpeechRecognitionEvent) => {\n if (pauseListening) {\n logMessage('Speech heard, but annyang is paused');\n return;\n }\n\n // Map the results to an array\n const SpeechRecognitionResults = event.results[event.resultIndex];\n const results = Array.from(SpeechRecognitionResults, result => result.transcript);\n parseResults(results);\n };\n};\n\n// If annyang isn't initialized, initialize it\nconst initIfNeeded = () => {\n if (!isInitialized()) {\n init();\n }\n};\n\nconst parseResults = (recognitionResults: string[]) => {\n invokeCallbacks(callbacks.get('result'), recognitionResults);\n\n // Log all recognition alternatives for debugging, regardless of match\n for (const rawText of recognitionResults) {\n logMessage(`Speech recognized: %c${rawText.trim()}`, debugStyle);\n }\n\n // Try to match each alternative to a command\n for (const rawText of recognitionResults) {\n const commandText = rawText.trim();\n for (const [originalPhrase, currentCommand] of commandsList) {\n const matchedCommand = currentCommand.command.exec(commandText);\n if (matchedCommand) {\n const parameters = matchedCommand.slice(1);\n logMessage(`command matched: %c${originalPhrase}`, debugStyle);\n if (parameters.length) {\n logMessage('with parameters', parameters);\n }\n currentCommand.callback(...parameters);\n invokeCallbacks(callbacks.get('resultMatch'), commandText, originalPhrase, recognitionResults);\n return;\n }\n }\n }\n invokeCallbacks(callbacks.get('resultNoMatch'), recognitionResults);\n};\n\n/**\n * Is SpeechRecognition supported in this environment?\n *\n * @returns {boolean} true if SpeechRecognition is supported by the browser\n */\nconst isSpeechRecognitionSupported = () => !!getSpeechRecognition();\n\nexport type CommandCallback = (...args: string[]) => void;\n\nexport interface CommandsList {\n [key: string]:\n | CommandCallback\n | {\n regexp: RegExp;\n callback: CommandCallback;\n };\n}\n\n/**\n * Add commands that annyang will respond to.\n * By default this will add to the existing commands. Pass `true` as the second parameter to remove all existing commands first.\n *\n * #### Examples:\n * ````javascript\n * const commands1 = {'hello :name': helloFunction, 'howdy': helloFunction};\n * const commands2 = {'hi': helloFunction};\n *\n * annyang.addCommands(commands1);\n * annyang.addCommands(commands2);\n * // annyang will now listen for all three commands defined in commands1 and commands2\n *\n * annyang.addCommands(commands2, true);\n * // annyang will now only listen for the command in commands2\n * ````\n *\n * @param {Object} commands - Commands that annyang should listen for\n * @param {boolean} [resetCommands=false] - Remove all existing commands before adding new commands? * @see [Commands Object](#commands-object)\n */\nconst addCommands = (commands: CommandsList, resetCommands = false) => {\n if (resetCommands) {\n commandsList.clear();\n }\n\n for (const phrase of Object.keys(commands)) {\n const cb = commands[phrase];\n\n if (typeof cb === 'function') {\n // convert command to regex then register the command\n registerCommand(commandToRegExp(phrase), cb, phrase);\n } else if (typeof cb === 'object' && cb.regexp instanceof RegExp) {\n // register the command\n registerCommand(new RegExp(cb.regexp.source, 'i'), cb.callback, phrase);\n } else {\n logMessage(`Can not register command: %c${phrase}`, debugStyle);\n }\n }\n};\n\n/**\n * Remove existing commands. Called with a single phrase, an array of phrases, or with no params to remove all commands.\n *\n * #### Examples:\n * ````javascript\n * const commands = {'hello': helloFunction, 'howdy': helloFunction, 'hi': helloFunction};\n *\n * // Remove all existing commands\n * annyang.removeCommands();\n *\n * // Add some commands\n * annyang.addCommands(commands);\n *\n * // Don't respond to hello\n * annyang.removeCommands('hello');\n *\n * // Don't respond to howdy or hi\n * annyang.removeCommands(['howdy', 'hi']);\n * ````\n * @param {string|string[]|undefined} [commandsToRemove] - Commands to remove\n */\nconst removeCommands = (commandsToRemove?: string | string[] | undefined) => {\n if (commandsToRemove === undefined) {\n commandsList.clear();\n } else {\n const commandsToRemoveArray = Array.isArray(commandsToRemove) ? commandsToRemove : [commandsToRemove];\n commandsToRemoveArray.forEach(command => commandsList.delete(command));\n }\n};\n\nexport interface StartOptions {\n autoRestart?: boolean;\n continuous?: boolean;\n paused?: boolean;\n}\n\n/**\n * Start listening.\n * It's a good idea to call this after adding some commands first (but not mandatory)\n *\n * Receives an optional options object which supports the following options:\n *\n * - `autoRestart` (boolean) Should annyang restart itself if it is closed indirectly (e.g. because of silence or window conflicts)?\n * - `continuous` (boolean) Allow forcing continuous mode on or off. annyang is pretty smart about this, so only set this if you know what you're doing.\n * - `paused` (boolean) Start annyang in paused mode.\n *\n * #### Examples:\n * ````javascript\n * // Start listening, don't restart automatically\n * annyang.start({ autoRestart: false });\n * // Start listening, don't restart automatically, stop recognition after first phrase recognized\n * annyang.start({ autoRestart: false, continuous: false });\n * ````\n * @param {Object} [options] - Optional options.\n */\nconst start = (options: StartOptions = {}) => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n pauseListening = !!options.paused;\n if (options.autoRestart !== undefined) {\n autoRestart = !!options.autoRestart;\n } else {\n autoRestart = true;\n }\n if (options.continuous !== undefined) {\n recognition.continuous = !!options.continuous;\n }\n\n lastStartedAt = new Date().getTime();\n try {\n recognition.start();\n } catch (e: unknown) {\n logMessage(e instanceof Error ? e.message : String(e));\n }\n};\n\n/**\n * Stop listening and turn off the mic.\n *\n * Alternatively, to only temporarily pause annyang responding to commands without stopping the SpeechRecognition engine or closing the mic, use pause() instead.\n * @see [pause()](#pause)\n */\nconst abort = () => {\n autoRestart = false;\n autoRestartCount = 0;\n if (isInitialized()) {\n recognition.abort();\n }\n};\n\n/**\n * Pause listening. annyang will stop responding to commands (until the resume or start methods are called), without turning off the browser's SpeechRecognition engine or the mic.\n *\n * Alternatively, to stop the SpeechRecognition engine and close the mic, use abort() instead.\n * @see [abort()](#abort)\n */\nconst pause = () => {\n pauseListening = true;\n};\n\n/**\n * Resumes listening and restore command callback execution when a command is matched.\n * If SpeechRecognition was aborted (stopped), start it.\n */\nconst resume = () => {\n start();\n};\n\n/**\n * Add a callback function to be called in case one of the following events happens:\n *\n * * `start` - Fired as soon as the browser's Speech Recognition engine starts listening.\n *\n * * `soundstart` - Fired as soon as any sound (possibly speech) has been detected.\n *\n * This will fire once per Speech Recognition starting. See https://is.gd/annyang_sound_start.\n *\n * * `error` - Fired when the browser's Speech Recognition engine returns an error, this generic error callback will be followed by more accurate error callbacks (both will fire if both are defined).\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorNetwork` - Fired when Speech Recognition fails because of a network error.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionBlocked` - Fired when the browser blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionDenied` - Fired when the user blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `end` - Fired when the browser's Speech Recognition engine stops.\n *\n * * `result` - Fired as soon as some speech was identified. This generic callback will be followed by either the `resultMatch` or `resultNoMatch` callbacks.\n *\n * The Callback functions for this event will be called with an array of possible phrases the user said as the first argument.\n *\n * * `resultMatch` - Fired when annyang was able to match between what the user said and a registered command.\n *\n * The Callback functions for this event will be called with three arguments in the following order:\n *\n * * The phrase the user said that matched a command.\n * * The command that was matched.\n * * An array of possible alternative phrases the user might have said.\n *\n * * `resultNoMatch` - Fired when what the user said didn't match any of the registered commands.\n *\n * Callback functions for this event will be called with an array of possible phrases the user might have said as the first argument.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('resultMatch', (userSaid, commandText, phrases) => {\n * console.log(userSaid); // sample output: 'hello'\n * console.log(commandText); // sample output: 'hello (there)'\n * console.log(phrases); // sample output: ['hello', 'halo', 'yellow', 'polo', 'hello kitty']\n * });\n *\n * // Returns an unsubscribe function\n * const unsubscribe = annyang.addCallback('error', () => {\n * console.log('There was an error!');\n * });\n * unsubscribe(); // removes the callback\n * ````\n * @param {string} type - Name of event that will trigger this callback\n * @param {function} callback - The function to call when event is triggered\n * @param {Object} [context] - Optional context for the callback function\n * @returns {function} A function that removes this callback when called\n */\nconst addCallback = <T extends CallbackType>(\n type: T,\n callback: CallbackMap[T],\n context: object | undefined = undefined\n): (() => void) => {\n const callbacksOfType = callbacks.get(type);\n if (typeof callback === 'function' && callbacksOfType) {\n const entry: StoredCallback = {\n callback: callback as AnyFunction,\n context,\n };\n callbacksOfType.push(entry);\n return () => {\n const arr = callbacks.get(type);\n if (arr) {\n const idx = arr.indexOf(entry);\n if (idx !== -1) arr.splice(idx, 1);\n }\n };\n }\n return () => {};\n};\n\n/**\n * Remove callbacks from events.\n *\n * - Pass an event name and a callback command to remove that callback command from that event type.\n * - Pass just an event name to remove all callback commands from that event type.\n * - Pass undefined as event name and a callback command to remove that callback command from all event types.\n * - Pass no params to remove all callback commands from all event types.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('start', myFunction1);\n * annyang.addCallback('start', myFunction2);\n * annyang.addCallback('end', myFunction1);\n * annyang.addCallback('end', myFunction2);\n *\n * // Remove all callbacks from all events:\n * annyang.removeCallback();\n *\n * // Remove all callbacks attached to end event:\n * annyang.removeCallback('end');\n *\n * // Remove myFunction2 from being called on start:\n * annyang.removeCallback('start', myFunction2);\n *\n * // Remove myFunction1 from being called on all events:\n * annyang.removeCallback(undefined, myFunction1);\n * ````\n *\n * @param type Name of event type to remove callback from\n * @param callback The callback function to remove\n * @returns undefined\n */\nconst removeCallback = (type?: CallbackType, callback?: CallbackMap[CallbackType]) => {\n callbacks.forEach((callbacksArray, callbackType) => {\n if (type === undefined || type === callbackType) {\n if (callback === undefined) {\n callbacks.get(callbackType)!.length = 0;\n } else {\n callbacks.set(\n callbackType,\n callbacksArray.filter(cb => cb.callback !== callback)\n );\n }\n }\n });\n};\n\n/**\n * Returns true if speech recognition is currently on.\n * Returns false if speech recognition is off or annyang is paused.\n *\n * @returns true if SpeechRecognition is on and annyang is not paused\n */\nconst isListening = () => {\n return listening && !pauseListening;\n};\n\nexport type AnnyangState = 'idle' | 'listening' | 'paused';\n\n/**\n * Returns the current state of annyang.\n *\n * @returns {'idle' | 'listening' | 'paused'} The current state\n */\nconst getState = (): AnnyangState => {\n if (!listening) return 'idle';\n if (pauseListening) return 'paused';\n return 'listening';\n};\n\n/**\n * Set the language the user will speak in. If this method is not called, annyang defaults to 'en-US'.\n *\n * @param {string} language - The language (locale)\n * @see [Languages](https://github.com/TalAter/annyang/blob/master/docs/FAQ.md#what-languages-are-supported)\n */\nconst setLanguage = (language: string): void => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n recognition.lang = language;\n};\n\n/**\n * Turn on the output of debug messages to the console.\n *\n * @param {boolean} [newState=true] - Turn debug messages on or off\n */\nconst debug = (newState: boolean = true): void => {\n debugState = !!newState;\n};\n\n/**\n * Match text against registered commands and fire the corresponding callbacks.\n * Works independently of the speech recognition engine — does not require `start()`, and works even in\n * environments where SpeechRecognition is not supported.\n *\n * Can accept either a string containing a single sentence or an array containing multiple sentences to be checked\n * in order until one of them matches a command (similar to the way Speech Recognition Alternatives are parsed)\n *\n * #### Examples:\n * ````javascript\n * annyang.trigger('Time for some thrilling heroics');\n * annyang.trigger(\n * ['Time for some thrilling heroics', 'Time for some thrilling aerobics']\n * );\n * ````\n *\n * @param sentences - A sentence as a string or an array of strings of possible sentences\n */\nconst trigger = (sentences: string | string[] = []) => {\n parseResults(Array.isArray(sentences) ? sentences : [sentences]);\n};\n\n/**\n * Returns the instance of the browser's SpeechRecognition object used by annyang.\n * Useful in case you want direct access to the browser's Speech Recognition engine.\n *\n * @returns SpeechRecognition The browser's Speech Recognizer instance currently used by annyang\n */\nconst getSpeechRecognizer = (): SpeechRecognition | undefined => {\n return recognition;\n};\n\n/**\n * @deprecated annyang no longer requires manual initialization. It initializes automatically on `start()` or `addCommands()`. Remove any calls to `init()`.\n */\nconst initDeprecated = () => {\n console.warn(\n 'annyang.init() is deprecated and no longer needed. ' +\n 'annyang initializes automatically on start() or addCommands(). Remove this call.'\n );\n};\n\nexport {\n abort,\n addCallback,\n addCommands,\n debug,\n getSpeechRecognizer,\n getState,\n initDeprecated as init,\n isListening,\n isSpeechRecognitionSupported,\n pause,\n removeCallback,\n removeCommands,\n resume,\n setLanguage,\n start,\n trigger,\n};\n\nconst annyang = {\n isSpeechRecognitionSupported,\n addCommands,\n removeCommands,\n start,\n abort,\n pause,\n resume,\n addCallback,\n removeCallback,\n isListening,\n setLanguage,\n trigger,\n debug,\n getSpeechRecognizer,\n getState,\n init: initDeprecated,\n get state() {\n return getState();\n },\n} as const;\n\nexport default annyang;\n"],"mappings":"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","names":[]}
|
package/dist/annyang.iife.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var annyang=(()=>{var R=Object.defineProperty;var
|
|
1
|
+
"use strict";var annyang=(()=>{var R=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var U=(e,t)=>{for(var n in t)R(e,n,{get:t[n],enumerable:!0})},q=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of W(t))!G.call(e,a)&&a!==n&&R(e,a,{get:()=>t[a],enumerable:!(o=B(t,a))||o.enumerable});return e};var H=e=>q(R({},"__esModule",{value:!0}),e);var oe={};U(oe,{abort:()=>L,addCallback:()=>$,addCommands:()=>M,debug:()=>j,default:()=>ne,getSpeechRecognizer:()=>z,getState:()=>E,init:()=>F,isListening:()=>D,isSpeechRecognitionSupported:()=>h,pause:()=>_,removeCallback:()=>P,removeCommands:()=>N,resume:()=>I,setLanguage:()=>O,start:()=>m,trigger:()=>V});var r,b=!1,u=!0,x=!1,p="font-weight: bold; color: #00f;",f=new Map,s=new Map([["start",[]],["error",[]],["end",[]],["soundstart",[]],["result",[]],["resultMatch",[]],["resultNoMatch",[]],["errorNetwork",[]],["errorPermissionBlocked",[]],["errorPermissionDenied",[]]]),k=0,y=0,g=!1,J=/\s*\((.*?)\)\s*/g,K=/(\(\?:[^)]+\))\?/g,Q=/(\(\?)?:\w+/g,X=/\*\w+/g,Y=/[{}[\]+?.\\^$|]/g,Z=e=>{let t=e.split(/([:*]\w+)/),n=t.length-1,o=t[n].replace(/[.!?]+$/,""),a=/\S/.test(o)&&(n===0||!o.trimEnd().endsWith(")"));a&&(t[n]=o);let l=t.map((i,S)=>S%2?i:i.replace(Y,"\\$&").replace(/([\p{L}\p{N}]),?(?=\s+[\p{L}\p{N}])/gu,"$1,?")).join("").replace(J,"(?:$1)?").replace(Q,(i,S)=>S?i:"([^\\s]+)").replace(X,"(.*?)").replace(K,"\\s*$1?\\s*");return new RegExp(`^${l}${a?"[.!?]*":""}$`,"iu")},C=()=>globalThis.SpeechRecognition||globalThis.webkitSpeechRecognition,A=()=>r!==void 0,d=(e,t)=>{x&&(e.indexOf("%c")===-1&&!t?console.log(e):console.log(e,t||p))},T=(e,t,n)=>{f.set(n,{command:e,callback:t}),d(`Command successfully loaded: %c${n}`,p)},c=(e=[],...t)=>{e.forEach(n=>{n.callback.apply(n.context,t)})},ee=()=>{C()&&(r&&r.abort&&r.abort(),r=new(C()),r.maxAlternatives=5,r.continuous=globalThis.location.protocol==="http:",r.lang="en-US",r.onstart=()=>{b=!0,c(s.get("start"))},r.onsoundstart=()=>{c(s.get("soundstart"))},r.onerror=e=>{switch(c(s.get("error"),e),e.error){case"network":c(s.get("errorNetwork"),e);break;case"not-allowed":case"service-not-allowed":u=!1,new Date().getTime()-k<200?c(s.get("errorPermissionBlocked"),e):c(s.get("errorPermissionDenied"),e);break;default:break}},r.onend=()=>{if(b=!1,c(s.get("end")),u){let e=new Date().getTime()-k;y+=1,y%10===0&&d("Speech Recognition is repeatedly stopping and starting. See http://is.gd/annyang_restarts for tips."),e<1e3?setTimeout(()=>{m({paused:g})},1e3-e):m({paused:g})}},r.onresult=e=>{if(g){d("Speech heard, but annyang is paused");return}let t=e.results[e.resultIndex],n=Array.from(t,o=>o.transcript);v(n)})},w=()=>{A()||ee()},v=e=>{c(s.get("result"),e);for(let t of e)d(`Speech recognized: %c${t.trim()}`,p);for(let t of e){let n=t.trim();for(let[o,a]of f){let l=a.command.exec(n);if(l){let i=l.slice(1);d(`command matched: %c${o}`,p),i.length&&d("with parameters",i),a.callback(...i),c(s.get("resultMatch"),n,o,e);return}}}c(s.get("resultNoMatch"),e)},h=()=>!!C(),M=(e,t=!1)=>{t&&f.clear();for(let n of Object.keys(e)){let o=e[n];typeof o=="function"?T(Z(n),o,n):typeof o=="object"&&o.regexp instanceof RegExp?T(new RegExp(o.regexp.source,"i"),o.callback,n):d(`Can not register command: %c${n}`,p)}},N=e=>{e===void 0?f.clear():(Array.isArray(e)?e:[e]).forEach(n=>f.delete(n))},m=(e={})=>{if(h()){w(),g=!!e.paused,e.autoRestart!==void 0?u=!!e.autoRestart:u=!0,e.continuous!==void 0&&(r.continuous=!!e.continuous),k=new Date().getTime();try{r.start()}catch(t){d(t instanceof Error?t.message:String(t))}}},L=()=>{u=!1,y=0,A()&&r.abort()},_=()=>{g=!0},I=()=>{m()},$=(e,t,n=void 0)=>{let o=s.get(e);if(typeof t=="function"&&o){let a={callback:t,context:n};return o.push(a),()=>{let l=s.get(e);if(l){let i=l.indexOf(a);i!==-1&&l.splice(i,1)}}}return()=>{}},P=(e,t)=>{s.forEach((n,o)=>{(e===void 0||e===o)&&(t===void 0?s.get(o).length=0:s.set(o,n.filter(a=>a.callback!==t)))})},D=()=>b&&!g,E=()=>b?g?"paused":"listening":"idle",O=e=>{h()&&(w(),r.lang=e)},j=(e=!0)=>{x=!!e},V=(e=[])=>{v(Array.isArray(e)?e:[e])},z=()=>r,F=()=>{console.warn("annyang.init() is deprecated and no longer needed. annyang initializes automatically on start() or addCommands(). Remove this call.")};var te={isSpeechRecognitionSupported:h,addCommands:M,removeCommands:N,start:m,abort:L,pause:_,resume:I,addCallback:$,removeCallback:P,isListening:D,setLanguage:O,trigger:V,debug:j,getSpeechRecognizer:z,getState:E,init:F,get state(){return E()}},ne=te;return H(oe);})();
|
package/dist/annyang.js
CHANGED
|
@@ -26,12 +26,19 @@ var optionalParam = /\s*\((.*?)\)\s*/g;
|
|
|
26
26
|
var optionalRegex = /(\(\?:[^)]+\))\?/g;
|
|
27
27
|
var namedParam = /(\(\?)?:\w+/g;
|
|
28
28
|
var splatParam = /\*\w+/g;
|
|
29
|
-
var escapeRegExp = /[
|
|
29
|
+
var escapeRegExp = /[{}[\]+?.\\^$|]/g;
|
|
30
30
|
var commandToRegExp = (command) => {
|
|
31
|
-
const
|
|
31
|
+
const parts = command.split(/([:*]\w+)/);
|
|
32
|
+
const last = parts.length - 1;
|
|
33
|
+
const ending = parts[last].replace(/[.!?]+$/, "");
|
|
34
|
+
const literalEnding = /\S/.test(ending) && (last === 0 || !ending.trimEnd().endsWith(")"));
|
|
35
|
+
if (literalEnding) parts[last] = ending;
|
|
36
|
+
const parsedCommand = parts.map(
|
|
37
|
+
(part, index) => index % 2 ? part : part.replace(escapeRegExp, "\\$&").replace(/([\p{L}\p{N}]),?(?=\s+[\p{L}\p{N}])/gu, "$1,?")
|
|
38
|
+
).join("").replace(optionalParam, "(?:$1)?").replace(namedParam, (match, optional) => {
|
|
32
39
|
return optional ? match : "([^\\s]+)";
|
|
33
40
|
}).replace(splatParam, "(.*?)").replace(optionalRegex, "\\s*$1?\\s*");
|
|
34
|
-
return new RegExp(`^${parsedCommand}$`, "
|
|
41
|
+
return new RegExp(`^${parsedCommand}${literalEnding ? "[.!?]*" : ""}$`, "iu");
|
|
35
42
|
};
|
|
36
43
|
var getSpeechRecognition = () => globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition;
|
|
37
44
|
var isInitialized = () => {
|
package/dist/annyang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/annyang.ts"],"sourcesContent":["const MIN_RESTART_INTERVAL_MS = 1000;\nconst RESTART_WARNING_INTERVAL = 10;\n\nlet recognition: SpeechRecognition;\nlet listening: boolean = false;\nlet autoRestart: boolean = true;\nlet debugState: boolean = false;\nconst debugStyle: string = 'font-weight: bold; color: #00f;';\n\nexport interface CallbackMap {\n start: () => void;\n end: () => void;\n soundstart: () => void;\n result: (phrases: string[]) => void;\n resultMatch: (userSaid: string, commandText: string, phrases: string[]) => void;\n resultNoMatch: (phrases: string[]) => void;\n error: (event: SpeechRecognitionErrorEvent) => void;\n errorNetwork: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionBlocked: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionDenied: (event: SpeechRecognitionErrorEvent) => void;\n}\n\nexport type CallbackType = keyof CallbackMap;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyFunction = (...args: any[]) => void;\n\ninterface StoredCallback {\n callback: AnyFunction;\n context: object | undefined;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst commandsList: Map<string, { command: RegExp; callback: (...args: any[]) => void }> = new Map();\nconst callbacks: Map<CallbackType, StoredCallback[]> = new Map([\n ['start', []],\n ['error', []],\n ['end', []],\n ['soundstart', []],\n ['result', []],\n ['resultMatch', []],\n ['resultNoMatch', []],\n ['errorNetwork', []],\n ['errorPermissionBlocked', []],\n ['errorPermissionDenied', []],\n]);\nlet lastStartedAt: number = 0;\nlet autoRestartCount: number = 0;\nlet pauseListening: boolean = false;\n\n// The command matching code is a modified version of Backbone.Router by Jeremy Ashkenas, under the MIT license.\nconst optionalParam = /\\s*\\((.*?)\\)\\s*/g;\nconst optionalRegex = /(\\(\\?:[^)]+\\))\\?/g;\nconst namedParam = /(\\(\\?)?:\\w+/g;\nconst splatParam = /\\*\\w+/g;\nconst escapeRegExp = /[-{}[\\]+?.,\\\\^$|#]/g;\nconst commandToRegExp = (command: string) => {\n const parsedCommand = command\n .replace(escapeRegExp, '\\\\$&')\n .replace(optionalParam, '(?:$1)?')\n .replace(namedParam, (match, optional) => {\n return optional ? match : '([^\\\\s]+)';\n })\n .replace(splatParam, '(.*?)')\n .replace(optionalRegex, '\\\\s*$1?\\\\s*');\n return new RegExp(`^${parsedCommand}$`, 'i');\n};\n\n// Get the SpeechRecognition object, accounting for possible browser prefixes\nconst getSpeechRecognition = () => globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition;\n\n// Check if annyang is already initialized\nconst isInitialized = () => {\n return recognition !== undefined;\n};\n\n// Method for logging to the console when debug mode is on\nconst logMessage = (text: string, extraParameters?: string | string[]) => {\n if (debugState) {\n if (text.indexOf('%c') === -1 && !extraParameters) {\n console.log(text);\n } else {\n console.log(text, extraParameters || debugStyle);\n }\n }\n};\n\n// Add a command to the commands list\nconst registerCommand = (command: RegExp, callback: AnyFunction, originalPhrase: string) => {\n commandsList.set(originalPhrase, { command, callback });\n logMessage(`Command successfully loaded: %c${originalPhrase}`, debugStyle);\n};\n\n// This method receives an array of callbacks and invokes each of them\nconst invokeCallbacks = (callbacksArr: StoredCallback[] = [], ...args: unknown[]) => {\n callbacksArr.forEach(cb => {\n cb.callback.apply(cb.context, args);\n });\n};\n\n// Initialize annyang\nconst init = () => {\n if (!getSpeechRecognition()) {\n return;\n }\n\n // Abort previous instances of recognition already running\n if (recognition && recognition.abort) {\n recognition.abort();\n }\n\n // initiate SpeechRecognition\n recognition = new (getSpeechRecognition())();\n\n // Set the max number of alternative transcripts to try and match with a command\n recognition.maxAlternatives = 5;\n\n // In HTTPS, turn off continuous mode for faster results.\n // In HTTP, turn on continuous mode for much slower results, but no repeating security notices\n recognition.continuous = globalThis.location.protocol === 'http:';\n\n // Sets the language to the default 'en-US'. This can be changed with annyang.setLanguage()\n recognition.lang = 'en-US';\n\n recognition.onstart = () => {\n listening = true;\n invokeCallbacks(callbacks.get('start'));\n };\n\n recognition.onsoundstart = () => {\n invokeCallbacks(callbacks.get('soundstart'));\n };\n\n recognition.onerror = event => {\n invokeCallbacks(callbacks.get('error'), event);\n switch (event.error) {\n case 'network':\n invokeCallbacks(callbacks.get('errorNetwork'), event);\n break;\n case 'not-allowed':\n case 'service-not-allowed':\n // if permission to use the mic is denied, turn off auto-restart\n autoRestart = false;\n // determine if permission was denied by user or automatically.\n if (new Date().getTime() - lastStartedAt < 200) {\n invokeCallbacks(callbacks.get('errorPermissionBlocked'), event);\n } else {\n invokeCallbacks(callbacks.get('errorPermissionDenied'), event);\n }\n break;\n default:\n break;\n }\n };\n\n recognition.onend = () => {\n listening = false;\n invokeCallbacks(callbacks.get('end'));\n // annyang will auto restart if it is closed automatically and not by user action.\n if (autoRestart) {\n // play nicely with the browser, and never restart annyang automatically more than once per second\n const timeSinceLastStart = new Date().getTime() - lastStartedAt;\n autoRestartCount += 1;\n if (autoRestartCount % RESTART_WARNING_INTERVAL === 0) {\n logMessage(\n 'Speech Recognition is repeatedly stopping and starting. See http://is.gd/annyang_restarts for tips.'\n );\n }\n if (timeSinceLastStart < MIN_RESTART_INTERVAL_MS) {\n setTimeout(() => {\n start({ paused: pauseListening });\n }, MIN_RESTART_INTERVAL_MS - timeSinceLastStart);\n } else {\n start({ paused: pauseListening });\n }\n }\n };\n\n recognition.onresult = (event: SpeechRecognitionEvent) => {\n if (pauseListening) {\n logMessage('Speech heard, but annyang is paused');\n return;\n }\n\n // Map the results to an array\n const SpeechRecognitionResults = event.results[event.resultIndex];\n const results = Array.from(SpeechRecognitionResults, result => result.transcript);\n parseResults(results);\n };\n};\n\n// If annyang isn't initialized, initialize it\nconst initIfNeeded = () => {\n if (!isInitialized()) {\n init();\n }\n};\n\nconst parseResults = (recognitionResults: string[]) => {\n invokeCallbacks(callbacks.get('result'), recognitionResults);\n\n // Log all recognition alternatives for debugging, regardless of match\n for (const rawText of recognitionResults) {\n logMessage(`Speech recognized: %c${rawText.trim()}`, debugStyle);\n }\n\n // Try to match each alternative to a command\n for (const rawText of recognitionResults) {\n const commandText = rawText.trim();\n for (const [originalPhrase, currentCommand] of commandsList) {\n const matchedCommand = currentCommand.command.exec(commandText);\n if (matchedCommand) {\n const parameters = matchedCommand.slice(1);\n logMessage(`command matched: %c${originalPhrase}`, debugStyle);\n if (parameters.length) {\n logMessage('with parameters', parameters);\n }\n currentCommand.callback(...parameters);\n invokeCallbacks(callbacks.get('resultMatch'), commandText, originalPhrase, recognitionResults);\n return;\n }\n }\n }\n invokeCallbacks(callbacks.get('resultNoMatch'), recognitionResults);\n};\n\n/**\n * Is SpeechRecognition supported in this environment?\n *\n * @returns {boolean} true if SpeechRecognition is supported by the browser\n */\nconst isSpeechRecognitionSupported = () => !!getSpeechRecognition();\n\nexport type CommandCallback = (...args: string[]) => void;\n\nexport interface CommandsList {\n [key: string]:\n | CommandCallback\n | {\n regexp: RegExp;\n callback: CommandCallback;\n };\n}\n\n/**\n * Add commands that annyang will respond to.\n * By default this will add to the existing commands. Pass `true` as the second parameter to remove all existing commands first.\n *\n * #### Examples:\n * ````javascript\n * const commands1 = {'hello :name': helloFunction, 'howdy': helloFunction};\n * const commands2 = {'hi': helloFunction};\n *\n * annyang.addCommands(commands1);\n * annyang.addCommands(commands2);\n * // annyang will now listen for all three commands defined in commands1 and commands2\n *\n * annyang.addCommands(commands2, true);\n * // annyang will now only listen for the command in commands2\n * ````\n *\n * @param {Object} commands - Commands that annyang should listen for\n * @param {boolean} [resetCommands=false] - Remove all existing commands before adding new commands? * @see [Commands Object](#commands-object)\n */\nconst addCommands = (commands: CommandsList, resetCommands = false) => {\n if (resetCommands) {\n commandsList.clear();\n }\n\n for (const phrase of Object.keys(commands)) {\n const cb = commands[phrase];\n\n if (typeof cb === 'function') {\n // convert command to regex then register the command\n registerCommand(commandToRegExp(phrase), cb, phrase);\n } else if (typeof cb === 'object' && cb.regexp instanceof RegExp) {\n // register the command\n registerCommand(new RegExp(cb.regexp.source, 'i'), cb.callback, phrase);\n } else {\n logMessage(`Can not register command: %c${phrase}`, debugStyle);\n }\n }\n};\n\n/**\n * Remove existing commands. Called with a single phrase, an array of phrases, or with no params to remove all commands.\n *\n * #### Examples:\n * ````javascript\n * const commands = {'hello': helloFunction, 'howdy': helloFunction, 'hi': helloFunction};\n *\n * // Remove all existing commands\n * annyang.removeCommands();\n *\n * // Add some commands\n * annyang.addCommands(commands);\n *\n * // Don't respond to hello\n * annyang.removeCommands('hello');\n *\n * // Don't respond to howdy or hi\n * annyang.removeCommands(['howdy', 'hi']);\n * ````\n * @param {string|string[]|undefined} [commandsToRemove] - Commands to remove\n */\nconst removeCommands = (commandsToRemove?: string | string[] | undefined) => {\n if (commandsToRemove === undefined) {\n commandsList.clear();\n } else {\n const commandsToRemoveArray = Array.isArray(commandsToRemove) ? commandsToRemove : [commandsToRemove];\n commandsToRemoveArray.forEach(command => commandsList.delete(command));\n }\n};\n\nexport interface StartOptions {\n autoRestart?: boolean;\n continuous?: boolean;\n paused?: boolean;\n}\n\n/**\n * Start listening.\n * It's a good idea to call this after adding some commands first (but not mandatory)\n *\n * Receives an optional options object which supports the following options:\n *\n * - `autoRestart` (boolean) Should annyang restart itself if it is closed indirectly (e.g. because of silence or window conflicts)?\n * - `continuous` (boolean) Allow forcing continuous mode on or off. annyang is pretty smart about this, so only set this if you know what you're doing.\n * - `paused` (boolean) Start annyang in paused mode.\n *\n * #### Examples:\n * ````javascript\n * // Start listening, don't restart automatically\n * annyang.start({ autoRestart: false });\n * // Start listening, don't restart automatically, stop recognition after first phrase recognized\n * annyang.start({ autoRestart: false, continuous: false });\n * ````\n * @param {Object} [options] - Optional options.\n */\nconst start = (options: StartOptions = {}) => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n pauseListening = !!options.paused;\n if (options.autoRestart !== undefined) {\n autoRestart = !!options.autoRestart;\n } else {\n autoRestart = true;\n }\n if (options.continuous !== undefined) {\n recognition.continuous = !!options.continuous;\n }\n\n lastStartedAt = new Date().getTime();\n try {\n recognition.start();\n } catch (e: unknown) {\n logMessage(e instanceof Error ? e.message : String(e));\n }\n};\n\n/**\n * Stop listening and turn off the mic.\n *\n * Alternatively, to only temporarily pause annyang responding to commands without stopping the SpeechRecognition engine or closing the mic, use pause() instead.\n * @see [pause()](#pause)\n */\nconst abort = () => {\n autoRestart = false;\n autoRestartCount = 0;\n if (isInitialized()) {\n recognition.abort();\n }\n};\n\n/**\n * Pause listening. annyang will stop responding to commands (until the resume or start methods are called), without turning off the browser's SpeechRecognition engine or the mic.\n *\n * Alternatively, to stop the SpeechRecognition engine and close the mic, use abort() instead.\n * @see [abort()](#abort)\n */\nconst pause = () => {\n pauseListening = true;\n};\n\n/**\n * Resumes listening and restore command callback execution when a command is matched.\n * If SpeechRecognition was aborted (stopped), start it.\n */\nconst resume = () => {\n start();\n};\n\n/**\n * Add a callback function to be called in case one of the following events happens:\n *\n * * `start` - Fired as soon as the browser's Speech Recognition engine starts listening.\n *\n * * `soundstart` - Fired as soon as any sound (possibly speech) has been detected.\n *\n * This will fire once per Speech Recognition starting. See https://is.gd/annyang_sound_start.\n *\n * * `error` - Fired when the browser's Speech Recognition engine returns an error, this generic error callback will be followed by more accurate error callbacks (both will fire if both are defined).\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorNetwork` - Fired when Speech Recognition fails because of a network error.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionBlocked` - Fired when the browser blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionDenied` - Fired when the user blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `end` - Fired when the browser's Speech Recognition engine stops.\n *\n * * `result` - Fired as soon as some speech was identified. This generic callback will be followed by either the `resultMatch` or `resultNoMatch` callbacks.\n *\n * The Callback functions for this event will be called with an array of possible phrases the user said as the first argument.\n *\n * * `resultMatch` - Fired when annyang was able to match between what the user said and a registered command.\n *\n * The Callback functions for this event will be called with three arguments in the following order:\n *\n * * The phrase the user said that matched a command.\n * * The command that was matched.\n * * An array of possible alternative phrases the user might have said.\n *\n * * `resultNoMatch` - Fired when what the user said didn't match any of the registered commands.\n *\n * Callback functions for this event will be called with an array of possible phrases the user might have said as the first argument.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('resultMatch', (userSaid, commandText, phrases) => {\n * console.log(userSaid); // sample output: 'hello'\n * console.log(commandText); // sample output: 'hello (there)'\n * console.log(phrases); // sample output: ['hello', 'halo', 'yellow', 'polo', 'hello kitty']\n * });\n *\n * // Returns an unsubscribe function\n * const unsubscribe = annyang.addCallback('error', () => {\n * console.log('There was an error!');\n * });\n * unsubscribe(); // removes the callback\n * ````\n * @param {string} type - Name of event that will trigger this callback\n * @param {function} callback - The function to call when event is triggered\n * @param {Object} [context] - Optional context for the callback function\n * @returns {function} A function that removes this callback when called\n */\nconst addCallback = <T extends CallbackType>(\n type: T,\n callback: CallbackMap[T],\n context: object | undefined = undefined\n): (() => void) => {\n const callbacksOfType = callbacks.get(type);\n if (typeof callback === 'function' && callbacksOfType) {\n const entry: StoredCallback = {\n callback: callback as AnyFunction,\n context,\n };\n callbacksOfType.push(entry);\n return () => {\n const arr = callbacks.get(type);\n if (arr) {\n const idx = arr.indexOf(entry);\n if (idx !== -1) arr.splice(idx, 1);\n }\n };\n }\n return () => {};\n};\n\n/**\n * Remove callbacks from events.\n *\n * - Pass an event name and a callback command to remove that callback command from that event type.\n * - Pass just an event name to remove all callback commands from that event type.\n * - Pass undefined as event name and a callback command to remove that callback command from all event types.\n * - Pass no params to remove all callback commands from all event types.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('start', myFunction1);\n * annyang.addCallback('start', myFunction2);\n * annyang.addCallback('end', myFunction1);\n * annyang.addCallback('end', myFunction2);\n *\n * // Remove all callbacks from all events:\n * annyang.removeCallback();\n *\n * // Remove all callbacks attached to end event:\n * annyang.removeCallback('end');\n *\n * // Remove myFunction2 from being called on start:\n * annyang.removeCallback('start', myFunction2);\n *\n * // Remove myFunction1 from being called on all events:\n * annyang.removeCallback(undefined, myFunction1);\n * ````\n *\n * @param type Name of event type to remove callback from\n * @param callback The callback function to remove\n * @returns undefined\n */\nconst removeCallback = (type?: CallbackType, callback?: CallbackMap[CallbackType]) => {\n callbacks.forEach((callbacksArray, callbackType) => {\n if (type === undefined || type === callbackType) {\n if (callback === undefined) {\n callbacks.get(callbackType)!.length = 0;\n } else {\n callbacks.set(\n callbackType,\n callbacksArray.filter(cb => cb.callback !== callback)\n );\n }\n }\n });\n};\n\n/**\n * Returns true if speech recognition is currently on.\n * Returns false if speech recognition is off or annyang is paused.\n *\n * @returns true if SpeechRecognition is on and annyang is not paused\n */\nconst isListening = () => {\n return listening && !pauseListening;\n};\n\nexport type AnnyangState = 'idle' | 'listening' | 'paused';\n\n/**\n * Returns the current state of annyang.\n *\n * @returns {'idle' | 'listening' | 'paused'} The current state\n */\nconst getState = (): AnnyangState => {\n if (!listening) return 'idle';\n if (pauseListening) return 'paused';\n return 'listening';\n};\n\n/**\n * Set the language the user will speak in. If this method is not called, annyang defaults to 'en-US'.\n *\n * @param {string} language - The language (locale)\n * @see [Languages](https://github.com/TalAter/annyang/blob/master/docs/FAQ.md#what-languages-are-supported)\n */\nconst setLanguage = (language: string): void => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n recognition.lang = language;\n};\n\n/**\n * Turn on the output of debug messages to the console.\n *\n * @param {boolean} [newState=true] - Turn debug messages on or off\n */\nconst debug = (newState: boolean = true): void => {\n debugState = !!newState;\n};\n\n/**\n * Match text against registered commands and fire the corresponding callbacks.\n * Works independently of the speech recognition engine — does not require `start()`, and works even in\n * environments where SpeechRecognition is not supported.\n *\n * Can accept either a string containing a single sentence or an array containing multiple sentences to be checked\n * in order until one of them matches a command (similar to the way Speech Recognition Alternatives are parsed)\n *\n * #### Examples:\n * ````javascript\n * annyang.trigger('Time for some thrilling heroics');\n * annyang.trigger(\n * ['Time for some thrilling heroics', 'Time for some thrilling aerobics']\n * );\n * ````\n *\n * @param sentences - A sentence as a string or an array of strings of possible sentences\n */\nconst trigger = (sentences: string | string[] = []) => {\n parseResults(Array.isArray(sentences) ? sentences : [sentences]);\n};\n\n/**\n * Returns the instance of the browser's SpeechRecognition object used by annyang.\n * Useful in case you want direct access to the browser's Speech Recognition engine.\n *\n * @returns SpeechRecognition The browser's Speech Recognizer instance currently used by annyang\n */\nconst getSpeechRecognizer = (): SpeechRecognition | undefined => {\n return recognition;\n};\n\n/**\n * @deprecated annyang no longer requires manual initialization. It initializes automatically on `start()` or `addCommands()`. Remove any calls to `init()`.\n */\nconst initDeprecated = () => {\n console.warn(\n 'annyang.init() is deprecated and no longer needed. ' +\n 'annyang initializes automatically on start() or addCommands(). Remove this call.'\n );\n};\n\nexport {\n abort,\n addCallback,\n addCommands,\n debug,\n getSpeechRecognizer,\n getState,\n initDeprecated as init,\n isListening,\n isSpeechRecognitionSupported,\n pause,\n removeCallback,\n removeCommands,\n resume,\n setLanguage,\n start,\n trigger,\n};\n\nconst annyang = {\n isSpeechRecognitionSupported,\n addCommands,\n removeCommands,\n start,\n abort,\n pause,\n resume,\n addCallback,\n removeCallback,\n isListening,\n setLanguage,\n trigger,\n debug,\n getSpeechRecognizer,\n getState,\n init: initDeprecated,\n get state() {\n return getState();\n },\n} as const;\n\nexport default annyang;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/annyang.ts"],"sourcesContent":["const MIN_RESTART_INTERVAL_MS = 1000;\nconst RESTART_WARNING_INTERVAL = 10;\n\nlet recognition: SpeechRecognition;\nlet listening: boolean = false;\nlet autoRestart: boolean = true;\nlet debugState: boolean = false;\nconst debugStyle: string = 'font-weight: bold; color: #00f;';\n\nexport interface CallbackMap {\n start: () => void;\n end: () => void;\n soundstart: () => void;\n result: (phrases: string[]) => void;\n resultMatch: (userSaid: string, commandText: string, phrases: string[]) => void;\n resultNoMatch: (phrases: string[]) => void;\n error: (event: SpeechRecognitionErrorEvent) => void;\n errorNetwork: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionBlocked: (event: SpeechRecognitionErrorEvent) => void;\n errorPermissionDenied: (event: SpeechRecognitionErrorEvent) => void;\n}\n\nexport type CallbackType = keyof CallbackMap;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyFunction = (...args: any[]) => void;\n\ninterface StoredCallback {\n callback: AnyFunction;\n context: object | undefined;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst commandsList: Map<string, { command: RegExp; callback: (...args: any[]) => void }> = new Map();\nconst callbacks: Map<CallbackType, StoredCallback[]> = new Map([\n ['start', []],\n ['error', []],\n ['end', []],\n ['soundstart', []],\n ['result', []],\n ['resultMatch', []],\n ['resultNoMatch', []],\n ['errorNetwork', []],\n ['errorPermissionBlocked', []],\n ['errorPermissionDenied', []],\n]);\nlet lastStartedAt: number = 0;\nlet autoRestartCount: number = 0;\nlet pauseListening: boolean = false;\n\n// The command matching code is a modified version of Backbone.Router by Jeremy Ashkenas, under the MIT license.\nconst optionalParam = /\\s*\\((.*?)\\)\\s*/g;\nconst optionalRegex = /(\\(\\?:[^)]+\\))\\?/g;\nconst namedParam = /(\\(\\?)?:\\w+/g;\nconst splatParam = /\\*\\w+/g;\nconst escapeRegExp = /[{}[\\]+?.\\\\^$|]/g;\nconst commandToRegExp = (command: string) => {\n const parts = command.split(/([:*]\\w+)/);\n const last = parts.length - 1;\n const ending = parts[last].replace(/[.!?]+$/, '');\n // Only relax sentence endings after literal text, never after a captured value\n // or an optional suffix that could disappear and expose a capture.\n const literalEnding = /\\S/.test(ending) && (last === 0 || !ending.trimEnd().endsWith(')'));\n if (literalEnding) parts[last] = ending;\n const parsedCommand = parts\n .map((part, index) =>\n index % 2 ? part : part.replace(escapeRegExp, '\\\\$&').replace(/([\\p{L}\\p{N}]),?(?=\\s+[\\p{L}\\p{N}])/gu, '$1,?')\n )\n .join('')\n .replace(optionalParam, '(?:$1)?')\n .replace(namedParam, (match, optional) => {\n return optional ? match : '([^\\\\s]+)';\n })\n .replace(splatParam, '(.*?)')\n .replace(optionalRegex, '\\\\s*$1?\\\\s*');\n return new RegExp(`^${parsedCommand}${literalEnding ? '[.!?]*' : ''}$`, 'iu');\n};\n\n// Get the SpeechRecognition object, accounting for possible browser prefixes\nconst getSpeechRecognition = () => globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition;\n\n// Check if annyang is already initialized\nconst isInitialized = () => {\n return recognition !== undefined;\n};\n\n// Method for logging to the console when debug mode is on\nconst logMessage = (text: string, extraParameters?: string | string[]) => {\n if (debugState) {\n if (text.indexOf('%c') === -1 && !extraParameters) {\n console.log(text);\n } else {\n console.log(text, extraParameters || debugStyle);\n }\n }\n};\n\n// Add a command to the commands list\nconst registerCommand = (command: RegExp, callback: AnyFunction, originalPhrase: string) => {\n commandsList.set(originalPhrase, { command, callback });\n logMessage(`Command successfully loaded: %c${originalPhrase}`, debugStyle);\n};\n\n// This method receives an array of callbacks and invokes each of them\nconst invokeCallbacks = (callbacksArr: StoredCallback[] = [], ...args: unknown[]) => {\n callbacksArr.forEach(cb => {\n cb.callback.apply(cb.context, args);\n });\n};\n\n// Initialize annyang\nconst init = () => {\n if (!getSpeechRecognition()) {\n return;\n }\n\n // Abort previous instances of recognition already running\n if (recognition && recognition.abort) {\n recognition.abort();\n }\n\n // initiate SpeechRecognition\n recognition = new (getSpeechRecognition())();\n\n // Set the max number of alternative transcripts to try and match with a command\n recognition.maxAlternatives = 5;\n\n // In HTTPS, turn off continuous mode for faster results.\n // In HTTP, turn on continuous mode for much slower results, but no repeating security notices\n recognition.continuous = globalThis.location.protocol === 'http:';\n\n // Sets the language to the default 'en-US'. This can be changed with annyang.setLanguage()\n recognition.lang = 'en-US';\n\n recognition.onstart = () => {\n listening = true;\n invokeCallbacks(callbacks.get('start'));\n };\n\n recognition.onsoundstart = () => {\n invokeCallbacks(callbacks.get('soundstart'));\n };\n\n recognition.onerror = event => {\n invokeCallbacks(callbacks.get('error'), event);\n switch (event.error) {\n case 'network':\n invokeCallbacks(callbacks.get('errorNetwork'), event);\n break;\n case 'not-allowed':\n case 'service-not-allowed':\n // if permission to use the mic is denied, turn off auto-restart\n autoRestart = false;\n // determine if permission was denied by user or automatically.\n if (new Date().getTime() - lastStartedAt < 200) {\n invokeCallbacks(callbacks.get('errorPermissionBlocked'), event);\n } else {\n invokeCallbacks(callbacks.get('errorPermissionDenied'), event);\n }\n break;\n default:\n break;\n }\n };\n\n recognition.onend = () => {\n listening = false;\n invokeCallbacks(callbacks.get('end'));\n // annyang will auto restart if it is closed automatically and not by user action.\n if (autoRestart) {\n // play nicely with the browser, and never restart annyang automatically more than once per second\n const timeSinceLastStart = new Date().getTime() - lastStartedAt;\n autoRestartCount += 1;\n if (autoRestartCount % RESTART_WARNING_INTERVAL === 0) {\n logMessage(\n 'Speech Recognition is repeatedly stopping and starting. See http://is.gd/annyang_restarts for tips.'\n );\n }\n if (timeSinceLastStart < MIN_RESTART_INTERVAL_MS) {\n setTimeout(() => {\n start({ paused: pauseListening });\n }, MIN_RESTART_INTERVAL_MS - timeSinceLastStart);\n } else {\n start({ paused: pauseListening });\n }\n }\n };\n\n recognition.onresult = (event: SpeechRecognitionEvent) => {\n if (pauseListening) {\n logMessage('Speech heard, but annyang is paused');\n return;\n }\n\n // Map the results to an array\n const SpeechRecognitionResults = event.results[event.resultIndex];\n const results = Array.from(SpeechRecognitionResults, result => result.transcript);\n parseResults(results);\n };\n};\n\n// If annyang isn't initialized, initialize it\nconst initIfNeeded = () => {\n if (!isInitialized()) {\n init();\n }\n};\n\nconst parseResults = (recognitionResults: string[]) => {\n invokeCallbacks(callbacks.get('result'), recognitionResults);\n\n // Log all recognition alternatives for debugging, regardless of match\n for (const rawText of recognitionResults) {\n logMessage(`Speech recognized: %c${rawText.trim()}`, debugStyle);\n }\n\n // Try to match each alternative to a command\n for (const rawText of recognitionResults) {\n const commandText = rawText.trim();\n for (const [originalPhrase, currentCommand] of commandsList) {\n const matchedCommand = currentCommand.command.exec(commandText);\n if (matchedCommand) {\n const parameters = matchedCommand.slice(1);\n logMessage(`command matched: %c${originalPhrase}`, debugStyle);\n if (parameters.length) {\n logMessage('with parameters', parameters);\n }\n currentCommand.callback(...parameters);\n invokeCallbacks(callbacks.get('resultMatch'), commandText, originalPhrase, recognitionResults);\n return;\n }\n }\n }\n invokeCallbacks(callbacks.get('resultNoMatch'), recognitionResults);\n};\n\n/**\n * Is SpeechRecognition supported in this environment?\n *\n * @returns {boolean} true if SpeechRecognition is supported by the browser\n */\nconst isSpeechRecognitionSupported = () => !!getSpeechRecognition();\n\nexport type CommandCallback = (...args: string[]) => void;\n\nexport interface CommandsList {\n [key: string]:\n | CommandCallback\n | {\n regexp: RegExp;\n callback: CommandCallback;\n };\n}\n\n/**\n * Add commands that annyang will respond to.\n * By default this will add to the existing commands. Pass `true` as the second parameter to remove all existing commands first.\n *\n * #### Examples:\n * ````javascript\n * const commands1 = {'hello :name': helloFunction, 'howdy': helloFunction};\n * const commands2 = {'hi': helloFunction};\n *\n * annyang.addCommands(commands1);\n * annyang.addCommands(commands2);\n * // annyang will now listen for all three commands defined in commands1 and commands2\n *\n * annyang.addCommands(commands2, true);\n * // annyang will now only listen for the command in commands2\n * ````\n *\n * @param {Object} commands - Commands that annyang should listen for\n * @param {boolean} [resetCommands=false] - Remove all existing commands before adding new commands? * @see [Commands Object](#commands-object)\n */\nconst addCommands = (commands: CommandsList, resetCommands = false) => {\n if (resetCommands) {\n commandsList.clear();\n }\n\n for (const phrase of Object.keys(commands)) {\n const cb = commands[phrase];\n\n if (typeof cb === 'function') {\n // convert command to regex then register the command\n registerCommand(commandToRegExp(phrase), cb, phrase);\n } else if (typeof cb === 'object' && cb.regexp instanceof RegExp) {\n // register the command\n registerCommand(new RegExp(cb.regexp.source, 'i'), cb.callback, phrase);\n } else {\n logMessage(`Can not register command: %c${phrase}`, debugStyle);\n }\n }\n};\n\n/**\n * Remove existing commands. Called with a single phrase, an array of phrases, or with no params to remove all commands.\n *\n * #### Examples:\n * ````javascript\n * const commands = {'hello': helloFunction, 'howdy': helloFunction, 'hi': helloFunction};\n *\n * // Remove all existing commands\n * annyang.removeCommands();\n *\n * // Add some commands\n * annyang.addCommands(commands);\n *\n * // Don't respond to hello\n * annyang.removeCommands('hello');\n *\n * // Don't respond to howdy or hi\n * annyang.removeCommands(['howdy', 'hi']);\n * ````\n * @param {string|string[]|undefined} [commandsToRemove] - Commands to remove\n */\nconst removeCommands = (commandsToRemove?: string | string[] | undefined) => {\n if (commandsToRemove === undefined) {\n commandsList.clear();\n } else {\n const commandsToRemoveArray = Array.isArray(commandsToRemove) ? commandsToRemove : [commandsToRemove];\n commandsToRemoveArray.forEach(command => commandsList.delete(command));\n }\n};\n\nexport interface StartOptions {\n autoRestart?: boolean;\n continuous?: boolean;\n paused?: boolean;\n}\n\n/**\n * Start listening.\n * It's a good idea to call this after adding some commands first (but not mandatory)\n *\n * Receives an optional options object which supports the following options:\n *\n * - `autoRestart` (boolean) Should annyang restart itself if it is closed indirectly (e.g. because of silence or window conflicts)?\n * - `continuous` (boolean) Allow forcing continuous mode on or off. annyang is pretty smart about this, so only set this if you know what you're doing.\n * - `paused` (boolean) Start annyang in paused mode.\n *\n * #### Examples:\n * ````javascript\n * // Start listening, don't restart automatically\n * annyang.start({ autoRestart: false });\n * // Start listening, don't restart automatically, stop recognition after first phrase recognized\n * annyang.start({ autoRestart: false, continuous: false });\n * ````\n * @param {Object} [options] - Optional options.\n */\nconst start = (options: StartOptions = {}) => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n pauseListening = !!options.paused;\n if (options.autoRestart !== undefined) {\n autoRestart = !!options.autoRestart;\n } else {\n autoRestart = true;\n }\n if (options.continuous !== undefined) {\n recognition.continuous = !!options.continuous;\n }\n\n lastStartedAt = new Date().getTime();\n try {\n recognition.start();\n } catch (e: unknown) {\n logMessage(e instanceof Error ? e.message : String(e));\n }\n};\n\n/**\n * Stop listening and turn off the mic.\n *\n * Alternatively, to only temporarily pause annyang responding to commands without stopping the SpeechRecognition engine or closing the mic, use pause() instead.\n * @see [pause()](#pause)\n */\nconst abort = () => {\n autoRestart = false;\n autoRestartCount = 0;\n if (isInitialized()) {\n recognition.abort();\n }\n};\n\n/**\n * Pause listening. annyang will stop responding to commands (until the resume or start methods are called), without turning off the browser's SpeechRecognition engine or the mic.\n *\n * Alternatively, to stop the SpeechRecognition engine and close the mic, use abort() instead.\n * @see [abort()](#abort)\n */\nconst pause = () => {\n pauseListening = true;\n};\n\n/**\n * Resumes listening and restore command callback execution when a command is matched.\n * If SpeechRecognition was aborted (stopped), start it.\n */\nconst resume = () => {\n start();\n};\n\n/**\n * Add a callback function to be called in case one of the following events happens:\n *\n * * `start` - Fired as soon as the browser's Speech Recognition engine starts listening.\n *\n * * `soundstart` - Fired as soon as any sound (possibly speech) has been detected.\n *\n * This will fire once per Speech Recognition starting. See https://is.gd/annyang_sound_start.\n *\n * * `error` - Fired when the browser's Speech Recognition engine returns an error, this generic error callback will be followed by more accurate error callbacks (both will fire if both are defined).\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorNetwork` - Fired when Speech Recognition fails because of a network error.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionBlocked` - Fired when the browser blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `errorPermissionDenied` - Fired when the user blocks the permission request to use Speech Recognition.\n *\n * The Callback function will be called with the error event as the first argument.\n *\n * * `end` - Fired when the browser's Speech Recognition engine stops.\n *\n * * `result` - Fired as soon as some speech was identified. This generic callback will be followed by either the `resultMatch` or `resultNoMatch` callbacks.\n *\n * The Callback functions for this event will be called with an array of possible phrases the user said as the first argument.\n *\n * * `resultMatch` - Fired when annyang was able to match between what the user said and a registered command.\n *\n * The Callback functions for this event will be called with three arguments in the following order:\n *\n * * The phrase the user said that matched a command.\n * * The command that was matched.\n * * An array of possible alternative phrases the user might have said.\n *\n * * `resultNoMatch` - Fired when what the user said didn't match any of the registered commands.\n *\n * Callback functions for this event will be called with an array of possible phrases the user might have said as the first argument.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('resultMatch', (userSaid, commandText, phrases) => {\n * console.log(userSaid); // sample output: 'hello'\n * console.log(commandText); // sample output: 'hello (there)'\n * console.log(phrases); // sample output: ['hello', 'halo', 'yellow', 'polo', 'hello kitty']\n * });\n *\n * // Returns an unsubscribe function\n * const unsubscribe = annyang.addCallback('error', () => {\n * console.log('There was an error!');\n * });\n * unsubscribe(); // removes the callback\n * ````\n * @param {string} type - Name of event that will trigger this callback\n * @param {function} callback - The function to call when event is triggered\n * @param {Object} [context] - Optional context for the callback function\n * @returns {function} A function that removes this callback when called\n */\nconst addCallback = <T extends CallbackType>(\n type: T,\n callback: CallbackMap[T],\n context: object | undefined = undefined\n): (() => void) => {\n const callbacksOfType = callbacks.get(type);\n if (typeof callback === 'function' && callbacksOfType) {\n const entry: StoredCallback = {\n callback: callback as AnyFunction,\n context,\n };\n callbacksOfType.push(entry);\n return () => {\n const arr = callbacks.get(type);\n if (arr) {\n const idx = arr.indexOf(entry);\n if (idx !== -1) arr.splice(idx, 1);\n }\n };\n }\n return () => {};\n};\n\n/**\n * Remove callbacks from events.\n *\n * - Pass an event name and a callback command to remove that callback command from that event type.\n * - Pass just an event name to remove all callback commands from that event type.\n * - Pass undefined as event name and a callback command to remove that callback command from all event types.\n * - Pass no params to remove all callback commands from all event types.\n *\n * #### Examples:\n * ````javascript\n * annyang.addCallback('start', myFunction1);\n * annyang.addCallback('start', myFunction2);\n * annyang.addCallback('end', myFunction1);\n * annyang.addCallback('end', myFunction2);\n *\n * // Remove all callbacks from all events:\n * annyang.removeCallback();\n *\n * // Remove all callbacks attached to end event:\n * annyang.removeCallback('end');\n *\n * // Remove myFunction2 from being called on start:\n * annyang.removeCallback('start', myFunction2);\n *\n * // Remove myFunction1 from being called on all events:\n * annyang.removeCallback(undefined, myFunction1);\n * ````\n *\n * @param type Name of event type to remove callback from\n * @param callback The callback function to remove\n * @returns undefined\n */\nconst removeCallback = (type?: CallbackType, callback?: CallbackMap[CallbackType]) => {\n callbacks.forEach((callbacksArray, callbackType) => {\n if (type === undefined || type === callbackType) {\n if (callback === undefined) {\n callbacks.get(callbackType)!.length = 0;\n } else {\n callbacks.set(\n callbackType,\n callbacksArray.filter(cb => cb.callback !== callback)\n );\n }\n }\n });\n};\n\n/**\n * Returns true if speech recognition is currently on.\n * Returns false if speech recognition is off or annyang is paused.\n *\n * @returns true if SpeechRecognition is on and annyang is not paused\n */\nconst isListening = () => {\n return listening && !pauseListening;\n};\n\nexport type AnnyangState = 'idle' | 'listening' | 'paused';\n\n/**\n * Returns the current state of annyang.\n *\n * @returns {'idle' | 'listening' | 'paused'} The current state\n */\nconst getState = (): AnnyangState => {\n if (!listening) return 'idle';\n if (pauseListening) return 'paused';\n return 'listening';\n};\n\n/**\n * Set the language the user will speak in. If this method is not called, annyang defaults to 'en-US'.\n *\n * @param {string} language - The language (locale)\n * @see [Languages](https://github.com/TalAter/annyang/blob/master/docs/FAQ.md#what-languages-are-supported)\n */\nconst setLanguage = (language: string): void => {\n if (!isSpeechRecognitionSupported()) {\n return;\n }\n initIfNeeded();\n recognition.lang = language;\n};\n\n/**\n * Turn on the output of debug messages to the console.\n *\n * @param {boolean} [newState=true] - Turn debug messages on or off\n */\nconst debug = (newState: boolean = true): void => {\n debugState = !!newState;\n};\n\n/**\n * Match text against registered commands and fire the corresponding callbacks.\n * Works independently of the speech recognition engine — does not require `start()`, and works even in\n * environments where SpeechRecognition is not supported.\n *\n * Can accept either a string containing a single sentence or an array containing multiple sentences to be checked\n * in order until one of them matches a command (similar to the way Speech Recognition Alternatives are parsed)\n *\n * #### Examples:\n * ````javascript\n * annyang.trigger('Time for some thrilling heroics');\n * annyang.trigger(\n * ['Time for some thrilling heroics', 'Time for some thrilling aerobics']\n * );\n * ````\n *\n * @param sentences - A sentence as a string or an array of strings of possible sentences\n */\nconst trigger = (sentences: string | string[] = []) => {\n parseResults(Array.isArray(sentences) ? sentences : [sentences]);\n};\n\n/**\n * Returns the instance of the browser's SpeechRecognition object used by annyang.\n * Useful in case you want direct access to the browser's Speech Recognition engine.\n *\n * @returns SpeechRecognition The browser's Speech Recognizer instance currently used by annyang\n */\nconst getSpeechRecognizer = (): SpeechRecognition | undefined => {\n return recognition;\n};\n\n/**\n * @deprecated annyang no longer requires manual initialization. It initializes automatically on `start()` or `addCommands()`. Remove any calls to `init()`.\n */\nconst initDeprecated = () => {\n console.warn(\n 'annyang.init() is deprecated and no longer needed. ' +\n 'annyang initializes automatically on start() or addCommands(). Remove this call.'\n );\n};\n\nexport {\n abort,\n addCallback,\n addCommands,\n debug,\n getSpeechRecognizer,\n getState,\n initDeprecated as init,\n isListening,\n isSpeechRecognitionSupported,\n pause,\n removeCallback,\n removeCommands,\n resume,\n setLanguage,\n start,\n trigger,\n};\n\nconst annyang = {\n isSpeechRecognitionSupported,\n addCommands,\n removeCommands,\n start,\n abort,\n pause,\n resume,\n addCallback,\n removeCallback,\n isListening,\n setLanguage,\n trigger,\n debug,\n getSpeechRecognizer,\n getState,\n init: initDeprecated,\n get state() {\n return getState();\n },\n} as const;\n\nexport default annyang;\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "annyang",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A JavaScript library for adding voice commands to your site, using speech recognition",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"speech",
|
|
7
|
+
"recognition",
|
|
8
|
+
"voice",
|
|
9
|
+
"commands",
|
|
10
|
+
"speechrecognition"
|
|
11
|
+
],
|
|
6
12
|
"homepage": "https://www.talater.com/annyang/",
|
|
7
13
|
"bugs": {
|
|
8
14
|
"url": "https://github.com/TalAter/annyang/issues"
|
|
@@ -29,11 +35,27 @@
|
|
|
29
35
|
"main": "./dist/annyang.cjs",
|
|
30
36
|
"module": "./dist/annyang.js",
|
|
31
37
|
"types": "./dist/annyang.d.ts",
|
|
32
|
-
"files": [
|
|
38
|
+
"files": [
|
|
39
|
+
"dist"
|
|
40
|
+
],
|
|
33
41
|
"sideEffects": false,
|
|
34
42
|
"engines": {
|
|
35
43
|
"node": ">=18"
|
|
36
44
|
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/dom-speech-recognition": "^0.0.9",
|
|
47
|
+
"concurrently": "^9.2.4",
|
|
48
|
+
"corti": "^2.1.0",
|
|
49
|
+
"eslint": "^10.12.0",
|
|
50
|
+
"eslint-config-prettier": "^10.1.8",
|
|
51
|
+
"prettier": "^3.8.1",
|
|
52
|
+
"tsup": "^8.5.1",
|
|
53
|
+
"typedoc": "^0.28.20",
|
|
54
|
+
"typedoc-plugin-markdown": "^4.11.0",
|
|
55
|
+
"typescript": "^5.9.3",
|
|
56
|
+
"typescript-eslint": "^8.58.0",
|
|
57
|
+
"vitest": "^4.1.11"
|
|
58
|
+
},
|
|
37
59
|
"scripts": {
|
|
38
60
|
"build": "tsup",
|
|
39
61
|
"dev": "tsup --watch",
|
|
@@ -45,22 +67,6 @@
|
|
|
45
67
|
"typecheck": "tsc --noEmit",
|
|
46
68
|
"docs": "typedoc && cat docs/api-intro.md docs/README.md docs/api-footer.md > docs/README.tmp && mv docs/README.tmp docs/README.md",
|
|
47
69
|
"test:manual": "pnpm build && cp dist/annyang.iife.min.js test-manual/ && npx esbuild test-manual/esm-app.js --bundle --alias:annyang=./dist/annyang.js --outfile=test-manual/dist/esm-app.js && npx esbuild test-manual/cjs-app.js --bundle --alias:annyang=./dist/annyang.cjs --outfile=test-manual/dist/cjs-app.js && npx http-server test-manual -p 8081 -c-1 -o",
|
|
48
|
-
"demo": "concurrently -n build,serve -c blue,green \"tsup --watch\" \"npx http-server . -p 8080 -c-1\""
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"@types/dom-speech-recognition": "^0.0.7",
|
|
53
|
-
"concurrently": "^9.2.1",
|
|
54
|
-
"corti": "^2.1.0",
|
|
55
|
-
"eslint": "^10.0.2",
|
|
56
|
-
"eslint-config-prettier": "^10.1.8",
|
|
57
|
-
"prettier": "^3.8.1",
|
|
58
|
-
"tsup": "^8.5.1",
|
|
59
|
-
"typedoc": "^0.28.17",
|
|
60
|
-
"typedoc-plugin-markdown": "^4.10.0",
|
|
61
|
-
"typescript": "^5.9.3",
|
|
62
|
-
"typescript-eslint": "^8.56.1",
|
|
63
|
-
"vitest": "^4.0.18"
|
|
64
|
-
},
|
|
65
|
-
"packageManager": "pnpm@10.30.3"
|
|
66
|
-
}
|
|
70
|
+
"demo": "concurrently -n build,serve -c blue,green \"tsup --watch\" \"npx http-server . -p 8080 -c-1\""
|
|
71
|
+
}
|
|
72
|
+
}
|