java에서 python 호출(java에서 외부 프로그램 실행하는 법)

byeol·2023년 2월 8일
0

java에서 python을 호출하는 방법은 Jython이용, ProcessBuilder를 이용하는 방법으로 크게 2가지

저는 ProcessBuilder에 대해서 설명해보려고 합니다.

파일 위치

먼저 생각해봐야할 것이 있습니다. 서버에 올렸을 때 저 python파일을 어디에 둬야할 것인가?

resources 폴더에 둬야하나?
일단 저는 이 방법이 잘못된 접근이었다는 것을 깨달았습니다.
저는 ProcessBuilder의 directory() 메서드를 통해서 저 python파일에 접근해야하기 때문에 python파일의 경로를 알아야합니다. (저 diretory메서드는 cd 명령어와 똑같은 기능을 합니다.) 그러나 jar 파일은 압축파일이기 때문에 내부의 경로는 알기 어렵습니다.
따라서 python파일은 jar파일과 분리해서 따로 서버에 올려야합니다.

.exe과 .py 파일

다음으로 python.py로 올릴 것인지 python.exe로 하여 py의 실행파일로 올릴 것인지에 대한 고민이 시작됩니다. exe는 python.py에 대한 배포파일이라고 생각하시면 됩니다. python이 설치되지 않은 환경에서 python을 실행시킬 수 있도록 해주는 것이기 때문입니다.
py파일을 exe로 바꿔주는 프로그램들이 있습니다. pyinstaller가 대표적입니다. 그러나 저는 계속 실패했기 때문에 그냥 py파일로 올렸습니다. 일단 py 자체로 올릴려면 서버에서 저 파일이 작동될 수 있도록 환경을 조성해주셔야 합니다. 따라서 서버에 python을 설치하고 pip를 통해서 python 패키지 라이브러리를 설치해주신 후에 서버에서 제대로 작동하는지 확인하는 작업이 필요합니다.

ProcessBuilder 코드

일단 다시 본론으로 돌아가서 ProcessBuilder를 통해서 어떻게 python파일을 불러올 것인가 이야기하겠습니다.

ProcessBuilder는 shell을 통해서 python파일을 실행합니다.

위와 같은 구조로 실행합니다.

package hello.chatbot.basic;

import hello.chatbot.basic.FileLink_Maker;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



public class PythonFile_Reader {
    private String path;
    //private File file;
    private String fileName;
    private String methodName;

    private Map<String,String> output = new HashMap<>();
    public PythonFile_Reader(String path, String fileName, String methodName) throws Exception {
        this.path = path;
        this.fileName = fileName;
        this.methodName = methodName;
        reader();
    }

    private Map<String,String> reader() throws Exception {

        StringBuilder input_result = new StringBuilder();
        StringBuilder output_result = new StringBuilder();
        StringBuilder error_result = new StringBuilder();
        String line;

        String module = fileName.substring(0, fileName.lastIndexOf('.'));
        //String command = "import " + module + "; " + module + "." + module + "." + methodName;
        String command = "import " + module + "; "+module+ "." + methodName;
        List<String> items = Arrays.asList("python3", "-c", command);
        // cmd 창에 python 호출을 위한 : import bert_chatbot; bert_chatbot.method(매개변수)

        ProcessBuilder pb = new ProcessBuilder(items);
        pb.directory(new File(path));
        Process p = pb.start();
        BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream(),"utf-8"));
        BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream(),"utf-8"));
        BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream(),"utf-8"));

        System.out.println();
        while ((line = in.readLine()) != null)
            input_result.append("\n").append(line);
       if (input_result.length() > 0)
           System.out.println(fileName + " : " + input_result);

        while ((line = out.readLine()) != null)
            output_result.append(" ").append(line);
        if (output_result.length() > 0)
           System.out.println("Output : " + output_result);

        while ((line = error.readLine()) != null)
            error_result.append(" ").append(line);
        if (error_result.length() > 0)
            System.out.println("Error : " + error_result);


        output = FileLink_Maker.fileLinkMaker(input_result);
        return output;
    }


    public Map<String,String> getOutput(){
        return output;
    }

}

저의 코드는 위와 같습니다. 이 코드는 python파일의 메서드에 매개변수를 넣어서 호출하기 위한 코드입니다.

python 코드는 아래와 같습니다.

# -*- coding: utf-8 -*-
"""Sentence Transformer를 이용한 챗봇 구현.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/11_7XmcSqs3KcXrlijl4BHzrPQ8xMocIt
"""
import os.path
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding='utf-8')



import openpyxl
import pandas as pd

from sentence_transformers import SentenceTransformer

file_path = "train_data_min.xlsx"

abs_file_path = os.path.abspath(file_path)

train_data = pd.read_excel(abs_file_path)
train_data.head()

model = SentenceTransformer('sentence-transformers/xlm-r-100langs-bert-base-nli-stsb-mean-tokens')

train_data['embedding'] = train_data.apply(lambda row: model.encode(row.Q), axis=1)

train_data


from numpy import dot
from numpy.linalg import norm

def cos_sim(A, B):
    return dot(A, B)/(norm(A)*norm(B))

def return_similar_answer(input):
    embedding = model.encode(input)
    train_data['score'] = train_data.apply(lambda x: cos_sim(x['embedding'], embedding), axis=1)
    return print(train_data.loc[train_data['score'].idxmax()]['A'])

✔️ 마지막으로 경로에 대해서 이야기해보려고 합니다.
중요한 것은 서버에서 저 파이썬 파일을 어떻게 찾을 것인가입니다. 저는 파이써 파일을 jar파일과 같은 경로에 두었기 때문에 아래와 같이 경로를 넘겨줬습니다.

  String path = new File("").getAbsolutePath();
profile
꾸준하게 Ready, Set, Go!

0개의 댓글

관련 채용 정보