먹고 기도하고 코딩하라

파이썬 장고 기반 카카오톡 API 챗봇 -> i 오픈빌더 챗봇으로 변경하기 본문

개발일지

파이썬 장고 기반 카카오톡 API 챗봇 -> i 오픈빌더 챗봇으로 변경하기

사과먹는사람 2020. 2. 21. 23:39
728x90
728x90

 

이 포스팅은 원래 카카오톡에서 API로 채팅봇을 운영하던 사람이 i 챗봇에서 스킬을 이용해서 똑같이 운영할 수 있는 간단한 방법을 알리는 포스팅이다. 참고로 여기서는 Django 를 이용한 앱만 설명하며, Flask는 다루지 않는다.

나는 원래 API 식으로 만들었는데 1년 좀 넘게 운영하다가 API형이 종료될 쯤에 부랴부랴 i 챗봇으로 갈아탔다. 과정이 고될 것 같았는데 생각보다 쉽고 편했다.

 

 

 

1. views.py 수정하기

일단 다른 건 바꿀 필요가 없으며 views.py 만 잘 수정해 주면 된다. i 챗봇에 맞게 바꾸기 전의 API 식일 때의 제일 간단한 views 파일을 살펴보자. 그 중에서도 깔끔하게 message 함수를 보자. 함수 이름이 message가 아닐 수도 있을 텐데, 뭐가 됐든 이 역할을 하는 함수를 수정하면 된다.

 

def message(request):
  answer = ((request.body).decode('utf-8'))
  return_json_str = json.loads(answer)
  return_str = return_json_str['content']
    
  if return_str == 'test':
    return JsonResponse({
      'message': {
        'text': 'Result: Test Success'
      },
      'keyboard': {
        'type': 'buttons',
        'buttons': 'Going back'
      }
    })

 

HTTP Request의 body를 utf-8로 디코딩해 JSON을 빼낸다. 그 중에서도 ['content']가 사용자가 키보드가 됐든 버튼이 됐든 뭐로든 입력한 바로 그 텍스트가 된다. 여기서는 return_str 이 바로 그 텍스트를 담는 변수이다.

if 문은 사용자가 test라고 입력했을 때 챗봇이 'Result: Test Success'라고 뱉어주며 'Going back'이라는 버튼을 올려주는 역할을 한다. else 문도 하려다가 최대한 간단하게 하려고 그냥 빼버렸다.

이게 예전에는 됐지만 지금은 어림도 없다. 새롭게 바꿔야 한다. 그러면 어떻게 바꿔야 할까? 일단 i 챗봇 버전으로 새롭게 바꾼 버전의 코드를 보고 난 다음에 문서를 보면서 하나하나 뜯어보자.

 

def message(request):
  answer = ((request.body).decode('utf-8'))
  return_json_str = json.loads(answer)
  return_str = return_json_str['userRequest']['utterance']
  
  if return_str == 'test':
    return JsonResponse({
      'version': "2.0",
      'template': {
        'outputs': [{
          'simpleText': {
            'text': 'Result: Test Success'
          }
        }],
        'quickReplies': [{
          'label': 'Going back',
          'action': 'message',
          'messageText': 'Going back'
        }]
      }
    })

 

일단 달라진 점을 보자. 처음 두 줄은 다를 게 없지만, 세 번째 줄은 ['content']에서 ['userRequest']['utterance']로 바뀌었다. 그 다음, JsonResponse 객체 형식이 좀 많이 달라졌다. 기존에는 text를 출력하고 싶었다면 단순히 message 안에 text를 key로 하고 그 다음에 value로 하고 싶은 말을 쓰면 됐는데, version이며 template이며 outputs에 simpleText, 그 안의 text까지 들어가야 그 다음에 하고 싶은 말을 쓸 수 있다. 그리고 버튼을 올리는 건 'keyboard'에서 형식을 정하는 게 아니라 'quickReplies'에서 정해야 한다. 

이제 문서를 볼 때가 됐다. 알짜배기는 여기 다 모여 있다. 시나리오나 엔티티, 블록 같은 것들은 실제로 카카오 i 빌더 홈페이지에서 만들어야 할 때 다시 보면 되고, 일단은 여기 먼저 보자. 추가로, 옛날 카카오 플러스친구 시절 스펙을 살펴보면 뭐가 달라졌는지 더 자세히 확인할 수 있으므로 추가 확인을 원한다면 살펴보자.

 

 

 

2. 달라진 점 살펴보기

