REST API를 파이프라인하여 새로운 융합 REST API 만들기 (ConvergedServingEndToEndExample)


본 예제에서는 사용자가 프로그래밍한 Python 함수를 KSB Dockerize를 이용하여 REST API로 만들고, 이러한 API 들을 연결하여 서빙하는 융합서빙 예제를 설명합니다.
KSB Dockerize 라이브러리는 사용자가 프로그래밍한 Python 함수를 Docker 이미지로 자동 변환할 뿐만 아니라 REST API 기능을 자동으로 추가하여, 사용자 Python 함수로 입력 데이터를 보내고 결과를 받을 수 있게 합니다.

입력 데이터 준비하기

본 예제에서는 다음과 같은 챗봇 시나리오를 가정합니다.

  1. 입력한 문장의 topic 분류
  2. topic이 일상적 대화일 경우, 일상적 대화들을 학습한 모델로 응답 문장 생성
    topic이 여행과 관련된 대화일 경우, 여행 관련 대화들을 학습한 모델로 응답 문장 생성

따라서 topic 분류 모델(이하 classify로 칭함), 일상적 대화들을 학습한 모델(이하 chitchat으로 칭함), 여행 관련 대화들을 학습한 모델(이하 travel로 칭함)이 필요합니다. 이러한 모델들을 KSB Dockerize를 이용하여 프레임워크에서 서빙하기 위해 Python 모듈 사용하기 (KSB Dockerize) 매뉴얼에서 제공하는 방법대로 base.pymain_func을 생성해야 합니다.

사용자 파이썬 코드 업로드

Host PC의 /home/csle/ksb-csle/examples/pyModules/ChatbotServing 폴더에 있는 사용자가 프로그래밍한 파이썬 함수를 HDFS repository에 웹툴킷을 이용하여 업로드 합니다.
dataset/pyModules 위치에 ChatbotServing 폴더를 업로드 합니다.

코드 업로드

파이썬 코드가 아래 폴더 구조로 업로드 되어야 합니다. KSB Dockerize를 이용하기 위해서 __init.py 파일과 base.py 파일을 작성합니다. base.pymain_func 이라는 함수를 포함하고 있어야 합니다. KSB Dockerize 라이브러리는 이 main_func을 불러 수행합니다.

코드 업로드

다음은 chitchat 폴더 내의 base.pymain_func 을 보여줍니다.

def main_func(x):

    # get input
    input = x
    text = tune_text(input)

    # call your function
    output_text = predict(text)

    return str(output_text)

워크플로우 생성하기

워크플로우 편집 화면에서 워크플로우를 작성합니다. 본 예제에서는 네 개의 엔진을 생성합니다.

속성 비고
name ConvergedServingEndToEndExample 워크플로우 이름
description 융합서빙 예제 워크플로우를 설명하는 글
isBatch false 융합서빙을 위한 워크플로우 이므로, false 로 지정
verbose false 디버깅을 위해 로그정보를 보고자할 경우, true 로 지정
순번 엔진 Type NickName RunType 설명
1 OnDemandExternalServing ClassifyDockerizeEngine 즉시실행 classify 함수 Dockerize
2 OnDemandExternalServing ChitchatDockerizeEngine 즉시실행 chitchat 함수 Dockerize
3 OnDemandExternalServing TravelDockerizeEngine 즉시실행 travel 함수 Dockerize
4 OnDemandPipeServing ChatbotServingEngine 즉시실행 API들을 연결하여 챗봇 서빙

첫 번째 엔진 작성하기

topic 분류 모델(classify) 을 구현한 파이썬 코드를 Dockerize 하고 REST API 로 만들기 위해 OnDemandExternalServing엔진을 선택합니다. 본 예제의 OnDemandExternalServing 엔진은 Runner 만 가집니다.

Runner

PyContainerRunner를 선택하고 아래표와 같은 속성을 지정합니다.

field value 설명
port 18001 REST API 포트 번호
imgName classify_image 생성할 도커 이미지 이름
codePath dataset/pyModules/ChatbotServing/classify 파이썬 코드가 있는 경로

두 번째 엔진 작성하기

일상적 대화들을 학습한 모델(chitchat) 을 구현한 파이썬 코드를 Dockerize 하고 REST API 로 만들기 위해 OnDemandExternalServing엔진을 선택합니다. 본 예제의 OnDemandExternalServing 엔진은 Runner 만 가집니다.

Runner

PyContainerRunner를 선택하고 아래표와 같은 속성을 지정합니다.

field value 설명
port 18002 REST API 포트 번호
imgName chitchat_image 생성할 도커 이미지 이름
codePath dataset/pyModules/ChatbotServing/chitchat 파이썬 코드가 있는 경로

세 번째 엔진 작성하기

