1. Wprowadzenie
Dołączasz do rozmowy w Meet, ale nie chcesz być pierwszą osobą, która to zrobi? Jeśli to dotyczy Ciebie, mamy rozwiązanie dla Ciebie.
W ramach tego ćwiczenia w programie utworzysz rozszerzenie do Chrome, które powiadomi Cię, gdy do rozmowy dołączy pierwszy uczestnik.
Poznaj różne elementy rozszerzenia do Chrome, a następnie szczegółowo zapoznaj się z każdą jego częścią. Poznasz funkcje rozszerzeń, takie jak skrypty treści, mechanizmy Service Worker i przekazywanie wiadomości.
Musisz przestrzegać pliku manifestu w wersji 3, aby móc otrzymywać powiadomienia za każdym razem, gdy uczestnik dołącza do rozmowy w Meet.
2. Zanim zaczniesz
Wymagania wstępne
To ćwiczenie w Codelabs jest odpowiednie dla początkujących, ale podstawowa znajomość języka JavaScript może znacznie ułatwić jego naukę.
Konfiguracja/wymagania
- Przeglądarka Chrome
- Konfiguracja IDE lub edytora w systemie lokalnym.
- Jeśli chcesz włączyć Gemini API za pomocą gcloud, zainstaluj gcloud cli.
Włączanie Gemini API
- W konsoli Google Cloud na stronie selektora projektów wybierz lub utwórz projekt Google Cloud.
- Sprawdź, czy w projekcie Cloud włączone są płatności. Dowiedz się, jak sprawdzić, czy w projekcie są włączone płatności.
- Aby włączyć interfejs API, otwórz stronę Gemini Marketplace. Aby włączyć interfejs API, możesz też użyć gcloud:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID
- Otwórz stronę Gemini w konsoli Cloud w nowej karcie i kliknij „Rozpocznij rozmowę”.
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. Zaczynamy zabawę
Podstawowa instalacja rozszerzeń
Utwórzmy katalog, którego użyjemy jako głównego katalogu naszego projektu.
mkdir gemini-chrome-ext
cd gemini-chrome-ext
Zanim zaczniemy zadawać Gemini konkretne pytania, zadajmy sobie kilka pytań o ogólną strukturę rozszerzenia do Chrome.
Prompt:
What are the important parts to build a chrome extension?
Otrzymujesz odpowiedź z informacją o drobnych szczegółach dotyczących pliku manifest
, pola background script
i szczegółów interfejsu użytkownika. Przyjrzyjmy się bliżej tym konkretnym plikom.
Prompt:
Create a manifest.json file to build a chrome extension. Make the name of the extension "Meet Joinees Notifier" and the author "<YOUR_EMAIL>"
W polu autora możesz wpisać wybraną nazwę i swój adres e-mail.
Gemini zwraca zawartość potrzebnego pliku manifestu, ale pojawia się kilka dodatkowych pól, które nie są potrzebne, np. pola action
. Potrzebujemy też opisu. Zajmijmy się tym.
Prompt:
Remove the "action" field and make the description as "Adds the ability to receive a notification when a participant joins a Google meet".
Umieśćmy tę treść w pliku manifest.json
w katalogu głównym projektu.
Na tym etapie plik manifestu powinien wyglądać mniej więcej tak.
{
"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>"
}
Na razie usuń wszystkie inne dodatkowe pola wygenerowane w pliku manifestu, ponieważ to ćwiczenia z programowania zakładają, że te pola są uwzględniane w pliku manifestu.
Jak mogę sprawdzić, czy to rozszerzenie działa? Zapytajmy naszego przyjaciela Gemini.
Prompt:
Guide me on the steps needed to test a chrome extension on my local filesystem.
Znajdziesz tam instrukcje, jak to przetestować. Otwórz chrome://extensions
i przejdź do "Extensions Page"
. Upewnij się, że jest włączony przycisk "Developer Mode"
. Powinien wyświetlić się przycisk "Load unpacked"
, który pozwala przejść do folderu z lokalnymi plikami rozszerzeń. Gdy to zrobimy, rozszerzenie powinno być widoczne w interfejsie "Extensions Page"
.
Świetnie. Nasze rozszerzenie jest widoczne, ale zaczynamy dodawać do nich funkcje.
4. Dodaj skrypt treści
Na stronie https://meet.google.com
chcemy uruchomić tylko fragmenty kodu JavaScript w skryptach treści. Zapytajmy Gemini, jak to osiągnąć w naszym rozszerzeniu.
Prompt:
How to add a content script in our chrome extension?
A dokładniej:
Prompt:
How to add a content script to run on meet.google.com subdomain in our chrome extension?
Lub inna wersja:
Prompt:
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 podaje nam dokładne zmiany, które musimy wprowadzić, w pliku manifest.json oraz JavaScript, którego potrzebujemy w pliku content.js
.
Po dodaniu skryptu content_scripts plik manifestu zmieni się w następujący sposób:
{
"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"]
}
]
}
Dzięki temu Chrome ma wstrzyknąć skrypt treści content.js
za każdym razem, gdy przechodzimy na stronę w subdomenie „ https://meet.google.com”. Dodajmy ten plik i przetestujemy go.
Dodajmy ten kod do pliku content.js
.
console.log("Hello Gemini");
Jasne! Gdy wchodzimy na meet.google.com, widzimy „Cześć Gemini”. w konsoli JavaScript(Mac: Cmd + Opt + J
/ Windows/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("Witaj Gemini!");
Ⰲ
Świetnie. Teraz możemy dodać funkcje JavaScriptu do naszej aplikacji. Zastanówmy się przez chwilę, co chcemy osiągnąć.
Ulepszanie skryptu treści
Chcemy móc otrzymywać powiadomienie, gdy ktoś dołączy do spotkania na stronie spotkania(gdzie dostępna jest opcja dołączenia do spotkania). Aby to osiągnąć, przyjrzyjmy się, jak ekran zmienia się wizualnie, gdy spotkanie jest puste, a kiedy ktoś dołączył do spotkania.
Tak wygląda to, gdy nikogo nie ma na spotkaniu.
Są to natomiast elementy wizualne, w przypadku których w spotkaniu biorą udział niektórzy uczestnicy.
Od razu widzimy 2 istotne różnice:
- Tekst stanu zmieni się z „Nikt inny tu nie ma” do „[Użytkownik] uczestniczy w tej rozmowie”.
- Widzimy zdjęcia użytkowników, którzy dołączyli do rozmowy.
Obie te zmiany zadziałają, jeśli chcemy wiedzieć, czy ktoś dołączył do spotkania. Jednak druga opcja daje pewne możliwości uzyskania informacji o użytkownikach, którzy już dołączyli do spotkania, więc warto korzystać z tych informacji.
Otwórz „Inspektora elementów”. w Chrome przy użyciu klawisza skrótu ( Mac: Cmd + Opt + C / Win: Ctrl + Shift + C
), a następnie kliknij obraz użytkownika, który dołączył.
Widzimy, że znajduje się na nim obraz z niewielką liczbą ciągów znaków dotyczących zajęć, a w atrybucie tego obrazu znajduje się nazwa użytkownika, który dołączył do spotkania. Dodatkowo ten tag graficzny jest zawarty w elemencie div z klasą U04fid
. Po dodaniu uczestników do spotkania testowego zauważymy, że nadrzędny element div zawiera wiele obrazów(odpowiadających różnym użytkownikom).
Przyjmujemy więc strategię częściową:
- Wykrywa, kiedy element div z klasą
U04fid
zawiera jakiekolwiek elementy. - Jeśli tak, oznacza to, że mamy uczestników spotkania.
- Powiadom użytkownika.
Wróćmy do Gemini i zapytajmy, jak krok po kroku możemy to osiągnąć.
Prompt:
How to detect for element changes in the HTML page?
Podpowiada nam, jak używać MutationObserver
, ale nie ma związku z naszymi wymaganiami. Spróbujmy zmodyfikować prompt.
Prompt:
How can I detect if an element "div.U04fid" has any child images in the HTML page?
Tym razem uzyskujemy rozwiązanie, które nie zawiera elementu MutationObserver
, lecz zawiera rozwiązanie, które sprawdza połączone elementy za pomocą nadrzędnego tagu div.
Oto, co dostaliśmy:
const divU04fid = document.querySelector('div.U04fid');
const childImages = divU04fid.querySelectorAll('img');
if (childImages.length > 0) {
// div.U04fid has at least one child image.
}
Spróbujmy jeszcze bardziej zmienić nasze podejście:
Prompt:
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.
Zwracana jest z następującym fragmentem kodu:
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
});
Skopiuj ten kod do pliku content.js
, załaduj ponownie rozszerzenie(a następnie załaduj ponownie stronę Meet).
Teraz gdy ktoś dołączy do spotkania, będzie można zobaczyć instrukcję dziennika w konsoli.
5. Wysyłanie powiadomienia do użytkownika
Udało nam się wykryć, kiedy uczestnik dołączył do spotkania, więc spróbujmy dodać część powiadomienia do naszego rozszerzenia do Chrome. Możemy przeglądać dokumentację rozszerzenia do Chrome lub nawet ulepszać prompty, aby dowiedzieć się, czego szukamy, ale zasadniczo musimy użyć interfejsu API chrome.notifications.create
, a wywołanie tej metody powinno pochodzić z skryptu service worker w tle.
Prompt:
Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.
Oto kilka szczegółowych kroków, z najważniejszymi:
- Dodaj uprawnienie
notifications
w pliku manifestu. - Uruchom połączenie na chrome.notifications.create
- Rozmowa powinna odbywać się w skrypcie w tle.
Aby dodać skrypt działający w tle do rozszerzenia do Chrome w języku manifest version 3
, w pliku manifest.json
potrzebujemy deklaracji background.service_worker
.
Tworzymy więc plik o nazwie background.js i dodajemy poniższy kod do pliku manifest.json.
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
Po dodaniu powyższych zmian plik manifestu zmienia się w:
{
"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"
]
}
Prompt:
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
Zapisz ten obraz w katalogu głównym folderu i zmień go na success.png
.
Następnie dodaj do background.js
ten fragment kodu.
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");
Teraz ponownie załaduj rozszerzenie na stronie rozszerzeń. Powinno od razu wyświetlić się wyskakujące okienko z powiadomieniem.
6. Dodawanie przekazywania wiadomości w rozszerzeniu do Chrome
Ostatnim ważnym krokiem jest połączenie wykrywania uczestnika przez skrypt treści z metodą sendNotification
w skrypcie działającym w tle. W kontekście rozszerzeń do Chrome można to zrobić za pomocą metody o nazwie message passing
.
Umożliwia to komunikację między różnymi częściami rozszerzenia do Chrome, w tym przypadku od skryptu treści do skryptu service worker w tle. Zapytajmy naszego znajomego Gemini, jak to zrobić.
Prompt:
How to send a message from the content script to the background script in a chrome extension
Gemini odpowiada, wysyłając odpowiednie wezwania do: chrome.runtime.sendMessage
i chrome.runtime.onMessage.addListener
.
Będziemy używać usługi sendMessage
do wysyłania ze skryptu treści wiadomości z informacją, że ktoś dołączył do rozmowy w Meet, a narzędzia onMessage.addListener
jako detektora zdarzeń, aby zareagować na wiadomość wysłaną przez skrypt treści. W tym przypadku wywołamy metodę sendNotification
z tego detektora zdarzeń.
Przekażemy komunikat z powiadomieniem i właściwość action
do procesu roboczego usługi w tle. Właściwość action
określa, na co odpowiada skrypt działający w tle.
Oto nasz kod 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"
});
}
A oto nasz kod 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"
});
}
Spróbujmy dostosować wiadomość z powiadomieniem i uzyskać unikalny identyfikator powiadomienia. W wiadomości z powiadomieniem możemy podać imię i nazwisko użytkownika. Jeśli wspomnimy w poprzednim kroku, możemy zobaczyć imię i nazwisko użytkownika w atrybucie tytułu zdjęcia. Możemy więc pobrać imię i nazwisko uczestnika za pomocą funkcji document.querySelector('div.U04fid > img').getAttribute('title').
Możemy pobrać identyfikator karty skryptu treści i użyć go jako identyfikatora powiadomienia. Można to zrobić w detektorze zdarzeń chrome.runtime.onMessage.addListener
za pomocą funkcji sender.tab.id.
Na koniec nasze pliki powinny wyglądać mniej więcej tak:
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. Gratulacje
W krótkim czasie udało nam się stworzyć rozszerzenie do Chrome przy pomocy Gemini. Niezależnie od tego, czy jesteś doświadczonym twórcą rozszerzeń do Chrome, czy dopiero zaczynasz przygodę z rozszerzeniami, Gemini pomoże Ci w każdej sytuacji.
Zachęcam do spytania o różne możliwości rozszerzenia do Chrome. Jest wiele interfejsów API, które warto przejrzeć, np. chrome.storage
, alarms
itp. Jeśli napotkasz problem, skorzystaj z Gemini lub dokumentacji, aby dowiedzieć się, co robisz nie tak, albo znaleźć różne sposoby rozwiązania problemu.
Aby uzyskać potrzebną pomoc, często trzeba zmodyfikować prompt, ale możemy to zrobić na jednej karcie, która zawiera wszystkie informacje o kontekście.