วิเคราะห์และติดป้ายกำกับข้อความ Gmail ด้วย Gemini และ Vertex AI

โซลูชันนี้ใช้ Vertex AI และ Gemini เพื่อวิเคราะห์ข้อความ Gmail และติดป้ายกำกับตามความรู้สึก

ระดับการเขียนโค้ด: ปานกลาง
ระยะเวลา: 30 นาที
ประเภทโปรเจ็กต์: ส่วนเสริมของ Google Workspace

  • ส่วนเสริมของ Google Workspace ที่ขยาย Gmail ในแถบด้านข้าง

    ส่วนเสริมการวิเคราะห์ความรู้สึก จะแสดงแถบด้านข้างใน Gmail ซึ่งผู้ใช้สามารถแจ้งให้ Gemini วิเคราะห์และติดป้ายกำกับข้อความตามความรู้สึกได้

  • ข้อความ Gmail ที่มีอารมณ์เป็นกลาง

    ส่วนเสริมจะติดป้ายกำกับข้อความ Gmail ด้วยป้ายกำกับโทนเป็นกลาง 😐

  • ข้อความ Gmail ที่มีอารมณ์เชิงบวก

    ส่วนเสริมจะติดป้ายกำกับข้อความ Gmail ด้วยป้ายกำกับโทนมีความสุข 😊

  •  ข้อความ Gmail ที่มีอารมณ์ไม่พอใจ

    ส่วนเสริมจะติดป้ายกำกับข้อความ Gmail ด้วยป้ายกำกับโทนไม่พอใจ 😡

วัตถุประสงค์

  • ทำความเข้าใจสิ่งที่โซลูชันทำ
  • ทำความเข้าใจสิ่งที่บริการของ Google ทำภายในโซลูชัน
  • ตั้งค่าสภาพแวดล้อม
  • ตั้งค่าโปรเจ็กต์ Google Apps Script
  • เรียกใช้สคริปต์

เกี่ยวกับโซลูชันนี้

ส่วนเสริมการวิเคราะห์ความรู้สึกของ Google Workspace

ส่วนเสริมการวิเคราะห์ความรู้สึกของ Google Workspace

โซลูชันนี้เป็นส่วนเสริมของ Google Workspace ที่ติดป้ายกำกับตามความรู้สึกของข้อความ Gmail ส่วนเสริมจะใช้ Vertex AI เพื่อแจ้งให้โมเดล Gemini 2.5 Flash วิเคราะห์เนื้อหาข้อความและแสดงความรู้สึกต่อไปนี้

  • บวก
  • ลบ
  • เป็นกลาง

ส่วนเสริมจะใช้การตอบกลับจาก Gemini เพื่อติดป้ายกำกับ Gmail ที่เกี่ยวข้องกับข้อความ

ส่วนเสริมนี้จะวิเคราะห์และติดป้ายกำกับเฉพาะข้อความ 10 รายการล่าสุดในกล่องจดหมายของผู้ใช้ Gmail เพื่อจำกัดคำขอไปยัง Vertex AI API ดูข้อมูลเพิ่มเติมเกี่ยวกับ โควต้าและขีดจำกัดได้ที่ เอกสารประกอบของ Vertex AI

วิธีการทำงาน

โซลูชันนี้สร้างขึ้นใน Google Apps Script และใช้บริการและผลิตภัณฑ์ของ Google ต่อไปนี้

  • Vertex AI API - แจ้งให้ โมเดล Gemini 2.5 Flash วิเคราะห์เนื้อหาข้อความ Gmail และระบุ ความรู้สึก
  • บริการ Apps Script

    • บริการ Gmail - ดึงและ ติดป้ายกำกับข้อความ Gmail และสร้างข้อความตัวอย่างเพื่อทดสอบส่วนเสริม (ไม่บังคับ)
    • บริการการ์ด - สร้างอินเทอร์เฟซผู้ใช้ ของส่วนเสริมที่ปรากฏเป็นแถบด้านข้างใน Gmail
    • บริการเรียก URL - เชื่อมต่อกับ Vertex AI API เพื่อวิเคราะห์ความรู้สึก
    • บริการสคริปต์ - เรียก Vertex AI API โดยรับโทเค็นเพื่อการเข้าถึง OAuth 2.0 สำหรับส่วนเสริมโดยใช้เมธอดgetOAuthToken

ข้อกำหนดเบื้องต้น

