Instructivo de Slack: Comandos con barra

En este instructivo, se muestra cómo usar Cloud Functions para implementar un comando de barra de Slack que busca en la API de Gráfico de conocimiento de Google.

Objetivos

  • Crear un comando de barra en Slack
  • Escribir e implementar una función de HTTP de Cloud Function
  • Buscar en la API de Gráfico de conocimiento de Google con el comando de barra

Costos

Este instructivo usa componentes facturables de Cloud Platform, incluidos los siguientes:

  • Google Cloud Functions

Usa la calculadora de precios para generar una estimación de los costos según el uso previsto.

Antes de comenzar

  1. Sign in to your Google Account.

    If you don't already have one, sign up for a new account.

  2. Select or create a Google Cloud Platform project.

    Go to the Manage resources page

  3. Comprueba que la facturación esté habilitada en tu proyecto.

    Descubre cómo puedes habilitar la facturación

  4. Habilita las Cloud Functions y Búsqueda en el Gráfico de conocimiento de Google API necesarias.

    Habilita las API

  5. Actualiza y, luego, instala los componentes de gcloud:

    Node.js 6

    gcloud components update

    Node.js 8 (Beta)

    gcloud components update &&
    gcloud components install beta

    Python (Beta)

    gcloud components update &&
    gcloud components install beta
  6. Prepara tu entorno de programación.

Visualiza el flujo de datos

El flujo de datos en la aplicación de instructivo del comando de barra de Slack incluye varios pasos, como se muestra a continuación:

  1. El usuario ejecuta el comando de barra /kg <search_query> en un canal de Slack.
  2. Slack envía la carga útil del comando al extremo de activación de Cloud Functions.
  3. La función de Cloud Functions envía una solicitud con la búsqueda del usuario a la API de Gráfico de conocimiento.
  4. La API de Gráfico de conocimiento responde con todos los resultado de coincidencia.
  5. La función de Cloud Functions da formato a la respuesta y la transforma en un mensaje de Slack.
  6. La función de Cloud Functions envía el mensaje de vuelta a Slack.
  7. El usuario ve la respuesta con formato en el canal de Slack.

El siguiente gráfico puede ayudarte a visualizar los pasos:

Prepara la función

  1. Clona el repositorio de la app de muestra en tu máquina local:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    De manera opcional, puedes descargar la muestra como un archivo zip y extraerla.

    Python (Beta)

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    De manera opcional, puedes descargar la muestra como un archivo zip y extraerla.

  2. Ve al directorio que contiene el código de muestra de Cloud Functions, como sigue:

    Node.js

    cd nodejs-docs-samples/functions/slack/

    Python (Beta)

    cd python-docs-samples/functions/slack/

  3. Configura la app de la siguiente forma:

    Node.js

    Con el archivo config.default.json como plantilla, crea un archivo config.json en el directorio app con los siguientes contenidos:
    {
    "SLACK_TOKEN": "YOUR_SLACK_TOKEN",
    "KG_API_KEY": "YOUR_KG_API_KEY",
    }
    • Reemplaza YOUR_SLACK_TOKEN por el token de verificación proporcionado por Slack en la página Información básica de la configuración de la app.
    • Reemplaza YOUR_KG_API_KEY por la clave de API de Gráfico de conocimiento que acabas de crear.

    Python (Beta)

    Edita el archivo config.json en el directorio app para que incluya los siguientes contenidos:
    {
    "SLACK_TOKEN": "YOUR_SLACK_TOKEN",
    "KG_API_KEY": "YOUR_KG_API_KEY",
    }
    • Reemplaza YOUR_SLACK_TOKEN por el token de verificación proporcionado por Slack en la página Información básica de la configuración de la app.
    • Reemplaza YOUR_KG_API_KEY por la clave de API de Gráfico de conocimiento que acabas de crear.

Implementa la función

Para implementar la función que se ejecuta cuando tú (o Slack) haces una solicitud HTTP POST al extremo de la función, ejecuta el siguiente comando en el directorio que contiene el código de muestra de Cloud Functions:

Node.js 6

gcloud functions deploy kgSearch --runtime nodejs6 --trigger-http

Node.js 8 (Beta)

gcloud functions deploy kgSearch --runtime nodejs8 --trigger-http

Python (Beta)

gcloud functions deploy kg_search --runtime python37 --trigger-http

Configura la aplicación

