1. บทนำ
หากคุณจะเข้าร่วมการโทรผ่าน Meet แต่ไม่ต้องการเป็นคนแรกที่เข้าร่วม หากคุณเป็นผู้ใช้ประเภทนี้ เรามีโซลูชันสำหรับคุณ
เมื่อทำตาม Codelab นี้ คุณจะสร้างส่วนขยาย Chrome ที่แจ้งเตือนเมื่อผู้เข้าร่วมคนแรกเข้าร่วมการโทร
คุณจะได้เรียนรู้องค์ประกอบต่างๆ ของส่วนขยาย Chrome แล้วเจาะลึกแต่ละส่วนของส่วนขยาย คุณจะได้เรียนรู้เกี่ยวกับฟังก์ชันของส่วนขยาย เช่น Content Script, Service Worker และ Message Passing
คุณต้องปฏิบัติตามการเปิดตัว Manifest V3 จึงจะได้รับการแจ้งเตือนทุกครั้งที่มีผู้เข้าร่วมเข้าร่วมการโทรผ่าน Meet
2. ก่อนเริ่มต้น
ข้อกำหนดเบื้องต้น
แม้ว่า Codelab นี้จะเหมาะสำหรับผู้เริ่มต้น แต่การมีความเข้าใจพื้นฐานเกี่ยวกับ JavaScript จะช่วยเพิ่มประสบการณ์การใช้งานของคุณได้อย่างมาก
การตั้งค่า/ข้อกำหนด
- เบราว์เซอร์ Chrome
- การตั้งค่า IDE/Editor ในระบบภายใน
- ติดตั้ง gcloud CLI หากต้องการเปิดใช้ Gemini API โดยใช้ gcloud
เปิดใช้ Gemini API
- ในคอนโซล Google Cloud ให้เลือกหรือสร้างโปรเจ็กต์ Google Cloud ในหน้าตัวเลือกโปรเจ็กต์
- ตรวจสอบว่าได้เปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ Cloud แล้ว ดูวิธีตรวจสอบว่าได้เปิดใช้การเรียกเก็บเงินในโปรเจ็กต์แล้วหรือไม่
- ไปที่หน้า Gemini Marketplace เพื่อเปิดใช้ API นอกจากนี้ คุณยังใช้ gcloud เพื่อเปิดใช้ API ได้ด้วย
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID - ไปที่หน้าคอนโซล Gemini สำหรับ Cloud ในแท็บใหม่ แล้วคลิก "เริ่มแชท"
Note that if you're writing the code in the Cloud Shell editor, then you will have to download the folder somewhere on your local filesystem to test the extension locally.
3. เริ่มต้นความสนุกกันได้เลย
การติดตั้งส่วนขยายพื้นฐาน
มาสร้างไดเรกทอรีที่เราจะใช้เป็นรูทของโปรเจ็กต์กัน
mkdir gemini-chrome-ext
cd gemini-chrome-ext
ก่อนที่เราจะเริ่มถามคำถามที่เฉพาะเจาะจงกับ Gemini เรามาถามคำถามเกี่ยวกับโครงสร้างทั่วไปของส่วนขยาย Chrome กันก่อน
พรอมต์:
What are the important parts to build a chrome extension?
เราได้รับการตอบกลับที่ระบุรายละเอียดเล็กๆ น้อยๆ เกี่ยวกับไฟล์ manifest, background script และรายละเอียดเกี่ยวกับอินเทอร์เฟซผู้ใช้ มาดูรายละเอียดเพิ่มเติมเกี่ยวกับไฟล์ที่เฉพาะเจาะจงเหล่านี้กัน
พรอมต์:
Create a manifest.json file to build a chrome extension. Make the name of the extension "Meet Joinees Notifier" and the author "<YOUR_EMAIL>"
คุณใช้ชื่อที่ต้องการและอีเมลของคุณในช่องผู้เขียนได้
Gemini จะแสดงเนื้อหาของไฟล์ Manifest ที่เราต้องการ แต่เราจะได้รับฟิลด์เพิ่มเติมบางส่วนซึ่งเราไม่จำเป็นต้องใช้ เช่น ฟิลด์ action นอกจากนี้ เรายังต้องการคำอธิบายด้วย เรามาแก้ปัญหานั้นกันดีกว่า
พรอมต์:
Remove the "action" field and make the description as "Adds the ability to receive a notification when a participant joins a Google meet".
มาใส่เนื้อหานี้ลงในไฟล์ manifest.json ในรูทของโปรเจ็กต์กัน
ในขั้นตอนนี้ ไฟล์ Manifest ควรมีลักษณะดังนี้
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>"
}
ตอนนี้ให้นำฟิลด์เพิ่มเติมอื่นๆ ที่สร้างขึ้นในไฟล์ Manifest ออก เนื่องจาก Codelab นี้ถือว่ามีฟิลด์เหล่านี้ในไฟล์ Manifest
ทีนี้เราจะทดสอบว่าส่วนขยายทํางานได้หรือไม่ได้อย่างไร มาถามเพื่อนของเราอย่าง Gemini กันดีกว่า
พรอมต์:
Guide me on the steps needed to test a chrome extension on my local filesystem.
แต่ก็มีขั้นตอนบางอย่างที่บอกวิธีทดสอบ ไปที่ "Extensions Page" โดยไปที่ chrome://extensions และตรวจสอบว่าได้เปิดใช้ปุ่ม "Developer Mode" แล้ว ซึ่งควรจะแสดงปุ่ม "Load unpacked" ซึ่งเราสามารถใช้เพื่อไปยังโฟลเดอร์ที่มีไฟล์ส่วนขยายในเครื่องได้ เมื่อดำเนินการดังกล่าวแล้ว เราจะเห็นส่วนขยายใน "Extensions Page"


