1

I am making this web app about bookstore which recommends books based on book user selects. I want it to run a python script and for that, I have used child process looking at this thread How to call a Python function from Node.js

Here's the code:

const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',["../../../python/book_recommendation.py","Timeline"]);

const Recommendations = pythonProcess.stdout.on('data', (data) => {
    console.log(data);
});

module.exports = Recommendations;

I want this code to run when I click on the product and get directed to productScreen page. But I get the error "TypeError: Spawn is not a function". With some google searching, I found out that I m calling this function through react and not node.js. I m using react as frontend and node.js as backend. How can I solve this problem?

Here's how I imported this in react ProductScreen.js page

import { Recommendations } from "../machine-learning/recommendation_engine"

Here's the file structure of my project

enter image description here

Update:

const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',["../python/book_recommendation.py","Timeline"]);
app.get("/product/:id", (req, res) => {
  pythonProcess.stdout.on('data', (data) => {
      console.log(data);
  });
});

I moved the above code in server.js backend folder now. How do I call it?

Yash Vishe
  • 61
  • 8
  • 1
    You can't. React apps run in the browser. The methods you are asking about are only for nodejs. If you want something like this, you need a backend. – The Fool Oct 17 '21 at 11:48
  • Based on the screenshot, OP already does have a backend, so they'd need to move this stuff there, and then do e.g. a `fetch()` call to the backend that'd then call the Python script. – AKX Oct 17 '21 at 11:51
  • I do have a backend though with node.js, I have made some progress and added the child process to server.js file in backend folder. but not sure if it's progress. – Yash Vishe Oct 17 '21 at 11:53

1 Answers1

1

I don't think it's good architecture wise. But if you insist on doing it that way, then you need to spawn the child process when the requests hit. You could then pipe its output to the response stream. In this example I am using pipeline which is somewhat safer than mystream.pipe.

const spawn = require("child_process").spawn;
const { pipeline } = require('stream');

app.get("/python-process", (request, response) => {
    const pythonProcess = spawn('python', [
        "../python/book_recommendation.py",
        "Timeline"
    ]);
    // pipe the python process stream into the response stream
    pipeline(pythonProcess, response, (err) => err && console.warn(err));
});

Note, I haven't tested this, but it is the gist of how you could go about it.

The Fool
  • 16,715
  • 5
  • 52
  • 86
  • Can I now, directly use axios to get the data, something like this : export const getRecommends = () => { return axios.get(``).then(res => res.data); }; in react – Yash Vishe Oct 17 '21 at 13:09
  • Yes, that is the way you have to use it. Since the process will only spawn on the request. So something like axios or the native fetch api to initate the request would make sense. Whatever the python process writes to stdout, will be the response data in your browser. This wouldn't be great if the python process takes a long time to complete. If that's the case, you could think about changing to an asynchronous request/response model. Where you return an empty response immediately with something like a 201, and later you send the results in some way. Maybe server sent events. – The Fool Oct 17 '21 at 13:32
  • alright thanks, hope this works – Yash Vishe Oct 17 '21 at 14:55