Después de implementar la función, es necesario que crees un comando de barra en Slack que envíe la consulta a tu función de Cloud Functions cada vez que se activa el comando.

  1. Crea una app de Slack para alojar el comando de barra de Slack. Asóciala con un equipo de Slack en el que tengas permisos para instalar integraciones.

  2. Ve a Comandos de barra y haz clic en el botón Crear comando nuevo.

  3. Ingresa /kg como el nombre del comando.

  4. Ingresa la URL del comando, como en el ejemplo:

    Node.js

    https://YOUR_REGION-YOUR_PROJECT_ID.cloudfunctions.net/kgSearch

    Python (Beta)

    https://YOUR_REGION-YOUR_PROJECT_ID.cloudfunctions.net/kg_search

    en la que YOUR_REGION es la región en la que tu función de Cloud Functions se implementa y YOUR_PROJECT_ID es el ID del proyecto de Cloud.

    Ambos valores se pueden ver en tu terminal cuando la función termina de implementarse

  5. Haz clic en Guardar.

  6. Ve a Información básica.

  7. Haz clic en Instala la app en tu lugar de trabajo y sigue las instrucciones en pantalla para habilitar la aplicación en tu lugar de trabajo.

    Tu comando de barra de Slack debería estar en línea en breve.

Comprende el código

Importa dependencias

La aplicación debe importar varias dependencias con el fin de comunicarse con los servicios de Google Cloud Platform:

Node.js

const config = require('./config.json');
const googleapis = require('googleapis');

// Get a reference to the Knowledge Graph Search component
const kgsearch = googleapis.kgsearch('v1');

Python (Beta)

import json

import apiclient
from flask import jsonify

with open('config.json', 'r') as f:
    data = f.read()
config = json.loads(data)

kgsearch = apiclient.discovery.build('kgsearch', 'v1',
                                     developerKey=config['KG_API_KEY'])

Recibe el webhook

La siguiente función se ejecuta cuando tú (o Slack) haces una solicitud HTTP POST al extremo de la función:

Node.js

/**
 * Receive a Slash Command request from Slack.
 *
 * Trigger this function by making a POST request with a payload to:
 * https://[YOUR_REGION].[YOUR_PROJECT_ID].cloudfunctions.net/kgsearch
 *
 * @example
 * curl -X POST "https://us-central1.your-project-id.cloudfunctions.net/kgSearch" --data '{"token":"[YOUR_SLACK_TOKEN]","text":"giraffe"}'
 *
 * @param {object} req Cloud Function request object.
 * @param {object} req.body The request payload.
 * @param {string} req.body.token Slack's verification token.
 * @param {string} req.body.text The user's search query.
 * @param {object} res Cloud Function response object.
 */
exports.kgSearch = (req, res) => {
  return Promise.resolve()
    .then(() => {
      if (req.method !== 'POST') {
        const error = new Error('Only POST requests are accepted');
        error.code = 405;
        throw error;
      }

      // Verify that this request came from Slack
      verifyWebhook(req.body);

      // Make the request to the Knowledge Graph Search API
      return makeSearchRequest(req.body.text);
    })
    .then(response => {
      // Send the formatted message back to Slack
      res.json(response);
    })
    .catch(err => {
      console.error(err);
      res.status(err.code || 500).send(err);
      return Promise.reject(err);
    });
};

Python (Beta)

def kg_search(request):
    if request.method != 'POST':
        return 'Only POST requests are accepted', 405

    verify_web_hook(request.form)
    kg_search_response = make_search_request(request.form['text'])
    return jsonify(kg_search_response)

La siguiente función autentica la solicitud entrante a través de la comprobación de tu token de verificación que generó Slack.

Node.js

/**
 * Verify that the webhook request came from Slack.
 *
 * @param {object} body The body of the request.
 * @param {string} body.token The Slack token to be verified.
 */
function verifyWebhook(body) {
  if (!body || body.token !== config.SLACK_TOKEN) {
    const error = new Error('Invalid credentials');
    error.code = 401;
    throw error;
  }
}

Python (Beta)

def verify_web_hook(form):
    if not form or form.get('token') != config['SLACK_TOKEN']:
        raise ValueError('Invalid request/credentials.')

Consulta a la API de Gráfico de conocimiento

La siguiente función envía una solicitud con la búsqueda del usuario a la API de Gráfico de conocimiento.

Node.js

/**
 * Send the user's search query to the Knowledge Graph API.
 *
 * @param {string} query The user's search query.
 */
function makeSearchRequest(query) {
  return new Promise((resolve, reject) => {
    kgsearch.entities.search(
      {
        auth: config.KG_API_KEY,
        query: query,
        limit: 1,
      },
      (err, response) => {
        console.log(err);
        if (err) {
          reject(err);
          return;
        }

        // Return a formatted message
        resolve(formatSlackMessage(query, response));
      }
    );
  });
}

Python (Beta)

def make_search_request(query):
    req = kgsearch.entities().search(query=query, limit=1)
    res = req.execute()
    return format_slack_message(query, res)

Formato de mensaje de Slack

Finalmente, la siguiente función da formato al resultado de Gráfico de conocimiento y lo transforma en un mensaje de Slack con formato enriquecido que se le mostrará al usuario.

Node.js

