Programování

NÁVOD: S pomocí ChatGPT jsme vytvořili vlastní rozšíření do prohlížeče. Na kliknutí pošle e-mail s připomenutím

Už dlouho jsem hledal rozšíření desktopového prohlížeče, které by mi na kliknutí poslalo do e-mailu informace o prohlížené stránce. Hodí se mi to v situacích, když na webu něco objevím a chci se k tomu později vrátit. Na mobilu a tabletu mi tuto funkčnost zajišťuje aplikace Note to self, postupy pro desktop mi ale po omezení služby IFTTT pořád nevyhovovaly.

Tak jsem si vyrobil vlastní doplněk a z velké části ho pro mě napsal ChatGPT.

image.png
Dvě nové ikony vedle adresního řádku v prohlížeči Edge. Jedna pošle e-mail na pracovní adresu, druhá na soukromou
image.png
A takhle mi potom dorazí zpráva do e-mailu

V článku ukážu, jak takový doplněk připravit. A také, jak při takové práci využívat konverzační AI chatboty. I když mám doplněk nainstalovaný v prohlížeči Edge, v Chrome by měl fungovat také a postup bude stejný.

Proč vlastně potřebuji e-mail? Popisuji to tady:

AI, řekni mi, co mám udělat

V ChatGPT Pro s modelem GPT-4 jsem začal novou konverzaci:

Chovej se jako vývojář. Potřebuji vytvořit rozšíření pro prohlížeč Edge. Po kliknutí na jeho ikonu se okamžitě odešle e-mail pomocí služby Gmail. Nezobrazí se žádné  HTML vyskakovací okno. Adresa příjemce se nastaví v kódu. Předmět e-mailu začíná řetězcem „Note ML: “ a pokračuje metatitulkem stránky. V těle e-mailu je pouze URL adresa stránky.

image.png
Napíšu, co chci, a ChatGPT navrhne řešení

Tím bych vlastně mohl skončit. ChatGPT odpověděl, co mám udělat: novou složku, v ní soubory manifest.json, background.js a ikonu. Protože nezvládne tak dlouhé výstupy, musel jsem ho jen dvakrát postrčit pomocí Continue, aby pokračoval.

Proč si s ním píšu anglicky? Mám pocit, že povelům potom víc rozumí, je rychlejší a odpovědi mohou být rozsáhlejší. Šlo by to ale i česky.

Postup a připravený kód fungoval. Jen se objevily problémy s českými znaky. A také jsem potřeboval podrobnější popis k přípravě autorizačních kódů a tokenu, aby doplněk mohl posílat zprávy přes můj Gmail.

image.png
V jednom kroku při přípravě tokenu jsem se setkával s chybou. Stačí ji popsat a hned jsem věděl, co dělat. Tohle je typická ukázka, jak s AI chatem pracovat: ptát se ho na velmi konkrétní věci

První soubor: Manifest

První soubor, který bylo potřeba ve složce vytvořit, byl manifest.json. Použil jsem kód, který ChatGPT navrhl a přepsal jen některé popisné texty.

{
  "manifest_version": 2,
  "name": "ML Note Work",
  "version": "1.0",
  "description": "Send an email with the current page's meta title and URL to work address",
  "icons": {
    "48": "icon.png"
  },
  "browser_action": {
    "default_icon": "icon.png",
    "default_title": "Poslat e-mail do práce"
  },
  "permissions": [
    "activeTab",
    "https://www.googleapis.com/*"
  ],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  }
}

K čemu manifest.json slouží? Nebudu předstírat, že jsem to vymyslel sám:

image.png
Když u ChatGPT přejdu do češtiny, odpovídá také česky

Vytvořil jsem také ikonu v rozměru 48 × 48 px a v průhledném PNG ji nahrál do složky.

Co se děje v Backgroundu

V druhém souboru background.js je kód, který provede samotné akce rozšíření. U něj jsme společně s ChatGPT dost bojovali s problematickou češtinou, ale nakonec se to podařilo vyřešit.

image.png
Tohle jsem nechtěl…

Co nám k background.js řekne ChatGPT? Je to skript, který se spustí na pozadí rozšíření prohlížeče. Jeho účelem je provádět akce, které nevyžadují interakci uživatele prostřednictvím uživatelského rozhraní (UI), například poslouchání událostí, komunikaci s webovými službami nebo práci s lokálním úložištěm.

  1. Když kliknu na ikonu rozšíření, spustí se událost browserAction.onClicked, která zavolá funkci sendPageEmail().
  2. Funkce sendPageEmail() extrahuje název (metatitle) a URL z aktuální webové stránky a připraví předmět e-mailu.
  3. Poté se zavolá funkce getAccessToken(), která získá přístupový token pomocí OAuth 2.0 a poskytnutého obnovovacího tokenu (refresh token). Přístupový token je nezbytný pro autorizaci požadavků na Gmail API.
  4. Jakmile skript získá přístupový token, zavolá funkci sendEmail() s tokenem, předmětem a tělem e-mailu (URL stránky). Funkce zakóduje obsah e-mailu do formátu Base64 a předá požadavek na Gmail API.
  5. Gmail API zpracuje požadavek a odešle e-mail.

