paint-brush
मैंने बिल्ली की नस्लों का पता लगाने के लिए जेनरेटिव एआई का उपयोग किया: यहां बताया गया है कि यह कैसे हुआद्वारा@raymondcamden
804 रीडिंग
804 रीडिंग

मैंने बिल्ली की नस्लों का पता लगाने के लिए जेनरेटिव एआई का उपयोग किया: यहां बताया गया है कि यह कैसे हुआ

द्वारा Raymond Camden9m2023/12/19
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

फ्रंट एंड के लिए, मैंने एक सरल HTML फॉर्म फ़ील्ड के माध्यम से उपयोगकर्ता के कैमरे तक पहुंचने के लिए एक मूल वेब प्लेटफ़ॉर्म सुविधा का उपयोग करने का निर्णय लिया। इनपुट टैग पर कैप्चर = "कैमरा" का उपयोग करके, आप सीधे डिवाइस कैमरे तक पहुंच प्राप्त करते हैं। ऐसा करने के और भी उन्नत तरीके हैं, लेकिन त्वरित और सरल तरीके से, यह ठीक काम करता है। इससे भी बेहतर, डेस्कटॉप पर, यह बस एक फ़ाइल चयनकर्ता के रूप में कार्य करता है।
featured image - मैंने बिल्ली की नस्लों का पता लगाने के लिए जेनरेटिव एआई का उपयोग किया: यहां बताया गया है कि यह कैसे हुआ
Raymond Camden HackerNoon profile picture

आइए ईमानदार रहें, बिल्लियों के साथ काम करने के अलावा जेनेरिक एआई का और क्या उपयोग है? यदि आपने Google के जेमिनी AI लॉन्च पर मेरी पिछली पोस्ट पढ़ी है, तो आपने मेरे परीक्षण संकेतों को देखा होगा जो चित्र में दिखाई गई बिल्ली की पहचान करने के लिए कह रहा है।


मैंने इसे क्रियान्वित एपीआई के वास्तविक उदाहरण के रूप में एक उचित वेब एप्लिकेशन में बदलने का निर्णय लिया। मैं यही लेकर आया हूं।

फ्रंट एंड

फ्रंट एंड के लिए, मैंने एक सरल HTML फॉर्म फ़ील्ड के माध्यम से उपयोगकर्ता के कैमरे तक पहुंचने के लिए एक मूल वेब प्लेटफ़ॉर्म सुविधा का उपयोग करने का निर्णय लिया। input टैग पर capture="camera" उपयोग करके, आप सीधे डिवाइस कैमरे तक पहुंच प्राप्त करते हैं।


ऐसा करने के और भी उन्नत तरीके हैं, लेकिन त्वरित और सरल तरीके से, यह ठीक काम करता है। इससे भी बेहतर, डेस्कटॉप पर, यह बस एक फ़ाइल चयनकर्ता के रूप में कार्य करता है।


मेरी सोच थी - एक छवि प्राप्त करने का एक तरीका प्रदान करना (या तो कैमरा या फ़ाइल चयन के माध्यम से), छवि प्रदर्शित करें, और इसे बैक एंड पर भेजें। जबकि अविश्वसनीय रूप से सरल और वेनिला जेएस ठीक होता, मैं आगे बढ़ा और अन्तरक्रियाशीलता के लिए अल्पाइन.जेएस का उपयोग किया।


सबसे पहले, HTML को छवि के लिए यूआई, छवि प्रदर्शित करने के लिए एक स्थान और परिणाम प्रदर्शित करने के लिए एक अन्य स्थान प्रदान करने की आवश्यकता है।


 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="app.css"> <title></title> </head> <body> <h2>🐈 Detector</h2> <div x-data="catDetector"> <input type="file" capture="camera" accept="image/*" @change="gotPic" :disabled="working"> <template x-if="imageSrc"> <p> <img :src="imageSrc"> </p> </template> <div x-html="status"></div> </div> <script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script> <script src="app.js"></script> </body> </html>


