如何从 Node.js 调用 Python 函数

2024-12-25 08:51:00
admin
原创
153
摘要:问题描述:我有一个 Express Node.js 应用程序,但我还有一个要在 Python 中使用的机器学习算法。有没有办法从我的 Node.js 应用程序调用 Python 函数来利用机器学习库的强大功能?解决方案 1:我知道的最简单的方法是使用节点附带的“child_process”包。然后你可以做类似...

问题描述:

我有一个 Express Node.js 应用程序,但我还有一个要在 Python 中使用的机器学习算法。有没有办法从我的 Node.js 应用程序调用 Python 函数来利用机器学习库的强大功能?


解决方案 1:

我知道的最简单的方法是使用节点附带的“child_process”包。

然后你可以做类似的事情:

const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',["path/to/script.py", arg1, arg2, ...]);

然后您要做的就是确保您import sys在您的 python 脚本中,然后您可以arg1使用 sys.argv[1]arg2使用 sys.argv[2]等等进行访问。

要将数据发送回节点,只需在 Python 脚本中执行以下操作:

print(dataToSendBack)
sys.stdout.flush()

然后节点可以使用以下方式监听数据:

pythonProcess.stdout.on('data', (data) => {
 // Do something with the data returned from python script
});

由于这允许使用 spawn 将多个参数传递给脚本,因此您可以重构 python 脚本,以便其中一个参数决定调用哪个函数,并将另一个参数传递给该函数,等等。

希望您说得清楚。如果需要澄清,请告诉我。

解决方案 2:

对于具有 Python 背景并希望将其机器学习模型集成到 Node.js 应用程序中的人,示例如下:

它使用child_process核心模块:

const express = require('express')
const app = express()

app.get('/', (req, res) => {

    const { spawn } = require('child_process');
    const pyProg = spawn('python', ['./../pypy.py']);

    pyProg.stdout.on('data', function(data) {

        console.log(data.toString());
        res.write(data);
        res.end('end');
    });
})

app.listen(4000, () => console.log('Application listening on port 4000!'))

它不需要sysPython 脚本中的模块。

下面是使用更模块化的方式执行任务Promise

const express = require('express')
const app = express()

let runPy = new Promise(function(success, nosuccess) {

    const { spawn } = require('child_process');
    const pyprog = spawn('python', ['./../pypy.py']);

    pyprog.stdout.on('data', function(data) {

        success(data);
    });

    pyprog.stderr.on('data', (data) => {

        nosuccess(data);
    });
});