Zpráva na cílovou adresu v Gmailu dorazí do několika sekund od stisknutí tlačítka rozšíření v prohlížeči.

Samotný kód v souboru background.js

const recipientEmail = 'e-mailová adresa příjemce';
const senderName = 'jméno odesílatele';
const senderEmail = 'e-mailová adresa odesílatele';
const clientId = 'váš řetězec clientId';
const clientSecret = 'váš řetězec clientSecret';
const refreshToken = 'váš refreshToken';

function getAccessToken() {
  return new Promise((resolve, reject) => {
    const data = new URLSearchParams();
    data.append('client_id', clientId);
    data.append('client_secret', clientSecret);
    data.append('refresh_token', refreshToken);
    data.append('grant_type', 'refresh_token');

    fetch('https://www.googleapis.com/oauth2/v4/token', {
      method: 'POST',
      body: data,
    })
      .then((response) => response.json())
      .then((data) => {
        if (data.access_token) {
          resolve(data.access_token);
        } else {
          reject('Error fetching access token');
        }
      });
  });
}

function utf8ToBase64(str) {
  const utf8Bytes = new TextEncoder().encode(str);
  return btoa(String.fromCharCode.apply(null, utf8Bytes))
    .replace('+', '-')
    .replace('/', '_')
    .replace(/=+$/, '');
}

function quotedPrintableEncode(str) {
  return str
    .split('')
    .map((char) => {
      const code = char.charCodeAt(0);
      return code < 32 || code > 126 || code === 61 ? '=' + code.toString(16).toUpperCase() : char;
    })
    .join('');
}

function sendEmail(accessToken, subject, body) {
  const encodedSubject = utf8ToBase64(subject);
  const encodedBody = quotedPrintableEncode(body);
  const emailContent = `From: "${senderName}" <${senderEmail}>\nSubject: =?utf-8?B?${encodedSubject}?=\nTo: ${recipientEmail}\nContent-Type: text/plain;charset=utf-8\nContent-Transfer-Encoding: quoted-printable\n\n${encodedBody}`;
  const base64Content = utf8ToBase64(emailContent)
    .replace('+', '-')
    .replace('/', '_')
    .replace(/=+$/, '');

    fetch('https://www.googleapis.com/gmail/v1/users/me/messages/send', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      raw: base64Content,
    }),
  })
    .then((response) => response.json())
    .then((data) => {
      if (data.id) {
        console.log('Email sent successfully');
      } else {
        console.error('Error sending email', data);
      }
    });
}

function sendPageEmail(tab) {
  let pageTitle = tab.title;
  const maxLength = 70;

  if (pageTitle.length > maxLength) {
    pageTitle = pageTitle.substring(0, maxLength - 1) + '…';
  }

  const pageUrl = tab.url;
  const subject = `Note ML: ${pageTitle}`;

  getAccessToken()
    .then((accessToken) => {
      sendEmail(accessToken, subject, pageUrl);
    })
    .catch((error) => {
      console.error(error);
    });
}

chrome.browserAction.onClicked.addListener((tab) => {
  sendPageEmail(tab);
});

V prvním bloku je několik proměnných, které musíte nastavit sami. V kódu funkce sendPageEmail() potom asi ještě budete chtít změnit úvodní řetězec Note ML.

Jak se domluvit s Gmailem

Složitější to bylo se získáním autorizačních řetězců clientIdclientSecretrefreshToken, aby rozšíření mohlo využívat můj Gmail. Tady mi ChatGPT s postupem hodně pomohl. Stručně:

Vytvořte nový projekt v Google Cloud. Na stránce APIs & Services mu přiřaďte Gmail API. Když se bude ptát na varianty, bude vám stačit gmail.send pro odesílání e-mailů.

V sekci Credentials vytvořte nové OAuth Client ID. Vyberte typ Web Application, do pole origins vložte http://localhost, do redirect URLs postupně adresy http://localhost/oauth2callback a https://developers.google.com/oauthplayground.

Po uložení získáte první první dva požadované řetězce Client IDClient secret. Nyní budete potřebovat refresh token, kterým bude rozšíření žádat o přístupový token nutný k odeslání e-mailu. Získáte ho na stránce OAuth 2.0 Playground.

Zde v pravém rohu klikněte na ozubené kolo, vyberte Use your own OAuth credentials a do polí zadejte své Client ID a Client secret. Na levé straně v seznamu najděte Gmail API v1, zaškrtněte u něj variantu gmail.send a klikněte na Authorize API. Nyní potvrdíte, že aplikace má mít práva posílat e-maily prostřednictvím vašeho Gmailu.

image.png
Potvrzení práv aplikaci

