QBoard » Artificial Intelligence & ML » AI and ML - Python » How to call a Python function from Node.js

How to call a Python function from Node.js

  • I have an Express Node.js application, but I also have a machine learning algorithm to use in Python. Is there a way I can call Python functions from my Node.js application to make use of the power of machine learning libraries?
      August 27, 2021 12:54 PM IST
    0
  • You can now use RPC libraries that support Python and Javascript such as zerorpc

    From their front page:

    Node.js Client

    var zerorpc = require("zerorpc");
    
    var client = new zerorpc.Client();
    client.connect("tcp://127.0.0.1:4242");
    
    client.invoke("hello", "RPC", function(error, res, more) {
        console.log(res);
    });

    Python Server

    import zerorpc
    
    class HelloRPC(object):
        def hello(self, name):
            return "Hello, %s" % name
    
    s = zerorpc.Server(HelloRPC())
    s.bind("tcp://0.0.0.0:4242")
    s.run()

     

      September 2, 2021 10:03 PM IST
    0
  • Most of previous answers call the success of the promise in the on("data"), it is not the proper way to do it because if you receive a lot of data you will only get the first part. Instead you have to do it on the end event.

    const { spawn } = require('child_process');
    const pythonDir = (__dirname + "/../pythonCode/"); // Path of python script folder
    const python = pythonDir + "pythonEnv/bin/python"; // Path of the Python interpreter
    
    /** remove warning that you don't care about */
    function cleanWarning(error) {
        return error.replace(/Detector is not able to detect the language reliably.\n/g,"");
    }
    
    function callPython(scriptName, args) {
        return new Promise(function(success, reject) {
            const script = pythonDir + scriptName;
            const pyArgs = [script, JSON.stringify(args) ]
            const pyprog = spawn(python, pyArgs );
            let result = "";
            let resultError = "";
            pyprog.stdout.on('data', function(data) {
                result += data.toString();
            });
    
            pyprog.stderr.on('data', (data) => {
                resultError += cleanWarning(data.toString());
            });
    
            pyprog.stdout.on("end", function(){
                if(resultError == "") {
                    success(JSON.parse(result));
                }else{
                    console.error(`Python error, you can reproduce the error with: \n${python} ${script} ${pyArgs.join(" ")}`);
                    const error = new Error(resultError);
                    console.error(error);
                    reject(resultError);
                }
            })
       });
    }
    module.exports.callPython = callPython;

     

    Call:

    const pythonCaller = require("../core/pythonCaller");
    const result = await pythonCaller.callPython("preprocessorSentiment.py", {"thekeyYouwant": value});

     

    python:

    try:
        argu = json.loads(sys.argv[1])
    except:
        raise Exception("error while loading argument")
      September 22, 2021 2:27 PM IST
    0
  • Easiest way I know of is to use "child_process" package which comes packaged with node.
    Then you can do something like:
    const spawn = require("child_process").spawn; const pythonProcess = spawn('python',["path/to/script.py", arg1, arg2, ...]);
    Then all you have to do is make sure that you import sys in your python script, and then you can access arg1 using sys.argv[1]arg2 using sys.argv[2], and so on.
    To send data back to node just do the following in the python script:
    print(dataToSendBack) sys.stdout.flush()
    And then node can listen for data using:
    pythonProcess.stdout.on('data', (data) => { // Do something with the data returned from python script });
    Since this allows multiple arguments to be passed to a script using spawn, you can restructure a python script so that one of the arguments decides which function to call, and the other argument gets passed to that function, etc.
    Hope this was clear. Let me know if something needs clarification.
      August 27, 2021 7:07 PM IST
    0
  • Many of the examples are years out of date and involve complex setup. You can give JSPyBridge/pythonia a try (full disclosure: I'm the author). It's vanilla JS that lets you operate on foreign Python objects as if they existed in JS. In fact, it does interoperability so Python code can in return call JS through callbacks and passed functions.

    numpy + matplotlib example, with the ES6 import system:

    import { py, python } from 'pythonia'
    const np = await python('numpy')
    const plot = await python('matplotlib.pyplot')
    
    // Fixing random state for reproducibility
    await np.random.seed(19680801)
    const [mu, sigma] = [100, 15]
    // Inline expression evaluation for operator overloading
    const x = await py`${mu} + ${sigma} * ${np.random.randn(10000)}`
    
    // the histogram of the data
    const [n, bins, patches] = await plot.hist$(x, 50, { density: true, facecolor: 'g', alpha: 0.75 })
    console.log('Distribution', await n) // Always await for all Python access
    await plot.show()
    python.exit()

     

    Through CommonJS (without top level await):

    const { py, python } = require('pythonia')
    async function main() {
      const np = await python('numpy')
      const plot = await python('matplotlib.pyplot')
      ...
      // the rest of the code
    }
    main().then(() => python.exit()) // If you don't call this, the process won't quit by itself.
      December 18, 2021 11:38 AM IST
    0