เยี่ยมเลย เราเห็นส่วนขยายแล้ว แต่มาเริ่มเพิ่มฟังก์ชันการทำงานกัน
4. เพิ่ม Content Script
เราต้องการเรียกใช้โค้ด JavaScript เฉพาะใน https://meet.google.com ซึ่งทำได้โดยใช้ Content Script มาถาม Gemini กันว่าเราจะทำอย่างนั้นในส่วนขยายได้อย่างไร
พรอมต์:
How to add a content script in our chrome extension?
หรืออย่างเจาะจงกว่านั้น
พรอมต์:
How to add a content script to run on meet.google.com subdomain in our chrome extension?
หรืออีกเวอร์ชันหนึ่ง
พรอมต์:
Help me add a content script named content.js to run on meet.google.com subdomain in our chrome extension. The content script should simply log "Hello Gemini" when we navigate to "meet.google.com".
Gemini บอกการเปลี่ยนแปลงที่แน่นอนที่เราต้องทำในไฟล์ manifest.json รวมถึง JavaScript ที่เราต้องการในไฟล์ content.js
เมื่อเพิ่ม content_scripts ไฟล์ Manifest จะมีลักษณะดังนี้
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "abc@example.com",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
]
}
ซึ่งจะบอกให้ Chrome แทรก Content Script content.js ทุกครั้งที่เราไปยังหน้าเว็บในโดเมนย่อย " https://meet.google.com" มาเพิ่มไฟล์นี้แล้วทดสอบกันดีไหม
มาเพิ่มโค้ดนี้ในไฟล์ content.js กัน
console.log("Hello Gemini");
ใช่เลย เมื่อไปที่ meet.google.com เราจะเห็นข้อความ "สวัสดี Gemini" ในคอนโซล JavaScript(Mac: Cmd + Opt + J / Win/Linux: Ctrl + Shift + J)
manifest.json
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "luke@cloudadvocacyorg.joonix.net",
"permissions": [
"tabs",
"notifications"
],
"content_scripts": [
{
"matches": [
"https://meet.google.com/*"
],
"js": [
"content.js"
]
}
]
}
content.js
console.log("Hello Gemini!");