अब, आइए जावास्क्रिप्ट की ओर मुड़ें। मैं आरंभिक संस्करण साझा करके शुरुआत करने जा रहा हूं क्योंकि यह समझाने की तुलना में अधिक सरल है कि यह कैसे विफल हुआ। प्रारंभ में, मुझे बस इतना करना था कि जब कोई फ़ाइल चुनी जाती थी, या कोई चित्र लिया जाता था, तो उसे नोटिस करता था और उसे DOM को प्रस्तुत करता था।


(मैंने दृश्यमान आकार को नियंत्रण में रखने के लिए यहां साझा नहीं किए गए सीएसएस का थोड़ा उपयोग किया। उस पर थोड़ा और अधिक।) मुझे सर्वर-साइड कोड पर फ़ाइल का बेस 64 संस्करण भेजने की भी आवश्यकता थी। यहाँ प्रारंभिक संस्करण है:


 //const IMG_FUNC = 'http://localhost:8787/'; const IMG_FUNC = 'https://catdetector.raymondcamden.workers.dev'; document.addEventListener('alpine:init', () => { Alpine.data('catDetector', () => ({ imageSrc:null, working:false, status:'', async init() { console.log('init'); }, async gotPic(e) { let file = e.target.files[0]; if(!file) return; let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = async e => { this.imageSrc = e.target.result; this.working = true; this.status = '<i>Sending image data to Google Gemini...</i>'; let body = { imgdata:this.imageSrc } let resp = await fetch(IMG_FUNC, { method:'POST', body: JSON.stringify(body) }); let result = await resp.json(); this.working = false; this.status = result.text; } } })) });


जब भी input फ़ील्ड onchange ईवेंट सक्रिय करता है तो gotPic विधि सक्रिय हो जाती है। मैं उपयोग की गई फ़ाइल/छवि लेता हूं, इसे डेटा यूआरएल (बेस 64) के रूप में पढ़ता हूं, और फिर इसे डीओएम में छवि को असाइन करता हूं और सर्वर पर भेजता हूं। अच्छा और सरल, है ना?


खैर, डेस्कटॉप पर सब कुछ ठीक काम कर रहा था, लेकिन जब मैंने अपने कैमरे, सैमसंग एस22 अल्ट्रा मैग्नस एक्सट्रीम 200 कैमरा लेंस संस्करण (असली नाम नहीं) पर स्विच किया, तो मुझे समस्याओं का सामना करना पड़ा जहां Google के एपीआई ने शिकायत की कि मैं बहुत अधिक डेटा भेज रहा था। फिर मुझे याद आया कि मेरा कैमरा वास्तव में विस्तृत तस्वीरें लेता है, और मुझे इसे भेजने से पहले छवि का आकार बदलना होगा।


मैं पहले से ही सीएसएस में आकार बदल रहा था, लेकिन जाहिर है, यह वास्तव में आकार बदलने जैसा नहीं है। मुझे ImageKit की साइट पर यह उत्कृष्ट लेख मिला: जावास्क्रिप्ट में छवियों का आकार कैसे बदलें? इस आलेख में, वे आकार बदलने के लिए HTML canvas तत्व का उपयोग करने का वर्णन करते हैं।