ตั้งค่าสภาพแวดล้อม

ส่วนนี้อธิบายวิธีกำหนดค่าและตั้งค่าสภาพแวดล้อมในคอนโซล Google Cloud และ Apps Script

กำหนดค่าโปรเจ็กต์ที่อยู่ในระบบคลาวด์ในคอนโซล Google Cloud

ส่วนนี้จะแสดงวิธีเปิดใช้ Vertex AI API และกำหนดค่าหน้าจอขอความยินยอม OAuth ในโปรเจ็กต์ที่อยู่ในระบบคลาวด์

เปิดใช้ Vertex AI API

  1. ในคอนโซล Google Cloud ให้เปิดโปรเจ็กต์ที่อยู่ในระบบคลาวด์ของ Google และเปิดใช้ Vertex AI API โดยทำดังนี้

    เปิดใช้ API

  2. ยืนยันว่าคุณกำลังเปิดใช้ API ในโปรเจ็กต์ที่อยู่ในระบบคลาวด์ที่ถูกต้อง แล้วคลิก ถัดไป

  3. ยืนยันว่าคุณกำลังเปิดใช้ API ที่ถูกต้อง แล้วคลิกเปิดใช้

กำหนดค่าหน้าจอขอความยินยอม OAuth

ส่วนเสริมของ Google Workspace ต้องมีการกำหนดค่าหน้าจอขอความยินยอม การกำหนดค่าหน้าจอขอความยินยอม OAuth ของส่วนเสริมจะกำหนดสิ่งที่ Google แสดงต่อผู้ใช้

  1. ในคอนโซล Google API ให้ไปที่เมนู > แพลตฟอร์มการตรวจสอบสิทธิ์ของ Google > การสร้างแบรนด์

    ไปที่การสร้างแบรนด์

  2. หากกำหนดค่าแพลตฟอร์มการตรวจสอบสิทธิ์ของ Google ไว้แล้ว คุณสามารถกำหนดค่าการตั้งค่าหน้าจอขอความยินยอม OAuth ต่อไปนี้ใน การสร้างแบรนด์, กลุ่มเป้าหมาย และ การเข้าถึงข้อมูล หากเห็นข้อความที่ระบุว่า Google Auth platform not configured yet ให้คลิกเริ่มต้นใช้งาน
    1. ในส่วนข้อมูลแอป ในชื่อแอป ให้ป้อนชื่อแอป
    2. ในส่วนอีเมลสนับสนุนสำหรับผู้ใช้ ให้เลือกอีเมลสนับสนุนที่ผู้ใช้สามารถติดต่อคุณได้หากมีคำถามเกี่ยวกับการให้ความยินยอม
    3. คลิกถัดไป
    4. ในส่วนกลุ่มเป้าหมาย ให้เลือกภายใน
    5. คลิกถัดไป
    6. ในส่วนข้อมูลติดต่อ ให้ป้อนอีเมล ที่คุณจะได้รับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงในโปรเจ็กต์
    7. คลิกถัดไป
    8. ในส่วนเสร็จสิ้น ให้อ่านนโยบายข้อมูลผู้ใช้สำหรับบริการ Google API และหากยอมรับ ให้เลือกฉันยอมรับบริการ Google API: นโยบายข้อมูลผู้ใช้
    9. คลิกต่อไป
    10. คลิกสร้าง
  3. ตอนนี้คุณสามารถข้ามการเพิ่มขอบเขตได้ ในอนาคต เมื่อสร้างแอปเพื่อใช้ภายนอกองค์กร Google Workspace คุณต้องเปลี่ยนประเภทผู้ใช้ เป็นภายนอก จากนั้น เพิ่มขอบเขตการให้สิทธิ์ที่แอปต้องใช้ ดูข้อมูลเพิ่มเติมได้ที่คู่มือฉบับเต็ม เกี่ยวกับการกำหนดค่าหน้าจอขอความยินยอม OAuth

สร้างและตั้งค่าโปรเจ็กต์ Apps Script

