Skip to content

Commit

Permalink
[v1.1.0] - add BigInt polyfill and loading model retries
Browse files Browse the repository at this point in the history
  • Loading branch information
pivanov committed Sep 22, 2020
1 parent 120d0c9 commit a3f59d5
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 129 deletions.
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Teachable Machine Node v1.0.0
# Teachable Machine Node

![teachable-machine-cover](https://media-blog.sashido.io/content/images/2020/09/teachable-machine-cover.png)

# About

**Teachable Machine Node v.1.0.0** empowers you to load any image classification model trained with Google's Teachable Machine tool in a Node.Js project.
**Teachable Machine Node** empowers you to load any image classification model trained with Google's Teachable Machine tool in a Node.Js project.

[Teachable Machine](https://teachablemachine.withgoogle.com/) makes AI easy for everyone, by offering a fast and fun way to train a real TensorFlow.js Machine Learning Models without any coding required. You can train the computer to recognize images, sounds, & poses, using your camera or your own dataset.
[Teachable Machine](https://teachablemachine.withgoogle.com/) makes AI easy for everyone, by offering a fast and fun way to train a real TensorFlow.js Machine Learning Models without any coding required. You can train the computer to recognize images, sounds, & poses, using your camera or your own dataset.

For now, Teachable Machine Node v.1.0.0 holds suport only for image models, but we won't stop here. Check out the [Roadmap](#Roadmap) of what comes next!
For now, Teachable Machine Node holds suport only for image models, but we won't stop here. Check out the [Roadmap](#Roadmap) of what comes next!

# Install

Expand All @@ -31,7 +31,7 @@ yarn add @sashido/teachablemachine-node

1. [Gathering samples](https://youtu.be/DFBbSTvtpy4) is the fundamental first step to your Teachable Machine Model. Use your camera to collect data or upload some preselected images.

2. [Train your Teachable Machine Image Model](https://teachablemachine.withgoogle.com/train?action=onboardOpen&id=CO67EQ0ZWgA).
2. [Train your Teachable Machine Image Model](https://teachablemachine.withgoogle.com/train?action=onboardOpen&id=CO67EQ0ZWgA).

![](https://media-blog.sashido.io/content/images/2020/09/tm_export_model.png)

Expand Down Expand Up @@ -117,15 +117,15 @@ app.listen(port, () => {

In the long run, we will add more options, so you can train and load all kinds of Teachable Machine Models.

1. Add support for Pose Models.
2. Add support for Audio Models.
3. Add support for Gifs.
1. Add support for Pose Models.

2. Add support for Audio Models.

3. Add support for Gifs.

4. Add support for Videos.
We would love to have your opinion which's the one you would like to see supported first. Don't be shy and drop us a line at [email protected].

We would love to have your opinion which's the one you would like to see supported first. Don't be shy and drop us a line at [email protected].

# Contribute

Expand Down
47 changes: 27 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
global.BigInt = require("bigint-polyfill");
global.fetch = require("node-fetch");

const tmImage = require("@teachablemachine/image");
const isImageUrl = require('is-image-url');
const canvas = require("canvas");

const { JSDOM } = require("jsdom");
const dom = new JSDOM("");


global.fetch = require("node-fetch");
global.document = dom.window.document;
global.HTMLVideoElement = dom.window.HTMLVideoElement;


const wait = ms => new Promise(r => setTimeout(r, ms));


const retryOperation = (operation, delay, times, retriesCounter = 0) => new Promise((resolve, reject) => {
const retryOperation = (operation, delay, times) => new Promise((resolve, reject) => {
return operation()
.then(({ cb }) => {
return resolve(cb());
})
.catch(({ message }) => {
if (retriesCounter === 0) {
console.info("[@sashido/teachablemachine-node] -", message);
}

if (times - 1 > 0) {
retriesCounter++;
return wait(delay)
.then(retryOperation.bind(null, operation, delay, times - 1, retriesCounter))
.then(retryOperation.bind(null, operation, delay, times - 1))
.then(resolve)
.catch(reject);
}
Expand All @@ -41,15 +36,17 @@ const byProbabilty = (predictionA, predictionB) => {
return 0;
}

class SashiDoTeachable {

class SashiDoTeachableMachine {
constructor(params) {
this.loadModel(params);
}


async loadModel({ modelUrl }) {
if (!modelUrl || modelUrl === "") {
console.error("[@sashido/teachablemachine-node] -", "Missing model URL!");
this.error = "Missing model URL!";
return null;
}

try {
Expand All @@ -59,32 +56,42 @@ class SashiDoTeachable {
}
}

async checkModel(cb) {
const { model } = this;

if (model) {
return Promise.resolve({ cb });
}

return Promise.reject({ message: "Loading model" });
}


async classify(params) {
const { model } = this;
const { imageUrl } = params;

if (!isImageUrl(imageUrl)) {
console.error("[@sashido/teachablemachine-node] -", "Image URL is not valid!");
return Promise.reject({ error: "Image URL is not valid!" });
}

if (!model) {
console.error("[@sashido/teachablemachine-node] -", "Model is not ready!");
return Promise.reject({ error: "Model is not ready!" });
if (this.error) {
return Promise.reject({ error: this.error });
}

return retryOperation(() => this.checkModel(() => this.inference(params)), 1000, 20); // method, delay, retries
}

async inference({ imageUrl }) {
try {
const image = new canvas.Image();
image.src = imageUrl;

const predictions = await this.model.predict(image);
return predictions.sort(byProbabilty);
} catch (error) {
console.error("[@sashido/teachablemachine-node] -", error);
return Promise.reject({ error });
}
}
}

module.exports = SashiDoTeachable;
module.exports = SashiDoTeachableMachine;
Loading

0 comments on commit a3f59d5

Please sign in to comment.