मैंने लगभग एक दशक से कैनवस का उपयोग नहीं किया था, लेकिन मैं उनके कोड को अपने फ्रंट एंड में अच्छी तरह से पुन: उपयोग करने में सक्षम था:


 //const IMG_FUNC = 'http://localhost:8787/'; const IMG_FUNC = 'https://catdetector.raymondcamden.workers.dev'; // Resize logic: https://imagekit.io/blog/how-to-resize-image-in-javascript/ const MAX_WIDTH = 400; const MAX_HEIGHT = 400; document.addEventListener('alpine:init', () => { Alpine.data('catDetector', () => ({ imageSrc:null, working:false, status:'', async init() { console.log('init'); }, async gotPic(e) { let file = e.target.files[0]; if(!file) return; let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = async e => { let img = document.createElement('img'); img.onload = async e => { let width = img.width; let height = img.height; if(width > height) { if(width > MAX_WIDTH) { height = height * (MAX_WIDTH / width); width = MAX_WIDTH; } } else { if (height > MAX_HEIGHT) { width = width * (MAX_HEIGHT / height); height = MAX_HEIGHT; } } let canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; let ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, width, height); this.imageSrc = canvas.toDataURL(file.type); this.working = true; this.status = '<i>Sending image data to Google Gemini...</i>'; let body = { imgdata:this.imageSrc } let resp = await fetch(IMG_FUNC, { method:'POST', body: JSON.stringify(body) }); let result = await resp.json(); this.working = false; this.status = result.text; }; img.src = e.target.result; } } })) });


आप देखेंगे कि कोड चौड़ाई और ऊंचाई दोनों के लिए अधिकतम आयाम का उपयोग करता है और समान पहलू अनुपात को बनाए रखते हुए सही ढंग से आकार बदलता है। फिर, मैं इसका श्रेय नहीं ले सकता, मनु चौधरी को उनके ब्लॉग पोस्ट के लिए धन्यवाद।


इस परिवर्तन का कुल परिणाम यह है कि अब मैं बैक एंड सेवा पर एक बहुत छोटी छवि भेज रहा हूं, और अंततः उस पर एक नज़र डालने का समय आ गया है।

पिछला अंत

अपने बैकएंड के लिए, मैंने क्लाउडफ़ेयर वर्कर्स का फिर से उपयोग करने का निर्णय लिया। मैं थोड़ा झिझक रहा था क्योंकि इसमें पहले एनपीएम पैकेज और मेरे डेमो के साथ कुछ समस्याएं थीं, लेकिन इस बार इसमें कोई समस्या नहीं थी। यदि आपको मेरी पिछली पोस्ट याद है, तो Google का AI स्टूडियो आपको आपके संकेतों से आसानी से नमूना कोड आउटपुट करने देता है, इसलिए मुझे बस उसे क्लाउडफ़ेयर वर्कर में शामिल करना था।


