Menganalisis dan memberi label pada pesan Gmail dengan Gemini dan Vertex AI

Punya waktu 5 menit?
Bantu kami meningkatkan kualitas dokumentasi Google Workspace dengan mengisi survei online singkat.

Solusi ini menggunakan Vertex AI dan Gemini untuk menganalisis pesan Gmail dan melabelinya berdasarkan sentimennya.

Tingkat coding: Menengah
Durasi: 30 menit
Jenis project: Add-on Google Workspace

  • Add-on Google Workspace yang memperluas Gmail di sidebar.
    Gambar 1: Add-on Analisis Sentimen menampilkan sidebar di Gmail tempat pengguna dapat meminta Gemini menganalisis dan menerapkan label ke pesan berdasarkan sentimen.
  • Pesan Gmail dengan sentimen netral.
    Gambar 2: Add-on memberi label pada pesan Gmail dengan label NADA NETRAL 😐.
  • Pesan Gmail dengan sentimen positif.
    Gambar 3: Add-on melabeli pesan Gmail dengan label HAPPY TONE 😊.
  • Pesan Gmail dengan sentimen negatif.
    Gambar 4: Add-on memberi label pada pesan Gmail dengan label UPSET TONE 😡.

Tujuan

  • Pahami fungsi solusi.
  • Pahami fungsi layanan Google dalam solusi.
  • Siapkan lingkungan.
  • Siapkan project Google Apps Script.
  • Jalankan skrip.

Tentang solusi ini

Screenshot add-on Google Workspace Analisis Sentimen

Solusi ini adalah add-on Google Workspace yang menerapkan label berdasarkan sentimen pesan Gmail. Untuk menganalisis konten pesan, add-on menggunakan Vertex AI untuk meminta model Gemini 2.5 Flash dan menampilkan salah satu sentimen berikut:

  • Positif
  • Negatif
  • Netral

Dengan respons dari Gemini, add-on menerapkan label Gmail yang sesuai ke pesan.

Untuk membatasi permintaan ke Vertex AI API, add-on ini hanya menganalisis dan menerapkan label ke 10 pesan terbaru di kotak masuk pengguna Gmail. Untuk mempelajari lebih lanjut kuota dan batas, buka dokumentasi Vertex AI.

Cara kerjanya

Solusi ini dibuat di Google Apps Script dan menggunakan layanan dan produk Google berikut:

  • Vertex AI API–Mendorong model Gemini 2.5 Flash untuk menganalisis konten pesan Gmail dan mengidentifikasi sentimen.
  • Layanan Apps Script:

    • Layanan Gmail–Mengambil dan menerapkan label ke pesan Gmail. Secara opsional, membuat pesan contoh untuk menguji add-on.
    • Layanan kartu–Membuat antarmuka pengguna add-on yang muncul sebagai sidebar di Gmail.
    • Layanan URL-fetch–Terhubung ke Vertex AI API untuk analisis sentimen.
    • Layanan skrip– Untuk memanggil Vertex AI API, dapatkan token akses OAuth 2.0 untuk add-on menggunakan metode getOAuthToken.

Prasyarat

Menyiapkan lingkungan Anda

Bagian ini menjelaskan cara mengonfigurasi dan menyiapkan lingkungan Anda di Konsol Google Cloud dan Apps Script.

Mengonfigurasi project Cloud Anda di konsol Google Cloud

Bagian ini menunjukkan cara mengaktifkan Vertex AI API dan mengonfigurasi layar izin OAuth di project Cloud Anda.

Mengaktifkan Vertex AI API

  1. Di konsol Google Cloud, buka project Google Cloud Anda dan aktifkan Vertex AI API:

    Mengaktifkan API

  2. Pastikan Anda mengaktifkan API di project Cloud yang benar, lalu klik Next.

  3. Pastikan Anda mengaktifkan API yang benar, lalu klik Aktifkan.

Mengonfigurasi layar izin OAuth

