Поделиться через


Руководство. Включение поддержки вложений файлов в приложении Чата

Пакет SDK чата легко работает с Microsoft Teams в контексте собрания. Только пользователь Teams может отправлять вложения файлов Службы коммуникации Azure пользователя. Пользователь Службы коммуникации Azure не может отправлять вложения файлов пользователю Teams. Сведения о текущих возможностях см. в чате взаимодействия Teams.

Добавление поддержки вложения файлов

Пакет SDK чата previewUrl предоставляет свойство для каждого вложения файла. В частности, previewUrl ссылки на веб-страницу в SharePoint, где пользователь может просматривать содержимое файла, изменять файл и скачивать файл, если разрешение разрешено.

Некоторые ограничения связаны с этой функцией:

  • Администратор Teams клиента отправителя может ввести политики, которые ограничивают или отключают эту функцию полностью. Например, администратор Teams может отключить определенные разрешения (например Anyone, которые могут привести к недоступности URL-адресаpreviewUrl вложения файла).

  • В настоящее время поддерживается только два разрешения на файлы:

    • Anyone
    • People you choose (с адресом электронной почты)

    Сообщите пользователям Teams, что все остальные разрешения (например People in your organization,) не поддерживаются. Пользователи Teams должны дважды проверка, чтобы убедиться, что разрешение по умолчанию поддерживается после отправки файла на клиент Teams.

  • URL-адрес прямого скачивания (url) не поддерживается.

Помимо обычных файлов (с AttachmentType ), пакет SDK чата fileтакже предоставляет AttachmentType свойство image. Службы коммуникации Azure пользователи могут присоединять изображения таким образом, что зеркало поведение клиента Microsoft Teams преобразует вложение изображений в встроенные изображения на уровне пользовательского интерфейса. Дополнительные сведения см. в разделе "Обработка вложений изображений".

Службы коммуникации Azure пользователи могут добавлять изображения с помощью Отправка с этого устройства, которое отображается на стороне Teams и пакет SDK чата возвращает такие вложения, какimage. Для изображений, отправленных через облачные файлы вложения, изображения обрабатываются как обычные файлы на стороне Teams, чтобы пакет SDK чата возвращал такие вложения, как file.

Кроме того, обратите внимание, что Службы коммуникации Azure пользователи могут отправлять файлы только с помощью перетаскивания или команды меню вложения с этого устройства и вложить облачные файлы. В настоящее время не поддерживаются некоторые типы сообщений с внедренными носителями (например, видеоклипы, звуковые сообщения и погодные карта).

В этом руководстве описывается, как включить поддержку вложений файлов с помощью пакета SDK для чата Службы коммуникации Azure для JavaScript.

Пример кода

Найдите завершенный код этого руководства на сайте GitHub.

Необходимые компоненты

Цели

  • Отрисовка вложения файла в потоке сообщений. Каждое вложение файла карта имеет кнопку "Открыть".
  • Отрисовка вложений изображений в виде встроенных изображений.

Обработка вложений файлов

Пакет SDK чата file для JavaScript возвращает ChatAttachmentType свойство для регулярных вложений файлов и image для изображений, входящих в сообщения.

export interface ChatMessageReceivedEvent extends BaseChatMessageEvent {
  /**
   * Content of the message.
   */
  message: string;

  /**
   * Chat message attachment.
   */
  attachments?: ChatAttachment[];
  
  ...
}

export interface ChatAttachment {
  /** Id of the attachment */
  id: string;
  /** The type of attachment. */
  attachmentType: AttachmentType;
  /** The name of the attachment content. */
  name?: string;
  /** The URL that is used to provide the original size of the inline images */
  url?: string;
  /** The URL that provides the preview of the attachment */
  previewUrl?: string;
}

/** Type of supported attachments. */
export type ChatAttachmentType = "image" | "file" | "unknown";

Например, в следующем формате JSON показано, что ChatAttachment может выглядеть для вложения изображения и вложения файла:

"attachments": [
    {
        "id": "08a182fe-0b29-443e-8d7f-8896bc1908a2",
        "attachmentType": "file",
        "name": "business report.pdf",
        "previewUrl": "https://contoso.sharepoint.com/:u:/g/user/h8jTwB0Zl1AY"
    },
    {
        "id": "9d89acb2-c4e4-4cab-b94a-7c12a61afe30",
        "attachmentType": "image", 
        "name": "Screenshot.png",
        "url": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/original?api-version=2023-11-15-preview",
        "previewUrl": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/small?api-version=2023-11-15-preview"
      }
]

Теперь давайте вернемся к обработчику событий, созданному в кратком руководстве: присоединение приложения чата к собранию Teams и добавление дополнительной логики для обработки вложений со свойствомfileattachmentType:

chatClient.on("chatMessageReceived", (e) => {
  console.log("Notification chatMessageReceived!");
  // Check whether the notification is intended for the current thread
  if (threadIdInput.value != e.threadId) {
     return;
  }
   
  if (e.sender.communicationUserId != userId) {
    renderReceivedMessage(e);
  } else {
    renderSentMessage(e.message);
  }
});

async function renderReceivedMessage(event) {
    messages += `<div class="container lighter"> ${event.message} </div>`;
    messagesContainer.innerHTML = messages;

    // Get the list of attachments and calls renderFileAttachments to construct a file attachment card
    var attachmentHtml = event.attachments
        .filter(attachment => attachment.attachmentType === "file")
        .map(attachment => renderFileAttachments(attachment))
        .join('');
    messagesContainer.innerHTML += attachmentHtml;
}

function renderFileAttachments(attachment) {
    var re = /(?:\.([^.]+))?$/;
    var fileExtension = re.exec(attachment.name)[1];  
    return '<div class="attachment-container">' +
        '<img class="attachment-icon" alt="attachment file icon" />' +
        '<div>' +
        '<p class="attachment-type">' + fileExtension + '</p>' +
        '<p>' + attachment.name + '</p>' +
        '<a href=' + attachment.previewUrl + ' target="_blank" rel="noreferrer">Open</a>' +
        '</div>' +
        '</div>';
}

Убедитесь, что вы добавите некоторые CSS для вложения карта:

  /* Let's make the chat popup scrollable */
  .chat-popup {

     ...

     max-height: 650px;
     overflow-y: scroll;
}

 .attachment-container {
     overflow: hidden;
     background: #f3f2f1;
     padding: 20px;
     margin: 0;
     border-radius: 10px;
}
 .attachment-container img {
     width: 50px;
     height: 50px;
     float: left;
     margin: 0;
}
 .attachment-container p {
     font-weight: 700;
     margin: 0 5px 20px 0;
}
 .attachment-container {
     display: grid;
     grid-template-columns: 100px 1fr;
     margin-top: 5px;
}
 .attachment-icon {
     content: url("data:image/svg+xml;base64, ...");
}
 .attachment-container a {
     background-color: #dadada;
     color: black;
     font-size: 12px;
     padding: 10px;
     border: none;
     cursor: pointer;
     border-radius: 5px;
     text-align: center;
     margin-right: 10px;
     text-decoration: none;
     margin-top: 10px;
}
 .attachment-container a:hover {
     background-color: black;
     color: white;
}
 .attachment-type {
     position: absolute;
     color: black;
     border: 2px solid black;
     background-color: white;
     margin-top: 50px;
     font-family: sans-serif;
     font-weight: 400;
     padding: 2px;
     text-transform: uppercase;
     font-size: 8px;
}

Это все, что вам нужно для обработки вложений файлов. Затем давайте запустите код.

Выполнение кода

Для Webpack можно использовать webpack-dev-server свойство для создания и запуска приложения. Выполните следующую команду, чтобы упаковать узел приложения на локальном веб-сервере:

npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map

Или сделайте так:

npm start

Демонстрация вложения файла

  1. Откройте свой браузер и перейдите по адресу http://localhost:8080/. Введите URL-адрес собрания и идентификатор потока.

  2. Отправьте некоторые вложения файлов из клиента Teams.

    Снимок экрана: клиент Teams с отправленным сообщением с тремя вложениями файлов.

  3. Вы увидите новое сообщение, отображаемое вместе с вложениями файлов.

    Снимок экрана: пример приложения с полученным входящий сообщение с тремя вложениями файлов.

Обработка вложений изображений

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

Прежде чем продолжить, выполните инструкции, демонстрирующие включение встроенной поддержки образов в приложении Чата. В этом руководстве описывается, как получить изображения, требующие маркера связи в заголовке запроса. После получения большого двоичного объекта изображения необходимо создать свойство, указывающее на этот большой двоичный ObjectUrl объект. Затем вы вставляете этот URL-адрес в src атрибут каждого встроенного образа.

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

Во-первых, вставьте image тег в содержимое сообщения всякий раз, когда есть вложение изображения:

async function renderReceivedMessage(event) {
    messages += `<div class="container lighter"> ${event.message} </div>`;
    messagesContainer.innerHTML = messages;
    console.log(event);
    // Filter out inline images from attachments
    const imageAttachments = event.attachments?.filter(
        (attachment) =>
        attachment.attachmentType === "image" && !messages.includes(attachment.id)
    );
    // Inject image tag for all image attachments
    var imageAttachmentHtml =
        imageAttachments
        .map((attachment) => renderImageAttachments(attachment))
        .join("") ?? "";
    messagesContainer.innerHTML += imageAttachmentHtml;

    // Get list of attachments and calls renderFileAttachments to construct a file attachment card
    var attachmentHtml =
        event.attachments
        ?.filter((attachment) => attachment.attachmentType === "file")
        .map((attachment) => renderFileAttachments(attachment))
        .join("") ?? "";
    messagesContainer.innerHTML += attachmentHtml;

    // Fetch and render preview images
    fetchPreviewImages(imageAttachments);
}

function renderImageAttachments(attachment) {
    return `<img alt="image" src="" itemscope="png" id="${attachment.id}" style="max-width: 100px">`
}

Теперь давайте заимствуем fetchPreviewImages() из руководства: включите встроенную поддержку образов и используйте его без каких-либо изменений:

function fetchPreviewImages(attachments) {
    if (!attachments.length > 0) {
        return;
    }
    Promise.all(
        attachments.map(async (attachment) => {
            const response = await fetch(attachment.previewUrl, {
                method: 'GET',
                headers: {
                    'Authorization': 'Bearer ' + tokenString,
                },
            });
            return {
                id: attachment.id,
                content: await response.blob(),
            };
        }),
    ).then((result) => {
        result.forEach((imageRef) => {
            const urlCreator = window.URL || window.webkitURL;
            const url = urlCreator.createObjectURL(imageRef.content);
            document.getElementById(imageRef.id).src = url;
        });
    }).catch((e) => {
        console.log('error fetching preview images');
    });
}

Эта функция нуждается в свойстве tokenString , поэтому требуется глобальная копия, инициализированная в init(), как показано в следующем фрагменте кода:

var tokenString = '';

async function init() {
    ...
    const {
        token,
        expiresOn
    } = tokenResponse;
    
    tokenString = token;
    ...
}

Теперь у вас есть поддержка вложений изображений. Перейдите к запуску кода и просмотрите его в действии.

Демонстрация вложения изображения

  1. Отправьте некоторые вложения изображений из клиента Teams.

    Снимок экрана: клиент Teams с полем отправки с вложенным изображением.

  2. После отправки вложения изображения обратите внимание, что он становится встроенным изображением на стороне клиента Teams.

    Снимок экрана: клиент Teams с сообщением с вложением изображения, отправленным другому участнику.

  3. Вернитесь к образцу приложения и убедитесь, что изображение отрисовывается.

    Снимок экрана: пример приложения, на котором показано входящее сообщение с одним встроенным изображением, отрисованным.

В этом руководстве описывается, как включить поддержку вложений файлов с помощью пакета SDK для чата Службы коммуникации Azure для C#.

В этом руководстве описано следующее:

  • Обработка вложений файлов.
  • Обработка вложений изображений.

Необходимые компоненты

  • Просмотрите краткое руководство по присоединению приложения чата к собранию Teams.
  • Создайте ресурс Службы коммуникации Azure, как описано в статье "Создание ресурса Службы коммуникации Azure". Для этого руководства необходимо записать строка подключения.
  • Настройте собрание Teams с помощью своей бизнес-учетной записи и подготовьте URL-адрес собрания.
  • Скачайте пакет SDK чата для C# (@azure/communication-chat) 1.3.0 или последнюю версию. Дополнительные сведения см. в клиентской библиотеке Чата коммуникации Azure.

Пример кода

Найдите завершенный код для этого руководства на сайте GitHub.

Обработка вложений файлов

Пакет SDK чата file для C# возвращает ChatAttachmentType свойство для обычных вложений файлов и image встроенных образов.

public readonly partial struct ChatAttachmentType : IEquatable<ChatAttachmentType>
{
        private const string ImageValue = "image";
        private const string FileValue = "file";
        /// <summary> image. </summary>
        public static ChatAttachmentType Image { get; } = new ChatAttachmentType(ImageValue);
        /// <summary> file. </summary>
        public static ChatAttachmentType File { get; } = new ChatAttachmentType(FileValue);
}


Например, в следующем формате JSON показано, что ChatAttachment может выглядеть для вложения изображения и вложения файла при получении запросов на стороне сервера:

"attachments": [
    {
        "id": "08a182fe-0b29-443e-8d7f-8896bc1908a2",
        "attachmentType": "file",
        "name": "business report.pdf",
        "previewUrl": "https://contoso.sharepoint.com/:u:/g/user/h8jTwB0Zl1AY"
    },
    {
        "id": "9d89acb2-c4e4-4cab-b94a-7c12a61afe30",
        "attachmentType": "image", 
        "name": "Screenshot.png",
        "url": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/original?api-version=2023-11-15-preview",
        "previewUrl": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/small?api-version=2023-11-15-preview"
      }
]

Теперь вернитесь к обработчику событий, созданному в предыдущем кратком руководстве , и добавьте дополнительную логику для обработки вложений со свойством ChatAttachmentType file:


await foreach (ChatMessage message in allMessages)
{
    // Get message attachments that are of type 'file'
    IEnumerable<ChatAttachment> fileAttachments = message.Content.Attachments.Where(x => x.AttachmentType == ChatAttachmentType.File);
    var chatAttachmentFileUris = new List<Uri>();
    foreach (var file in fileAttachments) 
    {
        chatAttachmentFileUris.Add(file.PreviewUri);
    }

    // Build message list
    if (message.Type == ChatMessageType.Html || message.Type == ChatMessageType.Text)
    {
        textMessages++;
        var userPrefix = message.Sender.Equals(currentUser) ? "[you]:" : "";
        var strippedMessage = StripHtml(message.Content.Message);
      


        var chatAttachments = fileAttachments.Count() > 0 ? "[Attachments]:\n" + string.Join(",\n", chatAttachmentFileUris) : "";
        messageList.Add(long.Parse(message.SequenceId), $"{userPrefix}{strippedMessage}\n{chatAttachments}");
    }
}

В частности, для каждого вложения файла вы получаете previewUrl свойство и создаете список URL-адресов в файле for loop. Затем вы внедряете строку вместе с содержимым сообщения чата.

Обработка вложений изображений

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

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

bool isImageAttachment = message.Content.Message.Contains(x.Id);

Если этот флаг имеет значение true, то для отрисовки применяется встроенная логика изображения:

IEnumerable<ChatAttachment> imageAttachments = message.Content.Attachments.Where(x => x.AttachmentType == ChatAttachmentType.Image);
// Fetch image and render
var chatAttachmentImageUris = new List<Uri>();
foreach (ChatAttachment imageAttachment in imageAttachments)
{
    client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", communicationTokenCredential.GetToken().Token);
    var response = await client.GetAsync(imageAttachment.PreviewUri);
    var randomAccessStream = await response.Content.ReadAsStreamAsync();
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        var bitmapImage = new BitmapImage();
        await bitmapImage.SetSourceAsync(randomAccessStream.AsRandomAccessStream());
        InlineImage.Source = bitmapImage;
    });
    chatAttachmentImageUris.Add(imageAttachment.PreviewUri);
}

Теперь приложение поддерживает вложения изображений.

Следующие шаги