Codelab: با استفاده از Gemini یک برنامه افزودنی کروم در جاوا اسکریپت بسازید

۱. مقدمه

آیا به یک تماس تلفنی دعوت می‌شوید اما نمی‌خواهید اولین نفری باشید که این کار را انجام می‌دهد؟ اگر این شرایط شما را توصیف می‌کند، ما راه حلی برای شما داریم!

با دنبال کردن این کدلاگ، یک افزونه کروم ایجاد خواهید کرد که وقتی اولین شرکت‌کننده به تماس ملحق می‌شود، به شما هشدار می‌دهد.

شما عناصر مختلف یک افزونه کروم را یاد خواهید گرفت و سپس به طور عمیق به هر بخش از افزونه خواهید پرداخت. در مورد توابع افزونه مانند اسکریپت‌های محتوا، سرویس ورکرها و ارسال پیام یاد خواهید گرفت.

برای اینکه بتوانید هر زمان که یک شرکت‌کننده به یک تماس ملاقات می‌پیوندد، اعلانی دریافت کنید، باید به نسخه مانیفست نسخه ۳ پایبند باشید.

۲. قبل از شروع

پیش‌نیازها

اگرچه این آزمایشگاه کد برای مبتدیان مناسب است، اما داشتن درک اولیه از جاوا اسکریپت می‌تواند تجربه شما را تا حد زیادی افزایش دهد.

تنظیمات/الزامات

  • مرورگر کروم
  • یک IDE/ویرایشگر روی سیستم محلی شما نصب شده باشد.
  • اگر می‌خواهید API جمینی را با استفاده از جی‌کلود فعال کنید، gcloud cli را نصب کنید.

فعال کردن API جمینی

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.

۳. بگذارید خوش بگذرد

نصب اولیه افزونه

بیایید یک دایرکتوری ایجاد کنیم که به عنوان ریشه پروژه خود از آن استفاده خواهیم کرد.

mkdir gemini-chrome-ext
cd gemini-chrome-ext

قبل از اینکه شروع به پرسیدن سوالات خاص از Gemini کنیم، بیایید چند سوال در مورد ساختار کلی یک افزونه کروم بپرسیم.

سریع:

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 محتویات فایل مانیفست مورد نیاز ما را برمی‌گرداند، اما چند فیلد اضافی مانند فیلد 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 در ریشه پروژه خود قرار دهیم.

در این مرحله، فایل مانیفست باید چیزی شبیه به این باشد.

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

فعلاً هر فیلد اضافی دیگری که در فایل مانیفست شما ایجاد شده است را حذف کنید، زیرا این آزمایشگاه کد، این فیلدها را در فایل مانیفست شما در نظر می‌گیرد.

حالا، چطور می‌توانیم آزمایش کنیم که افزونه کار می‌کند؟ بیایید از دوستمان جمینی بپرسیم، موافقید؟

سریع:

Guide me on the steps needed to test a chrome extension on my local filesystem.

این به من چند مرحله در مورد نحوه آزمایش آن می‌دهد. بیایید با رفتن به chrome://extensions به "Extensions Page" برویم و مطمئن شویم که دکمه "Developer Mode" را فعال کرده‌ایم، که باید دکمه "Load unpacked" را نشان دهد، که می‌توانیم از آن برای رفتن به پوشه‌ای که حاوی فایل‌های افزونه به صورت محلی است استفاده کنیم. پس از انجام این کار، باید بتوانیم افزونه را در "Extensions Page" ببینیم.

3d802a497ce0cfc2.png

92db1999a1800ecd.png

عالی! می‌توانیم افزونه‌مان را ببینیم، اما بیایید شروع به اضافه کردن برخی قابلیت‌ها کنیم.

۴. یک اسکریپت محتوا اضافه کنید

ما می‌خواهیم فقط روی https://meet.google.com کد جاوا اسکریپت اجرا کنیم که می‌توانیم با استفاده از اسکریپت‌های محتوا این کار را انجام دهیم. بیایید از 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 خود اعمال کنیم و همچنین جاوا اسکریپتی که در فایل content.js خود نیاز داریم را به ما می‌دهد.

با اضافه کردن content_scripts، فایل مانیفست ما به صورت زیر می‌شود:

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