Add-on Google Workspace memerlukan konfigurasi layar izin. Mengonfigurasi layar izin OAuth add-on Anda menentukan konten yang ditampilkan Google kepada pengguna.

  1. Di Konsol Google Cloud, buka Menu > > Branding.

    Buka Branding

  2. Jika sudah mengonfigurasi , Anda dapat mengonfigurasi setelan Layar Izin OAuth berikut di Branding, Audiens, dan Akses Data. Jika Anda melihat pesan yang menyatakan belum dikonfigurasi, klik Mulai:
    1. Di bagian Informasi Aplikasi, di Nama aplikasi, masukkan nama untuk aplikasi.
    2. Di Email dukungan pengguna, pilih alamat email dukungan yang dapat dihubungi pengguna jika mereka memiliki pertanyaan tentang izin mereka.
    3. Klik Berikutnya.
    4. Di bagian Audiens, pilih Internal.
    5. Klik Berikutnya.
    6. Di bagian Informasi Kontak, masukkan Alamat email tempat Anda dapat menerima notifikasi tentang perubahan apa pun pada project Anda.
    7. Klik Berikutnya.
    8. Di bagian Selesai, tinjau Kebijakan Data Pengguna Layanan Google API dan jika Anda setuju, pilih Saya setuju dengan Google API Services: User Data Policy.
    9. Klik Lanjutkan.
    10. Klik Buat.
  3. Untuk saat ini, Anda dapat melewati penambahan cakupan. Pada masa mendatang, saat Anda membuat aplikasi untuk digunakan di luar organisasi Google Workspace, Anda harus mengubah Jenis pengguna menjadi Eksternal. Kemudian tambahkan cakupan otorisasi yang diperlukan aplikasi Anda. Untuk mempelajari lebih lanjut, lihat panduan Mengonfigurasi izin OAuth selengkapnya.

Membuat dan menyiapkan project Apps Script

Untuk membuat dan menyiapkan project Apps Script untuk add-on, selesaikan langkah-langkah berikut:

  1. Klik tombol berikut untuk membuka project Apps Script Gmail Sentiment Analysis with Gemini and Vertex AI.
    Membuka project Apps Script

  2. Klik Ringkasan .

  3. Di halaman ringkasan, klik Buat salinan Ikon untuk membuat salinan.

  4. Dapatkan nomor project Cloud Anda:

    1. Di Konsol Google Cloud, buka Menu > IAM & Admin > Settings.

      Buka Setelan IAM & Admin

    2. Di kolom Project number, salin nilai.
  5. Hubungkan project Cloud Anda dengan project Apps Script Anda:

    1. Di project Apps Script yang Anda salin, klik Project Settings Ikon untuk setelan project.
    2. Pada Google Cloud Platform (GCP) Project, klik Change project.
    3. Di GCP project number, tempelkan nomor project Cloud.
    4. Klik Set project.

Menguji add-on

Untuk mencoba add-on, instal deployment pengujian lalu buka add-on di Gmail:

  1. Membuat dan menginstal deployment pengujian Apps Script:
    1. Di project Apps Script yang Anda salin, klik Editor .
    2. Buka file Code.gs, lalu klik Jalankan. Saat diminta, izinkan skrip.
    3. Klik Deploy > Test deployments.
    4. Klik Instal > Selesai.
  2. Buka Gmail.

    Buka Gmail

  3. Di sidebar kanan, buka add-on Sentiment Analysis.

  4. Jika diminta, izinkan add-on.

  5. Opsional: Untuk membuat pesan yang akan diuji dengan add-on Anda, klik Buat email contoh. Tiga pesan muncul di kotak masuk Anda. Jika Anda tidak melihatnya, muat ulang halaman.

  6. Untuk menambahkan label, klik Analisis email.

Add-on ini meninjau 10 pesan terbaru di kotak masuk Anda, lalu menerapkan salah satu label berikut berdasarkan konten pesan:

  • NADA BAHAGIA 😊
  • NUANSA NETRAL 😐
  • NADA KESAL 😡

Meninjau kode

Tinjau kode Apps Script untuk solusi ini:

Melihat kode sumber

Code.gs

gmail-sentiment-analysis/Code.gs
/*
Copyright 2024 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Triggered when the add-on is opened from the Gmail homepage.
 *
 * @param {Object} e - The event object.
 * @returns {Card} - The homepage card.
 */
function onHomepageTrigger(e) {
  return buildHomepageCard();
}

Cards.gs

gmail-sentiment-analysis/Cards.gs
/*
Copyright 2024-2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Builds the main card displayed on the Gmail homepage.
 *
 * @returns {Card} - The homepage card.
 */
