Download SpeechManager.js from stereoDrift/3d-model-playground: direct link, hf CLI and curl.
- Browser
- Download file 15.9 kB
-
https://huggingface.co/spaces/stereoDrift/3d-model-playground/resolve/main/SpeechManager.js
- Command line
-
hf download hf://spaces/stereoDrift/3d-model-playground/SpeechManager.js
-
curl -L -o SpeechManager.js https://huggingface.co/spaces/stereoDrift/3d-model-playground/resolve/main/SpeechManager.js
15.9 kB
| function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { | |
| try { | |
| var info = gen[key](arg); | |
| var value = info.value; | |
| } catch (error) { | |
| reject(error); | |
| return; | |
| } | |
| if (info.done) { | |
| resolve(value); | |
| } else { | |
| Promise.resolve(value).then(_next, _throw); | |
| } | |
| } | |
| function _async_to_generator(fn) { | |
| return function() { | |
| var self = this, args = arguments; | |
| return new Promise(function(resolve, reject) { | |
| var gen = fn.apply(self, args); | |
| function _next(value) { | |
| asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); | |
| } | |
| function _throw(err) { | |
| asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); | |
| } | |
| _next(undefined); | |
| }); | |
| }; | |
| } | |
| function _class_call_check(instance, Constructor) { | |
| if (!(instance instanceof Constructor)) { | |
| throw new TypeError("Cannot call a class as a function"); | |
| } | |
| } | |
| function _defineProperties(target, props) { | |
| for(var i = 0; i < props.length; i++){ | |
| var descriptor = props[i]; | |
| descriptor.enumerable = descriptor.enumerable || false; | |
| descriptor.configurable = true; | |
| if ("value" in descriptor) descriptor.writable = true; | |
| Object.defineProperty(target, descriptor.key, descriptor); | |
| } | |
| } | |
| function _create_class(Constructor, protoProps, staticProps) { | |
| if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |
| if (staticProps) _defineProperties(Constructor, staticProps); | |
| return Constructor; | |
| } | |
| function _ts_generator(thisArg, body) { | |
| var f, y, t, g, _ = { | |
| label: 0, | |
| sent: function() { | |
| if (t[0] & 1) throw t[1]; | |
| return t[1]; | |
| }, | |
| trys: [], | |
| ops: [] | |
| }; | |
| return g = { | |
| next: verb(0), | |
| "throw": verb(1), | |
| "return": verb(2) | |
| }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { | |
| return this; | |
| }), g; | |
| function verb(n) { | |
| return function(v) { | |
| return step([ | |
| n, | |
| v | |
| ]); | |
| }; | |
| } | |
| function step(op) { | |
| if (f) throw new TypeError("Generator is already executing."); | |
| while(_)try { | |
| if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | |
| if (y = 0, t) op = [ | |
| op[0] & 2, | |
| t.value | |
| ]; | |
| switch(op[0]){ | |
| case 0: | |
| case 1: | |
| t = op; | |
| break; | |
| case 4: | |
| _.label++; | |
| return { | |
| value: op[1], | |
| done: false | |
| }; | |
| case 5: | |
| _.label++; | |
| y = op[1]; | |
| op = [ | |
| 0 | |
| ]; | |
| continue; | |
| case 7: | |
| op = _.ops.pop(); | |
| _.trys.pop(); | |
| continue; | |
| default: | |
| if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { | |
| _ = 0; | |
| continue; | |
| } | |
| if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) { | |
| _.label = op[1]; | |
| break; | |
| } | |
| if (op[0] === 6 && _.label < t[1]) { | |
| _.label = t[1]; | |
| t = op; | |
| break; | |
| } | |
| if (t && _.label < t[2]) { | |
| _.label = t[2]; | |
| _.ops.push(op); | |
| break; | |
| } | |
| if (t[2]) _.ops.pop(); | |
| _.trys.pop(); | |
| continue; | |
| } | |
| op = body.call(thisArg, _); | |
| } catch (e) { | |
| op = [ | |
| 6, | |
| e | |
| ]; | |
| y = 0; | |
| } finally{ | |
| f = t = 0; | |
| } | |
| if (op[0] & 5) throw op[1]; | |
| return { | |
| value: op[0] ? op[1] : void 0, | |
| done: true | |
| }; | |
| } | |
| } | |
| export var SpeechManager = /*#__PURE__*/ function() { | |
| "use strict"; | |
| function SpeechManager(onTranscript, onRecognitionActive, onCommandRecognized) { | |
| var _this = this; | |
| _class_call_check(this, SpeechManager); | |
| this.onTranscript = onTranscript; | |
| this.onRecognitionActive = onRecognitionActive; // Callback for recognition state | |
| this.onCommandRecognized = onCommandRecognized; // Callback for recognized commands | |
| this.recognition = null; | |
| this.isRecognizing = false; | |
| this.finalTranscript = ''; | |
| this.interimTranscript = ''; | |
| var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; | |
| if (SpeechRecognition) { | |
| this.recognition = new SpeechRecognition(); | |
| this.recognition.continuous = true; // Keep listening even after a pause | |
| this.recognition.interimResults = true; // Get results while speaking | |
| this.recognition.onstart = function() { | |
| _this.isRecognizing = true; | |
| console.log('Speech recognition started.'); | |
| if (_this.onRecognitionActive) _this.onRecognitionActive(true); | |
| }; | |
| this.recognition.onresult = function(event) { | |
| _this.interimTranscript = ''; | |
| for(var i = event.resultIndex; i < event.results.length; ++i){ | |
| if (event.results[i].isFinal) { | |
| // Append to finalTranscript and then clear it for the next utterance | |
| // This way, `finalTranscript` holds the *current complete* utterance. | |
| var currentFinalTranscript = event.results[i][0].transcript.trim().toLowerCase(); | |
| _this.finalTranscript += currentFinalTranscript; // Append to potentially longer session transcript if needed, though we process per utterance | |
| if (_this.onTranscript) { | |
| // Display the raw transcript before processing as command | |
| _this.onTranscript(event.results[i][0].transcript, ''); // Send final, clear interim | |
| } | |
| // Check for commands | |
| var commandMap = { | |
| 'drag': 'drag', | |
| 'rotate': 'rotate', | |
| 'rotation': 'rotate', | |
| 'scale': 'scale', | |
| 'size': 'scale', | |
| 'zoom': 'scale', | |
| 'animate': 'animate', | |
| 'anime': 'animate', | |
| 'animation': 'animate' // Alias for animate | |
| }; | |
| var spokenCommands = Object.keys(commandMap); | |
| var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined; | |
| try { | |
| for(var _iterator = spokenCommands[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){ | |
| var spokenCmd = _step.value; | |
| if (currentFinalTranscript.includes(spokenCmd)) { | |
| var actualCommand = commandMap[spokenCmd]; | |
| if (_this.onCommandRecognized) { | |
| _this.onCommandRecognized(actualCommand); | |
| } | |
| break; // Process the first command found (and its alias) | |
| } | |
| } | |
| } catch (err) { | |
| _didIteratorError = true; | |
| _iteratorError = err; | |
| } finally{ | |
| try { | |
| if (!_iteratorNormalCompletion && _iterator.return != null) { | |
| _iterator.return(); | |
| } | |
| } finally{ | |
| if (_didIteratorError) { | |
| throw _iteratorError; | |
| } | |
| } | |
| } | |
| // Reset finalTranscript for the next full utterance if you are processing utterance by utterance | |
| // If you want to accumulate, then don't reset here. | |
| // For command processing, resetting per utterance is usually best. | |
| _this.finalTranscript = ''; | |
| } else { | |
| _this.interimTranscript += event.results[i][0].transcript; | |
| if (_this.onTranscript) { | |
| _this.onTranscript(null, _this.interimTranscript); | |
| } | |
| } | |
| } | |
| // If only interim results were processed in this event batch, ensure onTranscript is called | |
| if (_this.interimTranscript && !event.results[event.results.length - 1].isFinal) { | |
| if (_this.onTranscript) { | |
| _this.onTranscript(null, _this.interimTranscript); | |
| } | |
| } | |
| }; | |
| this.recognition.onerror = function(event) { | |
| console.error('Speech recognition error:', event.error); | |
| var oldIsRecognizing = _this.isRecognizing; | |
| _this.isRecognizing = false; | |
| _this.finalTranscript = ''; // Clear transcript on error | |
| _this.interimTranscript = ''; | |
| if (_this.onTranscript) _this.onTranscript('', ''); // Clear display | |
| if (oldIsRecognizing && _this.onRecognitionActive) _this.onRecognitionActive(false); | |
| // Automatically restart if it's an 'aborted' or 'no-speech' error | |
| if (event.error === 'aborted' || event.error === 'no-speech') { | |
| console.log('Restarting speech recognition due to inactivity or abort.'); | |
| // Don't call startRecognition directly, let onend handle it if continuous | |
| } | |
| }; | |
| this.recognition.onend = function() { | |
| var oldIsRecognizing = _this.isRecognizing; | |
| _this.isRecognizing = false; | |
| console.log('Speech recognition ended.'); | |
| _this.finalTranscript = ''; // Clear transcript on end | |
| _this.interimTranscript = ''; | |
| if (_this.onTranscript) _this.onTranscript('', ''); // Clear display | |
| if (oldIsRecognizing && _this.onRecognitionActive) _this.onRecognitionActive(false); | |
| // If it ended and continuous is true, restart it. | |
| // This handles cases where the browser might stop it. | |
| if (_this.recognition.continuous) { | |
| console.log('Continuous mode: Restarting speech recognition.'); | |
| _this.startRecognition(); // startRecognition already resets transcripts | |
| } | |
| }; | |
| } else { | |
| console.warn('Web Speech API is not supported in this browser.'); | |
| } | |
| } | |
| _create_class(SpeechManager, [ | |
| { | |
| key: "startRecognition", | |
| value: function startRecognition() { | |
| var _this = this; | |
| if (this.recognition && !this.isRecognizing) { | |
| try { | |
| this.finalTranscript = ''; // Reset transcript | |
| this.interimTranscript = ''; | |
| this.recognition.start(); | |
| } catch (e) { | |
| console.error("Error starting speech recognition:", e); | |
| // This can happen if it's already started or due to permissions | |
| if (e.name === 'InvalidStateError' && this.isRecognizing) { | |
| // Already started, do nothing | |
| } else { | |
| // Attempt to restart if it fails for other reasons (e.g. after an error) | |
| setTimeout(function() { | |
| return _this.startRecognition(); | |
| }, 500); | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| { | |
| key: "stopRecognition", | |
| value: function stopRecognition() { | |
| if (this.recognition && this.isRecognizing) { | |
| this.recognition.stop(); | |
| } | |
| } | |
| }, | |
| { | |
| key: "requestPermissionAndStart", | |
| value: // Call this on user interaction to request microphone permission | |
| function requestPermissionAndStart() { | |
| var _this = this; | |
| return _async_to_generator(function() { | |
| var err; | |
| return _ts_generator(this, function(_state) { | |
| switch(_state.label){ | |
| case 0: | |
| if (!_this.recognition) { | |
| console.log("Speech recognition not supported."); | |
| return [ | |
| 2 | |
| ]; | |
| } | |
| _state.label = 1; | |
| case 1: | |
| _state.trys.push([ | |
| 1, | |
| 3, | |
| , | |
| 4 | |
| ]); | |
| // Attempt to get microphone access (this might prompt the user) | |
| return [ | |
| 4, | |
| navigator.mediaDevices.getUserMedia({ | |
| audio: true | |
| }) | |
| ]; | |
| case 2: | |
| _state.sent(); | |
| console.log("Microphone permission granted."); | |
| _this.startRecognition(); | |
| return [ | |
| 3, | |
| 4 | |
| ]; | |
| case 3: | |
| err = _state.sent(); | |
| console.error("Microphone permission denied or error:", err); | |
| if (_this.onTranscript) { | |
| _this.onTranscript("Microphone access denied. Please allow microphone access in your browser settings.", ""); | |
| } | |
| return [ | |
| 3, | |
| 4 | |
| ]; | |
| case 4: | |
| return [ | |
| 2 | |
| ]; | |
| } | |
| }); | |
| })(); | |
| } | |
| } | |
| ]); | |
| return SpeechManager; | |
| }(); |