यहां संपूर्ण कोड है:


 const { GoogleGenerativeAI, HarmCategory, HarmBlockThreshold, } = require("@google/generative-ai"); const MODEL_NAME = "gemini-pro-vision"; export default { async fetch(request, env, ctx) { const API_KEY = env.GEMINI_KEY; console.log('begin serverless logic'); const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS", "Access-Control-Max-Age": "86400", }; let { imgdata } = await request.json(); imgdata = imgdata.replace(/data:.*?;base64,/, ''); const genAI = new GoogleGenerativeAI(API_KEY); const model = genAI.getGenerativeModel({ model: MODEL_NAME }); const generationConfig = { temperature: 0.4, topK: 32, topP: 1, maxOutputTokens: 4096, }; const safetySettings = [ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, ]; const parts = [ {text: "Look at this picture and if you see a cat, return the breed of the cat."}, { inlineData: { mimeType: "image/jpeg", data: imgdata } } ]; console.log('calling google'); const result = await model.generateContent({ contents: [{ role: "user", parts }], generationConfig, safetySettings, }); const response = result.response; let finalResult = { text: response.text() }; return new Response(JSON.stringify(finalResult), { headers: {...corsHeaders}}); }, };


अधिकांश कोड एआई स्टूडियो निर्यात से बॉयलरप्लेट है, अब को छोड़कर, मुझे अपना छवि डेटा कार्यकर्ता को पोस्ट की गई जानकारी से मिलता है। मैं विशेष रूप से संकेत देना चाहता हूँ:


 Look at this picture and if you see a cat, return the breed of the cat.


प्रारंभ में, मैंने JSON में परिणाम प्राप्त करने के लिए कड़ी मेहनत की और यदि चित्र बिल्ली नहीं था तो उसे एक रिक्त स्ट्रिंग लौटा दी। लेकिन फिर मैंने कुछ अच्छा देखा - जेमिनी ने उन तस्वीरों को संभालने में वास्तव में अच्छा काम किया जो बिल्लियों की नहीं थीं। जैसे... आश्चर्यजनक रूप से अच्छा।


मैं वास्तव में इस बात की सराहना करता हूं कि ऐप सिर्फ "नॉट ए कैट" नहीं कहेगा, बल्कि इसके बजाय समझाया कि यह क्या था। जाहिर है, इस तरह के एप्लिकेशन के लिए दोनों शैलियों के लिए जगह है, लेकिन मैंने जाकर Google की शब्दावली और उपयोगी प्रतिक्रियाएं रखीं।


अब, मज़ेदार भाग के लिए...परिणाम।

परिणाम

आइए बिल्लियों की कुछ तस्वीरों से शुरुआत करें।


सबसे पहले सुअर है, मेरी पसंदीदा बिल्ली जो मोटी नहीं है और जेबा द हट की तरह बिल्कुल भी नहीं दिखती है:

केलिको बिल्ली की तस्वीर सही ढंग से पहचानी गई


आगे, लूना की एक तस्वीर। इस मामले में, नस्ल गलत है - लेकिन कम से कम करीब।


एक माने जाने वाले मेन कून की एक तस्वीर


अब, आइए Google को कर्वबॉल फेंकें:


पानी देने की एक तस्वीर सही ढंग से पहचानी जा सकती है।


इससे मुझे सचमुच आश्चर्य हुआ। विवरण 100% सटीक है, और ईमानदारी से कहूं तो, अगर मैंने यह तस्वीर देखी होती और नहीं जानता होता, तो मैं इसे एक बिल्ली की मूर्ति के रूप में पहचानता, न कि पानी भरने के डिब्बे के रूप में। मेरा मतलब है, मुझे लगता है कि यह एक तरह से स्पष्ट है, लेकिन ईमानदारी से कहूं तो मुझे नहीं लगता कि मैंने खुद इस पर ध्यान दिया होगा।


अब, चलो पूरी तरह से पागल हो जाएं:


क्रिसमस ट्री का चित्र सही ढंग से पहचाना गया।

हाँ, यह सही है गूगल। एआई-जनित बिल्ली छवियों के बारे में क्या ख्याल है?


डीजे के रूप में एक बिल्ली की तस्वीर।


मुझे लगता है कि इसने इसे बहुत अच्छी तरह से संभाला।


अगला...

बिगफुट एक्शन फिगर की एक तस्वीर


हाँ, वह बिगफुट ठीक है। ज़रा सोचिए, वे सभी बिगफुट "शोधकर्ता" सेवानिवृत्त हो सकते हैं और बस अपने ट्रेल कैम को एआई से जोड़ सकते हैं!


स्केलेटर एक्शन फिगर का एक चित्र

मुझे कहना होगा - मैं प्रभावित हूं कि Google ने न केवल फ्रैंचाइज़ी को बल्कि वास्तविक चरित्र को भी मान्यता दी है, लेकिन ईमानदारी से कहें तो स्केलेटर का लुक काफी अलग है।


और अंत में, चूँकि मैंने (निश्चित रूप से अनुचित रूप से) अपनी बिल्ली की तुलना जाब्बा से की है, आइए देखें कि इसे कैसे संभाला जाता है:


Jabba हट


ओह, मुझे पता है मैंने कहा था कि मेरा काम हो गया, लेकिन निश्चित रूप से, मुझे एक कुत्ते का परीक्षण करना था:


एक सोफ़े पर कुत्ता


बहुत अच्छा काम, मिथुन। दुर्भाग्य से, मैं इस डेमो को लाइव होस्ट नहीं करूंगा (कोड में पहले वाला क्लाउडफ़ेयर 'लाइव' यूआरएल काम नहीं करेगा), लेकिन मैं कोड साझा कर सकता हूं।