Megosztás a következőn keresztül:


Oktatóanyag: Beágyazott kép támogatásának engedélyezése a csevegőalkalmazásban

A Csevegő SDK-t úgy tervezték, hogy zökkenőmentesen működjön együtt a Microsoft Teamsszel. A Csevegő SDK megoldást kínál beágyazott képek fogadására és beágyazott képek küldésére a Microsoft Teams felhasználóinak.

Ebben az oktatóanyagban megtudhatja, hogyan engedélyezheti a beágyazott rendszerképek támogatását az Azure Communication Services Chat SDK for JavaScript használatával.

A beágyazott képek olyan képek, amelyek közvetlenül a Teams-ügyfél küldési mezőjébe vannak másolva és beillesztve. Az eszköz menüjéből vagy húzással, például a Teams küldési mezőjébe közvetlenül áthúzott képek esetében a fájlmegosztási funkció részeként tekintse meg ezt az oktatóanyagot. (Lásd a "Képmellékletek kezelése" című szakaszt.)

A rendszerkép másolásához a Teams-felhasználók két lehetőséget választhatnak:

  • Az operációs rendszer helyi menüjével másolja a képfájlt, majd illessze be a Teams-ügyfél küldési mezőjébe.
  • Billentyűparancsok használata.

Ebben az oktatóanyagban megtudhatja, mit kell tennie, ha:

Feljegyzés

A beágyazott képek küldésének lehetősége jelenleg nyilvános előzetes verzióban érhető el. Csak JavaScripthez érhető el. Beágyazott képek fogadásához jelenleg általánosan elérhető. JavaScript és C# nyelven is elérhető egy Teams együttműködési csevegésben.

Előfeltételek

Mintakód

Keresse meg az oktatóanyag véglegesített kódját a GitHubon.

Fogadott beágyazott képek kezelése új üzeneteseményben

Ebben a szakaszban megtudhatja, hogyan jeleníthet meg beágyazott képeket egy új fogadott esemény üzenettartalmaiba ágyazva.

A rövid útmutatóban létrehozott egy eseménykezelőt az chatMessageReceived eseményhez, amely akkor aktiválódik, amikor új üzenetet kap a Teams-felhasználótól. A bejövő üzenet tartalmát messageContainer is hozzáfűzi közvetlenül az chatMessageReceived esemény fogadása után a chatClientkövetkezőhöz:

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.message);
   }
   else {
      renderSentMessage(e.message);
   }
});
   
async function renderReceivedMessage(message) {
   messages += '<div class="container lighter">' + message + '</div>';
   messagesContainer.innerHTML = messages;
}

A bejövő típusú ChatMessageReceivedEventeseményből egy elnevezett attachments tulajdonság információkat tartalmaz a beágyazott rendszerképről. Mindössze ennyi kell ahhoz, hogy beágyazott képeket jelenítsen meg a felhasználói felületen:

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

  /**
   * Metadata of the message.
   */
  metadata: Record<string, string>;

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

export interface ChatAttachment {
  /** Id of the attachment */
  id: string;
  /** The type of attachment. */
  attachmentType: ChatAttachmentType;
  /** The name of the attachment content. */
  name?: string;
  /** The URL where the attachment can be downloaded */
  url?: string;
  /** The URL where the preview of attachment can be downloaded */
  previewUrl?: string;
}

export type ChatAttachmentType = "image" | "unknown";

Most térjen vissza az előző kódhoz, és adjon hozzá néhány további logikát, például a következő kódrészleteket:

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

function renderReceivedMessage(e, isMyMessage) {
  const messageContent = e.message;

  const card = document.createElement('div');
  card.className = isMyMessage ? "container darker" : "container lighter";
  card.innerHTML = messageContent;
  
  messagesContainer.appendChild(card);
  
  // Filter out inline images from attachments
  const imageAttachments = e.attachments.filter((e) =>
    e.attachmentType.toLowerCase() === 'image');
  
  // Fetch and render preview images
  fetchPreviewImages(imageAttachments);
  
  // Set up onclick event handler to fetch full-scale image
  setImgHandler(card, imageAttachments);
}