این به کروم می‌گوید هر زمان که به صفحه‌ای در زیردامنه « https://meet.google.com » می‌رویم، اسکریپت محتوا content.js تزریق کند. بیایید این فایل را اضافه کنیم و آن را آزمایش کنیم.

بیایید این کد را به فایل content.js اضافه کنیم.

console.log("Hello Gemini");

مطمئناً! وقتی به meet.google.com سر می‌زنیم، عبارت «Hello Gemini» را در کنسول جاوا اسکریپت (مک: Cmd + Opt + J / ویندوز/لینوکس: Ctrl + Shift + J ) می‌بینیم.

مانیفست.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"

        ]

    }

]

}

محتوا.js

console.log("سلام جوزا!");

6216bab627c31e6c.png

d61631c9962ffe5.png

عالی! حالا در موقعیتی هستیم که می‌توانیم برخی قابلیت‌های خاص جاوااسکریپت را به برنامه خود اضافه کنیم. بیایید لحظه‌ای در مورد آنچه می‌خواهیم به دست آوریم فکر کنیم.

بهبود اسکریپت محتوا

ما می‌خواهیم بتوانیم وقتی کسی به جلسه می‌پیوندد، وقتی در صفحه جلسه هستیم (جایی که گزینه‌ای برای پیوستن به جلسه داریم)، ​​اعلانی دریافت کنیم. برای دستیابی به این هدف، بیایید ببینیم که صفحه نمایش وقتی جلسه خالی است در مقابل وقتی کسی به جلسه پیوسته است، چگونه تغییر می‌کند.

وقتی کسی در جلسه نیست، اوضاع این‌طور به نظر می‌رسد.

fe5a0c95b20e7f72.png

در حالی که اینها تصاویری هستند که در آن برخی از شرکت‌کنندگان در جلسه حضور دارند.

7a5ef60521d961cc.png

ما می‌توانیم دو تفاوت قابل توجه را از همان ابتدا ببینیم:

  1. متن وضعیت از «هیچ‌کس دیگری اینجا نیست» به «[کاربر] در این تماس است» تغییر می‌کند.
  2. می‌توانیم تصاویر کاربرانی را که به این فراخوان پیوسته‌اند، ببینیم.

اگر بخواهیم بدانیم کسی به جلسه پیوسته است یا خیر، هر دوی این تغییرات برای ما مفید خواهند بود، اما مورد دوم امکاناتی برای دریافت اطلاعات در مورد کاربرانی که قبلاً پیوسته‌اند دارد، بنابراین بیایید سعی کنیم از آن استفاده کنیم.

با استفاده از کلیدهای میانبر (مک: Cmd + Opt + C / Win: Ctrl + Shift + C ) در کروم، «بازرس عناصر» (Elements Inspector) را باز کنید، سپس روی تصویر کاربری که عضو شده است کلیک کنید.

می‌توانیم متوجه شویم که یک تصویر با چند رشته کلاس وجود دارد و ویژگی عنوان تصویر، نام کاربری است که به جلسه پیوسته است. علاوه بر این، این برچسب تصویر در یک div با کلاس U04fid قرار گرفته است. هنگامی که چند عضو به جلسه آزمایشی خود اضافه می‌کنیم، می‌توانیم ببینیم که این div والد میزبان چندین تصویر (مربوط به کاربران مختلف) است.

بنابراین، ما یک استراتژی جزئی در ذهن داریم:

  1. تشخیص اینکه چه زمانی div با کلاس U04fid حاوی عنصری است.
  2. اگر اینطور باشد، یعنی ما در جلسه خود شرکت‌کنندگانی داریم.
  3. به کاربر اطلاع دهید.

بیایید به 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 والد، joineeها را بررسی می‌کند.

این چیزی است که ما دریافت کردیم:

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 را مجدداً بارگذاری کنید).

حالا وقتی کسی به جلسه ما ملحق می‌شود، می‌توانیم دستور لاگ را در کنسول ببینیم.

۵. ارسال اعلان به کاربر

حالا که می‌توانیم تشخیص دهیم چه زمانی یک شرکت‌کننده به جلسه پیوسته است، بیایید بخش اعلان را به افزونه کروم خود اضافه کنیم. می‌توانیم مستندات افزونه کروم را مرور کنیم یا حتی اعلان‌ها را تغییر دهیم تا بدانیم به دنبال چه چیزی هستیم، اما اساساً باید از API مربوط به chrome.notifications.create استفاده کنیم و فراخوانی این متد باید از یک سرویس ورکر پس‌زمینه باشد.