function buildHomepageCard() {
  // Create a new card builder
  const cardBuilder = CardService.newCardBuilder();

  // Create a card header
  const cardHeader = CardService.newCardHeader();
  cardHeader.setImageUrl('https://fonts.gstatic.com/s/i/googlematerialicons/mail/v6/black-24dp/1x/gm_mail_black_24dp.png');
  cardHeader.setImageStyle(CardService.ImageStyle.CIRCLE);
  cardHeader.setTitle("Analyze your Gmail");

  // Add the header to the card
  cardBuilder.setHeader(cardHeader);

  // Create a card section
  const cardSection = CardService.newCardSection();

  // Create buttons for generating sample emails and analyzing sentiment
  const buttonSet = CardService.newButtonSet();

  // Create "Generate sample emails" button
  const generateButton = createFilledButton('Generate sample emails', 'generateSampleEmails', '#34A853');
  buttonSet.addButton(generateButton);

  // Create "Analyze emails" button
  const analyzeButton = createFilledButton('Analyze emails', 'analyzeSentiment', '#FF0000');
  buttonSet.addButton(analyzeButton);

  // Add the button set to the section
  cardSection.addWidget(buttonSet);

  // Add the section to the card
  cardBuilder.addSection(cardSection);

  // Build and return the card
  return cardBuilder.build();
}

/**
 * Creates a filled text button with the specified text, function, and color.
 *
 * @param {string} text - The text to display on the button.
 * @param {string} functionName - The name of the function to call when the button is clicked.
 * @param {string} color - The background color of the button.
 * @returns {TextButton} - The created text button.
 */
function createFilledButton(text, functionName, color) {
  // Create a new text button
  const textButton = CardService.newTextButton();

  // Set the button text
  textButton.setText(text);

  // Set the action to perform when the button is clicked
  const action = CardService.newAction();
  action.setFunctionName(functionName);
  textButton.setOnClickAction(action);

  // Set the button style to filled
  textButton.setTextButtonStyle(CardService.TextButtonStyle.FILLED);

  // Set the background color
  textButton.setBackgroundColor(color);

  return textButton;
}

/**
 * Creates a notification response with the specified text.
 *
 * @param {string} notificationText - The text to display in the notification.
 * @returns {ActionResponse} - The created action response.
 */
function buildNotificationResponse(notificationText) {
  // Create a new notification
  const notification = CardService.newNotification();
  notification.setText(notificationText);

  // Create a new action response builder
  const actionResponseBuilder = CardService.newActionResponseBuilder();

  // Set the notification for the action response
  actionResponseBuilder.setNotification(notification);

  // Build and return the action response
  return actionResponseBuilder.build();
}

Gmail.gs

gmail-sentiment-analysis/Gmail.gs
/*
Copyright 2024-2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Analyzes the sentiment of the first 10 threads in the inbox
 * and labels them accordingly.
 *
 * @returns {ActionResponse} - A notification confirming completion.
 */
function analyzeSentiment() {
  // Analyze and label emails
  analyzeAndLabelEmailSentiment();

  // Return a notification
  return buildNotificationResponse("Successfully completed sentiment analysis");
}

/**
 * Analyzes the sentiment of emails and applies appropriate labels.
 */
function analyzeAndLabelEmailSentiment() {
  // Define label names
  const labelNames = ["HAPPY TONE 😊", "NEUTRAL TONE 😐", "UPSET TONE 😡"];

  // Get or create labels for each sentiment
  const positiveLabel = GmailApp.getUserLabelByName(labelNames[0]) || GmailApp.createLabel(labelNames[0]);
  const neutralLabel = GmailApp.getUserLabelByName(labelNames[1]) || GmailApp.createLabel(labelNames[1]);
  const negativeLabel = GmailApp.getUserLabelByName(labelNames[2]) || GmailApp.createLabel(labelNames[2]);

  // Get the first 10 threads in the inbox
  const threads = GmailApp.getInboxThreads(0, 10);

  // Iterate through each thread
  for (const thread of threads) {
    // Iterate through each message in the thread
    const messages = thread.getMessages();
    for (const message of messages) {
      // Get the plain text body of the message
      const emailBody = message.getPlainBody();

      // Analyze the sentiment of the email body
      const sentiment = processSentiment(emailBody);

      // Apply the appropriate label based on the sentiment
      if (sentiment === 'positive') {
        thread.addLabel(positiveLabel);
      } else if (sentiment === 'neutral') {
        thread.addLabel(neutralLabel);
      } else if (sentiment === 'negative') {
        thread.addLabel(negativeLabel);
      }
    }
  }
}

