Facebook Messenger API + Flask 비망록 [실장편 1]

도입편 에서 계속, 일단 간단한 앵무새 반환에서.

pymessenger 이라는 써드파티제의 라이브러리도 있는 것 같지만, 2016년부터 갱신되어 있지 않기 때문에, 공부도 겸해 이번은 스스로 실장한다.

POST 요청 내용



자세한 내용은 여기 : Webhook Events, Send API

전부 읽는 것은 귀찮기 때문에 필요한 부분만 사용하면서 실장해 간다.

API의 webhook 본체는 이런 느낌. 우선 사용자가 앱에 제출하면
{
  'object': 'page',
  'entry': [
    {
      'id': '<FBページのID>',
      'time': 1607767826503,
      'messaging': [
        {
          'sender': {
            'id': '<FBユーザーのID>'
          },
          'recipient': {
            'id': '<FBページのID>'
          },
          'timestamp': 1607767826302,
          'message': {
            'mid': 'xxxxxxxxxxxxxxxxxxxxx',
            'text': 'hello'
          }
        }
      ]
    }
  ]
}

자신의 페이지측의 ID는 이미 알고 있으므로 취득할 필요는 없다. 즉 ['entry']['messaging'] 안의 ['sender']['id']['message']['text'] 를 꺼내면 된다. 여기서 ['entry'] 는 이벤트 배열, ['entry']['messaging'] 는 메시지 배열이므로 for 처리 등이 필요합니다. 라고 해도, 시도한 한은 미수신의 메시지가 모여 있어도 동시에 정리해 보내지는 것은 아니고, 1건뿐이었다.

또한 메시지 직후에 거의 동일한 형식으로 워터 마크가 전송됩니다. 여기에는 ['message'] 대신 ['delivery']가 있습니다.
{
  'object': 'page',
  'entry': [
    {
      'id': '<FBページのID>',
      'time': 1607767829878,
      'messaging': [
        {
          'sender': {
            'id': '<FBユーザーのID>'
          },
          'recipient': {
            'id': '<FBページのID>'
          }, 
          'timestamp': 1607767829912,
          'delivery': {
            'mids': [
               'xxxxxxxxxxxxxxx'
             ],
             'watermark': 1607767827879
          }
        }
      ]
    }
  ]
}

한편 회신용의 내용은 이것만으로 충분. 이것에 발행한 토큰을 access_token 로서 파라미터로 주고 헤더에 Content-Type: application/json 를 지정하면 OK.
{
  "recipient": {"id": "<FBユーザーのID>"},
  "message": {"text": "hello"}
}

되돌아 오는 구현



마지막 코드에 POST 부분을 추가합니다. 나중에 생각해, send_message() 라는 함수를 나누어 만들어 둔다.

덧붙여서 여기에서 취득한 userID 라는 것은, Facebook 계정의 ID와는 전혀 별개의 것으로, Page-scoped ID 라고 불리는 것 같다. 자신의 ID를 알기 위해서도 회신문 안에 묻는다.
import os, json
from flask import Flask, request
from dotenv import load_dotenv
load_dotenv() # 環境変数ファイル .env の読み込み
ACCESS_TOKEN = os.getenv('ACCESS_TOKEN') # .env に記載
VERIFY_TOKEN = os.getenv('VERIFY_TOKEN') # .env に記載

@app.route('/callback', methods=['GET', 'POST'])
def receive_message():
    if request.method == 'GET': # webhook テスト用 GET
        if request.args.get("hub.verify_token") == VERIFY_TOKEN:
            return request.args.get("hub.challenge")
        else:
            return 'ちがうよ'
    elif request.method == 'POST': # POSTリクエスト -> 返信処理
        body = request.get_json() # 中身取得 
        for entry in body['entry']: # iterate 'entry'
            for messaging in entry['messaging']: # iterate 'messaging'
                userID = messaging['sender']['id'] # ユーザーのID
                if messaging.get('message'): # メッセージ以外を除外
                    received_message = messaging['message']['text'] # テキスト
                    response = f'{userID}さん, {received_message}' # おうむ返し文
                    send_message(userID, response) # 返信実行
        return "finished" # なんでも良い。返信内容とは無関係だが、無いとエラーになり返信を繰り返す

# 返信リクエスト用関数
# 失敗したらログに出力, Heroku なら heroku logs --tail で確認可
def send_message(userID, message): 
    result = requests.post("https://graph.facebook.com/v9.0/me/messages",
        params={"access_token": ACCESS_TOKEN},
        headers={"Content-Type": "application/json"},
        data=json.dumps({
            "recipient": {"id": userID},
            "message": {"text": message}
        })
    )
    if result.status_code != 200:
        print('送信失敗だよ:', data)

일단 이것으로, 이런 회복이 가능하게 된다.



POST 테스트



메시지 전송 테스트를 할 때마다 Python 프로그램을 배포하는 것은 매우 번거롭기 때문에 전용 도구를 사용해보십시오.

Facebook은 브라우저상에서 API의 동작을 시도할 수 있다. 를 이용한다.

POST를 선택하고 URL에 https://graph.facebook.com/v9.0/me/messagesParams KEY에 access_token, VALUE에 발행 된 긴 액세스 토큰을 입력하십시오.
Graph API Explorer
Headers는 Content-Typeapplication/json Postman
마지막으로 Body는 raw를 선택하고 보내고 싶은 메시지를 json 형식으로 기입한다. 방금 전의 프로그램으로 취득한 자신의 ID를 입력한다.


따라서 메시지를 쉽게 보낼 수 있습니다. 이것 자체는 위에서 구현한 함수 send_message() 를 사용해도 물론 가능.

좋은 웹페이지 즐겨찾기