Предварительный просмотр ссылок в сообщениях Google Chat

Чтобы предотвратить переключение контекста, когда пользователи делятся ссылкой в Google Chat, ваше приложение Chat может выполнить предварительный просмотр ссылки, прикрепив к сообщению карточку, которая предоставляет дополнительную информацию и позволяет людям выполнять действия прямо из Google Chat.

Например, представьте себе пространство Google Chat, включающее всех агентов службы поддержки клиентов компании, а также чат-приложение Case-y. Агенты часто делятся ссылками на обращения в службу поддержки клиентов в пространстве Chat, и каждый раз, когда они это делают, их коллеги должны открывать ссылку на обращение, чтобы увидеть информацию, такую как ответственное лицо, статус и тема. Аналогично, если кто-то хочет взять на себя ответственность за обращение или изменить его статус, ему необходимо открыть ссылку.

Предварительный просмотр ссылок позволяет чат-приложению Case-y, встроенному в пространство, прикреплять карточку с указанием ответственного, статуса и темы к каждому обращению, которым кто-либо делится. Кнопки на карточке позволяют агентам взять на себя ответственность за обращение и изменить статус прямо из чата.

Когда кто-то добавляет ссылку в свое сообщение, появляется чип, информирующий о том, что приложение Chat может просмотреть ссылку.

Чип, указывающий, что приложение чата может просматривать ссылку

После отправки сообщения ссылка отправляется в приложение чата, которое затем генерирует и прикрепляет карточку к сообщению пользователя.

Приложение чата, просматривающее ссылку путем прикрепления карточки к сообщению

Помимо ссылки, карточка содержит дополнительную информацию о ней, включая интерактивные элементы, такие как кнопки. Ваше приложение Chat может обновлять прикреплённую карточку в ответ на действия пользователя, например, нажатие кнопок.

Если пользователь не хочет, чтобы приложение Chat открывало предварительный просмотр ссылки, прикрепляя карточку к сообщению, он может отменить предварительный просмотр, нажав на чипе предварительного просмотра. Пользователи могут в любой момент удалить прикреплённую карточку, нажав «Удалить предварительный просмотр» .

Предпосылки

HTTP

Надстройка для Google Workspace, расширяющая возможности Google Chat. Чтобы создать её, выполните краткое руководство по HTTP .

Скрипт приложений

Надстройка для Google Workspace, расширяющая возможности Google Chat. Чтобы создать её, выполните краткое руководство по Apps Script .

Зарегистрируйте определенные ссылки — например, example.com , support.example.com и support.example.com/cases/ — в качестве шаблонов URL на странице конфигурации вашего приложения Chat в консоли Google Cloud, чтобы ваше приложение Chat могло просматривать их.

Меню конфигурации предпросмотра ссылок

  1. Откройте консоль Google Cloud .
  2. Рядом с «Google Cloud» нажмите стрелку вниз и откройте проект приложения чата.
  3. В поле поиска введите Google Chat API и нажмите Google Chat API .
  4. Нажмите Управление > Конфигурация .
  5. В разделе «Предварительный просмотр ссылок» добавьте или отредактируйте шаблон URL.
    1. Чтобы настроить предварительный просмотр ссылок для нового шаблона URL, нажмите Добавить шаблон URL .
    2. Чтобы изменить конфигурацию существующего шаблона URL, нажмите стрелку вниз .
  6. В поле «Шаблон хоста» введите домен шаблона URL. Приложение чата будет отображать ссылки на этот домен.

    Чтобы получить ссылки предварительного просмотра приложения чата для определенного поддомена, например subdomain.example.com , включите этот поддомен.

    Чтобы ссылки предварительного просмотра приложения Chat отображались для всего домена, укажите подстановочный знак со звёздочкой (*) в качестве поддомена. Например, *.example.com соответствует subdomain.example.com и any.number.of.subdomains.example.com .

  7. В поле Префикс пути введите путь, который будет добавлен к домену шаблона хоста.

    Чтобы сопоставить все URL-адреса в домене шаблона хоста, оставьте префикс пути пустым.

    Например, если шаблон хоста — support.example.com , то для сопоставления URL-адресов для случаев, размещенных на support.example.com/cases/ , введите cases/ .

  8. Нажмите Готово .

  9. Нажмите «Сохранить» .

Теперь, когда кто-то добавляет ссылку, соответствующую шаблону URL-адреса предварительного просмотра ссылки, в сообщение в чат-пространстве, включающем ваше приложение Chat, ваше приложение отображает предварительный просмотр ссылки.

После настройки предварительного просмотра для определенной ссылки ваше приложение Chat сможет распознавать и просматривать ссылку, прикрепляя к ней дополнительную информацию.