หากต้องการสร้างและตั้งค่าโปรเจ็กต์ Apps Script สำหรับส่วนเสริม ให้ทำตามขั้นตอนต่อไปนี้

  1. คลิกปุ่มต่อไปนี้เพื่อเปิดโปรเจ็กต์ Apps Script การวิเคราะห์ความรู้สึกของ Gmail ด้วย Gemini และ Vertex AI
    เปิดโปรเจ็กต์ Apps Script

  2. คลิกภาพรวม

  3. ในหน้าภาพรวม ให้คลิกทำสำเนา ไอคอนสำหรับการทำสำเนา

  4. รับหมายเลขโปรเจ็กต์ Cloud โดยทำดังนี้

    1. ใน คอนโซล Google API ให้ไปที่เมนู > IAM และผู้ดูแลระบบ > การตั้งค่า

      ไปที่การตั้งค่า IAM และผู้ดูแลระบบ

    2. คัดลอกค่าในช่องหมายเลขโปรเจ็กต์
  5. เชื่อมต่อโปรเจ็กต์ที่อยู่ในระบบคลาวด์กับโปรเจ็กต์ Apps Script โดยทำดังนี้

    1. ในโปรเจ็กต์ Apps Script ที่คัดลอกไว้ คลิก การตั้งค่าโปรเจ็กต์ ไอคอนสำหรับการตั้งค่าโปรเจ็กต์
    2. ในส่วนโปรเจ็กต์ Google Cloud Platform (GCP) ให้คลิกเปลี่ยนโปรเจ็กต์
    3. ในส่วนหมายเลขโปรเจ็กต์ GCP ให้วางหมายเลขโปรเจ็กต์ที่อยู่ในระบบคลาวด์
    4. คลิกตั้งค่าโปรเจ็กต์

ทดสอบส่วนเสริม

หากต้องการลองใช้ส่วนเสริม ให้ติดตั้งการทำให้ใช้งานได้เพื่อทดสอบ แล้วเปิดส่วนเสริมใน Gmail โดยทำดังนี้

  1. สร้างและติดตั้งการทำให้ใช้งานได้เพื่อทดสอบของ Apps Script โดยทำดังนี้
    1. ในโปรเจ็กต์ Apps Script ที่คัดลอกไว้ ให้คลิก โปรแกรมแก้ไขโค้ด
    2. เปิดไฟล์ Code.gs แล้วคลิกเรียกใช้ ให้สิทธิ์สคริปต์เมื่อได้รับข้อความแจ้ง
    3. คลิกทำให้ใช้งานได้ > การทำให้ใช้งานได้เพื่อทดสอบ
    4. คลิกติดตั้ง > เสร็จสิ้น
  2. เปิด Gmail

    ไปที่ Gmail

  3. เปิดส่วนเสริม การวิเคราะห์ความรู้สึก ในแถบด้านข้างทางขวา

  4. ให้สิทธิ์ส่วนเสริมหากได้รับข้อความแจ้ง

  5. ไม่บังคับ: หากต้องการสร้างข้อความเพื่อทดสอบกับส่วนเสริม ให้คลิกสร้างอีเมลตัวอย่าง ข้อความ 3 รายการจะปรากฏในกล่องจดหมาย หากไม่เห็น ให้รีเฟรชหน้า

  6. หากต้องการติดป้ายกำกับ ให้คลิกวิเคราะห์อีเมล

ส่วนเสริมจะตรวจสอบข้อความ 10 รายการล่าสุดในกล่องจดหมาย แล้วติดป้ายกำกับข้อใดข้อหนึ่งต่อไปนี้ตามเนื้อหาข้อความ

  • โทนมีความสุข 😊
  • โทนเป็นกลาง 😐
  • โทนไม่พอใจ 😡

ตรวจสอบโค้ด

ตรวจสอบโค้ด Apps Script สำหรับโซลูชันนี้

ดูซอร์สโค้ด

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"
}

ล้างข้อมูล

เราขอแนะนำให้คุณลบโปรเจ็กต์ที่อยู่ในระบบคลาวด์เพื่อหลีกเลี่ยงการเรียกเก็บเงินกับบัญชี Google Cloud สำหรับ ทรัพยากรที่ใช้ในบทแนะนำนี้

  1. ในคอนโซล Google API ให้ไปที่หน้าจัดการทรัพยากร คลิก เมนู > IAM และผู้ดูแลระบบ > จัดการทรัพยากร.

    ไปที่ Resource Manager

  2. ในรายการโปรเจ็กต์ ให้เลือกโปรเจ็กต์ที่ต้องการลบ แล้วคลิก ลบ .
  3. ในกล่องโต้ตอบ ให้พิมพ์รหัสโปรเจ็กต์ แล้วคลิกปิด เพื่อลบ โปรเจ็กต์

ขั้นตอนถัดไป