/**
 * Format the Knowledge Graph API response into a richly formatted Slack message.
 *
 * @param {string} query The user's search query.
 * @param {object} response The response from the Knowledge Graph API.
 * @returns {object} The formatted message.
 */
function formatSlackMessage(query, response) {
  let entity;

  // Extract the first entity from the result list, if any
  if (
    response &&
    response.itemListElement &&
    response.itemListElement.length > 0
  ) {
    entity = response.itemListElement[0].result;
  }

  // Prepare a rich Slack message
  // See https://api.slack.com/docs/message-formatting
  const slackMessage = {
    response_type: 'in_channel',
    text: `Query: ${query}`,
    attachments: [],
  };

  if (entity) {
    const attachment = {
      color: '#3367d6',
    };
    if (entity.name) {
      attachment.title = entity.name;
      if (entity.description) {
        attachment.title = `${attachment.title}: ${entity.description}`;
      }
    }
    if (entity.detailedDescription) {
      if (entity.detailedDescription.url) {
        attachment.title_link = entity.detailedDescription.url;
      }
      if (entity.detailedDescription.articleBody) {
        attachment.text = entity.detailedDescription.articleBody;
      }
    }
    if (entity.image && entity.image.contentUrl) {
      attachment.image_url = entity.image.contentUrl;
    }
    slackMessage.attachments.push(attachment);
  } else {
    slackMessage.attachments.push({
      text: 'No results match your query...',
    });
  }

  return slackMessage;
}

Python (Beta)

def format_slack_message(query, response):
    entity = None
    if response and response.get('itemListElement') is not None and \
       len(response['itemListElement']) > 0:
        entity = response['itemListElement'][0]['result']

    message = {
        'response_type': 'in_channel',
        'text': 'Query: {}'.format(query),
        'attachments': []
    }

    attachment = {}
    if entity:
        name = entity.get('name', '')
        description = entity.get('description', '')
        detailed_desc = entity.get('detailedDescription', {})
        url = detailed_desc.get('url')
        article = detailed_desc.get('articleBody')
        image_url = entity.get('image', {}).get('contentUrl')

        attachment['color'] = '#3367d6'
        if name and description:
            attachment['title'] = '{}: {}'.format(entity["name"],
                                                  entity["description"])
        elif name:
            attachment['title'] = name
        if url:
            attachment['title_link'] = url
        if article:
            attachment['text'] = article
        if image_url:
            attachment['image_url'] = image_url
    else:
        attachment['text'] = 'No results match your query.'
    message['attachments'].append(attachment)

    return message

Tiempos de espera de la API de Slack

La API de Slack espera que tu función responda dentro de 3 segundos después de recibir una solicitud de webhook.

Los comandos que aparecen en este instructivo, por lo general, tardan más de 3 segundos en responder. En el caso de los comandos con tiempos de respuesta más largos, se recomienda configurar una función para solicitudes push (incluida su response_url) a un tema de Pub/Sub que actúa como una lista de tareas en cola.

Después puedes crear una segunda función activada por Pub/Sub que procese esas tareas y envíe resultados de vuelta a la response_url de Slack.

Usa el comando de barra

  1. Prueba el comando manualmente:

    Node.js

    curl -X POST "https://YOUR_REGION-YOUR_PROJECT_ID.cloudfunctions.net/kgSearch" -H "Content-Type: application/json" --data '{"token":"YOUR_SLACK_TOKEN","text":"giraffe"}'

    Python (Beta)

    curl -X POST "https://YOUR_REGION-YOUR_PROJECT_ID.cloudfunctions.net/kg_search" --data 'token=YOUR_SLACK_TOKEN&text=giraffe'

    en el que:

    • YOUR_REGION es la región en la que se implementa tu función. Esta se puede ver en tu terminal cuando la función termina de implementarse.
    • YOUR_PROJECT_ID es el ID del proyecto de Cloud. Este se puede ver en tu terminal cuando la función termina de implementarse.
    • YOUR_SLACK_TOKEN es el token que proporciona Slack en la configuración del comando de barra.
  2. Revisa los registros para asegurarte de que las ejecuciones se completaron:

    gcloud functions logs read --limit 100
    
  3. Escribe el comando en el canal de Slack:

    /kg giraffe

Limpieza

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:

Cómo borrar el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

Para borrar el proyecto, haz lo siguiente:

  1. In the GCP Console, go to the Projects page.

    Go to the Projects page

  2. In the project list, select the project you want to delete and click Delete .
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Borra la función de Cloud Functions

Para borrar la función de Cloud Functions que implementaste en este instructivo, ejecuta el siguiente comando:

Node.js

gcloud functions delete kgSearch 

Python (Beta)

gcloud functions delete kg_search 

También puedes borrar las funciones de Cloud Functions desde Google Cloud Platform Console.

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...