В чат-пространствах, включающих ваше приложение, когда чьё-либо сообщение содержит ссылку, соответствующую шаблону URL-адреса для предварительного просмотра ссылки, ваше приложение получает объект события с MessagePayload . В полезной нагрузке объект message.matchedUrl содержит ссылку, которую пользователь включил в сообщение:

JSON

message: {
  matchedUrl: {
    url: "https://support.example.com/cases/case123"
  },
  ... // other message attributes redacted
}

Проверяя наличие поля matchedUrl в полезной нагрузке события MESSAGE , ваше приложение Chat может добавлять информацию к сообщению с предварительно просмотренной ссылкой. Приложение Chat может либо ответить простым текстовым сообщением, либо прикрепить открытку.

Ответить текстовым сообщением

Для простых ответов ваше приложение Chat может отправлять текстовые сообщения для предварительного просмотра ссылки. В этом примере прикрепляется сообщение, повторяющее URL-адрес ссылки, соответствующий шаблону URL-адреса для предварительного просмотра ссылки.

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to messages that have links whose URLs match URL patterns configured
 * for link previewing.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Response to send back depending on the matched URL.
 */
function handlePreviewLink(chatMessage) {
  // If the Chat app does not detect a link preview URL pattern, reply
  // with a text message that says so.
  if (!chatMessage.matchedUrl) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'No matchedUrl detected.'
    }}}}};
  }

  // Reply with a text message for URLs of the subdomain "text"
  if (chatMessage.matchedUrl.url.includes("text.example.com")) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'event.chat.messagePayload.message.matchedUrl.url: ' + chatMessage.matchedUrl.url
    }}}}};
  }
}

Скрипт приложений

/**
 * Reply to messages that have links whose URLs match the pattern
 * "text.example.com" configured for link previewing.
 *
 * @param {Object} event The event object from Google Workspace add-on.
 *
 * @return {Object} The action response.
 */
function onMessage(event) {
  // Stores the Google Chat event as a variable.
  const chatMessage = event.chat.messagePayload.message;

  // If the Chat app doesn't detect a link preview URL pattern, reply
  // with a text message that says so.
  if (!chatMessage.matchedUrl) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'No matchedUrl detected.'
    }}}}};
  }

  // Reply with a text message for URLs of the subdomain "text".
  if (chatMessage.matchedUrl.url.includes("text.example.com")) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'event.chat.messagePayload.message.matchedUrl.url: ' + chatMessage.matchedUrl.url
    }}}}};
  }
}

Чтобы прикрепить карточку к предварительно просматриваемой ссылке, верните действие DataActions с объектом ChatDataActionMarkup типа UpdateInlinePreviewAction .

В следующем примере приложение чата добавляет карточку предварительного просмотра к сообщениям, содержащим шаблон URL support.example.com .

Приложение чата, просматривающее ссылку путем прикрепления карточки к сообщению

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to messages that have links whose URLs match URL patterns configured
 * for link previewing.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Response to send back depending on the matched URL.
 */
function handlePreviewLink(chatMessage) {
  // Attach a card to the message for URLs of the subdomain "support"
  if (chatMessage.matchedUrl.url.includes("support.example.com")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // the case information would be fetched and used to build the card.
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: { cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case basics',
        },
        sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // Use runtime environment variable set with self URL
          onClick: { action: { function: process.env.BASE_URL }}
        }]}}
        ]}]
      }
    }]}}}};
  }
}

Скрипт приложений

Этот пример отправляет сообщение с картой, возвращая JSON-файл карты . Вы также можете использовать сервис карт Apps Script .

/**
 * Attach a card to messages that have links whose URLs match the pattern
 * "support.example.com" configured for link previewing.
 *
 * @param {Object} event The event object from Google Workspace add-on.
 *
 * @return {Object} The action response.
 */
function onMessage(event) {
  // Stores the Google Chat event as a variable.
  const chatMessage = event.chat.messagePayload.message;

  // Attach a card to the message for URLs of the subdomain "support".
  if (chatMessage.matchedUrl.url.includes("support.example.com")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // the case information would be fetched and used to build the card.
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: { cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case summary',
        },
        sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // Clicking this button triggers the execution of the function
          // "assign" from the Apps Script project.
          onClick: { action: { function: 'assign'}}
        }]}}
        ]}]
      }
    }]}}}};
  }
}

Ваше приложение чата может обновлять карточку предварительного просмотра ссылки, когда пользователи взаимодействуют с ней, например, нажимают кнопку на карточке.

