8

I'm trying to move a tensorflow model from its original html into a react app (built with create-react-app).

My App.js looks like this:

import logo from './logo.svg';
import * as tf from "@tensorflow/tfjs";
// import { loadImageclassification } from "@tensorflow/tfjs";
import './App.css';
import * as automl from "@tensorflow/tfjs-automl";
import * as modelJSON from './model.json';

function App() {

var loadFile = function(event) {
    var image = document.getElementById('output');
    image.src = URL.createObjectURL(event.target.files[0]);
  run();
};

async function run() {
  console.log(modelJSON);
        // const model = await tf.loadImageclassification('model.json');
        const model = await automl.loadImageClassification(modelJSON);
        const image = document.getElementById('output');
        const predictions = await model.classify(image);
        console.log(predictions);

        const pre = document.getElementById('result');
        pre.textContent = JSON.stringify(predictions, null, 2);
}

  return (
  <div className="App">
    <div className="hero-text">
      <h1>classifier</h1>
      <h3>Upload a picture to see what type it is! </h3>
      <p>
        <input type="file"  accept="image/*" name="image" id="file"  onChange={loadFile} />
      </p>
      <div id="demobox">
        <p>
          <label htmlFor="file">Upload your image</label>
        </p>
      </div> 
      <p><img id="output" width="200" alt="output" /></p>
      <div className="result" id="result">
      </div>
    </div>
  </div>
  );
}

export default App;

My index.html looks like this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

I am getting the following error, which seems to be issuing from somewhere in the loadImageClassification method:

Unhandled Rejection (TypeError): modelUrl.lastIndexOf is not a function

Edit:

Apparently loadImageClassification uses a fetch request under the hood and so requires a remote file (which is strange, because it seemed to work fine in the static index.html original version of this same project).

So I am now trying it just with a localhost express server, which at present looks like this:

const modelJSON = require('./model.json');

const express = require("express");
const bodyParser = require("body-parser");
const CORS = require("cors");

const app = express();

app.use(bodyParser.json());
app.use(CORS());

let modelObj = modelJSON;

app.get("/", (req, res) => {
  // console.log(modelObj);
  res.send(modelObj);
});

app.listen(5000, () => {
  console.log("Server listening on port 5000");
});

I can see the correct data when I navigate to localhost5000, but when I change

async function run() {
  const model = await automl.loadImageClassification(modelJSON);

to

async function run() {
  const modelUrl = "http://localhost:5000/";
  const model = await automl.loadImageClassification(modelUrl);

I get these errors:

enter image description here

Edit 2:

My server.js file now looks like this:

enter image description here

This produces the same errors as in the previous screenshot. (I am leaving in the comments that mess of an attempt to include all the shard files in this server.js file screenshot just because it may illustrate that I don't understand how to pass those ancillary model files to loadImageClassification when it makes its fetch request.)

So presumably the problem now has to do with the fact that loadImageClassification assumes that the ...shard__of6.bin and dict files are in the same directory as the model.json file.

So the question may (?) be: how to simulate the file structure that it (i.e., loadImageClassification) is expecting within a remote node server.

Fundamental confusion:

I'm don't understand why, when loadImageClassification is in the original static html, it does not seem to require a remote url from which to fetch model.json — but then when I put it in my react app, it suddenly gives me this error: "Fetch API cannot load file:///Users///client/src/model.json. URL scheme must be 'http' or 'https' for CORS request."

Lyovin K.
  • 145
  • 7

1 Answers1

1

What's the location of the model on your local device?

Try changing

const modelUrl = "http://localhost:5000/"

to

const modelUrl = 'model/model.json'

if the model is in build/model/, or to whatever the location is.

  • For now, the location of the model is the same `src` folder as that of the react App.js file. So I assumed it would be something like this `const modelUrl = '/model.json'` or `const modelUrl = './model.json'`, but I've tried both of those and received something like: `Error: Failed to parse model JSON of response from ./model.json. Please make sure the server is serving valid JSON for this request.` (The JSON is definitely valid.) – Lyovin K. Dec 22 '20 at 21:10
  • I was originally doing it like you're suggesting (though I did `import * as modelJSON from "./model.json";` followed by ` const model = await automl.loadImageClassification(modelJSON);` —— But I was getting the above-mentioned `modelUrl.lastIndexOf is not a function` error. I only started trying to get it as a url because of this post, which seemed to be addressing a similar sort of problem: https://stackoverflow.com/questions/61804137/is-there-a-way-to-replace-script-tag-src-with-require-and-run-the-same-script-on/61822195#comment115633229_61822195 – Lyovin K. Dec 22 '20 at 21:18
  • 1
    Embarrassing. Your suggestion worked, Yarik. `const model = await automl.loadImageClassification('model.json');` was what it was supposed to be all along. The problem was that, when I first tried this, my model.json file was in my src, rather than public, directory. This is what shook me out of my dogmatic slumber: https://stackoverflow.com/questions/50007055/fetch-request-to-local-file-not-working . Siddhant Varma's: "First, as suggested in some of the answers above ensure that your json file is inside the public folder." Disgraceful. I'm going to sleep. – Lyovin K. Dec 24 '20 at 08:20
  • I'll give bounty when it lets me do so in ~20 hrs. – Lyovin K. Dec 24 '20 at 08:20
  • 1
    No worries, glad I could help you ;) Merry Christmas! – Yarik Sychov Dec 24 '20 at 15:23