function setImgHandler(element, imageAttachments) {
  // Do nothing if there are no image attachments
  if (!imageAttachments.length > 0) {
    return;
  }
  const imgs = element.getElementsByTagName('img');
  for (const img of imgs) {
    img.addEventListener('click', (e) => {
      // Fetch full-scale image upon click
      fetchFullScaleImage(e, imageAttachments);
    });
  }
}

async function fetchPreviewImages(attachments) {
  if (!attachments.length > 0) {
    return;
  }
  // Since each message could contain more than one inline image
  // we need to fetch them individually 
  const result = await Promise.all(
      attachments.map(async (attachment) => {
        // Fetch preview image from its 'previewURL'
        const response = await fetch(attachment.previewUrl, {
          method: 'GET',
          headers: {
            // The token here should be the same one from chat initialization
            'Authorization': 'Bearer ' + tokenString,
          },
        });
        // The response would be in an image blob, so we can render it directly
        return {
          id: attachment.id,
          content: await response.blob(),
        };
      }),
  );
  result.forEach((imageResult) => {
    const urlCreator = window.URL || window.webkitURL;
    const url = urlCreator.createObjectURL(imageResult.content);
    // Look up the image ID and replace its 'src' with object URL
    document.getElementById(imageResult.id).src = url;
  });
}

Ebben a példában két segédfüggvényt setImgHandlerés egy segédfüggvényt hozott létre. fetchPreviewImages Az első az előnézeti képet közvetlenül az previewURL egyes ChatAttachment objektumokban lévő, hitelesítési fejléccel ellátott objektumokból olvassa be. Hasonlóképpen beállít egy eseményt onclick a függvény setImgHandlerminden képéhez. Az eseménykezelőben egy teljes méretű képet fog lekérni a tulajdonságból url egy ChatAttachment hitelesítési fejléccel rendelkező objektumból.

Most közzé kell tennie a jogkivonatot a globális szinten, mert egy hitelesítési fejlécet kell létrehoznia vele. Módosítania kell a következő kódot:

// New variable for token string
var tokenString = '';

async function init() {

   ....
   
   let tokenResponse = await identityClient.getToken(identityResponse, [
      "voip",
      "chat"
	]);
	const { token, expiresOn } = tokenResponse;
   
   // Save to token string
   tokenString = token;
   
   ...
}

Ha egy átfedésben szeretné megjeleníteni a teljes méretű képet, új összetevőt is hozzá kell adnia:


<div class="overlay" id="overlay-container">
   <div class="content">
      <img id="full-scale-image" src="" alt="" />
   </div>
</div>

Néhány CSS-sel:


/* let's make chat popup scrollable */
.chat-popup {

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

 .overlay {
    position: fixed; 
    width: 100%; 
    height: 100%;
    background: rgba(0, 0, 0, .7);
    top: 0;
    left: 0;
    z-index: 100;
 }

.overlay .content {
   position: fixed; 
   width: 100%;
   height: 100%;
   text-align: center;
   overflow: hidden;
   z-index: 100;
   margin: auto;
   background-color: rgba(0, 0, 0, .7);
}

.overlay img {
   position: absolute;
   display: block;
   max-height: 90%;
   max-width: 90%;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
}

#overlay-container {
   display: none
}

Most, hogy be van állítva egy átfedés, itt az ideje, hogy dolgozzon a logikán a teljes méretű képek rendereléséhez. Ne feledje, hogy egy függvény fetchFullScaleImagemeghívásához létrehozott egy onClick eseménykezelőt:


const overlayContainer = document.getElementById('overlay-container');
const loadingImageOverlay = document.getElementById('full-scale-image');