เยี่ยมเลย ตอนนี้เราอยู่ในจุดที่สามารถเพิ่มฟังก์ชันการทำงานเฉพาะของ JavaScript ลงในแอปได้แล้ว ลองมาคิดกันสักครู่ว่าเราต้องการทำอะไร
การปรับปรุงสคริปต์เนื้อหา
เราต้องการรับการแจ้งเตือนเมื่อมีคนเข้าร่วมการประชุมขณะที่เราอยู่ในหน้าการประชุม(ซึ่งมีตัวเลือกให้เข้าร่วมการประชุม) เพื่อที่จะทำเช่นนี้ได้ เรามาดูว่าหน้าจอเปลี่ยนแปลงอย่างไรเมื่อไม่มีใครอยู่ในการประชุมเทียบกับเมื่อมีคนเข้าร่วมการประชุม
หน้าจอจะแสดงดังนี้เมื่อไม่มีใครอยู่ในการประชุม

ส่วนภาพเหล่านี้จะปรากฏเมื่อมีผู้เข้าร่วมในการประชุม

เราจะเห็นความแตกต่างที่สำคัญ 2 ประการตั้งแต่แรก ดังนี้
- ข้อความสถานะจะเปลี่ยนจาก "ไม่มีใครอยู่อีก" เป็น "[ผู้ใช้] อยู่ในการโทรนี้"
- เราจะเห็นรูปภาพของผู้ใช้ที่เข้าร่วมการโทร
การเปลี่ยนแปลงทั้ง 2 อย่างนี้จะช่วยให้เราทราบว่ามีใครเข้าร่วมการประชุมหรือไม่ แต่การเปลี่ยนแปลงอย่างหลังมีโอกาสที่จะได้รับข้อมูลเกี่ยวกับผู้ใช้ที่เข้าร่วมแล้ว ดังนั้นเรามาลองใช้การเปลี่ยนแปลงอย่างหลังกัน
เปิด "เครื่องมือตรวจสอบองค์ประกอบ" ใน Chrome ด้วยแป้นพิมพ์ลัด ( Mac: Cmd + Opt + C / Win: Ctrl + Shift + C) จากนั้นคลิกรูปภาพของผู้ใช้ที่เข้าร่วม
เราจะเห็นว่ามีรูปภาพที่มีสตริงคลาสเพียงไม่กี่รายการ และแอตทริบิวต์ชื่อของรูปภาพมีชื่อของผู้ใช้ที่เข้าร่วมการประชุม นอกจากนี้ แท็กรูปภาพนี้ยังอยู่ในแท็ก div ที่มีคลาส U04fid เมื่อเพิ่มผู้เข้าร่วมบางรายในการประชุมทดสอบแล้ว เราจะเห็นว่า Div หลักนี้โฮสต์รูปภาพหลายรูป(สอดคล้องกับผู้ใช้ที่แตกต่างกัน)
ดังนั้นเราจึงมีกลยุทธ์บางส่วนในใจ ดังนี้
- ตรวจหาเมื่อ div ที่มีคลาส
U04fidมีองค์ประกอบใดๆ - หากมี แสดงว่ามีผู้เข้าร่วมในการประชุม
- แจ้งให้ผู้ใช้ทราบ
กลับไปที่ Gemini แล้วถามว่าเราจะทำตามขั้นตอนนี้ได้อย่างไร
พรอมต์:
How to detect for element changes in the HTML page?
ซึ่งให้โซลูชันที่เกี่ยวข้องกับ MutationObserver แต่ไม่มีอะไรที่เฉพาะเจาะจงกับข้อกำหนดของเรา ลองแก้ไขพรอมต์กัน
พรอมต์:
How can I detect if an element "div.U04fid" has any child images in the HTML page?
คราวนี้เราจะได้รับโซลูชันที่ไม่มี MutationObserver แต่เป็นโซลูชันที่ตรวจสอบผู้เข้าร่วมโดยใช้ Div หลัก
สิ่งที่เราได้รับมีดังนี้
const divU04fid = document.querySelector('div.U04fid');
const childImages = divU04fid.querySelectorAll('img');
if (childImages.length > 0) {
// div.U04fid has at least one child image.
}
ลองปรับเปลี่ยนแนวทางของเราให้มากยิ่งขึ้น
พรอมต์:
Create a method which checks if the element div.U04fid has any child elements, if it does it should log it on the console. The method should be called checkJoinees and it should be called as a callback for MutationObserver which is observing the document.body.
โดยจะแสดงผลพร้อมข้อมูลโค้ดต่อไปนี้
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
// div.U04fid has at least one child element.
console.log('div.U04fid has at least one child element.');
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
คัดลอกโค้ดนี้ลงในไฟล์ content.js จากนั้นโหลดส่วนขยายซ้ำ(แล้วโหลดหน้า Meet ซ้ำ)
ตอนนี้เมื่อมีคนเข้าร่วมการประชุม เราจะเห็นคำสั่งบันทึกในคอนโซล
5. ส่งการแจ้งเตือนไปยังผู้ใช้
ตอนนี้เราตรวจพบได้แล้วว่าเมื่อใดที่ผู้เข้าร่วมเข้าร่วมการประชุม ลองเพิ่มส่วนการแจ้งเตือนในส่วนขยาย Chrome กัน เราสามารถเรียกดูเอกสารประกอบของส่วนขยาย Chrome หรือแม้แต่ปรับแต่งพรอมต์เพื่อดูว่าเรากำลังมองหาอะไร แต่โดยพื้นฐานแล้วเราต้องใช้ chrome.notifications.create API และการเรียกเมธอดนี้ควรมาจาก Service Worker ในเบื้องหลัง
พรอมต์:
Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.
เราเห็นขั้นตอนโดยละเอียดบางอย่าง โดยไฮไลต์สำคัญมีดังนี้
- เพิ่มสิทธิ์
notificationsในไฟล์ Manifest - โทรไปยัง chrome.notifications.create
- การเรียกใช้ควรอยู่ในสคริปต์ที่ทำงานในเบื้องหลัง
หากต้องการเพิ่มสคริปต์พื้นหลังลงในส่วนขยาย Chrome ใน manifest version 3 เราต้องมีประกาศ background.service_worker ในไฟล์ manifest.json
ดังนั้น เราจึงสร้างไฟล์ชื่อ background.js และเพิ่มข้อมูลต่อไปนี้ลงในไฟล์ manifest.json
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
เมื่อเพิ่มข้อมูลข้างต้น ไฟล์ Manifest จะมีลักษณะดังนี้
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
}
พรอมต์:
Create a method sendNotification that calls the chrome.notifications.create method with the message, "A user joined the call" for a chrome extension with manifest v3, the code is in the background service worker
บันทึกรูปภาพนี้ไว้ในรูทของโฟลเดอร์และเปลี่ยนชื่อเป็น success.png

