[처음 배우는 딥러닝 챗봇] Python을 이용한 딥러닝 챗봇 제작기 (7)

3 minute read

챗봇 API 서버 구현

지금까지 만든 챗봇 엔진을 카카오톡이나 네이버톡톡에서 사용할 수 있도록 챗봇 API 서버를 구현해보자. 카카오톡이나 네이버톡톡과 챗봇 엔진이 통신하기 위해서는 REST API 방식으로 챗봇 서버를 구현해야 한다. 이 때 REST API는 웹 상에서 호출할 수 있도록 웹 어플리케이션 형태로 만들어야 하므로 Flask를 사용한다.

이제 챗봇 API 서버를 구현한다. /chatbot_api 디렉터리를 생성하고 이 디렉터리에 app.py 파일을 생성하여 다음과 같이 코드를 작성한다.

from flask import Flask, request, jsonify, abort
import socket
import json

# 챗봇 엔진 서버 접속 정보
host = "127.0.0.1"  # 챗봇 엔진 서버 IP 주소
port = 5050  # 챗봇 엔진 서버 통신 포트

# Flask 어플리케이션
app = Flask(__name__)


# 챗봇 서버와 통신
def get_answer_from_engine(bottype, query):
    # 챗봇 엔진 서버 연결
    mySocket = socket.socket()
    mySocket.connect((host, port))

    # 챗봇 엔진 질의 요청
    json_data = {
        'Query': query,
        'BotType': bottype
    }
    message = json.dumps(json_data)
    mySocket.send(message.encode())

    # 챗봇 엔진 답변 출력
    data = mySocket.recv(2048).decode()
    ret_data = json.loads(data)

    # 챗봇 엔진 서버 연결 소켓 닫기
    mySocket.close()

    return ret_data


# 챗봇 엔진 query 전송 API
@app.route('/query/<bot_type>', methods=['POST'])
def query(bot_type):
    body = request.get_json()

    try:
        if bot_type == 'TEST':
            # 챗봇 API 테스트
            ret = get_answer_from_engine(bottype=bot_type, query=body['query'])
            return jsonify(ret)

        elif bot_type == "KAKAO":
            # 카카오톡 처리
            pass

        elif bot_type == "NAVER":
            # 네이버톡톡 처리
            pass

        else:
            # 정의되지 않은 bot type인 경우 404 오류
            abort(404)

    except Exception as ex:
        # 오류 발생시 500 오류
        abort(500)


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

카카오톡과 네이버톡톡을 처리하는 부분은 과정을 나누기 위해 일단 구현하지 않았다.

챗봇 API 서버에 카카오톡 연동

챗봇 API 서버와 카카오톡을 연동하기 위해 API 서버 프로토콜을 정의해야 한다. 이 때 프로토콜을 카카오톡에서는 스킬이라고 부른다.

카카오 스킬 템플릿을 생성하는 모듈을 구현한다. /chatbot_api 디렉터리에 KakaoTemplate.py 파일을 생성하여 다음과 같이 코드를 작성한다.

class KakaoTemplate:
    def __init__(self):
        # 템플릿 버전
        self.version = "2.0"

    # 단순 텍스트 출력 요소
    def simpleTextComponent(self, text):
        return {
            "simpleText": {"text": text}
        }

    # 단순 이미지 출력 요소
    def simpleImageComponent(self, imageUrl, altText):
        return {
            "simpleImage": {"imageUrl": imageUrl, "altText": altText}
        }

    # 사용자에게 응답 스킬 전송
    def send_response(self, bot_resp):
        responseBody = {
            "version": self.version,
            "template": {
                "outputs": []
            }
        }

        # 이미지 답변이 텍스트 답변보다 먼저 출력됨
        # 이미지 답변이 있는 경우
        if bot_resp['AnswerImageUrl'] is not None:
            responseBody['template']['outputs'].append(
                self.simpleImageComponent(bot_resp['AnswerImageUrl'], ''))

        # 텍스트 답변이 있는 경우
        if bot_resp['Answer'] is not None:
            responseBody['template']['outputs'].append(
                self.simpleTextComponent(bot_resp['Answer']))

        return responseBody