function fetchFullScaleImage(e, imageAttachments) {
  // Get the image ID from the clicked image element
  const link = imageAttachments.filter((attachment) =>
    attachment.id === e.target.id)[0].url;
  loadingImageOverlay.src = '';
  
  // Fetch the image
  fetch(link, {
    method: 'GET',
    headers: {'Authorization': 'Bearer ' + tokenString},
  }).then(async (result) => {
   
    // Now we set image blob to our overlay element
    const content = await result.blob();
    const urlCreator = window.URL || window.webkitURL;
    const url = urlCreator.createObjectURL(content);
    loadingImageOverlay.src = url;
  });
  // Show overlay
  overlayContainer.style.display = 'block';
}

Az egyik utolsó dolog, amit hozzá szeretne adni, az a lehetőség, hogy a kép kattintásakor el tudja utasítani az átfedést:

loadingImageOverlay.addEventListener('click', () => {
  overlayContainer.style.display = 'none';
});

Most végrehajtotta a valós idejű értesítésekből érkező üzenetek beágyazott rendszerképeinek megjelenítéséhez szükséges összes módosítást.

A kód futtatása

A Webpack-felhasználók létrehozhatják webpack-dev-server és futtathatják az alkalmazást. Futtassa az alábbi parancsot az alkalmazás gazdagépének helyi webkiszolgálón való kötegeléséhez:

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

Bemutató

Nyissa meg a böngészőt, és nyissa meg a kívánt elemet http://localhost:8080/. Adja meg az értekezlet URL-címét és a szálazonosítót. Küldjön néhány beágyazott képet a Teams-ügyfélről.

Képernyőkép egy Teams-ügyfélről a következő üzenettel: Íme néhány ötlet, tudassa velem, mit gondol! Az üzenet két beágyazott képet is tartalmaz a szoba belső makettjeiről.

Ezután az új üzenetnek az előnézeti képekkel együtt kell megjelennie.

Képernyőkép egy bejövő üzenettel rendelkező mintaalkalmazásról beágyazott képekkel.

Miután az Azure Communication Services felhasználója kiválasztotta az előnézeti képet, megjelenik egy átfedés a Teams-felhasználó által küldött teljes méretű képpel.

Képernyőkép egy teljes méretű kép átfedésével rendelkező mintaalkalmazásról.

Beágyazott képek küldésének kezelése új üzenetkérelemben

Fontos

Az Azure Communication Services ezen funkciója jelenleg előzetes verzióban érhető el.

Az előzetes verziójú API-k és SDK-k szolgáltatásszintű szerződés nélkül érhetők el. Javasoljuk, hogy éles számítási feladatokhoz ne használja őket. Előfordulhat, hogy egyes funkciók nem támogatottak, vagy korlátozott képességekkel rendelkeznek.

További információkért tekintse át a Microsoft Azure Előzetes verzió kiegészítő használati feltételeit.

A Beágyazott képekkel ellátott üzenetek kezelése mellett a JavaScripthez készült Csevegő SDK is kínál megoldást arra, hogy a kommunikációs felhasználó beágyazott képeket küldjön a Microsoft Teams-felhasználónak egy együttműködési csevegésben.

Tekintse meg az új API-t a következőből ChatThreadClient:

var imageAttachment = await chatThreadClient.uploadImage(blob, file.name, {
  "onUploadProgress": reportProgressCallback
});

Az API egy képblobot, egy fájlnév-sztringet és egy függvényvisszahívást vesz fel, amely a feltöltés előrehaladását jelenti.

Ha képet szeretne küldeni más csevegő résztvevőnek, a következőkre van szüksége:

  1. Töltse fel a képet az uploadImage API-val ChatThreadClient, és mentse a visszaadott objektumot.
  2. Írja meg az üzenet tartalmát, és állítson be egy mellékletet az előző lépésben mentett visszaadott objektumhoz.
  3. Küldje el az új üzenetet az sendMessage API-ból ChatThreadClient.

Hozzon létre egy új fájlválasztót, amely elfogadja a képeket:

