Menyesuaikan tampilan dan nuansa agen

Note

Artikel ini menjelaskan fitur yang digunakan oleh agen atau alur agen yang didukung oleh standard harness.

Kanvas dari agen mengendalikan bagaimana agen ditampilkan kepada pengguna. Anda dapat menyesuaikan kanvas dengan dua cara:

Anda juga dapat menggabungkan kanvas yang disesuaikan dengan mengonfigurasi mulai percakapan otomatis.

Anda dapat mengubah nama dan ikon agen di portal.

Setelah Anda publikasikan agen, pengguna dapat berinteraksi dengannya melalui kanvas Web Chat.

Important

Anda dapat menginstal dan menggunakan kode sampel yang disertakan dalam artikel ini hanya untuk digunakan dengan Copilot Studio. Kode sampel dilisensikan "sebagaimana adanya" dan dikecualikan dari perjanjian tingkat layanan atau layanan dukungan. Anda menanggung risiko menggunakannya.

Microsoft tidak memberikan jaminan, garansi, atau ketentuan tersurat dan mengecualikan semua jaminan tersirat, termasuk kelayakan untuk diperdagangkan, kesesuaian untuk tujuan tertentu, dan tidak adanya pelanggaran.

Ubah nama agen dan ikon

Important

  • Setelah Anda memperbarui ikon untuk agen, mungkin perlu waktu hingga 24 jam agar ikon baru muncul di mana-mana.
  • Jika agen Anda terhubung ke Omnichannel for Customer Service, properti Display name pada pendaftaran di portal Azure menentukan namanya.
  • Jika agen Anda dimaksudkan untuk diterbitkan ke Teams, tinjau syarat untuk ikon dalam dokumentasi pengembang Microsoft Teams.
  1. Buka halaman Ringkasan untuk agen Anda.

  2. Pilih Edit di samping Detail.

  3. Ubah nama dan ikon agen sesuai keinginan.

  4. Pilih Simpan.

Sesuaikan kanvas default (sederhana)

Gunakan JavaScript dan CSS untuk menyesuaikan kanvas default.