Získáte autorizační kód, modrým tlačítkem ho změníte na refresh token. Znovu otevřete předchozí panel s tímto tokenem, zaškrtnete checkbox pro Auto-refresh, aby se token obnovil před tím, než vyprší. A kód překopírujete do řádku v souboru background.js.

Instalace rozšíření

Teď ještě musíte dostat rozšíření do prohlížeče. U Edge je třeba na stránce s jejich přehledem edge://extensions/ povolit Režim vývojáře. Nahoře se ukáže odkaz Načíst nezabalené, kterým najdete svoji složku se soubory. Rozšíření se potom ukáže v sekci Z jiných zdrojů.

Já tady mám dvě, které se liší jen ikonou a cílovou e-mailovou adresou: domů a do práce.

image.png
Kdyby něco nefungovalo, pod odkazem Chyby můžete najít log s podrobnostmi

Jestli používáte více počítačů, tato lokální rozšíření se mezi nimi nesynchronizují. Musíte je uvedeným způsobem přidat na každém počítači.

Ladění kódu 2.0

Cílem tohoto článku nebylo jen ukázat, jak vytvořit rozlišení pro posílání e-mailu z webového prohlížeče. Ale hlavně jak při tom využít ChatGPT. Nebo třeba i Bing Chat, kde to jen bude složitější kvůli limitu počtu příspěvků v jednom vláknu. Ale i tady by to šlo.

Když vám něco není jasné, AI chatu se rovnou zeptejte. Jako třeba tady já, když jsem hledal, jak se dostat k refresh tokenu. Žádejte klidně potom o podrobnější vysvětlení, o vysvětlení jiným způsobem, o řešení chyb, o popis, co přesně která funkce nebo i její konkrétní řádek dělají. Čím je otázka konkrétnější, tím je větší šance, že chat při odpovědi neodvede téma jinam.

image.png
Na jednoduchou otázku dostanete podrobný návod
image.png
Ptejte se i česky, ChatGPT odpoví česky. Tady zrovna začíná s vysvětlováním příliš zeširoka, i když jsem mu říkal, že první dva údaje už mám. Hodí se ho zastavit a dotaz upřesnit. Anebo se v další otázce zeptat přesněji

V jedné fázi mi přišlo, že to už ChatGPT trochu komplikuje. Při řešení problému se znakovou sadou stále navrhoval další a další verze funkcí, k tomu úplně nové funkce. Vrátil jsem ho proto na začátek zkopírováním aktuálního kompletního kódu, ať řekne, co je špatně. A bylo hotovo. Našel chybu, navrhl řešení a už to fungovalo.

image.png
Rozvíjející se konverzaci a varianty je někdy dobré utnout a ve vlákně dostat chat zpět na začátek

Podívejte se také na tuto situaci, kdy v první části předmětu byla čeština správně, ale v závěru se opět objevily paznaky. ChatGPT napadlo, čím by to mohlo být, vysvětlil to, navrhl úpravu.

image.png
Bloky s kódem bývají pěkně odlišené. Když ale v příspěvku dojde vyhrazený prostor, ChatGPT ho ukončí a musíte napsat třeba Continue. Pak zase začne od dalšího řádku. Části musíte potom spojit

Tento návrh jsem nakonec nepřijal. Nepotřebuji tak dlouhé předměty, po sedmdesátém znaku je raději nechám useknout:

image.png
Uděláme to jednoduše, předměty budou kratší

Patláma, patláma, patláma a žbrluch!

Nejsem vývojář. Celkem zvládám statistické R, ale úsilí, které musím věnovat kódování v normálních jazycích, je často tak velké, že si to ještě před začátkem rozmyslím. Zrovna tato úloha byla navíc dost specifická a pročítání Stack Overflow by mi u ní asi nestačilo. Bez ChatGPT bych to prostě nedal.

Nebylo to navíc poprvé, kdy mi AI takhle pomohla. ChatGPT jsem už mnohokrát použil pro jednoúčelová makra v Apps Scriptu. Bylo to takhle i s přípravou  kódu rychlejší než dělat stejné operace na desítkách listů tabulky na Google disku.

Vím, není to spravedlivé. Někdo se musel učit programovat, já to teď spíchnu během půl hodiny díky nástroji jako ChatGPT – který se to navíc naučil z kódů těch, kteří programovat umí. Jediné řešení je začít ho taky efektivně využívat; nechat na něm rutinní úkoly, šetřit čas.

Na závěr doporučení: Nespouštějte kód, aniž byste tušili, co dělá, a nesnažili se mu porozumět. AI se vyplatí kontrolovat a cizí kód může být i nebezpečný. Ptejte se chatu, k čemu přesně slouží tato funkce, co dělá tento konkrétní řádek. Umí to pěkně vysvětlit a na rozdíl od lidí je velmi trpělivý.

Diskuze (13) Další článek: Kaufland jako Amazon či Aliexpress. Za dva týdny u nás spustí e-shop Marketplace

Témata článku: , , , , , , , , , , , , , , , , , , , , , , , ,