2-1. Request body 까는 방법

함께 살펴보자. 먼저 세 번째 줄이 왜 ['userRequest']['utterance']까지 들어가야 하는지 보자. 일단 옛날 스펙과 지금 스펙을 비교해보자.

 

 

구버전
새버전

 

 

옳거니, 옛날의 content가 자동응답 명령어의 텍스트 및 미디어 파일이고, 지금 payload 응답의 userRequest 필드 안의 utterance가 봇 시스템에 전달된 사용자의 발화이다. 이건 쉽게 풀어 쓰면 사용자가 키보드로 입력한 입력이나 다름없다. 그러므로 구버전의 content가 곧 새 버전의 utterance나 다름없는 것이다.

return_str = return_json_str['content'] #구버전
return_str = return_json_str['userRequest']['utterance'] #새버전

 

 

 

 

2-2. JsonResponse 변화 (message-outputs, keyboard-quickReplies)

그럼 응답으로 돌아가보자. JsonResponse는 왜 keyboard, message 구성에서 version, template(그것도 outputs 안에 또 뭔가가 있는!), quickReplies으로 나뉘어야 했던 걸까? 이 부분도 비교해보자.

 

 

구버전

 

 

 

새버전

 

일단 version은 스킬 응답의 버전을 나타내기 위한 것이고, 없다면 구 버전으로 간주하기 때문에 필요한 것이다. template은 뭘까? 스킬 응답의 출력이라는 것은 구버전의 message와 같은 기능을 하는 것이다. template이 그래서 뭔데? 건너뛰어서 자세히 보기를 하면 SkillTemplate 정보를 볼 수 있다.

 

 

 

 

template은 outputs과 quickReplies 두 개를 포함한다(위의 코드의 괄호를 잘 보면 이것이 사실임을 알 수 있다). 다시 말해 구버전 식으로 말하면 message와 keyboard를 모두 아우른다.

 

# 구버전
return JsonResponse({
  'message': {
    'text': ''
  }
})

# 신버전
return JsonResponse({
  'version': "2.0",
  'template': {
    'outputs': [{
      'simpleText': {
        'text': ''
      }
    }]
  }
})

 

위의 코드가 제일 기본이 되는 것이다. 일부러 text의 value도 비우고 뼈대만 남겼다. 보다시피, version은 구버전과 비교되는 것 없는 신버전에 그냥 덜렁 생긴 것이고, template의 outputs는 message와 똑같은 역할을 한다. 참고로 구버전의 Response에서 message는 필수이지만 keyboard는 필수가 아니며, 신버전의 Response template에서도 outputs는 필수이지만 quickReplies는 필수가 아니다.

 

 

 

 

2-2-1. Message(구버전) - outputs(신버전)

 

구버전
새버전

 

 

구버전의 message가 outputs가 똑같다고 보면 된다. message는 사용자가 어떤 것을 입력했을 때 그 값에 따라 챗봇에서 뭔가 응답해주는 건데, 그 타입은 text, photo, message_button 이 있었다. 말그대로 텍스트, 사진, 링크 버튼이다. text는 신버전에서 simpleText, photo는 simpleImage가 됐다. 그 밑에 Card들은 뭐지? 졸개들인가? 그건 아니고 신버전에 들어오면서 상품 브랜드에서 카카오톡 채널을 운영한다는 사실을 의식했는지 조금 밋밋한 텍스트와 이미지에서 조금 있어보이는(?) 카드 형식을 끼워넣은 것이다. 특히 커머스 카드나 basicCard 케로셀 형식의 경우 정말 있어보이게 써먹을 수 있다.

 

 

 

 

2-2-2. Keyboard(구버전) - quickReplies(신버전)

 

구버전
새버전

 

 

구버전의 keyboard button은 새 버전의 quickReplies와 같다. 다만 생긴 게 조금 다르다. quickReplies는 모서리가 둥근 직사각형 버튼이 나오는 반면 keyboard button은 채팅창 밑에서 올라오는 것처럼 생긴 것이다. 새 버전에서도 그걸 구현할 수는 있지만 굳이..? 싶다.

 

# 구버전
return JsonResponse({
  'message': {
    'text': 'text!'
  },
  'keyboard': {
    'type': 'buttons',
    'buttons': 'button!'
  }
})

# 신버전
return JsonResponse({
  'version': "2.0",
  'template': {
    'outputs': [{
      'simpleText': {
        'text': 'text!'
      }
    }],
    'quickReplies': [{
      'label': 'button!',
      'action': 'message',
      'messageText': 'button!'
    }]
  }
})

 