Чтобы обновить карточку, ваше приложение чата должно вернуть действие DataActions с одним из следующих объектов ChatDataActionMarkup :

  • Если пользователь отправил сообщение, вернуть объект UpdateMessageAction .
  • Если приложение чата отправило сообщение, верните объект UpdateInlinePreviewAction .

Чтобы определить, кто отправил сообщение, используйте полезную нагрузку события ( buttonClickedPayload ), чтобы проверить, задан ли отправитель ( message.sender.type ) как HUMAN (пользователь) или BOT (чат-приложение).

В следующем примере показано, как приложение чата обновляет предварительный просмотр ссылки всякий раз, когда пользователь нажимает кнопку « Назначить мне» , обновляя поле «Назначенный» карточки и отключая кнопку.

Приложение чата, просматривающее ссылку с обновленной версией карточки, прикрепленной к сообщению

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to clicks by assigning user and updating the card that was attached to a
 * message with a previewed link.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Action response depending on the original message.
 */
function handleCardClick(chatMessage) {
  // Creates the updated card that displays "You" for the assignee
  // and that disables the button.
  //
  // A hard-coded card is used in this example. In a real-life scenario,
  // an actual assign action would be performed before building the card.
  const message = { cardsV2: [{
    cardId: 'attachCard',
    card: {
      header: {
        title: 'Example Customer Service Case',
        subtitle: 'Case basics',
      },
      sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        // The assignee is now "You"
        { decoratedText: { topLabel: 'Assignee', text: 'You'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // The button is now disabled
          disabled: true,
          // Use runtime environment variable set with self URL
          onClick: { action: { function: process.env.BASE_URL }}
        }]}}
      ]}]
    }
  }]};

  // Checks whether the message event originated from a human or a Chat app
  // to return the adequate action response.
  if(chatMessage.sender.type === 'HUMAN') {
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: message }}};
  } else {
    return { hostAppDataAction: { chatDataAction: { updateMessageAction: message }}};
  }
}

Скрипт приложений

Этот пример отправляет сообщение с картой, возвращая JSON-файл карты . Вы также можете использовать сервис карт Apps Script .

/**
 * Assigns and updates the card that's attached to a message with a
 * previewed link of the pattern "support.example.com".
 *
 * @param {Object} event The event object from the Google Workspace add-on.
 *
 * @return {Object} Action response depending on the message author.
 */
function assign(event) {
  // Creates the updated card that displays "You" for the assignee
  // and that disables the button.
  //
  // A hard-coded card is used in this example. In a real-life scenario,
  // an actual assign action would be performed before building the card.
  const message = { cardsV2: [{
    cardId: 'attachCard',
    card: {
      header: {
        title: 'Example Customer Service Case',
        subtitle: 'Case summary',
      },
      sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        // The assignee is now "You"
        { decoratedText: { topLabel: 'Assignee', text: 'You'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // The button is now disabled
          disabled: true,
          onClick: { action: { function: 'assign'}}
        }]}}
      ]}]
    }
  }]};

  // Use the adequate action response type. It depends on whether the message
  // the preview link card is attached to was created by a human or a Chat app.
  if(event.chat.buttonClickedPayload.message.sender.type === 'HUMAN') {
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: message }}};
  } else {
    return { hostAppDataAction: { chatDataAction: { updateMessageAction: message }}};
  }
}

Ограничения и соображения

При настройке предварительного просмотра ссылок для вашего приложения Chat обратите внимание на следующие ограничения и соображения:

  • Каждое приложение чата поддерживает предварительный просмотр ссылок для 5 шаблонов URL.
  • Приложения чата позволяют просматривать только одну ссылку в каждом сообщении. Если в одном сообщении есть несколько ссылок для просмотра, отображается только первая из них.
  • Приложения чата позволяют просматривать только ссылки, начинающиеся с https:// , поэтому https://support.example.com/cases/ выполняет предварительный просмотр, а support.example.com/cases/ нет.
  • Если сообщение не содержит другой информации, отправляемой в приложение Chat, например, команды с косой чертой , то при предварительном просмотре ссылок в приложение Chat отправляется только URL-адрес ссылки.
  • Если пользователь публикует ссылку, приложение Chat может обновить карточку предварительного просмотра ссылки только при взаимодействии пользователя с карточкой, например, при нажатии кнопки. Вы не можете вызвать метод update() API Chat для ресурса Message для асинхронного обновления сообщения пользователя.
  • Приложения чата должны предоставлять предварительный просмотр ссылок всем участникам чата, поэтому в сообщении не должно быть поля privateMessageViewer .

При реализации предварительного просмотра ссылок вам может потребоваться отладить приложение Chat, прочитав его логи. Чтобы ознакомиться с журналами, откройте Logs Explorer в консоли Google Cloud.