Pertama, konfigurasikan tempat Anda menyebarkan kanvas agen Anda.

  1. Buat dan publikasikan agen.

  2. Salin sampel kode HTML ke dalam file bernama index.html. Anda juga dapat menggunakan editor coba-coba HTML.

    
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="Contoso Web Chat Assistant" />
        <title>Contoso Sample Web Chat Test</title>
        <script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
        <script>
          let webChatInstance = null;
          let directLineUrl = null;
    
          // Replace with your token endpoint
          const tokenEndpoint = "<YOUR TOKEN ENDPOINT>";
          const styleOptions = {
            "accent": "#0078D4",
            "autoScrollSnapOnPage": true,
            "autoScrollSnapOnPageOffset": 0,
            "avatarBorderRadius": "7%",
            "avatarSize": 31,
            "backgroundColor": "#e8e9eb",
            "botAvatarBackgroundColor": "#ffffff00",
            "botAvatarImage": "https://powercatexternal.blob.core.windows.net/creatorkit/Assets/ChatbotLogoBlue.png",
            "botAvatarInitials": "B",
            "bubbleAttachmentMaxWidth": 480,
            "bubbleAttachmentMinWidth": 250,
            "bubbleBackground": "#f0eded",
            "bubbleBorderColor": "#f5f5f5",
            "bubbleBorderRadius": 41,
            "bubbleBorderStyle": "solid",
            "bubbleBorderWidth": 1,
            "bubbleFromUserBackground": "#ebefff",
            "bubbleFromUserBorderColor": "#f5f5f5",
            "bubbleFromUserBorderRadius": 41,
            "bubbleFromUserBorderStyle": "solid",
            "bubbleFromUserBorderWidth": 1,
            "bubbleFromUserNubOffset": 0,
            "bubbleFromUserNubSize": 0,
            "bubbleFromUserTextColor": "#242424",
            "bubbleImageHeight": 10,
            "bubbleImageMaxHeight": 240,
            "bubbleImageMinHeight": 240,
            "bubbleMessageMaxWidth": 480,
            "bubbleMessageMinWidth": 120,
            "bubbleMinHeight": 50,
            "bubbleNubOffset": 0,
            "bubbleTextColor": "#242424",
            "emojiSet": true,
            "fontSizeSmall": "70%",
            "hideUploadButton": false,
            "messageActivityWordBreak": "break-word",
            "monospaceFont": "Consolas",
            "paddingRegular": 10,
            "paddingWide": 10,
            "primaryFont": null,
            "sendBoxBackground": "#e8e9eb",
            "sendBoxBorderTop": "solid 1px #808080",
            "sendBoxButtonColor": "#0078d4",
            "sendBoxButtonColorOnHover": "#006cbe",
            "sendBoxButtonShadeBorderRadius": 40,
            "sendBoxButtonShadeColorOnHover": "",
            "sendBoxHeight": 60,
            "sendBoxPlaceholderColor": "#171616",
            "sendBoxTextColor": "#2e2d2d",
            "showAvatarInGroup": "status",
            "spinnerAnimationHeight": 16,
            "spinnerAnimationPadding": 12,
            "spinnerAnimationWidth": 16,
            "subtleColor": "#000000FF",
            "suggestedActionBackgroundColor": "#006FC4FF",
            "suggestedActionBackgroundColorOnHover": "#0078D4",
            "suggestedActionBorderColor": "",
            "suggestedActionBorderRadius": 10,
            "suggestedActionBorderWidth": 1,
            "suggestedActionLayout": "flow",
            "suggestedActionTextColor": "#FFFFFFFF",
            "typingAnimationBackgroundImage": "url('https://wpamelia.com/wp-content/uploads/2018/11/ezgif-2-6d0b072c3d3f.gif')",
            "typingAnimationDuration": 5000,
            "typingAnimationHeight": 20,
            "typingAnimationWidth": 64,
            "userAvatarBackgroundColor": "#222222",
            "userAvatarImage": "https://avatars.githubusercontent.com/u/8174072?v=4&size=64",
            "userAvatarInitials": "U"
          };
          const backgroundImage = "";
    
          document.addEventListener('DOMContentLoaded', () => {
            const root = document.documentElement;
            root.style.setProperty('--primary-color', createGradient(styleOptions.accent));
            root.style.setProperty('--header-textColor', styleOptions.suggestedActionTextColor);
    
            if (backgroundImage) {
              const webchatElement = document.getElementById('webchat');
              webchatElement.style.backgroundImage = `url(${backgroundImage})`;
              webchatElement.style.backgroundSize = 'cover';
              webchatElement.style.backgroundPosition = 'center';
              webchatElement.style.backgroundRepeat = 'no-repeat';
    
              const overlay = document.createElement('div');
              overlay.className = 'webchat-overlay';
              webchatElement.appendChild(overlay);
            }
          });
    
          function createGradient(baseColor) {
            const r = parseInt(baseColor.slice(1, 3), 16);
            const g = parseInt(baseColor.slice(3, 5), 16);
            const b = parseInt(baseColor.slice(5, 7), 16);
            const lighterColor = `#${Math.min(255, r + 30).toString(16).padStart(2, '0')}${Math.min(255, g + 30).toString(16).padStart(2, '0')}${Math.min(255, b + 30).toString(16).padStart(2, '0')}`;
            const darkerColor = `#${Math.max(0, r - 30).toString(16).padStart(2, '0')}${Math.max(0, g - 30).toString(16).padStart(2, '0')}${Math.max(0, b - 30).toString(16).padStart(2, '0')}`;
            return `linear-gradient(135deg, ${lighterColor}, ${baseColor}, ${darkerColor})`;
          }
    
          const environmentEndPoint = tokenEndpoint.slice(
            0,
            tokenEndpoint.indexOf("/powervirtualagents")
          );
          const apiVersion = tokenEndpoint
            .slice(tokenEndpoint.indexOf("api-version"))
            .split("=")[1];
          const regionalChannelSettingsURL = `${environmentEndPoint}/powervirtualagents/regionalchannelsettings?api-version=${apiVersion}`;
    
          function showChat() {
            const popup = document.getElementById("chatbot-popup");
            const openButton = document.getElementById("open-chat");
            popup.classList.add("visible");
            openButton.classList.add("hidden");
          }
    
          function hideChat() {
            const popup = document.getElementById("chatbot-popup");
            const openButton = document.getElementById("open-chat");
            popup.classList.remove("visible");
            openButton.classList.remove("hidden");
          }
    
          function createCustomStore() {
            return window.WebChat.createStore(
              {},
              ({ dispatch }) =>
                (next) =>
                (action) => {
                  if (action.type === "DIRECT_LINE/CONNECT_FULFILLED") {
                    dispatch({
                      type: "DIRECT_LINE/POST_ACTIVITY",
                      meta: { method: "keyboard" },
                      payload: {
                        activity: {
                          channelData: { postBack: true },
                          name: "startConversation",
                          type: "event",
                        },
                      },
                    });
                  }
                  return next(action);
                }
            );
          }
    
          async function restartConversation() {
            try {
              if (!directLineUrl) {
                console.error("DirectLine URL not initialized");
                return;
              }
    
              const response = await fetch(tokenEndpoint);
              const conversationInfo = await response.json();
    
              if (!conversationInfo.token) {
                throw new Error("Failed to get conversation token");
              }
    
              const newDirectLine = window.WebChat.createDirectLine({
                domain: `${directLineUrl}v3/directline`,
                token: conversationInfo.token,
              });
    
              const webchatElement = document.getElementById("webchat");
              webChatInstance = window.WebChat.renderWebChat(
                {
                  directLine: newDirectLine,
                  styleOptions,
                  store: createCustomStore(),
                },
                webchatElement
              );
            } catch (err) {
              console.error("Failed to restart conversation:", err);
            }
          }
    
          async function initializeChat() {
            try {
              const response = await fetch(regionalChannelSettingsURL);
              const data = await response.json();
              directLineUrl = data.channelUrlsById.directline;
    
              if (!directLineUrl) {
                throw new Error("Failed to get DirectLine URL");
              }
    
              const conversationResponse = await fetch(tokenEndpoint);
              const conversationInfo = await conversationResponse.json();
    
              if (!conversationInfo.token) {
                throw new Error("Failed to get conversation token");
              }
    
              const directLine = window.WebChat.createDirectLine({
                domain: `${directLineUrl}v3/directline`,
                token: conversationInfo.token,
              });
    
              webChatInstance = window.WebChat.renderWebChat(
                {
                  directLine,
                  styleOptions,
                  store: createCustomStore(),
                },
                document.getElementById("webchat")
              );
            } catch (err) {
              console.error("Failed to initialize chat:", err);
            }
          }
    
          initializeChat();
      </script>
      <style>
        :root {
          --primary-gradient: var(--primary-color);
          --chat-width: 450px;
          --chat-height: 520px;
          --header-height: 56px;
          --border-radius: 16px;
          --transition-speed: 0.3s;
        }
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
          font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
            Roboto, sans-serif;
        }
        body {
          min-height: 100vh;
          background-color: #f3f4f6;
        }
        #chatbot-popup {
          display: none;
          position: fixed;
          bottom: 32px;
          right: 32px;
          width: var(--chat-width);
          height: var(--chat-height);
          background: white;
          border-radius: var(--border-radius);
          box-shadow: 0 18px 40px -5px rgba(0, 0, 0, 0.2),
            0 15px 20px -5px rgba(0, 0, 0, 0.1);
          overflow: hidden;
          opacity: 0;
          transform-origin: bottom right;
          transform: scale(0.95);
          transition: all var(--transition-speed) ease-in-out;
          z-index: 999;
        }
        #chatbot-popup.visible {
          display: block;
          opacity: 1;
          transform: scale(1);
        }
        #chatbot-header {
          background: var(--primary-color);
          padding: 16px 20px;
          height: var(--header-height);
          display: flex;
          justify-content: space-between;
          align-items: center;
          color: var(--header-textColor);
        }
        .header-title {
          display: flex;
          align-items: center;
          gap: 12px;
          font-size: 16px;
          font-weight: 500;
        }
        .header-buttons {
          display: flex;
          gap: 12px;
          align-items: center;
        }
        .icon-button {
          background: none;
          border: none;
          color: var(--header-textColor);
          cursor: pointer;
          padding: 8px;
          border-radius: 8px;
          display: flex;
          align-items: center;
          justify-content: center;
          transition: all 0.2s ease;
        }
        .icon-button:hover {
          color: var(--header-textColor);
          background: rgba(255, 255, 255, 0.1);
        }
        .icon-button:focus {
          outline: 2px solid rgba(255, 255, 255, 0.5);
          outline-offset: 2px;
        }
        #webchat {
          height: calc(100% - var(--header-height));
          background-color: #f9fafb;
          position: relative;
        }
        .webchat-overlay {
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background: rgba(255, 255, 255, 0.85);
          pointer-events: none;
          z-index: 1;
        }
        #webchat > div {
          position: relative;
          z-index: 2;
        }
        #webchat .webchat__basic-transcript__content {
          white-space: pre-wrap !important;
          word-break: break-word !important;
        }
        #webchat .webchat__bubble__content {
          padding: 8px 12px !important;
        }
        #webchat .webchat__bubble {
          max-width: 85% !important;
          margin: 8px !important;
        }
        #webchat .webchat__basic-transcript__content ul,
        #webchat .webchat__basic-transcript__content ol,
        #webchat .webchat__bubble__content ul,
        #webchat .webchat__bubble__content ol {
          padding-left: 24px !important;
          margin: 8px 0 !important;
          list-style-position: outside !important;
        }
        #webchat .webchat__basic-transcript__content li,
        #webchat .webchat__bubble__content li {
          margin: 4px 0 !important;
          padding-left: 4px !important;
        }
        #open-chat {
          position: fixed;
          bottom: 32px;
          right: 32px;
          width: 64px;
          height: 64px;
          border-radius: 50%;
          background: var(--primary-gradient);
          border: none;
          cursor: pointer;
          display: flex;
          align-items: center;
          justify-content: center;
          box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
          transition: all var(--transition-speed) ease-in-out;
          z-index: 998;
        }
        #open-chat.hidden {
          opacity: 0;
          transform: scale(0.95) translateY(10px);
          pointer-events: none;
        }
        #open-chat:hover {
          transform: translateY(-4px);
          box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
        }
        #open-chat:focus {
          outline: 3px solid rgba(79, 70, 229, 0.5);
          outline-offset: 2px;
        }
        #open-chat svg {
          width: 28px;
          height: 28px;
          color: white;
          transition: transform 0.2s ease;
        }
        .main-content {
          max-width: 1200px;
          margin: 0 auto;
          padding: 48px 24px;
        }
        .main-content h1 {
          font-size: 36px;
          color: #111827;
          text-align: center;
        }
        .main-content p {
          font-size: 18px;
          color: #4b5563;
          line-height: 1.6;
          margin-bottom: 48px;
          text-align: center;
          max-width: 800px;
          margin-left: auto;
          margin-right: auto;
        }
        .content-grid {
          display: grid;
          grid-template-columns: repeat(2, 1fr);
          gap: 32px;
          margin-bottom: 32px;
        }
        .content-box {
          background: linear-gradient(135deg, #e6e6e6, #c4c4c4, #9f9f9f);
          padding: 32px;
          border-radius: 12px;
          box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
                      0 2px 4px -1px rgba(0, 0, 0, 0.06);
          min-height: 300px;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          text-align: center;
          position: relative;
          overflow: hidden;
        }
        .content-box::before {
          content: '';
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          height: 4px;
        }
        .content-box.featured {
          grid-column: span 2;
          min-height: 350px;
          background: linear-gradient(135deg, #e6e6e6, #c4c4c4, #9f9f9f);
          color: #000000;
        }
        .content-box h2 {
          font-size: 24px;
          margin-bottom: 16px;
          position: relative;
        }
        .content-box p {
          font-size: 16px;
          color: #6b7280;
          margin-bottom: 0;
        }
        .content-box.featured p {
          color: #000000;
        }
        @media (max-width: 768px) {
          .content-grid {
            grid-template-columns: 1fr;
          }
          .content-box.featured {
            grid-column: span 1;
          }
          .main-content {
            padding: 24px 16px;
          }
          .main-content h1 {
            font-size: 28px;
          }
          #chatbot-popup {
            width: 100%;
            height: 100%;
            bottom: 0;
            right: 0;
            border-radius: 0;
          }
        }
      </style>
    </head>
    <body>
      <div class="main-content">
        <h1>Header</h1>
        <p>Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat.</p>
        <div class="content-grid">
          <div class="content-box featured">
            <h2>Featured Content</h2>
            <p>Primary content area with custom styling and gradient background</p>
          </div>
          <div class="content-box">
            <h2>Section One</h2>
            <p>Content box with minimal design</p>
          </div>
          <div class="content-box">
            <h2>Section Two</h2>
            <p>Another content section with consistent styling</p>
          </div>
        </div>
      </div>
      <div id="chatbot-popup" role="complementary" aria-label="Chat Assistant">
        <div id="chatbot-header">
          <div class="header-title">
            <svg
              class="chat-icon"
              width="24"
              height="24"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
              aria-hidden="true"
            >
              <path
                d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
              ></path>
            </svg>
            <span>Contoso Assistant</span>
          </div>
          <div class="header-buttons">
            <button
              class="icon-button"
              id="restart-button"
              onclick="restartConversation()"
              aria-label="Restart Conversation"
            >
              <svg
                width="20"
                height="20"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                aria-hidden="true"
              >
                <path
                  d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"
                ></path>
                <path d="M3 3v5h5"></path>
              </svg>
            </button>
            <button
              class="icon-button"
              id="close-button"
              onclick="hideChat()"
              aria-label="Close Chat"
            >
              <svg
                width="20"
                height="20"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                aria-hidden="true"
              >
                <line x1="18" y1="6" x2="6" y2="18"></line>
                <line x1="6" y1="6" x2="18" y2="18"></line>
              </svg>
            </button>
          </div>
        </div>
        <div id="webchat" role="main"></div>
      </div>
      <button
        id="open-chat"
        onclick="showChat()"
        aria-label="Open Chat Assistant"
      >
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
          aria-hidden="true"
        >
          <path
            d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
          ></path>
        </svg>
      </button>
    </body>
    </html>
    
    
  3. Ambil titik akhir token.

  4. Di index.html, ganti:

    const tokenEndpoint = "<YOUR TOKEN ENDPOINT>";
    

    dengan titik akhir token Anda.

  5. Buka index.html di browser modern, seperti Microsoft Edge.

  6. Uji agen.

Jika agen tidak merespons:

  • Yakinkan agen telah diterbitkan.
  • Verifikasi nilai titik akhir token.
  • Konfirmasikan titik akhir token muncul setelah =, dan dikelilingi oleh tanda kutip ganda ".

Ambil titik akhir token untuk agen Anda

Untuk menyesuaikan kanvas, baik kanvas default maupun kustom yang disambungkan ke, Anda memerlukan titik akhir token untuk agen Anda.

  1. Di Pengaturan, pilih Saluran.

  2. Pilih Email.

  3. Di samping Titik Akhir Token, pilih Salin.

Sesuaikan ikon agen, warna latar belakang, dan nama

styleOptions Gunakan objek untuk mengonfigurasi gaya yang telah ditentukan sebelumnya.

Untuk informasi lebih lanjut tentang apa yang dapat Anda sesuaikan dan tautan ke file defaultStyleOptions.js, lihat kustomisasi Web Chat.

Mengubah ikon agen

  1. index.html Perbarui file dengan kode sampel berikut:

    const styleOptions = {
      "accent": "#00809d",
      "botAvatarBackgroundColor": "#FFFFFF",
      "botAvatarImage": "https://learn.microsoft.com/azure/bot-service/v4sdk/media/logo_bot.svg",
      "botAvatarInitials": "BT",
      "userAvatarImage": "https://avatars.githubusercontent.com/u/661465",
      "userAvatarInitials": "U"
    };
    
  2. Ganti kedua gambar avatar dengan gambar perusahaan Anda. Jika Anda tidak memiliki URL gambar, gunakan string gambar yang dikodekan Base64 sebagai gantinya.

Ubah warna latar belakang

  1. Dalam index.html, tambahkan elemen backgroundColor ke definisi styleOptions Anda.

    const styleOptions = {
      "backgroundColor": "lightgray",
      // ...
    };
    
  2. Ubah backgroundColor ke warna apa pun yang Anda inginkan. Gunakan nama warna CSS standar, nilai RGB, atau HEX.

Mengubah nama agen

  1. Perbarui <h1> teks header dalam index.html file dengan kode berikut:

    <body>
      <div id="banner">
        <h1><img src="contoso-agent.png"> Contoso agent name</h1>
      </div>
      <!-- ... -->
    
  2. Ubah teks menjadi apa pun yang ingin Anda sebut untuk agen tersebut. Anda juga dapat menyisipkan gambar, tetapi Anda mungkin perlu menata gambarnya agar sesuai dengan bagian judul.

Menyesuaikan dan meng-host kanvas obrolan Anda (lanjutan)

Anda dapat menghubungkan agen Copilot Studio dengan kanvas kustom yang Anda host sebagai aplikasi web mandiri. Opsi ini bekerja paling baik jika Anda perlu menyematkan iFrame yang disesuaikan di beberapa halaman web.

Note

Hosting kanvas kustom memerlukan pengembangan perangkat lunak. Panduan ini ditujukan untuk profesional TI berpengalaman, seperti admin TI atau pengembang yang memiliki pemahaman yang baik tentang alat pengembang, utilitas, dan lingkungan pengembangan terintegrasi (IDEs).

Mulailah dengan salah satu sampel yang dibuat khusus ini untuk bekerja dengan Copilot Studio:

  • Full bundle adalah kanvas kustom yang dapat menampilkan semua konten beragam dari Copilot Studio. Contohnya:

    Kanvas kustom bundel penuh.

  • Lokasi dan pengunggahan berkas adalah kanvas kustom yang dapat memperoleh lokasi pengguna dan mengirimkannya ke agen Copilot Studio. Contohnya:

    Lokasi dan kanvas kustom untuk pengunggahan file.

Atau, coba beberapa kanvas Web Chat sample lainnya dari Bot Framework.

Seperti kanvas default, Anda dapat menggunakan styleSetOptions untuk menyesuaikan kanvas khusus. Semua properti yang dapat disesuaikan tercantum dalam defaultStyleOptions.js. Untuk informasi selengkapnya tentang apa yang dapat Anda kustomisasi, lihat kustomisasi Web Chat.

Dukung pengaturan koneksi dalam kanvas kustom

Ketika agen yang didukung oleh harness standar membutuhkan koneksi pengguna, kanvas chat menerima Adaptive Card yang memerlukan koneksi. Kanvas kustom Anda harus menangani aksi pada kartu Action.OpenUrlDialog. Tanpa penanganan ini, memilih Sambungkan tidak akan membuka jendela koneksi yang sedang difokuskan.

Buka jendela koneksi

  1. Daftarkan Action.OpenUrlDialog di renderer Kartu Adaptif Anda dan baca properti url. Terima hanya absolute http:// atau https:// URL.
  2. Tentukan apakah origin tujuan dipercaya sebelum membukanya. Percayalah hanya pada origin yang Anda kendalikan atau yang tim keamanan Anda tinjau dan masukkan ke daftar izin.
  3. Buka URL langsung dari pilihan pengguna dengan window.open(url, "_blank", "popup"). Membuka jendela dari aksi pengguna mengurangi kemungkinan browser memblokirnya.
  4. Untuk tujuan tepercaya, dalam argumen windowFeatures dari window.open, hilangkan noopener dan noreferrer sehingga jendela koneksi dapat mengembalikan hasil ke window.opener. Untuk tujuan lain, gunakan noopener,noreferrer dan jangan terima pesan balasan.
  5. Pertahankan referensi yang dikembalikan Window dan ID aktivitas kartu yang memerlukan koneksi. Jika popup diblokir, atau jika pengguna menutupnya tanpa hasil yang valid, pastikan Lanjutkan atau tindakan pemulihan lain tetap tersedia. Jangan mengartikan penutupan jendela sebagai koneksi yang berhasil dibuat.

Kartu Adaptif JavaScript SDK tidak mengimplementasikan Action.OpenUrlDialog secara default. Daftarkan aksi melalui SerializationContext.actionRegistry, atau tangani aksi langsung di renderer yang Anda miliki. Action.OpenUrl Fallback dapat membuka tujuan di klien yang tidak mendukung aksi dialog, tetapi fallback tidak dapat mengembalikan hasil popup.

Important

Jendela koneksi dengan akses ke window.opener dapat menavigasi atau memengaruhi halaman obrolan. Tinjau tujuan dan pengalihan bersama tim keamanan web Anda. Jangan biarkan destinasi tepercaya mengalihkan ke situs yang tidak tepercaya sambil mempertahankan akses opener.

Jika Anda menyematkan Bot Framework Web Chat, penanganan Action.OpenUrlDialog-nya akan membuka jendela koneksi. Jendela dengan origin yang sama dipercaya secara default. Untuk tujuan lintas-origin yang telah ditinjau, atur styleOptions.callURLActionTrustedOrigin ke asal yang diizinkan secara tepat. Pisahkan beberapa asal dengan koma. Anda juga dapat mengatur callURLActionPopupWindowHeight dan callURLActionPopupWindowWidth. Jangan tambahkan origin yang belum Anda ulas.

Lanjutkan setelah pengaturan koneksi berhasil (pratinjau)

[Bagian ini adalah dokumentasi prarilis dan dapat berubah sewaktu-waktu.]

Important

Artikel ini berisi dokumentasi pratinjau Microsoft Copilot Studio dan dapat berubah.

Fitur pratinjau tidak dimaksudkan untuk penggunaan produksi dan mungkin memiliki fungsionalitas terbatas. Fitur ini tersedia sebelum rilis resmi agar Anda bisa memperoleh akses awal dan memberikan tanggapan.

Jika Anda membangun agen yang siap untuk produksi, silakan lihat Gambaran Umum Microsoft Copilot Studio.

Jendela koneksi terpercaya dapat mengirimkan hasil penyelesaian/proses selesai ke halaman chat dengan window.opener.postMessage. Gunakan origin yang sama persis dari halaman obrolan sebagai origin target, bukan *.

Di halaman obrolan:

  1. Jika window.open mengembalikan null, jangan terima pesan untuk percobaan tersebut. Jika tidak, terima pesan hanya jika event.source sesuai dengan referensi popup yang dipertahankan dan event.origin sesuai dengan asal yang diharapkan.

  2. Pastikan bahwa data pesan memiliki type: "postback" dan nilai dalam bentuk yang diharapkan oleh agen atau runtime Anda.

    Contoh berikut mengirimkan pesan dengan teks "hello-world" kepada agen. Fitur ini tidak terlihat di antarmuka chat.

    { "type": "postback", "value": { hello: "World!" } }
    

    Contoh berikut mengirim pesan dengan JSON { hello: "World!" } ke agen.

    { "type": "postback", "value": { hello: "World!" } }
    
  3. Kirim nilai yang disetujui melalui mekanisme postback Bot Framework. Gunakan ID aktivitas yang disimpan sebagai replyToId; jangan terima ID aktivitas balasan dari popup.

  4. Terima paling banyak satu hasil untuk setiap popup. Hapus event listener dan hapus timernya setelah menerima hasil, menolak pesan yang salah dari popup tepercaya, mendeteksi popup tertutup, atau mencapai batas waktu. Web Chat menggunakan batas waktu lima menit.

  5. Koordinasikan dengan agen atau runtime untuk mengkorelasikan postback dengan interaksi asli yang memerlukan koneksi dan lanjutkan giliran tersebut tepat sekali.

Pesan browser tidak dijamin. Pemblokir pop-up, navigasi, Cross-Origin-Opener-Policy, atau jendela tertutup dapat mencegah kelanjutan otomatis. Pastikan Continue atau jalur pemulihan lain tetap tersedia, dan jangan mengartikan pesan yang hilang sebagai keberhasilan.

Terapkan kanvas kustom Anda

Untuk menghosting kanvas kustom Anda, sebarkan semua file ke aplikasi web.