จากนั้นเพิ่มข้อมูลโค้ดต่อไปนี้ลงใน background.js
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
sendNotification("notif-id", "test message");
ตอนนี้ให้โหลดส่วนขยายซ้ำจากหน้าส่วนขยาย แล้วคุณจะเห็นป๊อปอัปการแจ้งเตือนทันที
6. เพิ่มการส่งผ่านข้อความในส่วนขยาย Chrome
ตอนนี้ขั้นตอนสำคัญสุดท้ายที่เราต้องทำคือการเชื่อมต่อการตรวจหาผู้เข้าร่วมของ Content Script กับเมธอด sendNotification ใน Background Script ในบริบทของส่วนขยาย Chrome วิธีการดำเนินการดังกล่าวคือผ่านเทคนิคที่เรียกว่า message passing
ซึ่งช่วยให้การสื่อสารระหว่างส่วนต่างๆ ของส่วนขยาย Chrome เป็นไปได้ ในกรณีของเราคือจาก Content Script ไปยัง Background Service Worker มาถาม Gemini เพื่อนของเรากันดีกว่าว่าต้องทำอย่างไร
พรอมต์:
How to send a message from the content script to the background script in a chrome extension
Gemini ตอบกลับด้วยการเรียกใช้ที่เกี่ยวข้องกับ chrome.runtime.sendMessage และ chrome.runtime.onMessage.addListener
โดยพื้นฐานแล้ว เราจะใช้ sendMessage เพื่อส่งข้อความจาก Content Script ว่ามีคนเข้าร่วมการโทรผ่าน Meet และใช้ onMessage.addListener เป็น Listener เหตุการณ์ เพื่อตอบโต้ข้อความที่ส่งโดย Content Script ในกรณีนี้ เราจะทริกเกอร์การเรียกใช้เมธอด sendNotification จาก Listener เหตุการณ์นี้
เราจะส่งข้อความแจ้งเตือนและพร็อพเพอร์ตี้ action ไปยัง Service Worker ที่ทำงานอยู่เบื้องหลัง พร็อพเพอร์ตี้ action อธิบายว่าสคริปต์พื้นหลังตอบสนองต่ออะไร
ดังนั้น content.js รหัสของเราจึงเป็นดังนี้
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
// div.U04fid has at least one child element.
sendMessage();
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
function sendMessage() {
chrome.runtime.sendMessage({
txt: "A user has joined the call!",
action: "people_joined"
});
}
และนี่คือรหัส background.js ของเรา
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "people_joined") {
sendNotification("notif-id", message.txt);
}
});
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
มาลองปรับแต่งข้อความแจ้งเตือนและรับรหัสการแจ้งเตือนที่ไม่ซ้ำกันกัน สำหรับข้อความแจ้งเตือน เราสามารถใส่ชื่อของผู้ใช้ได้ หากจำได้จากขั้นตอนก่อนหน้า เราจะเห็นชื่อผู้ใช้ในแอตทริบิวต์ชื่อของรูปภาพ ดังนั้น เราจึงดึงชื่อผู้เข้าร่วมได้โดยใช้ document.querySelector('div.U04fid > img').getAttribute('title').
สำหรับรหัสการแจ้งเตือน เราสามารถดึงข้อมูลรหัสแท็บของ Content Script และใช้เป็นรหัสการแจ้งเตือนได้ ซึ่งทำได้ภายใน Listener เหตุการณ์ chrome.runtime.onMessage.addListener โดยใช้ sender.tab.id.
สุดท้าย ไฟล์ควรมีลักษณะดังนี้
manifest.json
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
}
content.js
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
const name = document.querySelector('div.U04fid > img').getAttribute('title');
sendMessage(name);
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
function sendMessage(name) {
const joinee = (name === null ? 'Someone' : name),
txt = `${joinee} has joined the call!`;
chrome.runtime.sendMessage({
txt,
action: "people_joined",
});
}
background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "people_joined") {
sendNotification("" + sender.tab.id, message.txt); // We are casting this to string as notificationId is expected to be a string while sender.tab.id is an integer.
}
});
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
7. ขอแสดงความยินดี
เราสามารถสร้างส่วนขยาย Chrome ได้ในเวลาอันสั้นด้วยความช่วยเหลือจาก Gemini ไม่ว่าคุณจะเป็นนักพัฒนาส่วนขยาย Chrome ที่มีประสบการณ์หรือเพิ่งเข้าสู่โลกของส่วนขยาย Gemini ก็ช่วยคุณทำงานต่างๆ ได้ตามที่ต้องการ
เราขอแนะนำให้คุณสอบถามเกี่ยวกับสิ่งต่างๆ ที่ทำได้ด้วยส่วนขยาย Chrome มี API มากมายที่ควรค่าแก่การเรียกดู เช่น chrome.storage, alarms ฯลฯ เมื่อใดก็ตามที่คุณรู้สึกว่าติดขัด ให้ใช้ Gemini หรือเอกสารประกอบเพื่อดูว่าคุณทำอะไรผิดพลาด หรือรวบรวมวิธีต่างๆ ในการแก้ปัญหา
โดยมักจะต้องแก้ไขพรอมต์เพื่อให้ได้รับความช่วยเหลือที่ต้องการ แต่เราสามารถทำได้จากแท็บเดียวซึ่งจะเก็บเส้นทางตามบริบททั้งหมดของเราไว้