<label for="myfile">Attach images:</label>
<input id="upload" type="file" id="myfile" name="myfile" accept="image/*" multiple>
<input style="display: none;" id="upload-result"></input>

Most állítson be egy eseményfigyelőt arra az esetre, ha állapotváltozás történik:

document.getElementById("upload").addEventListener("change", uploadImages);

Új függvényt kell létrehoznia az állapotváltozások esetén:

var uploadedImageModels = [];

async function uploadImages(e) {
  const files = e.target.files;
  if (files.length === 0) {
    return;
  }
  for (let key in files) {
    if (files.hasOwnProperty(key)) {
        await uploadImage(files[key]);
    }
}
}

async function uploadImage(file) {
  const buffer = await file.arrayBuffer();
  const blob = new Blob([new Uint8Array(buffer)], {type: file.type });
  const url = window.URL.createObjectURL(blob);
  document.getElementById("upload-result").innerHTML += `<img src="${url}" height="auto" width="100" />`;
  let uploadedImageModel = await chatThreadClient.uploadImage(blob, file.name, {
    imageBytesLength: file.size
  });
  uploadedImageModels.push(uploadedImageModel);
}

Ebben a példában létrehozott egy-egy FileReader képet az egyes képek kódolt képként base64való olvasásához, majd a ChatSDK API meghívása előtt létrehozott egy Blob fájlt a feltöltésükhöz. Létrehozott egy globálist uploadedImageModels a feltöltött képek adatmodelljeinek mentéséhez a Csevegő SDK-ból.

Végül módosítania kell a sendMessageButton korábban létrehozott eseményfigyelőt a feltöltött képek csatolásához.

sendMessageButton.addEventListener("click", async () => {
  let message = messagebox.value;
  let attachments = uploadedImageModels;

    // Inject image tags for images we have selected
  // so they can be treated as inline images
  // Alternatively, we can use some third-party libraries 
  // to have a rich text editor with inline image support
  message += attachments.map((attachment) => `<img id="${attachment.id}" />`).join("");

  let sendMessageRequest = {
    content: message,
    attachments: attachments,
  };

  let sendMessageOptions = {
    senderDisplayName: "Jack",
    type: "html"
  };

  let sendChatMessageResult = await chatThreadClient.sendMessage(
    sendMessageRequest,
    sendMessageOptions
  );
  let messageId = sendChatMessageResult.id;
  uploadedImageModels = [];

  messagebox.value = "";
  document.getElementById("upload").value = "";
  console.log(`Message sent!, message id:${messageId}`);
});

Ennyi az egész. Most futtassa a kódot, hogy működés közben láthassa.

A kód futtatása

A Webpack-felhasználók létrehozhatják webpack-dev-server és futtathatják az alkalmazást. Futtassa az alábbi parancsot az alkalmazás gazdagépének helyi webkiszolgálón való kötegeléséhez:

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

Bemutató

Nyissa meg a böngészőt, és nyissa meg a kívánt elemet http://localhost:8080/. A küldési mezőben egy új szakasz található a képek csatolásához.

Képernyőkép a képek csatolásához újonnan hozzáadott szakaszt tartalmazó mintaalkalmazásról.

Ezután kiválaszthatja a csatolni kívánt képeket.

Képernyőkép egy fájlválasztóról, amelyen a felhasználók által az üzenetekhez csatolható képek listája látható.

Képernyőkép a mintaalkalmazásról két csatolt képpel.

A Teams-felhasználónak most meg kell kapnia az imént elküldött képet, amikor a Küldés lehetőséget választja.

Képernyőkép a mintaalkalmazásról egy elküldött üzenettel két beágyazott képpel.

Képernyőkép a Teams-ügyfélről egy fogadott üzenettel két beágyazott képpel.

Ez az oktatóanyag bemutatja, hogyan engedélyezheti a beágyazott rendszerképek támogatását az Azure Communication Services Chat SDK for C# használatával.

Ebben az oktatóanyagban az alábbiakkal fog megismerkedni:

  • Új üzenetek beágyazott lemezképeinek kezelése.

