チュートリアル: チャット アプリで添付ファイルのサポートを有効にする
Chat SDK は、会議のコンテキストで Microsoft Teams とシームレスに連携します。 Azure Communication Services ユーザーに添付ファイルを送信できるのは、Teams ユーザーだけです。 Azure Communication Services ユーザーは、Teams ユーザーに添付ファイルを送信できません。 現在の機能については、Teams とチャットの相互運用性に関する記事を参照してください。
添付ファイルのサポートを追加する
Chat SDK は、添付ファイルごとに previewUrl
プロパティを提供します。 具体的には、previewUrl
は SharePoint 上の Web ページへのリンクを提供します。これを通じ、アクセス許可があれば、ユーザーはファイルの内容の表示、ファイルの編集、ファイルのダウンロードを行うことができます。
この機能に関連する次のような制約があります。
送信者のテナントの Teams 管理者は、この機能を制限するか完全に無効にするポリシーを適用できます。 たとえば、Teams 管理者は、特定のアクセス許可 (
Anyone
など) を無効にすることで、添付ファイルの URL (previewUrl
) をアクセス不可にできます。現在、2 つのファイル アクセス許可のみがサポートされています。
Anyone
People you choose
(メール アドレス付き)
他のすべてのアクセス許可 (
People in your organization
など) がサポートされていないことを Teams ユーザーに周知します。 Teams ユーザーは Teams クライアントにファイルをアップロードした後、既定のアクセス許可がサポートされているかダブル チェックする必要があります。直接ダウンロード URL (
url
) はサポートされていません。
Chat SDK では、通常のファイル (file
の AttachmentType
) に加えて、image
の AttachmentType
プロパティも提供されます。 Azure Communication Services ユーザーは、Microsoft Teams クライアントが UI レイヤーで画像の添付ファイルをインライン画像に変換する方法の動作に似た方法で画像を添付できます。 詳細については、「画像の添付ファイルを処理する」を参照してください。
Azure Communication Services ユーザーは、[このデバイスからアップロード] を介して画像を追加できます。画像は Teams 側でレンダリングされ、Chat SDK はこのような 添付ファイルを image
として返します。 [クラウド ファイルの添付] を介してアップロードされた画像の場合、画像は Teams 側で通常のファイルとして扱われ、Chat SDK はそのような添付ファイルを file
として返します。
また、Azure Communication Services ユーザーは、ドラッグ アンド ドロップを使用するか、[このデバイスからアップロード] および [クラウド ファイルの添付] の添付ファイル メニュー コマンドを使用してのみファイルをアップロードできることに注意してください。 埋め込みメディアを含む特定の種類のメッセージ (ビデオ クリップ、オーディオ メッセージ、天気カードなど) は現在サポートされていません。
このチュートリアルでは、JavaScript 用 Azure Communication Services Chat SDK を使用して添付ファイルのサポートを有効にする方法を説明します。
サンプル コード
このチュートリアルの最終的なコードは GitHub にあります。
前提条件
- クイックスタート「チャット アプリを Teams の会議に参加させる」を参照してください。
- Azure Communication Services リソースを作成します。 詳細については、Azure Communication Services リソースの作成に関するページを参照してください。 このチュートリアルで使用する接続文字列を記録する必要があります。
- ビジネス アカウントを使用して Teams 会議を設定し、会議の URL を準備します。
- JavaScript 用 Chat SDK (@azure/communication-chat) 1.5.0 または最新版を使用します。 詳細については、JavaScript 用 Azure Communication Chat クライアント ライブラリに関する記事を参照してください。
目標
- メッセージ スレッドで添付ファイルをレンダリングします。 各添付ファイル カードには、[開く] ボタンがあります。
- 画像添付ファイルをインライン画像としてレンダリングします。
添付ファイルを処理する
JavaScript 用 Chat SDK は、通常の添付ファイルの file
とメッセージのインライン画像の image
の ChatAttachmentType
プロパティを返します。
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 の会議に参加させる」で作成したイベント ハンドラーに戻り、file
の attachmentType
プロパティを使用して添付ファイルを処理するための追加ロジックを追加します。
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
を使用してアプリをビルドして実行できます。 ローカルの Web サーバーにアプリケーション ホストをバンドルするには、次のコマンドを実行します。
npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map
または:
npm start
添付ファイルのデモ
自分のブラウザーを開き、
http://localhost:8080/
にアクセスします。 会議 URL とスレッド ID を入力します。Teams クライアントから添付ファイルをいくつか送信します。
新しいメッセージが添付ファイルと一緒にレンダリングされるのを確認できます。
画像添付ファイルを処理する
画像の添付ファイルは、標準的な file
の添付ファイルとは異なる方法で処理する必要があります。 画像の添付ファイルは image
の attachmentType
プロパティを持つため、プレビュー画像またはフルサイズの画像を取得するための通信トークンが必要です。
続行する前に、チャット アプリでインライン画像のサポートを有効にする方法を説明したチュートリアルを完了してください。 このチュートリアルでは、要求ヘッダーで通信トークンを必要とする画像をフェッチする方法について説明しています。 画像 BLOB を受け取ったら、この BLOB を指す 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;
...
}
これで、画像の添付ファイルがサポートされるようになりました。 次に、コードを実行して動作を確認してみます。
画像添付ファイルのデモ
Teams クライアントから画像の添付ファイルをいくつか送信します。
画像の添付ファイルを送信すると、Teams クライアント側ではインライン画像になることに注意してください。
サンプル アプリに戻り、同じ画像がレンダリングされていることを確認します。
このチュートリアルでは、C# 用 Azure Communication Services Chat SDK を使用して添付ファイルのサポートを有効にする方法を説明します。
このチュートリアルでは、次の作業を行う方法について説明します。
- 添付ファイルを処理します。
- 画像の添付ファイルを処理します。
前提条件
- クイックスタート「チャット アプリを Teams の会議に参加させる」を参照してください。
- 「Azure Communication Services リソースの作成」の説明に従って、Azure Communication Services リソースを作成します。 このチュートリアルで使用する接続文字列を記録する必要があります。
- ビジネス アカウントを使用して Teams 会議を設定し、会議の URL を準備します。
- Chat SDK for C# (@azure/communication-chat) 1.3.0 以降をダウンロードします。 詳細については、Azure Communication Chat クライアント ライブラリに関する記事を参照してください。
サンプル コード
このチュートリアルの最終的なコードは GitHub にあります。
添付ファイルを処理する
C# 用 Chat SDK は、通常の添付ファイルの file
とインライン画像の image
の ChatAttachmentType
プロパティを返します。
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"
}
]
ここで、前のクイックスタートで作成したイベント ハンドラーに戻り、 file
の ChatAttachmentType
プロパティを使用して添付ファイルを処理するための追加ロジックを追加します。
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
プロパティを取得し、for loop
に URL の一覧を作成します。 次に、チャット メッセージの内容と共に文字列を埋め込みます。
画像添付ファイルを処理する
画像の添付ファイルは、標準の file
添付ファイルとは異なる方法で処理する必要があります。 画像の添付ファイルは image
の ChatAttachmentType
プロパティを持つため、プレビュー画像またはフルサイズの画像を取得するための通信トークンが必要です。
続行する前に、「インライン画像のサポートを有効にする」チュートリアルを完了してください。 画像の添付ファイルを識別するには、メッセージの内容に添付ファイルと同じ画像 ID が含まれているかどうかを確認する必要があります。
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);
}
これで、アプリで画像の添付ファイルがサポートされるようになりました。
次のステップ
- インライン画像のサポートを有効にする方法の詳細をご覧ください。
- その他のサポートされている相互運用性機能の詳細をご覧ください。
- チャットのヒーロー サンプルをご覧ください。
- チャットのしくみの詳細をご覧ください。