سریع:

Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.

ما مراحل مفصلی را می‌بینیم که نکات برجسته اصلی آنها عبارتند از:

  • مجوز notifications را در فایل مانیفست اضافه کنید.
  • فایل chrome.notifications.create را فراخوانی کنید.
  • فراخوانی باید در یک اسکریپت پس‌زمینه باشد.

برای افزودن یک اسکریپت پس‌زمینه به افزونه کروم در manifest version 3 ، به تعریف background.service_worker در فایل manifest.json خود نیاز داریم.

بنابراین، ما یک فایل به نام background.js ایجاد می‌کنیم و موارد زیر را به فایل manifest.json خود اضافه می‌کنیم.

"background": {
        "service_worker": "background.js"
},
"permissions": [
        "notifications"
]

با اضافه کردن موارد فوق، فایل مانیفست ما به صورت زیر می‌شود:

{
    "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 تغییر دهید.

b2c22f064a3f2d9c.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");

اکنون افزونه را از صفحه افزونه‌ها مجدداً بارگذاری کنید و باید فوراً یک پنجره اعلان مشاهده کنید.

۶. ارسال پیام را در افزونه کروم خود اضافه کنید

حالا، آخرین مرحله‌ی اصلی که نیاز داریم، اتصال تشخیص یک شرکت‌کننده توسط اسکریپت محتوا و متد sendNotification در اسکریپت پس‌زمینه است. در زمینه‌ی افزونه‌های کروم، روش انجام این کار از طریق تکنیکی به نام message passing ) است.

این کار ارتباط بین بخش‌های مختلف یک افزونه کروم، در مورد ما از اسکریپت محتوا تا سرویس ورکر پس‌زمینه را ممکن می‌سازد. بیایید از دوستمان 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 به عنوان یک شنونده رویداد برای واکنش به پیام ارسال شده توسط content script استفاده خواهیم کرد. در این حالت، فراخوانی متد sendNotification را از این شنونده رویداد آغاز خواهیم کرد.

ما پیام اعلان و یک ویژگی action را به سرویس ورکر پس‌زمینه ارسال خواهیم کرد. ویژگی 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"
    });
}

بیایید سعی کنیم پیام اعلان را سفارشی کنیم و یک شناسه اعلان منحصر به فرد دریافت کنیم. برای پیام اعلان، می‌توانیم نام کاربر را وارد کنیم. اگر از مرحله قبل به یاد بیاوریم، می‌توانستیم نام کاربر را در ویژگی title تصویر ببینیم. بنابراین، می‌توانیم نام شرکت‌کننده را با استفاده از document.querySelector('div.U04fid > img').getAttribute('title').

در مورد شناسه اعلان، می‌توانیم شناسه برگه (tab ID) اسکریپت محتوا را دریافت کرده و از آن به عنوان شناسه اعلان استفاده کنیم. این کار را می‌توان در شنونده رویداد chrome.runtime.onMessage.addListener با استفاده از sender.tab.id.

در نهایت، فایل‌های ما باید چیزی شبیه به این باشند:

مانیفست.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"
    ]
}

محتوا.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",
    });
}

پس‌زمینه.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"
    });
}

۷. تبریک

در مدت زمان کوتاهی ما توانستیم با کمک Gemini یک افزونه کروم بسازیم. چه یک توسعه‌دهنده باتجربه افزونه‌های کروم باشید و چه تازه وارد دنیای افزونه‌ها، Gemini می‌تواند در هر کاری که می‌خواهید انجام دهید به شما کمک کند.

من شما را تشویق می‌کنم که در مورد کارهای مختلفی که می‌توانید با یک افزونه کروم انجام دهید، سوال کنید. API های زیادی وجود دارند که ارزش مرور کردن دارند، مانند chrome.storage ، alarms و غیره. هر جا که احساس کردید گیر کرده‌اید، از Gemini یا مستندات استفاده کنید تا بفهمید چه اشتباهی مرتکب می‌شوید یا راه‌های مختلفی برای حل مشکل جمع‌آوری کنید.

اغلب لازم است که برای دریافت کمک مورد نیاز، اعلان را تغییر دهیم، اما می‌توانیم این کار را از طریق یک تب انجام دهیم که تمام مسیر متنی ما را حفظ می‌کند.