app.get('/', (req, res) => {

    res.write('welcome
');

    runPy.then(function(fromRunpy) {
        console.log(fromRunpy.toString());
        res.end(fromRunpy);
    });
})

app.listen(4000, () => console.log('Application listening on port 4000!'))

解决方案 3:

python-shell模块extrabacon是一种从 Node.js 运行 Python 脚本的简单方法,具有基本但高效的进程间通信和更好的错误处理功能。

安装:

使用 npm:
npm install python-shell

或者用纱线:
yarn add python-shell

运行一个简单的 Python 脚本:

const PythonShell = require('python-shell').PythonShell;

PythonShell.run('my_script.py', null, function (err) {
  if (err) throw err;
  console.log('finished');
});

使用参数和选项运行 Python 脚本:

const PythonShell = require('python-shell').PythonShell;

var options = {
  mode: 'text',
  pythonPath: 'path/to/python',
  pythonOptions: ['-u'],
  scriptPath: 'path/to/my/scripts',
  args: ['value1', 'value2', 'value3']
};

PythonShell.run('my_script.py', options, function (err, results) {
  if (err) 
    throw err;
  // Results is an array consisting of messages collected during execution
  console.log('results: %j', results);
});

有关完整文档和源代码,请查看https://github.com/extrabacon/python-shell

解决方案 4:

您现在可以使用支持 Python 和 Javascript 的 RPC 库,例如zerorpc

摘自他们的头版:

Node.js 客户端

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 服务器

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()

解决方案 5:

许多示例都过时了好几年,而且设置复杂。您可以尝试JSPyBridge/pythonia(完全披露:我是作者)。它是原生 JS,允许您操作外部 Python 对象,就像它们存在于 JS 中一样。事实上,它具有互操作性,因此 Python 代码可以通过回调和传递的函数调用 JS。

numpy + matplotlib 示例,使用 ES6 导入系统:

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()

通过 CommonJS(无顶层 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.

解决方案 6:

之前大多数答案都在 on("data") 中调用承诺的成功,但这不是正确的做法,因为如果您收到大量数据,您将只能获得第一部分。相反,您必须在结束事件中执行此操作。

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.
/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: 
${python} ${script} ${pyArgs.join(" ")}`);
                const error = new Error(resultError);
                console.error(error);
                reject(resultError);
            }
        })
   });
}
module.exports.callPython = callPython;

称呼:

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")

解决方案 7:

我在节点 10 和子进程上1.0.2。来自 python 的数据是一个字节数组,必须进行转换。这只是在 python 中发出 http 请求的另一个简单示例。

节点

const process = spawn("python", ["services/request.py", "https://www.google.com"])

return new Promise((resolve, reject) =>{
    process.stdout.on("data", data =>{
        resolve(data.toString()); // <------------ by default converts to utf-8
    })
    process.stderr.on("data", reject)
})

请求.py

import urllib.request
import sys

def karl_morrison_is_a_pedant():   
    response = urllib.request.urlopen(sys.argv[1])
    html = response.read()
    print(html)
    sys.stdout.flush()

karl_morrison_is_a_pedant()

ps 这不是一个人为的例子,因为节点的 http 模块没有加载我需要发出的一些请求

解决方案 8:

Boa 可以满足您的需求,请参阅keras.Sequential在 JavaScript 中扩展 Python tensorflow 类的示例。

const fs = require('fs');
const boa = require('@pipcook/boa');
const { tuple, enumerate } = boa.builtins();

const tf = boa.import('tensorflow');
const tfds = boa.import('tensorflow_datasets');

const { keras } = tf;
const { layers } = keras;

const [
  [ train_data, test_data ],
  info
] = tfds.load('imdb_reviews/subwords8k', boa.kwargs({
  split: tuple([ tfds.Split.TRAIN, tfds.Split.TEST ]),
  with_info: true,
  as_supervised: true
}));

const encoder = info.features['text'].encoder;
const padded_shapes = tuple([
  [ null ], tuple([])
]);
const train_batches = train_data.shuffle(1000)
  .padded_batch(10, boa.kwargs({ padded_shapes }));
const test_batches = test_data.shuffle(1000)
  .padded_batch(10, boa.kwargs({ padded_shapes }));

const embedding_dim = 16;
const model = keras.Sequential([
  layers.Embedding(encoder.vocab_size, embedding_dim),
  layers.GlobalAveragePooling1D(),
  layers.Dense(16, boa.kwargs({ activation: 'relu' })),
  layers.Dense(1, boa.kwargs({ activation: 'sigmoid' }))
]);

model.summary();
model.compile(boa.kwargs({
  optimizer: 'adam',
  loss: 'binary_crossentropy',
  metrics: [ 'accuracy' ]
}));

完整示例位于:https: //github.com/alibaba/pipcook/blob/master/example/boa/tf2/word-embedding.js

我在另一个项目 Pipcook 中使用了 Boa,该项目旨在解决 JavaScript 开发人员的机器学习问题,我们通过 boa 库在 Python 生态系统(tensorflow、keras、pytorch)上实现了 ML/DL 模型。

解决方案 9:

您可以取出 Python,对其进行转译,然后像调用 JavaScript 一样调用它。我已经成功地为 screeps 完成了此操作,甚至让它像brython一样在浏览器中运行。

解决方案 10:

/*eslint-env es6*/
/*global require*/
/*global console*/
var express = require('express'); 
var app = express();

// Creates a server which runs on port 3000 and  
// can be accessed through localhost:3000
app.listen(3000, function() { 
    console.log('server running on port 3000'); 
} ) 

app.get('/name', function(req, res) {

    console.log('Running');

    // Use child_process.spawn method from  
    // child_process module and assign it 
    // to variable spawn 
    var spawn = require("child_process").spawn;   
    // Parameters passed in spawn - 
    // 1. type_of_script 
    // 2. list containing Path of the script 
    //    and arguments for the script  

    // E.g : http://localhost:3000/name?firstname=Levente
    var process = spawn('python',['apiTest.py', 
                        req.query.firstname]);

    // Takes stdout data from script which executed 
    // with arguments and send this data to res object
    var output = '';
    process.stdout.on('data', function(data) {

        console.log("Sending Info")
        res.end(data.toString('utf8'));
    });

    console.log(output);
}); 

这对我有用。必须将 python.exe 添加到此代码片段的路径变量中。另外,请确保您的 python 脚本位于您的项目文件夹中。

解决方案 11:

2023 年我还会向您推荐pymport。

它允许所有 Python 代码与 Node.js 完全兼容,包括二进制模块。与其他模块不同,它不会生成单独的 Python 进程 - Python 代码和 Node.js 代码共存于一个具有同步垃圾收集器的共享内存进程中。

npm install pymport
npx pympip3 install numpy

然后只需在 JavaScript 中:

const { pymport, proxify } = require('pymport');
const np = proxify(pymport('numpy'));

const a = np.array([2, 3, 4]);
console.log(a.toString());

(我是它的作者)

解决方案 12:

您可以在 npm 上查看我的包
https://www.npmjs.com/package/@guydev/native-python

它提供了一种非常简单而强大的方法来从节点运行python函数

import { runFunction } from '@guydev/native-python'

const example = async () => {
   const input = [1,[1,2,3],{'foo':'bar'}]
   const { error, data } = await runFunction('/path/to/file.py','hello_world', '/path/to/python', input)

   // error will be null if no error occured.
   if (error) {
       console.log('Error: ', error)
   }

   else {
       console.log('Success: ', data)
       // prints data or null if function has no return value
   }
}

python 模块

# module: file.py

def hello_world(a,b,c):
    print( type(a), a) 
    # <class 'int'>, 1

    print(type(b),b)
    # <class 'list'>, [1,2,3]

    print(type(c),c)
    # <class 'dict'>, {'foo':'bar'}

解决方案 13:

您可以使用node-calls-python模块!与基于子进程的解决方案的区别在于,它在进程内运行 Python 代码,速度更快,灵活性更高,因为您可以在模块内运行单个函数,并且可以更轻松地传递数据,包括成熟的 Python 对象(支持调用其方法)。

python.py:

def add(a, b):
    return a + b

index.js:

import { interpreter as py } from 'node-calls-python'

const myModule = await py.load('./python.py')

console.log(await py.call(myModule, 'add', 1, 2)) // 3

如果这样更方便并且操作不需要很长时间,您也可以使用同步方法而不是异步方法:

console.log(py.callSync(myModule, 'add', 1, 2)) // 3

当然,您也可以创建调用 Python 函数的 JS 函数包装器,以使集成更加无缝。查看上面链接的文档以获取更多信息,例如如何在 JS 中创建和使用 Python 对象、如何传递 kwargs 等等。

解决方案 14:

const util = require('util');
const exec = util.promisify(require('child_process').exec);
    
function runPythonFile() {
  const { stdout, stderr } = await exec('py ./path_to_python_file -s asdf -d pqrs');
  if (stdout) { // do something }
  if (stderr) { // do something }
}

有关更多信息,请访问官方 Nodejs 子进程页面:https ://nodejs.org/api/child_process.html#child_processexeccommand-options-callback

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3998  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2749  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   85  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   96  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   83  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用