Cansada de ser feliz

Bienvenidos a mi flujo de conciencia

Cómo hacer bot para Facebook en Python

| Comments

Primero creamos una aplicación en Facebook, vamos al menú de configuración y agregamos el servicio de messenger (“Add Product”):

Luedo vamos a hacer click en el botón “Setup Webhooks”:

Para poder verificar que nuestro bot esté bien configurado, Facebook nos mandará una peticicón GET a nuestro servidor

1
GET https://mipagina.com/bot/fb-webhook/?hub.mode=subscribe&hub.challenge=1122334455&hub.verify_token=una-frase-secreta

y esperará que le respondemos con el código 200 y el contenido del paramentro hub.challenge cuando verify_token coincide con la frase secreta que especificamos, o con el código HTTP 403 en el caso opuesto.

Entonces esribimos una vista que se encargará de eso:

urls.py
1
2
3
4
5
6
7
    # ...
    url(
        r'fb-webhook/$',
        FacebookCommandReceiveView.as_view(),
        name='fb_webhook',
    ),
    # ...
urls.py
1
2
3
4
5
6
7
class FacebookCommandReceiveView(View):

    def get(self, request):
        if request.GET.get('hub.mode') == 'subscribe' and request.GET.get('hub.verify_token') == settings.FACEBOOK_VERIFY_TOKEN:
            return HttpResponse(request.GET.get('hub.challenge'))
        else:
            return HttpResponseForbidden()

Cuando la vista esté lista y desplegada en producción, podemos oprimir el botón “Verify and Save”. Después de eso Facebook nos dará un token de la aplicación y permitirá configurar un webhook:

Ahora podemos suscribirnos a los eventos en messenger, es decir: cada vez que alguien escibe un mensaje vía messanger a nuestra página de Facebook, Facebook enviará una petición POST al weebhook con el JSON que tendrá todos los datos del mensaje.

Desúés de oprimir el botón “Add to Subscription”, Facebook nos mostrará el enlace “Edit notes”:

Damos click en “Edit notes” y entramos a el formulario de configuración. Aquí especificamos la página a los mensajes de la cual vamos a suscribirnos e escribimos ejemplos de respuestas que dará nuesto bot a ciertos mensajes en Messanger:

Eso sirve para que Facebook pueda verificar que nuestro bot efectivamente responde bien a los mensajes de chat.

Después de que Facebook verifique el comportamiento de nuestro bot, recibimos el mensaje de aprobación, diciendo que desde ahora nuestro bot está activo:

Eso nos permite hacer pruebas de la plataforma, porque el bot va a poder responder sólo a los mensajer enviados por los administradores de nuestra página de Facebook.

Cuando nuestro bot esté listo, lo podemos activar para todos los usuarios (hacerlo público):

Y ahora ¿cómo me llegan los mensajes?

Los mensajes llegan en un JSON que tiene un formato como éste:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
    "object": "page",
    "entry": [{
        "messaging": [
            {
                "timestamp": 148596022321686,
                "message": {
                    "seq": 110377,
                    "mid": "mid.1424360289686:0b78d5e099",
                    "text": "Hola"
                }, "recipient": {
                    "id": "2445077123307282"
                }, "sender": {
                    "id": "1341234970435656"
                }
            }
        ],
        "id": "51247423670015",
        "time": 1485960807075
    }]
}

¿Cómo podemos responder?

La llave entry tiene un listado de mensajes recibidos por nuestro bot. Si un elemento del listado messaging tiene una llave message podemos identificar que es un mensaje enviado por nuestro interlocutor (y no confirmación de que nuestro mensaje fue recibido, por ejemplo). En este caso el atributo text va a tener el texto de mensaje:

views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class FacebookCommandReceiveView(View):

    def post(self, request, bot_keyword):
        if bot_keyword != settings.FACEBOOK_VERIFY_TOKEN:
            return HttpResponseForbidden('Invalid token')

        data = json.loads(request.body.decode('utf-8'))

        # Make sure this is a page subscription
        if data['object'] == 'page':
            # Iterate over each entry - there may be multiple if batched
            for entry in data['entry']:
                # Iterate over each messaging event
                for event in entry['messaging']:
                    if event.get('message'):
                        # Recibimos un mensaje
                    elif event.get('delivery'):
                        # Mensaje recibido
                    elif event.get('read'):
                        # Mensaje leído
                    elif event.get('postback'):
                        # Postback, por ejemplo, de un botón
                    # ...

        return HttpResponse()

Cada mensaje tiene el atributo sender con el id de nuestro interlocutor. Con ese id podemos conseguir la infirmación pública de la persona que envió el mensaje.

En nuestro ejemplo en el caso de que nos escriben «hola» respondemos con el texto «Hola :)»:

views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
recipient_id = event['sender']['id']
message = event['message']
message_text = message.get('text', '')

if 'hola' in message_text:
    payload = {
        'message': {
            'text': 'Hola :)',
        },
        'recipient': {
            'id': recipient_id,
        }
    }

    base_url = 'https://graph.facebook.com/v2.6/me/messages'
    response = requests.post(
        '{}?access_token={}'.format(base_url, ACCESS_TOKEN),
        json=payload,
    )
    if response.status_code == 200:
        response_body = response.json()
    else:
        logger.error('Unable to send message')

Aparte de texto plano podemos enviar imágenes como adjuntos:

El formato en este caso sería el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
payload = {
    'message': {
        'attachment': {
            'type': 'image',
            'payload': {
                'url': image_url,
            }
        }
    },
    'recipient': {
        'id': recipient_id,
    }
}

También se puede pedir a usuario a enviar información ​específica por medio de «Quick Replies»:

1
2
3
4
5
6
7
8
9
10
11
payload = {
    'message': {
        'text': message,
        'quick_replies': [{
            'content_type': 'location',
        }]
    },
    'recipient': {
        'id': recipient_id,
    }
}

Enlaces:

Comments