두 코드는 quickReplies 버튼 모양이 조금 다르게 생겼다는 걸 빼고는 똑같은 효과를 갖는 코드이다. 좀 길어지긴 했지만 어쩌랴? 엿장수 맘이다. 이것이 공식에서 제공하는 기본 사용법이다.

 

 

 

 

3. 스킬 적용하기

자, 이제 틀린 그림 찾기와 분석은 끝났다. 이제 실제로 스킬을 적용하는 일만 남았다. 어렵지 않다. 일단 i 빌더 페이지에 로그인해서 챗봇 페이지에 들어간다(미리 챗봇은 만들어놨을 거라고 생각하며...). 미리 설정에서 기존에 가지고 있는 카카오톡 친구와 연동하는 것은 어렵지 않으니 생략한다. 여튼 연동까지 하고, 시나리오 탭에 들어가면 아래와 같은 화면이 보인다.

 

 

 

내가 1월부터 쓰고 있던 챗봇이라 이미 시나리오들이 몇 개 있지만, 다른 건 무시하자. 파란색 시나리오 버튼을 누르면 시나리오가 하나 생긴다. 시나리오 등의 자세한 설명이 보고 싶다면 아까 그 설명서를 다시 보자. 시나리오를 만들면 '시나리오 01' 하면서 시나리오가 생기는데, 나는 이 시나리오 이름을 '테스트 시나리오'로 바꿔놨다. 시나리오 안에는 블록이 있어야 해서 지금 블록 이름 입력해 달라고 빨갛게 나오는 거다. 블록 추가를 해서 블록도 하나 만들자. 나는 이름을 '테스트 블록'이라고 짓겠다. 이제 이 views.py를 실험해보려 한다. 내 코드는 다음과 같다.

 

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json

# Create your views here.
def keyboard(request):
    return JsonResponse({
        'type': 'text'
    })

@csrf_exempt
def message(request):
    answer = ((request.body).decode('utf-8'))
    return_json_str = json.loads(answer)
    return_str = return_json_str['userRequest']['utterance']

    if return_str == '테스트':
        return JsonResponse({
            'version': "2.0",
            'template': {
                'outputs': [{
                    'simpleText': {
                        'text': "테스트 성공입니다."
                    }
                }],
                'quickReplies': [{
                    'label': '처음으로',
                    'action': 'message',
                    'messageText': '처음으로'
                }]
            }
        })

 

내가 기대하는 효과는 '테스트'라고 입력하면 "테스트 성공입니다" 라는 말과 함께 '처음으로'라는 버튼이 나오는 것이다. 이렇게 나오게 하려면 일단 블록을 저장한 다음 스킬 탭으로 가서 스킬 생성을 하면 된다. 대충 스킬 이름을 정한 다음, url에는 갖고 있는 서버의 IP 주소를 적고 /message까지 붙여준다(이유는 다른 포스팅에서 설명함). 그러고 나서 저장하면 된다. ver. 1로 저장된다.

 

 

다시 시나리오 탭으로 돌아가 아까 그 테스트 시나리오의 테스트 블록을 연다. 파라미터 설정 옆의 두 개의 option에서 아까 만든 스킬을 선택하고 버전 선택을 한다. 봇 응답에는 스킬 데이터 사용을 선택한다. 그러고 나서 블록을 저장한다. 너무나 쉽다!

그리고 배포 탭에서 스킬을 배포를 해줘야 한다!! 이 부분을 까먹으면 적용이 되지 않는다. 방금 다시 테스트를 해보는데 배포를 안 하니 적용이 되지 않는다.

 

 

내가 테스트용으로 만들어둔 카카오톡 채널과 연결해서 실험해봤다.

 

 

 

 

보다시피 제대로 된다! 안 된다면 뭔가 문제가 있는 것이다. 기존 버전에서 잘 됐고, message 함수 외에 아무것도 고치지 않았다면 인덴트 문제거나 오타 문제일 확률이 아주 높으므로 python3 views.py를 꼭 해보자.

 

 

 

이렇게 구버전과 새 버전의 기본적인 Request 까기와 Response하는 JsonResponse 변화를 살펴봤다. 이것으로 포스팅을 마친다.

고맙습니다 ^^

 

 

Reference

카카오 i 오픈빌더 도움말

 

 

728x90
반응형
Comments