Előfeltételek

Cél

  • previewUri A beágyazott képmellékletek tulajdonságának megragadása.

Új üzenetek beágyazott lemezképeinek kezelése

A rövid útmutatóban lekérdezi az üzeneteket, és hozzáfűzi az új üzeneteket a messageList tulajdonsághoz. Erre a funkcióra később építhet, így elemezheti és lekérheti a beágyazott képeket.

  CommunicationUserIdentifier currentUser = new(user_Id_);
  AsyncPageable<ChatMessage> allMessages = chatThreadClient.GetMessagesAsync();
  SortedDictionary<long, string> messageList = [];
  int textMessages = 0;
  await foreach (ChatMessage message in allMessages)
  {
      if (message.Type == ChatMessageType.Html || message.Type == ChatMessageType.Text)
      {
          textMessages++;
          var userPrefix = message.Sender.Equals(currentUser) ? "[you]:" : "";
          var strippedMessage = StripHtml(message.Content.Message);
          messageList.Add(long.Parse(message.SequenceId), $"{userPrefix}{strippedMessage}");
      }
  }

A bejövő típusú ChatMessageReceivedEventeseményből a névvel ellátott attachments tulajdonság információkat tartalmaz a beágyazott rendszerképről. Mindössze ennyi kell ahhoz, hogy beágyazott képeket jelenítsen meg a felhasználói felületen.

public class ChatAttachment
{
    public ChatAttachment(string id, ChatAttachmentType attachmentType)
    public ChatAttachmentType AttachmentType { get }
    public string Id { get }
    public string Name { get }
    public System.Uri PreviewUrl { get }
    public System.Uri Url { get }
}

public struct ChatAttachmentType : System.IEquatable<AttachmentType>
{
    public ChatAttachmentType(string value)
    public static File { get }
    public static Image { get }
}

Az alábbi JSON egy példa ChatAttachment egy képmellékletre:

"attachments": [
    {
        "id": "9d89acb2-c4e4-4cab-b94a-7c12a61afe30",
        "attachmentType": "image",
        "name": "Screenshot.png",
        "url": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/original?api-version=2023-11-03",
        "previewUrl": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/small?api-version=2023-11-03"
      }
]

Most lépjen vissza, és cserélje le a kódot, hogy további logikát adjon hozzá a képmellékletek elemzéséhez és lekéréséhez:

  CommunicationUserIdentifier currentUser = new(user_Id_);
  AsyncPageable<ChatMessage> allMessages = chatThreadClient.GetMessagesAsync();
  SortedDictionary<long, string> messageList = [];
  int textMessages = 0;
  await foreach (ChatMessage message in allMessages)
  {
      // Get message attachments that are of type 'image'
      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);
      }

      // 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 = chatAttachmentImageUris.Count > 0 ? "[Attachments]:\n" + string.Join(",\n", chatAttachmentImageUris) : "";
          messageList.Add(long.Parse(message.SequenceId), $"{userPrefix}{strippedMessage}\n{chatAttachments}");
      }

Ebben a példában a típusüzenet Image összes mellékletét megragadja, majd beolvassa az egyes képeket. Engedélyezési célokra a Bearer kérelem fejlécének a részében kell használniaToken. A kép letöltése után hozzárendelheti a InlineImage nézet eleméhez.

A melléklet URI-jainak listáját is tartalmaznia kell a szöveges üzenetlistában megjelenő üzenettel együtt.

Bemutató

  • Futtassa az alkalmazást az integrált fejlesztési környezetből (IDE).
  • Adja meg a Teams-értekezlet hivatkozását.
  • Csatlakozzon az értekezlethez.
  • Fogadja el a felhasználót a Teams oldalán.
  • Küldjön egy üzenetet a Teams oldaláról egy képpel.

Az üzenethez tartozó URL-cím megjelenik az üzenetlistában. Az utolsó fogadott kép az ablak alján jelenik meg.

Következő lépések