여행 관련 대화들을 학습한 모델(travel) 을 구현한 파이썬 코드를 Dockerize 하고 REST API 로 만들기 위해 OnDemandExternalServing엔진을 선택합니다. 본 예제의 OnDemandExternalServing 엔진은 Runner 만 가집니다.

Runner

PyContainerRunner를 선택하고 아래표와 같은 속성을 지정합니다.

field value 설명
port 18003 REST API 포트 번호
imgName travel_image 생성할 도커 이미지 이름
codePath dataset/pyModules/ChatbotServing/travel 파이썬 코드가 있는 경로

네 번째 엔진 작성하기

여기에서는 하나 이상의 REST API들을 연결하여 상위의 REST API를 제공하기 위한 엔진을 정의합니다. 이를 위해서 융합서빙엔진을 정의하기 위한 과정을 설명합니다.
먼저 융합서빙엔진을 구성하기 위한 엔진컨터이너로서 OnDemandPipeServing 엔진컨테이너를 선택합니다. 참고로 OnDemandPipeServing 엔진은 REST API를 통해서 request를 받아 일련의 오퍼레이터를 거치면서 처리한 결과를 response에 실어서 보냅니다. 따라서 데이터를 입출력하기 위한 Reader 와 Writer는 별도로 필요로 하지 않습니다.

Controller

하나 이상의 REST API를 하나의 로직으로 연결하여 서빙하기 위한, 하나 이상의 오퍼레이터들의 호출흐름을 제어하기 위한 컨트롤러로서 OnDemandCompositeServingRestfulController를 선택합니다.
(OnDemandCompositeServingRestfulController는 restfulActorName과 uri정보를 설정할 수 있으며, 본 예제에서는 별도의 설정없이 기본값을 사용합니다. 요청 uri를 변경하고자 할 경우, 값을 입력하면 됩니다.)

Runner

REST 서비스를 실행하기 위한 Runner로써 ServingPipeRunner를 선택합니다. 사용자가 챗봇 서비스를 받기 위한 REST API에 대한 접근 주소와 포트번호를 설정합니다. (아래 표 참조)

field value 설명
host 0.0.0.0 융합 서빙 주소
port 18080 융합 서빙 포트 번호

Operator

본 챗봇 예제에서는 문장으로부터 topic을 분류하기 위한 REST API와 분류된 topic 내에서 문장에 대한 응답을 생성하는 REST API를 엮기 위해 총 3개의 오퍼레이터를 사용합니다.
각각의 오퍼레이터의 역할은 다음과 같습니다:

  1. RouteRestfulContextQueryPipeOperator
field value 설명
url http://SERVER_IP:18001 REST API 주소
method POST REST API 방식
header 아래의 표 참고

header 설정은 다음과 같이 합니다.

field value 설명
paramValue Content-Type
paramName text/plain; charset=utf-8
  1. RouteMappingPipeOperator
field value 설명
routeMap 아래의 표 참고

routeMap 설정은 [+] 버튼을 두 번 클릭하여 다음과 같이 합니다.

field value 설명
idx 0
route http://SERVER_IP:18002 '0' 인덱스값에 대한 호출할 REST API 주소
field value 설명
idx 1
route http://SERVER_IP:18003 '1' 인덱스값에 대한 호출할 REST API 주소
  1. OutputRestfulContextQueryPipeOperator
field value 설명
url http://SERVER_IP:18002 route 정보가 넘어오지 않을 경우 디폴트로 호출할 REST API 주소
method POST REST API 방식
header 아래의 표 참고

header 설정은 다음과 같이 합니다.

field value 설명
paramValue Content-Type
paramName text/plain; charset=utf-8


워크플로우 완성 화면

ksbuser@etri.re.kr 계정으로 로그인하면, 본 예제 워크플로우가 이미 만들어져 있는 것을 확인할 수 있습니다. 불러오기 메뉴를 통해 본 예제를 실행할 수 있습니다.

워크플로우 실행 및 모니터링하기

워크플로우 실행하기

워크플로우 편집기 화면 상단의 실행 버튼을 눌러서, 위에서 작성한 워크플로우를 실행합니다. REST API를 서빙하는 워크플로우 이므로 Batch 체크박스를 해제하고 Run 버튼을 클릭합니다.

워크플로우 모니터링 하기

KSB 웹툴킷 상단 메뉴의 Monitoring 탭을 클릭하면 Workflow 탭이 선택되어 있습니다. Workflow 탭 화면에서 실행한 워크플로우와 엔진의 동작 상태를 확인할 수 있습니다. 정상적으로 실행되어 Status 값이 Inprogress(실행중)인 것을 확인할 수 있습니다.

워크플로우 동작 상태 확인

Workflow History 탭을 선택하면 워크플로우가 동작하며 발생시킨 각 엔진의 로그 정보를 확인할 수 있습니다.

