thumbnail
NodeJS에서 파이썬 코드 실행하는 법
Coding / KOR
2022.07.17.

1. 문제 제기

프로그램을 작성 중, 파이썬 라이브러리를 사용해서 딥러닝 관련 응답을 받아와야 할 일이 생겼다. NodeJS는 기본적으로 다른 확장자의 파일을 실행할 수 있는 기능을 라이브러리로 제공한다. 따라서 라이브러리를 사용하지 않는(혹은 pip로 설치하지 않는 라이브러리만 사용하는) 경우는 간단하게 파이썬을 실행시켜 결과값을 가져올 수 있다. 하지만 그렇지 않다면…? 딥러닝은 수많은 라이브러리를 사용하는데? python venv설정은? NodeJS와 연동이 되나? 이러한 궁금증을 바탕으로, 그냥 한 번 악으로 깡으로 해보기로 했다.

2. 첫 번째 방법 : Child.spawn()을 이용해 파이썬 파일 실행 (실패)

첫 번째는 기본적인 NodeJS라이브러리를 활용하여 python 파일을 실행시키는 경우다. 거두절미하고 코드부터 봐보자.

const express = require("express");
const cors = require("cors");
const app = express();
const bodyPaser = require("body-parser");
const axios = require("axios");
const helmet = require("helmet");
const spawn = require('child_process').spawn;

app.use(helmet());
app.use(cors());
app.use(bodyPaser.json());
app.post("/message", async (req, res) => {
  try {
    const message = req.body.info || "Null";
    if (message == "Null") {
      res.send("메세지를 정확히 입력해주세요!");
    } else {
        //파이썬 코드를 child.spawn()로 실행해준다. stdout.on으로 파이썬 프로그램에서 뭔가를 출력(print)한다면 그걸 캐치해서 가져온다. 
      const result = spawn('python', ['main.py', '매개변수1']);
      const data = result.stdout.on('data', function(data) {
    console.log(data.toString());
    });
      res.send(data);
    }
  } catch (e) {
    res.send(e);
  }
});

app.listen(8080, () => {
  console.log("App Started");
});

역시 실행이 되지 않는다. (파이썬에서 문장을 넘겨 그것을 분석하여 문장에 대한 answer을 print하는 코드를 작성하였다.)

오류를 보자면, 첫 번째로 라이브러리 호출도 되지 않고, python 함수 내에서 pandas로 읽어오는 .csv 파일 또한 경로가 확인되지 않는다는, 이상한 오류가 뜬다. 사실 VS Code로 실행해서 (평소에는 PyCharm 사용) 내가 venv 설정이라던지, 라이브러리 설정을 잘못 한 것일 수도 있지만, 일단 venv도 설정해보고, 라이브러리도 새로 설치해보고 해봤지만, 실행이 잘 되지 않는다. 결정적으로 무슨 이유에서인지 csv파일을 읽어오지 못한다. 아마 pandas 라이브러리가 제대로 호출되지 않아서 그런 듯 싶다.

PyCharm으로 NodeJS가 아닌 파이썬 코드만 실행시키면 물론 작동이 된다! 하지만 NodeJS 서버에서 파이썬의 결과값을 불러올 수 없다면 어차피 무용지물이기에 깔끔하게 포기. 왜 안된건진 추후에 리팩토링 해보고 이유 적어보도록 하겠다 :)

3. 두 번쨰 방법 : Python Flask 간이 서버를 만들어 처리 (성공)

두 번째 방법으로는, 그냥 파이썬 Flask 서버를 하나 여는것이다. 어차피 지금 만드는 웹 애플리케이션은 두 개 정도의 요청을 제외하고는 파이썬 코드를 실행시킬 일이 없다. 그냥 간단한 라우터 두 개만 넣어서 서버를 실행시켜놓고, 요청 오면 전달해주면 되지 않을까? 라는 생각이었고, 사실 생각이라기보단 이게 안 될 리가 없다. 이건 그냥 따로 파이썬을 실행시키는 방법이니…

const express = require("express");
const cors = require("cors");
const app = express();
const bodyPaser = require("body-parser");
const axios = require("axios");
const helmet = require("helmet");

app.use(helmet());
app.use(cors());
app.use(bodyPaser.json());
app.post("/message", async (req, res) => {
  try {
    const message = req.body.info || "Null";
    if (message == "Null") {
      res.send("메세지를 정확히 입력해주세요!");
    } else {
        //파이썬 서버 주소인 5000번 포트로 요청을 전달해준다.
      const result = await axios.post("http://localhost:5000", {
        info: message,
      });
      res.send(result.data);
    }
  } catch (e) {
    res.send(e);
  }
});

app.listen(8080, () => {
  console.log("App Started");
});

파이썬 코드

import pandas as pd
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import json
from flask import Flask, request

app = Flask(__name__)

def cached_model():
    model = SentenceTransformer('jhgan/ko-sroberta-multitask')
    return model

def get_dataset():
    df = pd.read_csv('wellness_dataset.csv')
    df['embedding'] = df['embedding'].apply(json.loads)
    return df
def result(value) :
    model = cached_model()
    df = get_dataset()
    user_input = value
    embedding = model.encode(user_input)
    df['distance'] = df['embedding'].map(lambda x: cosine_similarity([embedding], [x]).squeeze())
    answer = df.loc[df['distance'].idxmax()]
    return answer['챗봇']

@app.route('/', methods=['GET','POST'])
def request_main():
    value = request.json['info']
    abc = result(value)
    return abc
    //1번에서는 여기가 print(abc)였다! 물론 flask 코드도 없었다.

if __name__ == '__main__':
    app.run()

이건 역시나 에러없이 한번에 성공, 물론 귀찮은 점은 (로컬에서 실행할 땐) IDE 두 개 켜놓고 하나는 Flask 하나는 NodeJS React 실행시켜야 한 다는 점이긴 하지만, 솔직히 이게 가장 효율적이고 정석적인 방법이 아닐까 싶다.

4. 결론

분명히 간단한 코드라면 NodeJS상에서 바로 다른 확장자의 파일을 실행시켜도 되겠지만, 딥러닝처럼 복잡한 로직과 많은 라이브러리를 활용하는 함수의 경우에는 그냥 Flask서버를 하나 만들어 NodeJS서버와 통신을 시키거나, 클라이언트에서 직접 통신을 받거나 하는 편이 더 나은 것 같다. 실제로 엘리스 마지막 프로젝트에서 AI를 활용할때도 Flask서버를 따로 만들어 NginX 위에서 가동시켰었고.


Source

  • My Brain