Alt bellikleri, elýeterli web sahypalaryny gurmagyň iň belli tarapy, ýöne gynansak-da köplenç äsgerilmeýär ýa-da pes ýerine ýetirilýär. Alt bellikleri şekillere goşulan gysga tekst beýanydyr. Ekranyň okyjylary web sahypasynyň mazmunyny ulanyjylara okaýarlar, suratdaky düşündirişler, sahypadaky şekillerdäki zatlary görmeýän ulanyjylara habar bermek üçin okaýan zatlarydyr.
Gynansagam, suratlaryň islendik alt belliklerini düýbünden ýitirmegi adaty zat. Şeýle hem, diňe "surat" ýa-da "şekil" diýýän bellikler ýaly, görmeýän ulanyjy üçin ýagdaýy kynlaşdyrýan alt bellikleri, suratdaky zatlara salgylanmazdan awtoryň goşan owadan ýazgylary ýaly bellikleri gördüm ( blogagny, blog sahypasynda kofeniň we noutbukyň şekili, "eziz gündelik, myhman ýazyjy hökmünde saýlanmagymy isleýärin"). Şeýle hem SEO açar sözleriniň 3 setirini öz içine alýan alt belliklerini gördüm. Web sahypasyndaky zatlary diňe “suratyň suratyny” ýa-da SEO açar sözleriniň uzyn sanawyny diňlemek üçin göz öňüne getirip bilersiňizmi?
Bu, erbet alt belliklerini gaýtadan ýazmaga mümkinçilik berýän we AI-den döredilen düşündirişleri girizmek üçin Açyk AI-den peýdalanyp, görmeýän ulanyjylara kuwwat bermek üçin döredilen Chrome giňeltmesi. Bu, görmeýän ulanyjylara web sahypasyndaky ähli mazmuna girmäge mümkinçilik berýär (ýa-da iň bolmanda SEO açar sözleriniň uzyn sanawy bilen haýallaşmaýar).
Diňe giňeltme isleseňiz, bu repony göçürip alyp, README-de görkezmeleri ýerine ýetirip bilersiňiz.
Şeýle-de bolsa, “OpenAI” bilen “Chrome” giňeltmesini nädip gurmalydygy barada ädimme-ädim gollanma bilen gyzyklanýan bolsaňyz, aşakdaky gezelenç.
Ilki bilen, esasy Chrome gazany alyp, işledeliň. Bu ammary klonlaň we README-de görkezmelere eýeriň:
Ony gurup, gurnanyňyzdan soň, uzaldyş paneliňizde şekil nyşany bolmaly (synagy has çaltlaşdyrmak üçin dakmagy maslahat berýärin), şoňa basanyňyzda “salam dünýäsi” atly bir çykýan penjäni görmeli.
Geliň, kody açalyň we bar bolan faýllardan geçeliň. Bu, şeýle hem, “Chrome Extension” esaslaryny öz içine alar:
Static / manifest.json - Her Chrome giňeltmesinde manifest.json faýly bar. Giňeltmek barada esasy maglumatlary we gurnamalary öz içine alýar. Manifest faýlymyzda adymyz, düşündirişimiz, src / background.js-a düzülen fon faýly, image-icon.png-a düzülen nyşan bar (bu giňeltmeler menýusynda giňeltmäni görkezýän nyşan), we popup.html çykýan ýerimiz üçin faýl çeşmesi hökmünde düzýär.
src / background.js - Manifestimizde gurlan background.js faýly. Bu faýldaky kod fonda işlär we giňeltmede işlemäge sebäp bolýan wakalara gözegçilik eder.
src / content.js - Web sahypasynyň çäginde işleýän ýa-da web sahypasyny üýtgedýän islendik skript mazmun skriptine girizilýär.
src / popup.js, static / popup.css, we static / popup.html - Bu faýllar, giňeltme nyşanyna basanyňyzda görýän çykýan penjäňizi dolandyrýar
Geliň, käbir esaslary düzeliň - statik / manifest.json açyň we adyny we düşündirişini “Ekranyň okyjysynyň surat beýany generatoryna” (ýa-da islän zadyňyzy) üýtgedeliň.
Mazmun skriptini ulanyp, web sahypalary bilen täsirleşmäge mümkinçilik beriň
Giňeldişimiz, ulanyjynyň web sahypasyndaky alt belliklerini täzeden ýazmakçy, bu bolsa html sahypasyna girmelidigimizi aňladýar. Muny “Chrome Extensions” -da etmegiň usuly mazmun skriptleri arkaly amala aşyrylýar. Mazmun skriptimiz src / content.js faýlymyzda bolar.
Mazmun skriptini sanjymyň iň ýönekeý usuly, js faýlyna salgylanmak bilen manifete “skriptler” meýdançasyny goşmakdyr. Mazmun skriptini şeýle guranyňyzda, uzaldylan ýüklenen skript işlener. Şeýle-de bolsa, ulanyjy giňeltmäni açanda giňeltmämiziň awtomatiki işlemegini islemeýäris. Käbir web sahypalarynda şekillerde ajaýyp alt bellikleri bar, şonuň üçin ulanyjy zerur bolanda karar bermek isleýäris.
Ulanyjy düwmä basanda mazmun skripti ýüklener ýaly, açylan ýerimize bir düwme we mazmun skriptimize konsol ýazgysyny goşarys, sözlerimiziň Chrome konsolynda çap edilendigini görüp bileris.
Popup.html
<button id="generate-alt-tags-button">Generate image descriptions</button>
src / content.js
console.log('hello console')
Şol düwmäni birikdirmegiň usuly, çykýan penjire mazmun skriptine basmak üçin popup.js we background.js degişlidir.
Popup.js-da, DOM-dan düwmäni alarys we waka diňleýjisini goşarys. Ulanyjy şol düwmä bassa, mazmun skriptiniň sanjylmalydygyny görkezýän habar ibereris. “InjectContentScript” habaryna at bereris
const generateAltTagButton = document.body.querySelector('#generate-alt-tags-button'); generateAltTagButton.addEventListener('click', async () => { chrome.runtime.sendMessage({action: 'injectContentScript'}) });
Background.js-da, wakalara gözegçilik edýän we olara reaksiýa berýän kodumyz bar. Bu ýerde, waka diňleýjisini gurýarys we alnan habar 'инжektContentScript' bolsa, mazmun skriptini işjeň goýmada ýerine ýetirer (ulanyjynyň häzirki web sahypasy).
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'injectContentScript') { chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { chrome.scripting.executeScript({ target: { tabId: tabs[0].id }, files: ['content.js'] }); }); } });
Muny gurmak üçin iň soňky ädim, manifestimize “activeTab” we “skript” rugsatlaryny goşmakdyr. Mazmun skriptini işletmek üçin “skript” rugsady talap edilýär. Şeýle hem, skripti sanjylýan sahypalarymyz üçin rugsatlar goşmalydyrys. Bu ýagdaýda, ulanyjynyň häzirki web sahypasyna skriptini sanjym ederis, bu bolsa olaryň işjeň goýmasy we işjeňTab rugsady.
Manifestde.json:
"permissions": [ "activeTab", "scripting" ],
Bu pursatda, Chrome-dan giňeltmäni aýyrmaly we dogry işlemegi üçin täzeden ýüklemeli bolmagyňyz mümkin. Işläp başlansoň, Chrome konsolymyzda konsol gündeligimizi görmeli.
Ine, bu etapda repo üçin iş kody üçin github baglanyşygy .
Sahypanyň suratlaryny ýygnamak we synag alt belliklerini goýmak
Indiki ädimimiz, sahypadaky ähli suratlary ele almak üçin mazmun skript faýlymyzy ulanmak, şonuň üçin surat düşündirişlerini almak üçin API çagyryşlarymyza ibermäge taýyn maglumatlarymyz bar. Şeýle hem, diňe düşündirişleriň bolmagy peýdaly bolan suratlar üçin jaň edýändigimize göz ýetirmek isleýäris. Käbir şekiller diňe bezegli we ekrany okyjylary düşündirişleri bilen haýallatmagyň zerurlygy ýok. Mysal üçin, “gözleg” belligi we ulaldyjy aýna nyşany bolan gözleg paneli bar bolsa. Eger bir suratyň alt belligi boş setire düzülen bolsa ýa-da aria bilen gizlenen bolsa, bu şekiliň ekran okyjysyna goşulmagynyň zerurlygy ýok we biz onuň üçin düşündiriş döredip bilmeris.
Şonuň üçin ilki bilen content.js sahypasyndaky ähli suratlary sahypada ýygnarys. Dogry işleýändigini tiz tassyklamak üçin console.log goşýaryn:
const images = document.querySelectorAll("img"); console.log(images)
Soňra suratlaryň üstünden bararys we alt belligi döretmeli şekilleri barlarys. Alt belligi bolmadyk ähli suratlary we boş setir bolmadyk alt belligi bolan suratlary we aria-gizlin häsiýeti bolan ekran okyjylaryndan aç-açan gizlenmedik suratlary öz içine alýar.
for (let image of images) { const imageHasAltTag = image.hasAttribute('alt'); const imageAltTagIsEmptyString = image.hasAttribute('alt') && image.alt === ""; const isAriaHidden = image.ariaHidden ?? false; if (!imageHasAltTag || !imageAltTagIsEmptyString || !isAriaHidden) { // this is an image we want to generate an alt tag for! } }
Soňra alt belliklerini bellemek üçin synag setirini goşup bileris, şonuň üçin OpenAI jaňlarymyza geçmezden ozal olary düzmegiň funksional usulynyň bardygyny tassyklap bileris. Mazmuny.js indi meňzeýär:
function scanPhotos() { const images = document.querySelectorAll("img"); console.log(images) for (let image of images) { const imageHasAltTag = image.hasAttribute('alt'); const imageAltTagIsEmptyString = image.hasAttribute('alt') && image.alt === ""; const isAriaHidden = image.ariaHidden ?? false; if (!imageHasAltTag || !imageAltTagIsEmptyString || !isAriaHidden) { image.alt = 'Test Alt Text' } } } scanPhotos()
Bu pursatda, Chrome dev gurallary elementlerini açsak, surata bassaňyz, alt belligi hökmünde “Test Alt Text” -i görmelidiris.
Kodyň şu etapda ýerleşýän ýeri üçin işleýän repo şu ýerde.
OpenAI guruň we şekil düşündirişlerini dörediň
OpenAI-ni ulanmak üçin OpenAI açaryny döretmeli we hasabyňyza karz goşmaly bolarsyňyz. OpenAI açaryny döretmek üçin:
Bu açary ýazdyryň. Mundan başga-da, ony gizlin saklaň - ony köpçülikleýin git reposyna salmaň.
Indi reposymyza gaýdyp, ilki bilen OpenAi gurmak isleýäris. Taslama bukjasynyň içindäki terminalda:
npm install openai
Indi content.js-da, bu kody faýlyň ýokarsyna goşup, OpenAI açaryňyzy 1-nji setirde goýup, OpenAI import ederis:
const openAiSecretKey = 'YOUR_KEY_GOES_HERE' import OpenAI from "openai"; const openai = new OpenAI({ apiKey: openAiSecretKey, dangerouslyAllowBrowser: true });
“DangerouslyAllowBrowser” jaňy brauzerden açaryňyz bilen amala aşyrmaga mümkinçilik berýär. Umuman, bu howply amal. Bu taslamany diňe ýerli derejede alyp barýandygymyz sebäpli, yzky gözleg gurmagyň ýerine, ony şeýle goýarys. OpenAI-ni beýleki taslamalarda ulanýan bolsaňyz, esasy syry saklamak boýunça iň oňat tejribä eýerýändigiňize göz ýetiriň.
Indi, OpenAI şekil düşündirişlerini döretmek üçin jaňymyzy goşýarys. Çat gutarnykly gutarnykly nokady ( Çat gutarmagyň ahyrky nokady üçin OpenAI resminamalary ) diýip atlandyrýarys.
Biz öz islegimizi ýazmaly we şekiliň src URL-de geçmeli ( AI gyssagly in engineeringenerçilik hakda has giňişleýin maglumat ). Sorag isleýşiňiz ýaly uýgunlaşdyryp bilersiňiz. Düşündirişleri 20 eser bilen çäklendirmegi saýladym, sebäbi OpenAI uzyn beýany yzyna gaýtarýardy. Mundan başga-da, munuň “Yelp” ýa-da “Facebook” logotipleri (ýagny, içindäki ak harply uly gök guty) ýaly logotipleri doly suratlandyrýandygyna göz ýetirdim. Infografiki bolsa, çäk sözüniň äsgerilmezligini we şekiliň doly tekstiniň paýlaşylmagyny haýyş edýärin.
Ine, ilkinji AI jogabynyň mazmunyny yzyna gaýtaryp berýän we ýalňyşlygy “handleError” funksiýasyna geçirýän doly jaň. Çagyryşyň üstünlikli ýa-da üstünlikli däldigi barada has çalt seslenme almak üçin her jogabyň konsol.logyny goşdum:
async function generateDescription(imageSrcUrl) { const response = await openai.chat.completions.create({ model: "gpt-4o-mini", messages: [ { role: "user", content: [ { type: "text", text: "Describe this image in 20 words or less. If the image looks like the logo of a large company, just say the company name and then the word logo. If the image has text, share the text. If the image has text and it is more than 20 words, ignore the earlier instruction to limit the words and share the full text."}, { type: "image_url", image_url: { "url": imageSrcUrl, }, }, ], }, ], }).catch(handleError); console.log(response) if (response) { return response.choices[0].message.content;} } function handleError(err) { console.log(err); }
Öň ýazan sözlerimize bu funksiýa jaň goşýarys (bu asynkron jaňy goşmak üçin scanImages funksiýasynyň başynda asynk açar söz goşmalydyrys):
const imageDescription = await generateDescription(image.src) if (!imageDescription) { return; } image.alt = imageDescription
Ine, şu wagt doly mazmun.js we repo bilen baglanyşyk.
UI gurmak
Ondan soň, ulanyjy bellikleri döretmek üçin düwmä basandan soň nämeleriň bolup geçýändigini bilmek üçin UI-ni gurmak isleýäris. Bellikleriň ýüklenmegi üçin birnäçe sekunt gerek, şonuň üçin ulanyjynyň işleýändigini bilmek üçin 'ýüklemek' habaryny isleýäris. Mundan başga-da, munuň üstünlikli bolandygyny ýa-da ýalňyşlyk bar bolsa olara habar bermek isleýäris. Simpleönekeý zatlary ýönekeýleşdirmek üçin html-de umumy ulanyjy habary bolar, soň bolsa giňeltmede bolup geçýän wakalara esaslanyp ulanyja degişli habary dinamiki girizmek üçin popup.js ulanarys.
“Chrome” giňeltmeleriniň gurulmagy, mazmun skriptimiz (content.js) popup.js-den aýrylýar we üýtgeýänleri adaty JavaScript faýllary ýaly paýlaşyp bilmeýärler. Mazmun skriptiniň bellikleriň ýüklenýändigini ýa-da üstünlikli ýüklenendigini habar beriş usuly habaryň üsti bilen amala aşyrylýar. Ulanyjy asyl düwmä basanda mazmun skriptine sanjym etmegi habar berenimizde, eýýäm habary ulanýardyk.
Ilki bilen, html-de düwmämiziň aşagyndaky id 'ulanyjy-habary' bilen diw goşarys. Başlangyç habar üçin birneme has köp düşündiriş goşdum.
<div id="user-message"> <img src="image-icon.png" width="40" class="icon" alt=""/> This extension uses OpenAI to generate alternative image descriptions for screen readers. </div>
Soňra, popup.js sahypamyzda, giňeltme ýagdaýyna täzelenme bolup biljek iberilen habarlary diňleýän diňleýji goşarys. Mazmun skriptinden haýsy döwlet netijesini alsak, şoňa sanjym etmek üçin käbir html ýazarys.
const userMessage = document.body.querySelector('#user-message'); chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { renderUI(message.action) } ); function renderUI(extensionState) { generateAltTagButton.disabled=true; if (extensionState === 'loading') { userMessage.innerHTML = '<img src="loading-icon.png" width="50" class="icon" alt=""/> New image descriptions are loading... <br> <br>Please wait. We will update you when the descriptions have loaded.' } else if (extensionState === 'success') { userMessage.innerHTML = '<img src="success-icon.png" width="50" class="icon" alt=""/> New image descriptions have been loaded! <br> <br> If you would like to return to the original image descriptions set by the web page author, please refresh the page.' } else if (extensionState === 'errorGeneric') { userMessage.innerHTML = '<img src="error-icon.png" width="50" class="icon"alt=""/> There was an error generating new image descriptions. <br> <br> Please refresh the page and try again.' } else if (extensionState === 'errorAuthentication') { userMessage.innerHTML = '<img src="error-icon.png" width="50" class="icon"alt=""/> There was an error generating new image descriptions. <br> <br> Your OpenAI key is not valid. Please double check your key and try again.' } else if (extensionState === 'errorMaxQuota') { userMessage.innerHTML = '<img src="error-icon.png" width="50" class="icon"alt=""/> There was an error generating new image descriptions. <br> <br> You\'ve either used up your current OpenAI plan and need to add more credit, or you\'ve made too many requests too quickly. Please check your plan, add funds if needed, or slow down the requests.' } }
Mazmun skriptimiziň içinde 'başlangyç' (giňeltme ýüklenýär, ýöne hiç zat bolmady), 'ýüklemek', 'üstünlik' ýa-da 'ýalňyşlyk' bolup bilýän 'extensionState' atly täze üýtgeýjini kesgitläris. OpenAI säwlik habarlaryna esaslanýan käbir beýleki ýalňyş ýagdaýlary goşar). Şeýle hem, giňeltme döwlet üýtgeýjisini täzeläris we her gezek döwlet üýtgäninde popup.js-a habar ibereris.
let extensionState = 'initial';
Biziň ýalňyş işleýjimiz:
function handleError(err) { if (JSON.stringify(err).includes('401')) { extensionState = 'errorAuthentication' chrome.runtime.sendMessage({action: extensionState}) } else if (JSON.stringify(err).includes('429')) { extensionState = 'errorMaxQuota' chrome.runtime.sendMessage({action: extensionState}) } else { extensionState = 'errorGeneric' chrome.runtime.sendMessage({action: extensionState}) } console.log(err); }
“ScanPhotos” funksiýamyzyň içinde, funksiýanyň başynda döwleti “ýüklemek”, ýalňyşlyklar bolmasa doly işleýän bolsa “üstünlik” diýip kesgitleýäris.
async function scanPhotos() { extensionState = 'loading' chrome.runtime.sendMessage({action: extensionState}) const images = document.querySelectorAll("img"); for (let image of images) { const imageHasAltTag = image.hasAttribute('alt'); const imageAltTagIsEmptyString = image.hasAttribute('alt') && image.alt === ""; const isAriaHidden = image.ariaHidden ?? false; if (!imageHasAltTag || !imageAltTagIsEmptyString || !isAriaHidden) { const imageDescription = await generateDescription(image.src) if (!imageDescription) { return; } image.alt = imageDescription } } extensionState = 'success' chrome.runtime.sendMessage({action: extensionState}) }
Açylýan bulaşyk hereketi düzetmek - açylan ýerler ýapylanda we açylanda dowamly uzaldyş ýagdaýy
Şu wagt alt bellikleri döredip, üstünlik habaryny alsaňyz we açylan penjäni ýapsaňyz we açsaňyz, ulanyjynyň täze alt belliklerini döretmegine itergi berýän başlangyç habary görkezjekdigini görüp bilersiňiz. Döredilen alt bellikleri häzir kodda bolsa-da!
“Chrome” -da her gezek giňeltme popup açanyňyzda, ol täze açylýar. Giňeldiş bilen ozal edilen ýa-da mazmun skriptinde işleýän zady ýada salmaz. Şeýle-de bolsa, täze açylan açylan penjire jaň edip, giňeltmäniň takyk ýagdaýyny görkezýändigine göz ýetirip bileris. Munuň üçin, bu gezek uzaldyş ýagdaýyny talap edip, başga bir habary açarys we bu habary diňleýän we häzirki ýagdaýyny yzyna iberýän mazmuny.js-a habar diňleýjisini goşarys.
popup.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {action: "getExtensionState"}, function(response) { // if the content script hasn't been injected, then the code in that script hasn't been run, and we'll get an error or no response if (chrome.runtime.lastError || !response) { return; } else if (response) { // if the code in content script HAS been injected, we'll get a response which tells us what state the code is at (loading, success, error, etc) renderUI(response.extensionState) } }); });
mazmun.js
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { if (request.action === "getExtensionState") sendResponse({extensionState}); });
Mazmun skripti hiç haçan işlenmedik bolsa (ulanyjy alt bellikleri döretmek üçin düwmä basmady), giňeldiş ýagdaýy üýtgeýän ýa-da hadysany diňleýji bolmaz. Bu ýagdaýda, hrom jogap hökmünde iş wagtyndaky ýalňyşlygy yzyna getirer. Şeýlelik bilen, säwlik barlygyny goşýarys we birini alsak, adaty UI-ni bolşy ýaly goýuň.
Giňeldiş elýeterliligi - aria-göni, reňk kontrasty we ýapmak düwmesi
Bu giňeltme, ekran okyjylaryny ulanýan adamlar üçin niýetlenendir, şonuň üçin indi onuň ekran okyjysy bilen ulanyljakdygyna göz ýetirmeli! Indi ekran okyjyňyzy açyp, hemmesiniň gowy işleýändigini görmek üçin amatly pursat.
Elýeterlilik üçin arassalamak isleýän birnäçe zadymyz bar. Ilki bilen, ähli tekstleriň ýeterlik derejede kontrast derejesidigine göz ýetirmek isleýäris. Düwme üçin fonuny # 0250C5, şriftini ak goýy diýip bellemegi makul bildim. Munuň ters gatnaşygy 7.1 bolup, AA we AAA derejelerinde WCAG laýyk gelýär. WebAim kontrast barlagçysynda haýsy reňkleri ulanmak isleseňiz, kontrast derejelerini barlap bilersiňiz.
Ikinjiden, ekrany okaýjymy ulananymda, ulanyjy habary ýükleme, üstünlik ýa-da säwlik habary üýtgedilende ekran okyjysynyň täzelenmeleri awtomatiki okamaýandygyny görýärin. Muny düzetmek üçin aria-live atly html atributyny ulanarys. “Aria-live” döredijilere üýtgeşmeleriň ulanyjylaryny täzelemegi ekrana okyjylara habar bermäge mümkinçilik berýär. “Aria-live” -ni ynamly ýa-da mylakatly edip düzüp bilersiňiz - eger tassyklaýjy bolsa, ekranyň okyjy nobatynda okalmagyna garaşýan başga zatlaryň bardygyna garamazdan täzelenmeler derrew okalýar. Sypaýylyk bilen düzülen bolsa, täzelenme ekran okyjysynyň okaýan ähli zadynyň soňunda okalýar. Biziň ýagdaýymyzda, ulanyjyny gysga wagtda täzelemek isleýäris. Şeýlelik bilen, ulanyjy-habar elementimiziň esasy elementi bolan pop-konteýnerde şol atributy goşarys.
<div class="popup-container" aria-live="assertive">
Iň soňunda, ekrany okaýjyny ulanyp, çykýan penjäni ýapmagyň aňsat usulynyň ýokdugyna göz ýetirýärin. Syçan ulananyňyzda, çykýan ýeriň daşyndaky islendik ýere basýarsyňyz we ol ýapylýar, ýöne klawiaturany ulanyp nädip ýapmalydygyny bilip bilemok. Şeýlelik bilen, açylan sahypanyň aşagyna 'ýapmak' düwmesini goşarys, şonuň üçin ulanyjylar ony aňsatlyk bilen ýapyp, web sahypasyna gaýdyp bilerler.
Popup.html-de goşýarys:
<div> <button id="close-button">Close</button> </div>
Popup.js-da, onclick-a ýakyn funksiýany goşýarys:
const closeButton = document.body.querySelector('#close-button'); closeButton.addEventListener('click', async () => { window.close() });
Ine! Soraglaryňyz ýa-da teklipleriňiz bar bolsa, habarlaşyň.