diff --git a/extensions/src/doodlebot/index.ts b/extensions/src/doodlebot/index.ts index 93c2d0d39..37f1cf6b2 100644 --- a/extensions/src/doodlebot/index.ts +++ b/extensions/src/doodlebot/index.ts @@ -8,7 +8,10 @@ import { categoryByGesture, classes, emojiByGesture, gestureDetection, gestureMe import { line0, line1, line2, line3, line4, line5, line6, line7, line8 } from './Points'; import { followLine } from "./LineFollowing"; import { createLineDetector } from "./LineDetection"; +import tmPose from '@teachablemachine/pose'; import { calculateArcTime } from "./TimeHelper"; +import tmImage from '@teachablemachine/image'; +import * as speechCommands from '@tensorflow-models/speech-commands'; const details: ExtensionMenuDisplayDetails = { name: "Doodlebot", @@ -61,13 +64,26 @@ export default class DoodlebotBlocks extends extension(details, "ui", "indicator imageStream: HTMLImageElement; videoDrawable: ReturnType; + predictionState = {}; + latestAudioResults: any; + ModelType = { + POSE: 'pose', + IMAGE: 'image', + AUDIO: 'audio', + }; + teachableImageModel; + + lastUpdate: number = null; + maxConfidence: number = null; + modelConfidences = {}; + isPredicting: number = 0; + INTERVAL = 16; + DIMENSIONS = [480, 360]; init(env: Environment) { this.openUI("Connect"); this.setIndicator("disconnected"); - - // idea: set up polling mechanism to try and disable unused sensors - // idea: set up polling mechanism to destroy gesture recognition loop + this._loop(); } setDoodlebot(doodlebot: Doodlebot) { @@ -110,57 +126,6 @@ export default class DoodlebotBlocks extends extension(details, "ui", "indicator return drawable; } - @block({ - type: "command", - text: "displayLine" - }) - async displayLine() { - console.log("displayLine"); - if (!this.lineDetector) { - const ipAddress = await this.doodlebot?.getIPAddress(); - console.log("DEBUG IP Address:", ipAddress); - if (!ipAddress) { - console.error("Unable to get IP address for line detection"); - return; - } - const imageStream = await this.getImageStream(); - this.lineDetector = createLineDetector(ipAddress, imageStream); - } - - const lineCoordinates = await this.lineDetector(); - console.log("Raw line coordinates:", lineCoordinates); - if (lineCoordinates.length === 0) { - console.log("No line detected"); - return; - } - - console.log("Line coordinates:", JSON.stringify(lineCoordinates)); - - if (!this.videoDrawable) { - this.videoDrawable = await this.createVideoStreamDrawable(); - } - - const canvas = document.createElement('canvas'); - canvas.width = this.imageStream.width; // Assume these properties exist - canvas.height = this.imageStream.height; - const ctx = canvas.getContext('2d'); - - if (ctx) { - ctx.drawImage(this.imageStream, 0, 0, canvas.width, canvas.height); - - ctx.beginPath(); - ctx.moveTo(lineCoordinates[0][0], lineCoordinates[0][1]); - for (let i = 1; i < lineCoordinates.length; i++) { - ctx.lineTo(lineCoordinates[i][0], lineCoordinates[i][1]); - } - ctx.strokeStyle = 'red'; - ctx.lineWidth = 2; - ctx.stroke(); - - this.videoDrawable.update(canvas); - } - } - @buttonBlock("Connect Robot") connect() { this.openUI("Connect"); @@ -603,4 +568,267 @@ export default class DoodlebotBlocks extends extension(details, "ui", "indicator : await this.doodlebot?.sendWebsocketCommand(candidates[0], ...splitArgsString(args)); } -} \ No newline at end of file + @block({ + type: "command", + text: (url) => `import model ${url}`, + arg: { + type: "string", + defaultValue: "URL HERE" + } + }) + async importModel(url: string) { + await this.useModel(url); + } + + + @block({ + type: "hat", + text: (className) => `when model detects ${className}`, + arg: { + type: "string", + options: function() { + if (!this) { + throw new Error('Context is undefined'); + } + return this.getModelClasses() || ["Select a class"]; + }, + defaultValue: "Select a class" + } + }) + whenModelDetects(className: string) { + return this.model_match(className); + } + + @block({ + type: "reporter", + text: "model prediction", + }) + modelPrediction() { + return this.getModelPrediction(); + } + + + async useModel(url: string) { + try { + const modelUrl = this.modelArgumentToURL(url); + console.log('Loading model from URL:', modelUrl); + this.getPredictionStateOrStartPredicting(modelUrl, true); + console.log('Model state:', this.predictionState[modelUrl]); + this.updateStageModel(modelUrl); + } catch (e) { + console.error('Error loading model:', e); + this.teachableImageModel = null; + } + } + + modelArgumentToURL(modelArg: string) { + const endpointProvidedFromInterface = "https://teachablemachine.withgoogle.com/models/"; + // NOTE: It's possible Google will change this endpoint in the future, and that will break this extension. + // TODO: https://github.com/mitmedialab/prg-extension-boilerplate/issues/343 + const redirectEndpoint = "https://storage.googleapis.com/tm-model/"; + return modelArg.startsWith(endpointProvidedFromInterface) + ? modelArg.replace(endpointProvidedFromInterface, redirectEndpoint) + : redirectEndpoint + modelArg + "/"; + } + + getPredictionStateOrStartPredicting(modelUrl, override = false) { + const hasPredictionState = this.predictionState.hasOwnProperty(modelUrl); + if (!hasPredictionState || override) { + this.startPredicting(modelUrl); + return null; + } + return this.predictionState[modelUrl]; + } + + async startPredicting(modelDataUrl) { + const alreadyLoaded = Boolean(this.predictionState[modelDataUrl]); + try { + const indicator = await this.indicate({ + type: "warning", + msg: alreadyLoaded ? "Updating model" : "Loading model" + }); + this.predictionState[modelDataUrl] = {}; + // https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/image + const { model, type } = await this.initModel(modelDataUrl); + this.predictionState[modelDataUrl].modelType = type; + this.predictionState[modelDataUrl].model = model; + this.runtime.requestToolboxExtensionsUpdate(); + indicator.close(); + this.indicateFor({ type: "success", msg: "Model loaded" }, 1); + } catch (e) { + this.predictionState[modelDataUrl] = {}; + console.log("Model initialization failure!", e); + this.indicateFor({ type: "error", msg: "Unable to load model." }, 1); + } + } + + async initModel(modelUrl) { + const avoidCache = `?x=${Date.now()}`; + const modelURL = modelUrl + "model.json" + avoidCache; + const metadataURL = modelUrl + "metadata.json" + avoidCache; + const customMobileNet = await tmImage.load(modelURL, metadataURL); + if ((customMobileNet as any)._metadata.hasOwnProperty('tfjsSpeechCommandsVersion')) { + const recognizer = await speechCommands.create("BROWSER_FFT", undefined, modelURL, metadataURL); + await recognizer.ensureModelLoaded(); + await recognizer.listen(async result => { + this.latestAudioResults = result; + }, { + includeSpectrogram: true, // in case listen should return result.spectrogram + probabilityThreshold: 0.75, + invokeCallbackOnNoiseAndUnknown: true, + overlapFactor: 0.50 // probably want between 0.5 and 0.75. More info in README + }); + return { model: recognizer, type: this.ModelType.AUDIO }; + } else if ((customMobileNet as any)._metadata.packageName === "@teachablemachine/pose") { + const customPoseNet = await tmPose.load(modelURL, metadataURL); + return { model: customPoseNet, type: this.ModelType.POSE }; + } else { + console.log(customMobileNet.getMetadata(), customMobileNet.getTotalClasses(), customMobileNet.getClassLabels()); + return { model: customMobileNet, type: this.ModelType.IMAGE }; + } + } + + updateStageModel(modelUrl) { + const stage = this.runtime.getTargetForStage(); + this.teachableImageModel = modelUrl; + if (stage) { + (stage as any).teachableImageModel = modelUrl; + } + } + + model_match(state) { + const modelUrl = this.teachableImageModel; + const className = state; + + const predictionState = this.getPredictionStateOrStartPredicting(modelUrl); + if (!predictionState) { + return false; + } + + const currentMaxClass = predictionState.topClass; + return (currentMaxClass === String(className)); + } + + getModelClasses(): string[] { + if ( + !this.teachableImageModel || + !this.predictionState || + !this.predictionState[this.teachableImageModel] || + !this.predictionState[this.teachableImageModel].hasOwnProperty('model') + ) { + return ["Select a class"]; + } + + if (this.predictionState[this.teachableImageModel].modelType === this.ModelType.AUDIO) { + return this.predictionState[this.teachableImageModel].model.wordLabels(); + } + + return this.predictionState[this.teachableImageModel].model.getClassLabels(); + } + + getModelPrediction() { + const modelUrl = this.teachableImageModel; + const predictionState: { topClass: string } = this.getPredictionStateOrStartPredicting(modelUrl); + if (!predictionState) { + console.error("No prediction state found"); + return ''; + } + return predictionState.topClass; + } + + private _loop() { + setTimeout(this._loop.bind(this), Math.max(this.runtime.currentStepTime, this.INTERVAL)); + console.log('Running loop'); + const time = Date.now(); + if (this.lastUpdate === null) { + this.lastUpdate = time; + } + if (!this.isPredicting) { + this.isPredicting = 0; + } + const offset = time - this.lastUpdate; + + if (offset > this.INTERVAL && this.isPredicting === 0) { + this.lastUpdate = time; + this.isPredicting = 0; + this.getImageStreamAndPredict(); + } + } + + private async getImageStreamAndPredict() { + try { + const imageStream = await this.getImageStream(); + if (!imageStream) { + console.error("Failed to get image stream"); + return; + } + console.log("received new image stream"); + const imageBitmap = await createImageBitmap(imageStream); + this.predictAllBlocks(imageBitmap); + } catch (error) { + console.error("Error in getting image stream and predicting:", error); + } + } + + private async predictAllBlocks(frame: ImageBitmap) { + console.log('Starting prediction with frame:', frame); + for (let modelUrl in this.predictionState) { + if (!this.predictionState[modelUrl].model) { + console.log('No model found for:', modelUrl); + continue; + } + if (this.teachableImageModel !== modelUrl) { + console.log('Model URL mismatch:', modelUrl); + continue; + } + ++this.isPredicting; + console.log('Starting prediction, isPredicting:', this.isPredicting); + const prediction = await this.predictModel(modelUrl, frame); + console.log('Prediction:', prediction); + this.predictionState[modelUrl].topClass = prediction; + --this.isPredicting; + } + } + + private async predictModel(modelUrl: string, frame: ImageBitmap) { + const predictions = await this.getPredictionFromModel(modelUrl, frame); + if (!predictions) { + return; + } + let maxProbability = 0; + let maxClassName = ""; + for (let i = 0; i < predictions.length; i++) { + const probability = predictions[i].probability.toFixed(2); + const className = predictions[i].className; + this.modelConfidences[className] = probability; + if (probability > maxProbability) { + maxClassName = className; + maxProbability = probability; + } + } + this.maxConfidence = maxProbability; + return maxClassName; + } + + private async getPredictionFromModel(modelUrl: string, frame: ImageBitmap) { + const { model, modelType } = this.predictionState[modelUrl]; + switch (modelType) { + case this.ModelType.IMAGE: + if (!frame) return null; + return await model.predict(frame); + case this.ModelType.POSE: + if (!frame) return null; + const { pose, posenetOutput } = await model.estimatePose(frame); + return await model.predict(posenetOutput); + case this.ModelType.AUDIO: + if (this.latestAudioResults) { + return model.wordLabels().map((label, i) => ({ + className: label, + probability: this.latestAudioResults.scores[i] + })); + } + return null; + } + } +} + diff --git a/extensions/src/doodlebot/package.json b/extensions/src/doodlebot/package.json index 6b40ca0d2..79f34a49b 100644 --- a/extensions/src/doodlebot/package.json +++ b/extensions/src/doodlebot/package.json @@ -14,6 +14,10 @@ "license": "ISC", "dependencies": { "@mediapipe/tasks-vision": "^0.10.12", + "@teachablemachine/image": "^0.8.5", + "@teachablemachine/pose": "^0.8.6", + "@tensorflow-models/speech-commands": "^0.5.4", + "@tensorflow/tfjs": "^4.17.0", "@types/web-bluetooth": "^0.0.20", "axios": "^1.7.7", "bezier-js": "^6.1.4", diff --git a/extensions/src/doodlebot/pnpm-lock.yaml b/extensions/src/doodlebot/pnpm-lock.yaml index 8c3d9e091..79e49c9de 100644 --- a/extensions/src/doodlebot/pnpm-lock.yaml +++ b/extensions/src/doodlebot/pnpm-lock.yaml @@ -11,6 +11,18 @@ importers: '@mediapipe/tasks-vision': specifier: ^0.10.12 version: 0.10.14 + '@teachablemachine/image': + specifier: ^0.8.5 + version: 0.8.5(@tensorflow/tfjs@4.22.0(seedrandom@3.0.5)) + '@teachablemachine/pose': + specifier: ^0.8.6 + version: 0.8.6(@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0))(@tensorflow/tfjs-core@4.22.0)(@tensorflow/tfjs@4.22.0(seedrandom@3.0.5)) + '@tensorflow-models/speech-commands': + specifier: ^0.5.4 + version: 0.5.4(@tensorflow/tfjs-core@4.22.0)(@tensorflow/tfjs-data@4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5))(@tensorflow/tfjs-layers@4.22.0(@tensorflow/tfjs-core@4.22.0)) + '@tensorflow/tfjs': + specifier: ^4.17.0 + version: 4.22.0(seedrandom@3.0.5) '@types/web-bluetooth': specifier: ^0.0.20 version: 0.0.20 @@ -42,9 +54,89 @@ packages: '@mediapipe/tasks-vision@0.10.14': resolution: {integrity: sha512-vOifgZhkndgybdvoRITzRkIueWWSiCKuEUXXK6Q4FaJsFvRJuwgg++vqFUMlL0Uox62U5aEXFhHxlhV7Ja5e3Q==} + '@teachablemachine/image@0.8.5': + resolution: {integrity: sha512-u6BLQ8RBn38BKee7mmAl+HS9qWgM/2YmUbQYy21eQfqhb7E8xT5LDp7QqEU31rtgEIMDwB/OG8cjmSiuHpqb7A==} + peerDependencies: + '@tensorflow/tfjs': 1.3.1 + + '@teachablemachine/pose@0.8.6': + resolution: {integrity: sha512-72UHof2okPdyKlDMSnFcDk/h7dj4I9BBbGsJs64P+B/WQb1rwFcxAeeUFud5rJ2HFwElLDLEjnyaHZljeWV2Bg==} + peerDependencies: + '@tensorflow/tfjs': 1.3.1 + + '@tensorflow-models/posenet@2.2.2': + resolution: {integrity: sha512-0SXIksRet/IdX7WVH+JSD6W3upkGHix1hwtd3xykIoIMGR7zQ4SC5+wZcNt9ofASyxNYQoI+tUULUo4LNw0c3w==} + peerDependencies: + '@tensorflow/tfjs-converter': ^3.0.0-rc.1 + '@tensorflow/tfjs-core': ^3.0.0-rc.1 + + '@tensorflow-models/speech-commands@0.5.4': + resolution: {integrity: sha512-r0c/MvC15/09xWujx1pKe6mA0nta+4jQWDXGkqfSVkXLo8ARrwcZ4mTGLlfvT43ySfidiveUo0m+P51+UK821Q==} + peerDependencies: + '@tensorflow/tfjs-core': ^3.0.0 + '@tensorflow/tfjs-data': ^3.0.0 + '@tensorflow/tfjs-layers': ^3.0.0 + + '@tensorflow/tfjs-backend-cpu@4.22.0': + resolution: {integrity: sha512-1u0FmuLGuRAi8D2c3cocHTASGXOmHc/4OvoVDENJayjYkS119fcTcQf4iHrtLthWyDIPy3JiPhRrZQC9EwnhLw==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 4.22.0 + + '@tensorflow/tfjs-backend-webgl@4.22.0': + resolution: {integrity: sha512-H535XtZWnWgNwSzv538czjVlbJebDl5QTMOth4RXr2p/kJ1qSIXE0vZvEtO+5EC9b00SvhplECny2yDewQb/Yg==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 4.22.0 + + '@tensorflow/tfjs-converter@4.22.0': + resolution: {integrity: sha512-PT43MGlnzIo+YfbsjM79Lxk9lOq6uUwZuCc8rrp0hfpLjF6Jv8jS84u2jFb+WpUeuF4K33ZDNx8CjiYrGQ2trQ==} + peerDependencies: + '@tensorflow/tfjs-core': 4.22.0 + + '@tensorflow/tfjs-core@4.22.0': + resolution: {integrity: sha512-LEkOyzbknKFoWUwfkr59vSB68DMJ4cjwwHgicXN0DUi3a0Vh1Er3JQqCI1Hl86GGZQvY8ezVrtDIvqR1ZFW55A==} + engines: {yarn: '>= 1.3.2'} + + '@tensorflow/tfjs-data@4.22.0': + resolution: {integrity: sha512-dYmF3LihQIGvtgJrt382hSRH4S0QuAp2w1hXJI2+kOaEqo5HnUPG0k5KA6va+S1yUhx7UBToUKCBHeLHFQRV4w==} + peerDependencies: + '@tensorflow/tfjs-core': 4.22.0 + seedrandom: ^3.0.5 + + '@tensorflow/tfjs-layers@4.22.0': + resolution: {integrity: sha512-lybPj4ZNj9iIAPUj7a8ZW1hg8KQGfqWLlCZDi9eM/oNKCCAgchiyzx8OrYoWmRrB+AM6VNEeIT+2gZKg5ReihA==} + peerDependencies: + '@tensorflow/tfjs-core': 4.22.0 + + '@tensorflow/tfjs@4.22.0': + resolution: {integrity: sha512-0TrIrXs6/b7FLhLVNmfh8Sah6JgjBPH4mZ8JGb7NU6WW+cx00qK5BcAZxw7NCzxj6N8MRAIfHq+oNbPUNG5VAg==} + hasBin: true + + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + + '@types/node@22.10.1': + resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} + + '@types/offscreencanvas@2019.3.0': + resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==} + + '@types/offscreencanvas@2019.7.3': + resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} + + '@types/seedrandom@2.4.34': + resolution: {integrity: sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==} + '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + '@webgpu/types@0.1.38': + resolution: {integrity: sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==} + abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -56,6 +148,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + aproba@2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} @@ -64,9 +160,16 @@ packages: engines: {node: '>=10'} deprecated: This package is no longer supported. + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autobind-decorator@2.4.0: + resolution: {integrity: sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==} + engines: {node: '>=8.10', npm: '>=6.4.1'} + axios@1.7.7: resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} @@ -83,10 +186,24 @@ packages: resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} engines: {node: '>=6'} + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true @@ -101,6 +218,9 @@ packages: console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + core-js@3.29.1: + resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==} + cubic-spline@3.0.3: resolution: {integrity: sha512-yAvcHgrpf/k83pZiO4+R2reWOJlufgjpQhmDD3OXa8YMbjmRgjtUK8pcFOCZvJwqXaMD1isZdL7Z4ghqDPN/yw==} @@ -135,6 +255,10 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -164,10 +288,18 @@ packages: engines: {node: '>=10'} deprecated: This package is no longer supported. + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} @@ -186,6 +318,9 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -228,6 +363,15 @@ packages: nan@2.20.0: resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==} + node-fetch@2.6.13: + resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -264,6 +408,13 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -272,6 +423,12 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + seedrandom@2.4.4: + resolution: {integrity: sha512-9A+PDmgm+2du77B5i0Ip2cxOqqHjgNxnBgglxLcX78A2D6c2rTo61z4jnVABpF4cKeDMDG+cmXXvdnqse2VqMA==} + + seedrandom@3.0.5: + resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -293,6 +450,9 @@ packages: simple-get@3.1.1: resolution: {integrity: sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -304,6 +464,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -311,6 +475,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -323,12 +490,28 @@ packages: wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + snapshots: '@mapbox/node-pre-gyp@1.0.11': @@ -348,8 +531,115 @@ snapshots: '@mediapipe/tasks-vision@0.10.14': {} + '@teachablemachine/image@0.8.5(@tensorflow/tfjs@4.22.0(seedrandom@3.0.5))': + dependencies: + '@tensorflow/tfjs': 4.22.0(seedrandom@3.0.5) + autobind-decorator: 2.4.0 + seedrandom: 2.4.4 + + '@teachablemachine/pose@0.8.6(@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0))(@tensorflow/tfjs-core@4.22.0)(@tensorflow/tfjs@4.22.0(seedrandom@3.0.5))': + dependencies: + '@tensorflow-models/posenet': 2.2.2(@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0))(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs': 4.22.0(seedrandom@3.0.5) + autobind-decorator: 2.4.0 + seedrandom: 3.0.5 + transitivePeerDependencies: + - '@tensorflow/tfjs-converter' + - '@tensorflow/tfjs-core' + + '@tensorflow-models/posenet@2.2.2(@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0))(@tensorflow/tfjs-core@4.22.0)': + dependencies: + '@tensorflow/tfjs-converter': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-core': 4.22.0 + + '@tensorflow-models/speech-commands@0.5.4(@tensorflow/tfjs-core@4.22.0)(@tensorflow/tfjs-data@4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5))(@tensorflow/tfjs-layers@4.22.0(@tensorflow/tfjs-core@4.22.0))': + dependencies: + '@tensorflow/tfjs-core': 4.22.0 + '@tensorflow/tfjs-data': 4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5) + '@tensorflow/tfjs-layers': 4.22.0(@tensorflow/tfjs-core@4.22.0) + + '@tensorflow/tfjs-backend-cpu@4.22.0(@tensorflow/tfjs-core@4.22.0)': + dependencies: + '@tensorflow/tfjs-core': 4.22.0 + '@types/seedrandom': 2.4.34 + seedrandom: 3.0.5 + + '@tensorflow/tfjs-backend-webgl@4.22.0(@tensorflow/tfjs-core@4.22.0)': + dependencies: + '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-core': 4.22.0 + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.34 + seedrandom: 3.0.5 + + '@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0)': + dependencies: + '@tensorflow/tfjs-core': 4.22.0 + + '@tensorflow/tfjs-core@4.22.0': + dependencies: + '@types/long': 4.0.2 + '@types/offscreencanvas': 2019.7.3 + '@types/seedrandom': 2.4.34 + '@webgpu/types': 0.1.38 + long: 4.0.0 + node-fetch: 2.6.13 + seedrandom: 3.0.5 + transitivePeerDependencies: + - encoding + + '@tensorflow/tfjs-data@4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5)': + dependencies: + '@tensorflow/tfjs-core': 4.22.0 + '@types/node-fetch': 2.6.12 + node-fetch: 2.6.13 + seedrandom: 3.0.5 + string_decoder: 1.3.0 + transitivePeerDependencies: + - encoding + + '@tensorflow/tfjs-layers@4.22.0(@tensorflow/tfjs-core@4.22.0)': + dependencies: + '@tensorflow/tfjs-core': 4.22.0 + + '@tensorflow/tfjs@4.22.0(seedrandom@3.0.5)': + dependencies: + '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-backend-webgl': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-converter': 4.22.0(@tensorflow/tfjs-core@4.22.0) + '@tensorflow/tfjs-core': 4.22.0 + '@tensorflow/tfjs-data': 4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5) + '@tensorflow/tfjs-layers': 4.22.0(@tensorflow/tfjs-core@4.22.0) + argparse: 1.0.10 + chalk: 4.1.2 + core-js: 3.29.1 + regenerator-runtime: 0.13.11 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - seedrandom + + '@types/long@4.0.2': {} + + '@types/node-fetch@2.6.12': + dependencies: + '@types/node': 22.10.1 + form-data: 4.0.1 + + '@types/node@22.10.1': + dependencies: + undici-types: 6.20.0 + + '@types/offscreencanvas@2019.3.0': {} + + '@types/offscreencanvas@2019.7.3': {} + + '@types/seedrandom@2.4.34': {} + '@types/web-bluetooth@0.0.20': {} + '@webgpu/types@0.1.38': {} + abbrev@1.1.1: {} agent-base@6.0.2: @@ -360,6 +650,10 @@ snapshots: ansi-regex@5.0.1: {} + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + aproba@2.0.0: {} are-we-there-yet@2.0.0: @@ -367,8 +661,14 @@ snapshots: delegates: 1.0.0 readable-stream: 3.6.2 + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + asynckit@0.4.0: {} + autobind-decorator@2.4.0: {} + axios@1.7.7: dependencies: follow-redirects: 1.15.9 @@ -395,8 +695,25 @@ snapshots: - encoding - supports-color + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chownr@2.0.0: {} + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + color-support@1.1.3: {} combined-stream@1.0.8: @@ -407,6 +724,8 @@ snapshots: console-control-strings@1.1.0: {} + core-js@3.29.1: {} + cubic-spline@3.0.3: {} curve-matcher@1.1.1: {} @@ -427,6 +746,8 @@ snapshots: emoji-regex@8.0.0: {} + escalade@3.2.0: {} + events@3.3.0: {} follow-redirects@1.15.9: {} @@ -455,6 +776,8 @@ snapshots: strip-ansi: 6.0.1 wide-align: 1.1.5 + get-caller-file@2.0.5: {} + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -464,6 +787,8 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + has-flag@4.0.0: {} + has-unicode@2.0.1: {} https-proxy-agent@5.0.1: @@ -482,6 +807,8 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + long@4.0.0: {} + make-dir@3.1.0: dependencies: semver: 6.3.1 @@ -515,6 +842,10 @@ snapshots: nan@2.20.0: {} + node-fetch@2.6.13: + dependencies: + whatwg-url: 5.0.0 + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -546,12 +877,20 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + regenerator-runtime@0.13.11: {} + + require-directory@2.1.1: {} + rimraf@3.0.2: dependencies: glob: 7.2.3 safe-buffer@5.2.1: {} + seedrandom@2.4.4: {} + + seedrandom@3.0.5: {} + semver@6.3.1: {} semver@7.6.3: {} @@ -568,6 +907,8 @@ snapshots: once: 1.4.0 simple-concat: 1.0.1 + sprintf-js@1.0.3: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -582,6 +923,10 @@ snapshots: dependencies: ansi-regex: 5.0.1 + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + tar@6.2.1: dependencies: chownr: 2.0.0 @@ -593,6 +938,8 @@ snapshots: tr46@0.0.3: {} + undici-types@6.20.0: {} + util-deprecate@1.0.2: {} webidl-conversions@3.0.1: {} @@ -606,6 +953,26 @@ snapshots: dependencies: string-width: 4.2.3 + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrappy@1.0.2: {} + y18n@5.0.8: {} + yallist@4.0.0: {} + + yargs-parser@20.2.9: {} + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 diff --git a/package.json b/package.json index 44fd3ca97..41ad05bd2 100644 --- a/package.json +++ b/package.json @@ -33,5 +33,11 @@ "ts-node": { "typescript": "$typescript" } + }, + "dependencies": { + "@teachablemachine/image": "^0.8.5", + "@teachablemachine/pose": "^0.8.6", + "@tensorflow-models/speech-commands": "0.4.2", + "@tensorflow/tfjs": "1.3.1" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40e737ba1..208556893 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,19 @@ settings: importers: .: + dependencies: + '@teachablemachine/image': + specifier: ^0.8.5 + version: 0.8.5(@tensorflow/tfjs@1.3.1(seedrandom@3.0.5)) + '@teachablemachine/pose': + specifier: ^0.8.6 + version: 0.8.6(@tensorflow/tfjs-converter@3.21.0(@tensorflow/tfjs-core@1.3.1))(@tensorflow/tfjs-core@1.3.1)(@tensorflow/tfjs@1.3.1(seedrandom@3.0.5)) + '@tensorflow-models/speech-commands': + specifier: 0.4.2 + version: 0.4.2(@tensorflow/tfjs@1.3.1(seedrandom@3.0.5)) + '@tensorflow/tfjs': + specifier: 1.3.1 + version: 1.3.1(seedrandom@3.0.5) devDependencies: '@types/node': specifier: ^20.12.2 @@ -49,6 +62,55 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@teachablemachine/image@0.8.5': + resolution: {integrity: sha512-u6BLQ8RBn38BKee7mmAl+HS9qWgM/2YmUbQYy21eQfqhb7E8xT5LDp7QqEU31rtgEIMDwB/OG8cjmSiuHpqb7A==} + peerDependencies: + '@tensorflow/tfjs': 1.3.1 + + '@teachablemachine/pose@0.8.6': + resolution: {integrity: sha512-72UHof2okPdyKlDMSnFcDk/h7dj4I9BBbGsJs64P+B/WQb1rwFcxAeeUFud5rJ2HFwElLDLEjnyaHZljeWV2Bg==} + peerDependencies: + '@tensorflow/tfjs': 1.3.1 + + '@tensorflow-models/posenet@2.2.2': + resolution: {integrity: sha512-0SXIksRet/IdX7WVH+JSD6W3upkGHix1hwtd3xykIoIMGR7zQ4SC5+wZcNt9ofASyxNYQoI+tUULUo4LNw0c3w==} + peerDependencies: + '@tensorflow/tfjs-converter': ^3.0.0-rc.1 + '@tensorflow/tfjs-core': ^3.0.0-rc.1 + + '@tensorflow-models/speech-commands@0.4.2': + resolution: {integrity: sha512-XpfRUzVy0DtQkMvR/jqRWCFgcka9pgwEdfqtHTqnIBoueAUJiuq1edD+RNzbK01O3bAJ9FIL/VuiTZmxNx92NQ==} + peerDependencies: + '@tensorflow/tfjs': ^1.5.2 + + '@tensorflow/tfjs-converter@1.3.1': + resolution: {integrity: sha512-8IHzcIZwqCofcRBhaCTN6W73m2RGdBDH6BEORf0KDdbgbz4DouItVcKX692PrA8gchY+Xy8ZHMpj93PcAOs17g==} + peerDependencies: + '@tensorflow/tfjs-core': 1.3.1 + + '@tensorflow/tfjs-converter@3.21.0': + resolution: {integrity: sha512-12Y4zVDq3yW+wSjSDpSv4HnpL2sDZrNiGSg8XNiDE4HQBdjdA+a+Q3sZF/8NV9y2yoBhL5L7V4mMLDdbZBd9/Q==} + peerDependencies: + '@tensorflow/tfjs-core': 3.21.0 + + '@tensorflow/tfjs-core@1.3.1': + resolution: {integrity: sha512-X4MKhpg1gLEZetKUMeQNW6diP3gbFFddeF6UT816sH8jOenX/8x2HnVmANpNnUxCTPhDniY3V9zhBWwbl13+Yg==} + engines: {yarn: '>= 1.3.2'} + + '@tensorflow/tfjs-data@1.3.1': + resolution: {integrity: sha512-GCATkRXKBewLdri+qfzTLcVsToX9W7fz5JwApY6Ysel/aTtKSYArU8+OppUKAfWkczBA/fZKlJTONnqC42H6bA==} + peerDependencies: + '@tensorflow/tfjs-core': 1.3.1 + seedrandom: ~2.4.3 + + '@tensorflow/tfjs-layers@1.3.1': + resolution: {integrity: sha512-LiC9mGU9ZQ7+c3PiQ6MDkvT/gZgqNN67TsypfKm+L44u2TLtMZf77mRaQ/8rW/F89Ey4PDDFftDRDYv0t3fukw==} + peerDependencies: + '@tensorflow/tfjs-core': 1.3.1 + + '@tensorflow/tfjs@1.3.1': + resolution: {integrity: sha512-eJ8+WYRYYx6o3R4daV3T46ZHI/FN0+wslNnobh6d2Sp/T8PfaFpdR38nRrYtxnz33A80B2pMk4VxzoVivS4/jA==} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -61,9 +123,24 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + '@types/node@20.12.12': resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + '@types/offscreencanvas@2019.3.0': + resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==} + + '@types/seedrandom@2.4.27': + resolution: {integrity: sha512-YvMLqFak/7rt//lPBtEHv3M4sRNA+HGxrhFZ+DQs9K2IkYJbNwVIb8avtJfhDiuaUBX/AW0jnjv48FV8h3u9bQ==} + + '@types/webgl-ext@0.0.30': + resolution: {integrity: sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==} + + '@types/webgl2@0.0.4': + resolution: {integrity: sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw==} + '@types/webgl2@0.0.6': resolution: {integrity: sha512-50GQhDVTq/herLMiqSQkdtRu+d5q/cWHn4VvKJtrj4DJAjo1MNkWYa2MA41BaBO1q1HgsUjuQvEOk0QHvlnAaQ==} @@ -93,6 +170,13 @@ packages: arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + autobind-decorator@2.4.0: + resolution: {integrity: sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==} + engines: {node: '>=8.10', npm: '>=6.4.1'} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -104,9 +188,17 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -118,6 +210,10 @@ packages: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -134,13 +230,34 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + node-fetch@2.1.2: + resolution: {integrity: sha512-IHLHYskTc2arMYsHZH82PVX8CSKT5lzb7AXeyO06QnjGDKtkv+pv3mEki6S7reB/x1QPo+YPxQRNEVgR5V/w3Q==} + engines: {node: 4.x || >=6.0.0} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + seedrandom@2.4.3: + resolution: {integrity: sha512-2CkZ9Wn2dS4mMUWQaXLsOAfGD+irMlLEeSP3cMxpGbgyOOzJGFa+MWCOMTOCMyZinHRPxyOj/S/C57li/1to6Q==} + + seedrandom@2.4.4: + resolution: {integrity: sha512-9A+PDmgm+2du77B5i0Ip2cxOqqHjgNxnBgglxLcX78A2D6c2rTo61z4jnVABpF4cKeDMDG+cmXXvdnqse2VqMA==} + + seedrandom@3.0.5: + resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -220,6 +337,68 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 + '@teachablemachine/image@0.8.5(@tensorflow/tfjs@1.3.1(seedrandom@3.0.5))': + dependencies: + '@tensorflow/tfjs': 1.3.1(seedrandom@3.0.5) + autobind-decorator: 2.4.0 + seedrandom: 2.4.4 + + '@teachablemachine/pose@0.8.6(@tensorflow/tfjs-converter@3.21.0(@tensorflow/tfjs-core@1.3.1))(@tensorflow/tfjs-core@1.3.1)(@tensorflow/tfjs@1.3.1(seedrandom@3.0.5))': + dependencies: + '@tensorflow-models/posenet': 2.2.2(@tensorflow/tfjs-converter@3.21.0(@tensorflow/tfjs-core@1.3.1))(@tensorflow/tfjs-core@1.3.1) + '@tensorflow/tfjs': 1.3.1(seedrandom@3.0.5) + autobind-decorator: 2.4.0 + seedrandom: 3.0.5 + transitivePeerDependencies: + - '@tensorflow/tfjs-converter' + - '@tensorflow/tfjs-core' + + '@tensorflow-models/posenet@2.2.2(@tensorflow/tfjs-converter@3.21.0(@tensorflow/tfjs-core@1.3.1))(@tensorflow/tfjs-core@1.3.1)': + dependencies: + '@tensorflow/tfjs-converter': 3.21.0(@tensorflow/tfjs-core@1.3.1) + '@tensorflow/tfjs-core': 1.3.1 + + '@tensorflow-models/speech-commands@0.4.2(@tensorflow/tfjs@1.3.1(seedrandom@3.0.5))': + dependencies: + '@tensorflow/tfjs': 1.3.1(seedrandom@3.0.5) + + '@tensorflow/tfjs-converter@1.3.1(@tensorflow/tfjs-core@1.3.1)': + dependencies: + '@tensorflow/tfjs-core': 1.3.1 + + '@tensorflow/tfjs-converter@3.21.0(@tensorflow/tfjs-core@1.3.1)': + dependencies: + '@tensorflow/tfjs-core': 1.3.1 + + '@tensorflow/tfjs-core@1.3.1': + dependencies: + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.27 + '@types/webgl-ext': 0.0.30 + '@types/webgl2': 0.0.4 + node-fetch: 2.1.2 + seedrandom: 2.4.3 + + '@tensorflow/tfjs-data@1.3.1(@tensorflow/tfjs-core@1.3.1)(seedrandom@3.0.5)': + dependencies: + '@tensorflow/tfjs-core': 1.3.1 + '@types/node-fetch': 2.6.12 + node-fetch: 2.1.2 + seedrandom: 3.0.5 + + '@tensorflow/tfjs-layers@1.3.1(@tensorflow/tfjs-core@1.3.1)': + dependencies: + '@tensorflow/tfjs-core': 1.3.1 + + '@tensorflow/tfjs@1.3.1(seedrandom@3.0.5)': + dependencies: + '@tensorflow/tfjs-converter': 1.3.1(@tensorflow/tfjs-core@1.3.1) + '@tensorflow/tfjs-core': 1.3.1 + '@tensorflow/tfjs-data': 1.3.1(@tensorflow/tfjs-core@1.3.1)(seedrandom@3.0.5) + '@tensorflow/tfjs-layers': 1.3.1(@tensorflow/tfjs-core@1.3.1) + transitivePeerDependencies: + - seedrandom + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -228,10 +407,23 @@ snapshots: '@tsconfig/node16@1.0.4': {} + '@types/node-fetch@2.6.12': + dependencies: + '@types/node': 20.12.12 + form-data: 4.0.1 + '@types/node@20.12.12': dependencies: undici-types: 5.26.5 + '@types/offscreencanvas@2019.3.0': {} + + '@types/seedrandom@2.4.27': {} + + '@types/webgl-ext@0.0.30': {} + + '@types/webgl2@0.0.4': {} + '@types/webgl2@0.0.6': {} '@types/yargs-parser@21.0.3': {} @@ -252,6 +444,10 @@ snapshots: arg@4.1.3: {} + asynckit@0.4.0: {} + + autobind-decorator@2.4.0: {} + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -264,14 +460,26 @@ snapshots: color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + create-require@1.1.1: {} + delayed-stream@1.0.0: {} + diff@4.0.2: {} emoji-regex@8.0.0: {} escalade@3.1.2: {} + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + get-caller-file@2.0.5: {} is-fullwidth-code-point@3.0.0: {} @@ -280,10 +488,24 @@ snapshots: make-error@1.3.6: {} + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimist@1.2.8: {} + node-fetch@2.1.2: {} + require-directory@2.1.1: {} + seedrandom@2.4.3: {} + + seedrandom@2.4.4: {} + + seedrandom@3.0.5: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0