또한 기존에 생성했던 /chatbot_api/app.py 파일에 카카오톡 스킬 처리 부분을 추가한다.

# 카카오톡 처리
body = request.get_json()
utterance = body['userRequest']['utterance']
ret = get_answer_from_engine(bottype=bot_type, query=utterance)

from KakaoTemplate import KakaoTemplate
skillTemplate = KakaoTemplate()
return skillTemplate.send_response(ret)

챗봇 API 서버에 네이버톡톡 연동

카카오톡과 마찬가지로, 챗봇 API 서버와 네이버톡톡을 연동하기 위해 API 서버 프로토콜을 정의해야 한다.

네이버톡톡 응답 이벤트를 생성하는 모듈을 구현한다. /chatbot_api 디렉터리에 NaverEvent.py 파일을 생성하여 다음과 같이 코드를 작성한다.

import requests, json


class NaverEvent:
    def __init__(self, authorization):
        self.authorization_key = authorization

    # 텍스트 컨텐트 출력 요소
    def textContentComponent(self, text):
        return {
            "textContent": {
                "text": text
            }
        }

    # 이미지 컨텐트 출력 요소
    def imageContentComponent(self, imageUrl):
        return {
            "imageContent": {
                "imageUrl": imageUrl
            }
        }

    # 보내기 API로 메시지 전송
    def send_message(self, user_key, component):
        headers = {
            'Content-Type': 'application/json;charset=UTF-8',
            'Authorization': self.authorization_key,
        }

        data = {
            "event": "send",
            "user": user_key,
        }
        data.update(component)

        # 보내기 API 호출
        message = json.dumps(data)  # JSON 문자열 변경
        return requests.post(
            'https://gq.talk.naver.com/chatbot/v1/event',
            headers=headers,
            data=message)

    # 사용자에게 응답 전송
    def send_response(self, dst_user_key, bot_resp):
        # 이미지 답변이 텍스트 답변보다 먼저 출력됨
        # 이미지 답변이 있는 경우
        if bot_resp['AnswerImageUrl'] is not None:
            image = self.imageContentComponent(bot_resp['AnswerImageUrl'])
            self.send_message(user_key=dst_user_key, component=image)

        # 텍스트 답변이 있는 경우
        if bot_resp['Answer'] is not None:
            text = self.textContentComponent(bot_resp['Answer'])
            self.send_message(user_key=dst_user_key, component=text)

        return json.dumps({}), 200

또한 기존에 생성했던 /chatbot_api/app.py 파일에 네이버톡톡 이벤트 처리 부분을 추가한다.

# 네이버톡톡 처리
body = request.get_json()
user_key = body['user']
event = body['event']

from NaverEvent import NaverEvent
authorization_key = '<보내기 API 인증키>'
naverEvent = NaverEvent(authorization_key)

if event == "open":
    # 사용자가 채팅방에 들어왔을 때 처리
    print("채팅방에 유저가 들어왔습니다.")
    return json.dumps({}), 200

elif event == "leave":
    # 사용자가 채팅방에서 나갔을 때 처리
    print("채팅방에서 유저가 나갔습니다.")
    return json.dumps({}), 200

elif event == "send":
    # 사용자가 챗봇에 send 이벤트를 전송했을 때
    user_text = body['textContent']['text']
    ret = get_answer_from_engine(bottype=bot_type, query=user_text)
    return naverEvent.send_response(user_key, ret)

출처

조경래 님이 집필하신 처음 배우는 딥러닝 챗봇 교재를 참고하여 글을 작성하였다.

예제 또한 저자 분의 Github 에서 발췌하였다.

Leave a comment