Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to call python model from server with Spring #58

Open
hwanld opened this issue Nov 15, 2022 · 0 comments
Open

How to call python model from server with Spring #58

hwanld opened this issue Nov 15, 2022 · 0 comments

Comments

@hwanld
Copy link
Member

hwanld commented Nov 15, 2022

Spring 서버 내부에서 Python을 불러올 수 있는 방법 중, 저희가 사용할 수 있을법한 방안들은 다음과 같습니다.
관련 레퍼런스 : https://www.baeldung.com/java-working-with-python

  1. Apache Commons Exec ()
  2. ProcessBuilder
  3. WebServer (Python HTTPServer 라이브러리 활용)

2번 ProcessBuilder의 경우 Spring 라이브러리 내부에서 자체적으로 지원하는 방법이고, 1번 Apache Commons Exec의 경우 2번의 방법을 활용해서 조금 더 편리하게 사용할 수 있는, Apache에서 지원하는 라이브러리 입니다.

사실 3번 WebServer 를 만들어서 사용하는 방법이 제일 적합하지만, learning curve가 높고 남은 시간이 여유롭지 못하다는 점에서 1번의 방법으로 우선 구현해 보고자 합니다.


Server side Scenario

앞서 말씀드린 바와 같이, Apache Commons Exec 를 사용해서 python 파일을 실행하고자 합니다.

package com.entrip.service

import com.entrip.socket.InfoWebSocketSessionStatsInfo
import com.google.common.collect.ImmutableList
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.apache.commons.exec.PumpStreamHandler
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.io.ByteArrayOutputStream

@Service
class TravelRecommendService {

    private var logger : Logger = LoggerFactory.getLogger(TravelRecommendService::class.java)

    fun call_python() {
        val command : Array<String> = arrayOf("python3", "/Users/donghwan/pythonWorkSpace/main.py", "10", "20")
        try {
            exec_python(command)
        } catch(e : Exception) {
            e.printStackTrace()
        }
    }

    fun exec_python (command : Array<String>) {
        var commandLine : CommandLine = CommandLine.parse(command[0])

        for (i : Int in 1..command.size-1)
            commandLine.addArgument(command[i])

        val outputStream = ByteArrayOutputStream()
        val pumpStreamHandler = PumpStreamHandler(outputStream)

        val executor = DefaultExecutor()
        executor.streamHandler = pumpStreamHandler

        var result : Int = executor.execute(commandLine)
        logger.info("result : $result")
        logger.info("output : ${outputStream.toString()}")

    }
}
import sys

def sum(v1,v2):
    result = int(v1) + int(v2)
    print(result)

def main(argv):
    sum(argv[1], argv[2])

if __name__ == "__main__":
    main(sys.argv)

원리는 다음과 같습니다.

  1. 콘솔 창에다가 python3 /Users/donghwan/pythonWorkSpace/main.py 10 20 와 같이 실행하면, 해당 경로에 존재하는 py 파일에 전달 인자로 10, 20을 넘겨줌과 동시에 실행될 것 입니다. (현재 테스트하는 로컬의 경우 Mac OS이기때문에 명령어가 python3 입니다만, 윈도우에선 python일 수도 있습니다.)

  2. 이를 그대로 apache common exec 라이브러리를 적용해서 spring에서 실행합니다.

  3. 실행 결과는 outputStream 에 저장됩니다. .py 에서 실행한 결과를 print 하면, print 되는 콘솔 창의 결과가 outputStream 에 저장된다고 보시면 됩니다. 서버에서는 해당 결과를 String으로 다시 반환해서 가져올 수 있습니다.

  4. 이때 서버로 전달되는 String 이 특정 템플릿을 따른다면 (예를 들어서, 3 5 Hello 라면 int int string) 서버에서는 3 5 Hello 라는 문자열을 공백을 기준으로 split 한 뒤, 각각의 자료형에 맞게 다시 형변환 해서 사용할 수 있습니다.


Server side 요구사항

하나의 .py 파일에 특정 값들을 전달하면, 결과 값을 print 해주셔야 합니다.

하나의 print() 함수는 하나의 개행 문자를 포함합니다. 만약 여러 개의 결과를 print 하셔야 한다면, 한 줄에 유의미한 결과를 묶어서 출력해 주시면 됩니다. 아래 코드 예시 참고해주세요.

def main():
    # 결과 값은 다음과 같이 여러 개여도 상관 없지만 특정 양식을 반드시 따라야 합니다.
    print("경기도 수원시 장안구 수원화성 유적지 1234")
    print("경기도 수원시 장안구 방화수류정 유적지 1072")
    print("경기도 가평군 가평읍 가평빠지 액티비티 2983")

모델의 실행을 위해서 서버에서 사용자의 정보를 전달해야 할텐데, input 함수를 사용해서 입력할 수가 없습니다. 따라서, 아래 코드와 같이 어떤 함수의 입력 값이 다음과 같이 주어진다고 가정하고 함수화 부탁드릴게요. (sys.argv 를 사용해서 코드를 작성해 주시면 더욱 좋을 것 같습니다!)

import sys

def sum(v1,v2):
    result = int(v1) + int(v2)
    print(result)

def main(argv):
    sum(argv[1], argv[2])

if __name__ == "__main__":
    main(sys.argv)

위와 같은 코드를 작성했다고 했을 때, 콘솔 (cmd) 에서 실행 시 다음과 같이 결과가 나와야 합니다.

# 명렁어 (python3 .py파일 위치 전달인자1 전달인자2 ,,,)
python3 /Users/donghwan/pythonWorkSpace/main.py 10 20
# 출력값
30

@hwanld hwanld changed the title How to use python model inside the server side with spring framework How to call python model from server with Spring Nov 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant