Tutorial: Habilitación de la compatibilidad con archivos adjuntos en la aplicación Chat
El SDK de Chat funciona sin problemas con Microsoft Teams en contextos de reunión. Solo los usuarios de Teams pueden enviar datos adjuntos de archivos a los usuarios de Azure Communication Services. Los usuarios de Azure Communication Services no pueden enviar datos adjuntos de archivos a los usuarios de Teams. Para conocer las funcionalidades actuales, consulte Chat de interoperabilidad de Teams.
Adición de compatibilidad con archivos adjuntos
El SDK de chat proporciona la propiedad previewUrl
para cada archivo adjunto. De forma específica, previewUrl
vincula a una página web en SharePoint donde el usuario puede ver el contenido del archivo, editarlo y descargarlo si los permisos lo permiten.
Esta característica tiene asociadas algunas restricciones:
El administrador de Teams del inquilino del remitente podría imponer directivas que limiten o deshabiliten completamente esta característica. Por ejemplo, el administrador de Teams podría deshabilitar determinados permisos (como
Anyone
) que podrían hacer que la URL de los archivos adjuntos (previewUrl
) no fuera accesible.Actualmente solo se admiten dos permisos de archivo:
Anyone
People you choose
(con dirección de correo electrónico)
Informe a los usuarios de Teams de que no se admiten todos los demás permisos (como
People in your organization
). Los usuarios de Teams deberían comprobarlo para asegurarse de que se admita el permiso predeterminado después de cargar el archivo en el cliente de Teams.No se admite la URL de descarga directa (
url
).
Además de los archivos normales (con AttachmentType
de file
), el SDK de Chat también proporciona la propiedad AttachmentType
de image
. Los usuarios de Azure Communication Services pueden adjuntar imágenes de forma que reflejen el comportamiento de cómo el cliente de Microsoft Teams convierte los datos adjuntos de imagen en imágenes insertadas en la capa de interfaz de usuario. Para obtener más información, consulte Controlar datos adjuntos de imagen.
Los usuarios de Azure Communication Services pueden agregar imágenes a través de Cargar desde este dispositivo, que se representa en el lado de Teams y el SDK de Chat devuelve tales datos adjuntos como image
. En el caso de imágenes cargadas a través de Adjuntar archivos en la nube, las imágenes se tratarán como archivos normales en Teams, por lo que el SDK de Chat devolverá tales datos adjuntos como file
.
Tenga en cuenta también que los usuarios de Azure Communication Services solo podrán cargar archivos mediante arrastrar y colocar, o bien a través de los comandos de menú de datos adjuntos Cargar desde este dispositivo y Adjuntar archivos en la nube. Actualmente, no se admiten determinados tipos de mensajes con medios insertados (como clips de vídeo, mensajes de audio y tarjetas meteorológicas).
En este tutorial se describe cómo habilitar la compatibilidad con archivos insertados mediante el SDK de Azure Communication Services Chat para JavaScript.
Código de ejemplo
Encuentre el código finalizado de este tutorial en GitHub.
Requisitos previos
- Revise el inicio rápido Unirse a reuniones de Teams con la aplicación Chat.
- Cree un recurso de Azure Communication Services. Para más información, consulte Creación de un recurso de Azure Communication Services. Debe registrar la cadena de conexión para este tutorial.
- Configure una reunión de Teams con su cuenta empresarial y tenga lista la dirección URL de la reunión.
- Use el SDK de chat para JavaScript (@azure/communication-chat) 1.5.0 o la versión más reciente. Para obtener más información, consulte Biblioteca cliente de Chat de comunicación de Azure para JavaScript.
Objetivos
- Representar los datos adjuntos del archivo en el subproceso del mensaje. Cada tarjeta de datos adjuntos de archivo tiene un botón Abrir.
- Representar datos adjuntos de imágenes como imágenes insertadas.
Controlar archivos adjuntos
El SDK de Chat para JavaScript devuelve una propiedad ChatAttachmentType
de file
para datos adjuntos de archivos normales y image
para imágenes insertadas con mensajes.
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";
Por ejemplo, el siguiente JSON muestra cómo ChatAttachment
podría mostrar los datos adjuntos de imagen y los datos adjuntos de un archivo:
"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"
}
]
Ahora volveremos al controlador de eventos que creó en Inicio rápido: unir la aplicación Chat a una reunión de Teams y agregaremos cierta lógica adicional para manipular los datos adjuntos con la propiedad attachmentType
de file
:
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>';
}
Asegúrese de agregar algunas CSS para la tarjeta de datos adjuntos:
/* 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;
}
Es todo lo que necesita para controlar los datos adjuntos de archivos. A continuación, ejecutemos el código.
Ejecución del código
En cuanto a WebPack, use la propiedad webpack-dev-server
para compilar y ejecutar la aplicación. Ejecute el siguiente comando para agrupar el host de la aplicación en un servidor web local:
npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map
O:
npm start
Demostración de archivos adjuntos
Abra su explorador y diríjase a
http://localhost:8080/
. Escriba la dirección URL de la reunión y el identificador de la conversación.Envíe algunos datos adjuntos de archivo desde el cliente de Teams.
Debería ver el nuevo mensaje representado junto con los datos adjuntos de archivo.
Controlar datos adjuntos de imagen
Los datos adjuntos de imagen deben tratarse de forma diferente a los datos adjuntos estándar file
. Los datos adjuntos de imagen tienen la propiedad attachmentType
de image
, lo que requiere el token de comunicación para recuperar las imágenes de tamaño completo o de vista previa.
Antes de continuar, complete el tutorial que muestra cómo habilitar la compatibilidad con imágenes insertadas en la aplicación Chat. En este tutorial, se describe cómo capturar imágenes que requieran un token de comunicación en el encabezado de solicitud. Después de recibir el blob de imágenes, es necesario crear una propiedad ObjectUrl
que apunte a este blob. A continuación, se inserta esta URL en el atributo src
de cada imagen insertada.
Como ya está familiarizado con el funcionamiento de las imágenes insertadas, puede representar datos adjuntos de imagen como imágenes insertadas normales.
En primer lugar, inserte una etiqueta image
en el contenido del mensaje siempre que haya datos adjuntos de imagen:
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">`
}
Ahora tomaremos prestado fetchPreviewImages()
del Tutorial: habilitación de la compatibilidad con imágenes insertadas y lo usaremos tal y como está, sin cambios:
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');
});
}
Esta función necesita una propiedad tokenString
, por lo que necesitará una copia global inicializada en init()
, tal y como se muestra en el siguiente fragmento de código:
var tokenString = '';
async function init() {
...
const {
token,
expiresOn
} = tokenResponse;
tokenString = token;
...
}
Ya tiene compatibilidad con datos adjuntos de imágenes. Continúe ejecutando el código y véalo en acción.
Demostración de datos adjuntos de imagen
Envíe algunos datos adjuntos de imagen desde el cliente de Teams.
Al enviar los datos adjuntos de imagen, observe que se convierte en una imagen insertada en el lado del cliente de Teams.
Vuelva a la aplicación de ejemplo y asegúrese de que se represente la misma imagen.
En este tutorial aprenderá a habilitar la compatibilidad con imágenes insertadas mediante el SDK de Azure Communication Services Chat para C#.
En este tutorial, aprenderá a:
- Controlar datos adjuntos de archivo.
- Controlar datos adjuntos de imagen.
Requisitos previos
- Revise el inicio rápido Unirse a reuniones de Teams con la aplicación Chat.
- Cree un recurso de Azure Communication Services, tal y como se describe en Creación de recursos de Azure Communication Services. Debe registrar la cadena de conexión para este tutorial.
- Configure una reunión de Teams con su cuenta empresarial y tenga lista la dirección URL de la reunión.
- Descargue el SDK de Chat para C# (@azure/communication-chat) 1.3.0 o la versión más reciente. Para obtener más información, consulte Biblioteca cliente de Chat de comunicación de Azure.
Código de ejemplo
Encuentre el código finalizado para este tutorial en GitHub.
Controlar archivos adjuntos
El SDK de Chat para C# devuelve una propiedad ChatAttachmentType
de file
para datos adjuntos de archivos normales y image
para imágenes insertadas.
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);
}
Por ejemplo, el siguiente JSON muestra cómo ChatAttachment
podría mostrar los datos adjuntos de imagen y los datos adjuntos de un archivo al recibir solicitudes del lado servidor:
"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"
}
]
Ahora volvamos al controlador de eventos que creó en el inicio rápido anterior y agreguemos cierta lógica adicional para controlar los datos adjuntos con la propiedad ChatAttachmentType
de 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}");
}
}
En concreto, para cada archivo adjunto, obtendrá la propiedad previewUrl
y creará una lista de direcciones URL en el for loop
. A continuación, insertará la cadena junto con el contenido del mensaje de Chat.
Controlar datos adjuntos de imagen
Es necesario controlar los datos adjuntos de imagen de forma diferente a los datos adjuntos estándar file
. Los datos adjuntos de imagen tienen la propiedad ChatAttachmentType
de image
, que requiere el token de comunicación para recuperar las imágenes de tamaño completo o de vista previa.
Antes de continuar, finalice el tutorial Habilitación de la compatibilidad con imágenes insertadas. Para identificar los datos adjuntos de imágenes, es necesario averiguar si el contenido del mensaje contiene el mismo id. de imagen de los datos adjuntos.
bool isImageAttachment = message.Content.Message.Contains(x.Id);
Si esta marca es true, aplique la lógica de imagen insertada para representarla:
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);
}
La aplicación ya admite adjuntar imágenes.
Pasos siguientes
- Más información sobre cómo habilitar la compatibilidad con imágenes insertadas.
- Obtenga más información sobre otras características de interoperabilidad admitidas.
- Consulte la muestra de héroe de Chat.
- Obtenga más información sobre cómo funciona Chat.