워크플로우 히스토리

클라이언트에서 융합 REST API 로 쿼리 요청하기

프레임워크에서 서빙하고 있는 융합 REST API (http://0.0.0.0:18080) 로 클라이언트에서 쿼리를 요청하는 방법은 다음과 같습니다.

◼ 약속된 Json 형태 : {"input" : "???"}
"input" 키워드와 함께 보내고자 하는 데이터를 {"input" : "???"} 형태의 Json 으로 보냅니다. 이 경우 응답도 json 으로 옵니다. 약속된 Json 형태로 쿼리를 요청하는 것을 권장합니다.

◼ 문자열 형태
보내고자 하는 데이터를 문자열로 보냅니다 (예를 들면, "aaa"). 이 경우 응답도 문자열로 옵니다.
문자열 형태로 쿼리를 보낼 경우, 사용자가 작성한 그대로의 문자열을 KSB Dockerize 라이브러리의 base.pymain_func 으로 보냅니다. (예를 들면, 'aaa' )
따라서 사용자 파이썬 코드에서는 아래와 같이 입력데이터를 읽을 수 있습니다.

def main_func(x):
    # In this example, x is Python string.
    input = x

    ...

클라이언트 프로그램 구현 가이드 (파이썬)

융합 REST API 로 쿼리를 보내는 클라이언트 프로그램을 파이썬으로 구현한 예제 코드입니다.

◼ 약속된 Json 형태 : {"input" : "???"}

import requests

url = 'http://0.0.0.0:18080'
userId = 'ksbuser@etri.re.kr'
query_str = '{0}/postQuery?userId={1}&password="pw"&key="key"'
query_str = query_str.format(url, userId)

# data_str = {"input": "hellow"}
# data_str = {"input": "{\"key1\":\"aaa\", \"key2\":\"bbb\", \"key3\":\"ccc\"}"}
data_str = {"input": '{"key1":"aaa", "key2":"bbb", "key3":"ccc"}'}

r = requests.post(query_str, json=data_str)
print('Status: ', r.status_code)
print('Response: ', r.text)

◼ 문자열 형태

import requests

url = 'http://0.0.0.0:18080'
userId = 'ksbuser@etri.re.kr'
query_str = '{0}/postQuery?userId={1}&password="pw"&key="key"'
query_str = query_str.format(url, userId)

data_str = 'I want to go LA'

r = requests.post(query_str, data=data_str)
print('Status: ', r.status_code)
print('Response: ', r.text)

융합서빙 서비스 확인하기

본 예제에서는 클라이언트로 Postman 프로그램을 활용하여 융합서빙 엔진이 제공하는 챗봇 서비스(융합 REST API)를 테스트 합니다. Postman을 실행하여 아래와 같이 설정합니다. (Postman 설명 바로가기)

Postman 설정

챗봇 서비스 확인하기


챗봇 서비스 확인하기

생성된 Docker 이미지 확인하기

커맨드 창에서 아래 명령어를 실행합니다.

docker container ls

아래 그림과 같이 Docker 이미지가 생성된 것을 확인할 수 있습니다.

Docker 이미지 생성

KSB Dockerize를 통해 생성된 REST API 동작 확인하기

커맨드 창에서 아래 명령어를 실행하여 KSB Dockerize를 통해 생성된 REST API 가 잘 동작하는 지 테스트할 수 있습니다.

curl -d '{"input": "TEXT"}' http://0.0.0.0:PORT

Docker 이미지 테스트

워크플로우 종료하기

KSB 웹툴킷 Monitoring 화면의 Workflow 탭에서, 현재 Status가 Inprogress인 ConvergedServingEndToEndExample 워크플로우의 정지() 버튼을 눌러 종료 시킵니다.

워크플로우 재실행 시 유의사항

동일한 워크플로우를 재실행하기 위해서 기존 생성된 chitchat_image, classify_image, travel_image 도커 이미지와 컨테이너를 지운 후 워크플로우를 재실행 합니다.

아래 명령어를 이용하여 Docker 이미지 목록을 확인합니다.

docker images

아래 명령어를 이용하여 Docker 컨테이너를 삭제합니다.

docker rm -f {IMAGE_ID}

아래 명령어를 이용하여 Docker 이미지를 삭제합니다.

docker rmi {IMAGE_ID}
csle@csle1:~$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
chitchat_image                  latest              054e56309341        2 hours ago         221MB
classify_image                  latest              a4fd33bd0ba6        2 hours ago         221MB
travel_image                    latest              6c3bff27b0f5        2 hours ago         221MB

csle@csle1:~$ docker rm -f chitchat_image classify_image travel_image
csle@csle1:~$ docker rmi chitchat_image classify_image travel_image