/**
 * Generates sample emails for testing the sentiment analysis.
 *
 * @returns {ActionResponse} - A notification confirming email generation.
 */
function generateSampleEmails() {
  // Get the current user's email address
  const userEmail = Session.getActiveUser().getEmail();

  // Define sample emails
  const sampleEmails = [
    {
      subject: 'Thank you for amazing service!',
      body: 'Hi, I really enjoyed working with you. Thank you again!',
      name: 'Customer A'
    },
    {
      subject: 'Request for information',
      body: 'Hello, I need more information on your recent product launch. Thank you.',
      name: 'Customer B'
    },
    {
      subject: 'Complaint!',
      body: '',
      htmlBody: `<p>Hello, You are late in delivery, again.</p>
<p>Please contact me ASAP before I cancel our subscription.</p>`,
      name: 'Customer C'
    }
  ];

  // Send each sample email
  for (const email of sampleEmails) {
    GmailApp.sendEmail(userEmail, email.subject, email.body, {
      name: email.name,
      htmlBody: email.htmlBody
    });
  }

  // Return a notification
  return buildNotificationResponse("Successfully generated sample emails");
}

Vertex.gs

gmail-sentiment-analysis/Vertex.gs
/*
Copyright 2024-2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Replace with your project ID
const PROJECT_ID = '[ADD YOUR GCP PROJECT ID HERE]';

// Location for your Vertex AI model
const VERTEX_AI_LOCATION = 'us-central1';

// Model ID to use for sentiment analysis
const MODEL_ID = 'gemini-2.5-flash';

/**
 * Sends the email text to Vertex AI for sentiment analysis.
 *
 * @param {string} emailText - The text of the email to analyze.
 * @returns {string} - The sentiment of the email ('positive', 'negative', or 'neutral').
 */
function processSentiment(emailText) {
  // Construct the API endpoint URL
  const apiUrl = `https://${VERTEX_AI_LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION}/publishers/google/models/${MODEL_ID}:generateContent`;

  // Prepare the request payload
  const payload = {
    contents: [
      {
        role: "user",
        parts: [
          {
            text: `Analyze the sentiment of the following message: ${emailText}`
          }
        ]
      }
    ],
    generationConfig: {
      temperature: 0.9,
      maxOutputTokens: 1024,
      responseMimeType: "application/json",
      // Expected response format for simpler parsing.
      responseSchema: {
        type: "object",
        properties: {
          response: {
            type: "string",
            enum: ["positive", "negative", "neutral"]
          }
        }
      }
    }
  };

  // Prepare the request options
  const options = {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
    },
    contentType: 'application/json',
    muteHttpExceptions: true, // Set to true to inspect the error response
    payload: JSON.stringify(payload)
  };

  // Make the API request
  const response = UrlFetchApp.fetch(apiUrl, options);

  // Parse the response. There are two levels of JSON responses to parse.
  const parsedResponse = JSON.parse(response.getContentText());
  const sentimentResponse = JSON.parse(parsedResponse.candidates[0].content.parts[0].text).response;

  // Return the sentiment
  return sentimentResponse;
}

appsscript.json

gmail-sentiment-analysis/appsscript.json
{
  "timeZone": "America/Toronto",
  "oauthScopes": [
    "https://www.googleapis.com/auth/cloud-platform",
    "https://www.googleapis.com/auth/gmail.addons.execute",
    "https://www.googleapis.com/auth/gmail.labels",
    "https://www.googleapis.com/auth/gmail.modify",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/userinfo.email"
  ],
  "addOns": {
    "common": {
      "name": "Sentiment Analysis",
      "logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/sentiment_extremely_dissatisfied/v6/black-24dp/1x/gm_sentiment_extremely_dissatisfied_black_24dp.png"
    },
    "gmail": {
      "homepageTrigger": {
        "runFunction": "onHomepageTrigger",
        "enabled": true
      }
    }
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

Pembersihan

Agar tidak menimbulkan biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, sebaiknya hapus project Cloud tersebut.

  1. Di Konsol Google Cloud, buka halaman Manage resources. Klik Menu > IAM & Admin > Kelola Resource.

    Buka Resource Manager

  2. Dalam daftar project, pilih project yang ingin Anda hapus, lalu klik Hapus .
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.

Langkah berikutnya