আসুন সত্য কথা বলি, বিড়ালদের সাথে কাজ করা ছাড়া জেনারেটিভ এআইয়ের আর কী ব্যবহার আছে? আপনি যদি Google-এর জেমিনি AI লঞ্চে আমার আগের পোস্টটি পড়েন, তাহলে আপনি হয়তো আমার পরীক্ষার প্রম্পট দেখেছেন যে এটি একটি ছবিতে দেখানো বিড়ালের ধরণ সনাক্ত করতে বলছে।
আমি এপিআই-এর বাস্তব উদাহরণ হিসেবে এটিকে একটি সঠিক ওয়েব অ্যাপ্লিকেশনে পরিণত করার সিদ্ধান্ত নিয়েছি। এখানে আমি কি সঙ্গে এসেছি.
সামনের দিকের জন্য, আমি একটি সাধারণ HTML ফর্ম ক্ষেত্রের মাধ্যমে ব্যবহারকারীর ক্যামেরা অ্যাক্সেস করতে একটি নেটিভ ওয়েব প্ল্যাটফর্ম বৈশিষ্ট্য ব্যবহার করার সিদ্ধান্ত নিয়েছি। একটি input
ট্যাগে capture="camera"
ব্যবহার করে, আপনি সরাসরি ডিভাইসের ক্যামেরায় অ্যাক্সেস পান।
এটি করার আরও উন্নত উপায় আছে, কিন্তু দ্রুত এবং সহজ জন্য, এটি সূক্ষ্ম কাজ করে। আরও ভাল, একটি ডেস্কটপে, এটি কেবল একটি ফাইল নির্বাচক হিসাবে কাজ করে।
আমার চিন্তাভাবনা ছিল - একটি চিত্র পাওয়ার উপায় প্রদান করা (হয় ক্যামেরা বা ফাইল নির্বাচনের মাধ্যমে), চিত্রটি প্রদর্শন করা এবং এটিকে পিছনের প্রান্তে পাঠানো। যদিও অবিশ্বাস্যভাবে সহজ এবং ভ্যানিলা জেএস ভাল হত, আমি এগিয়ে গিয়েছিলাম এবং ইন্টারঅ্যাক্টিভিটির জন্য Alpine.js ব্যবহার করেছি।
প্রথমত, এইচটিএমএলকে ছবির জন্য UI, ছবি প্রদর্শনের জন্য একটি জায়গা এবং ফলাফল প্রদর্শনের জন্য অন্য একটি জায়গা প্রদান করতে হবে।
<!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-এ রেন্ডার করা হয়েছিল তখন লক্ষ্য করা হয়েছিল।
(আমি দৃশ্যমান আকার চেক রাখার জন্য এখানে শেয়ার করা হয়নি এমন একটি বিট CSS ব্যবহার করেছি। কিছুক্ষণের মধ্যে এটি সম্পর্কে আরও।) আমাকে সার্ভার-সাইড কোডে ফাইলটির একটি base64 সংস্করণ পাঠাতে হবে। এখানে প্রাথমিক সংস্করণ:
//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
পদ্ধতিটি বরখাস্ত করা হয়। আমি ব্যবহৃত ফাইল/ইমেজটি নিই, এটিকে ডেটা URL (base64) হিসাবে পড়ি এবং তারপর DOM-এর ছবিতে এটিকে বরাদ্দ করি এবং সার্ভারে পাঠাই। সুন্দর এবং সহজ, তাই না?
ঠিক আছে, ডেস্কটপে সবকিছু ঠিকঠাক কাজ করেছিল, কিন্তু যখন আমি আমার ক্যামেরায় স্যুইচ করি, Samsung S22 Ultra Magnus Extreme 200 Camera Lens Edition (আসল নাম নয়), তখন আমি এমন সমস্যায় পড়েছিলাম যেখানে Google এর API অভিযোগ করেছিল যে আমি খুব বেশি ডেটা পাঠাচ্ছি। আমি তখন মনে রাখলাম যে আমার ক্যামেরাটি সত্যিই বিশদ ছবি তোলে এবং এটি পাঠানোর আগে আমাকে ছবিটির আকার পরিবর্তন করতে হবে।
আমি ইতিমধ্যে সিএসএসে আকার পরিবর্তন করছিলাম, তবে স্পষ্টতই, এটি সত্যিই আকার পরিবর্তনের মতো নয়। আমি ইমেজকিটের সাইটে এই দুর্দান্ত নিবন্ধটি পেয়েছি: জাভাস্ক্রিপ্টে কীভাবে চিত্রগুলি পুনরায় আকার দেওয়া যায়? এই নিবন্ধে, তারা আকার পরিবর্তন করতে একটি 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; } } })) });
আপনি লক্ষ্য করবেন যে কোডটি প্রস্থ এবং উচ্চতা উভয়ের জন্য সর্বাধিক মাত্রা ব্যবহার করে এবং একই অনুপাত বজায় রেখে সঠিকভাবে আকার পরিবর্তন করে। আবার, আমি এর কোনোটির কৃতিত্ব নিতে পারি না, মনু চৌধুরীকে তার ব্লগ পোস্টের জন্য ধন্যবাদ।
এই পরিবর্তনের নেট ফলাফল হল যে এখন আমি ব্যাক এন্ড সার্ভিসে একটি অনেক ছোট ইমেজ পাঠাচ্ছি, এবং অবশেষে এটি একবার দেখার সময় এসেছে।
আমার পিছনের জন্য, আমি আবার ক্লাউডফ্লেয়ার ওয়ার্কারদের ব্যবহার করার সিদ্ধান্ত নিয়েছি। আমি একটু দ্বিধাগ্রস্ত ছিলাম কারণ এর আগে NPM প্যাকেজ এবং আমার ডেমোতে কিছু সমস্যা ছিল, কিন্তু এবারে এতে কোনো সমস্যা হয়নি। আপনি যদি আমার শেষ পোস্ট থেকে মনে রাখেন, 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}}); }, };
বেশিরভাগ কোড AI স্টুডিও এক্সপোর্ট থেকে বয়লারপ্লেট, এখন ছাড়া, আমি কর্মীকে পোস্ট করা তথ্য থেকে আমার ইমেজ ডেটা পাই। আমি বিশেষ করে প্রম্পটটি কল করতে চাই:
Look at this picture and if you see a cat, return the breed of the cat.
প্রাথমিকভাবে, আমি JSON-এ ফলাফল পাওয়ার জন্য কঠোর চেষ্টা করেছি এবং ছবিটি একটি বিড়াল না হলে এটি একটি ফাঁকা স্ট্রিং ফেরত দিয়েছি। কিন্তু তারপরে আমি একটি দুর্দান্ত জিনিস লক্ষ্য করেছি - জেমিনি বিড়ালের নয় এমন ছবিগুলি পরিচালনা করার জন্য সত্যিই ভাল কাজ করেছে। ভালো লেগেছে... আশ্চর্যজনকভাবে ভালো।
আমি আসলে সত্যিই প্রশংসা করেছি যে অ্যাপটি কেবল "বিড়াল নয়" বলবে না, বরং ব্যাখ্যা করেছে যে এটি কী ছিল। স্পষ্টতই, এই ধরনের একটি অ্যাপ্লিকেশনের জন্য উভয় শৈলীর জন্য জায়গা আছে, কিন্তু আমি গিয়েছিলাম এবং Google এর ভারবোস এবং সহায়ক প্রতিক্রিয়াগুলি রেখেছিলাম।
এখন, মজার অংশের জন্য... ফলাফল।
বিড়ালের কয়েকটি ছবি দিয়ে শুরু করা যাক।
প্রথমে শূকর, আমার প্রিয় বিড়াল যে মোটা নয় এবং দেখতে মোটেও জব্বা দ্য হাটের মতো নয়:
এর পরে, লুনার একটি ছবি। এই ক্ষেত্রে, শাবকটি ভুল - তবে অন্তত বন্ধ।
এখন, গুগলকে একটি কার্ভবল নিক্ষেপ করা যাক:
এটা সত্যিই আমাকে অবাক করেছে। বর্ণনাটি 100% নির্ভুল, এবং সত্যি কথা বলতে, আমি যদি এই ছবিটি দেখতাম এবং না জানতাম, তবে আমি এটিকে একটি বিড়ালের ভাস্কর্য হিসাবে চিনতাম, জল দেওয়ার ক্যান হিসাবে নয়। আমি বলতে চাচ্ছি, আমি অনুমান করি এটি এক ধরণের সুস্পষ্ট, তবে আমি সত্যই মনে করি না যে আমি নিজেই এটি লক্ষ্য করেছি।
এখন, আসুন সম্পূর্ণ পাগল হয়ে যাই:
হ্যাঁ, এটা ঠিক গুগল। এআই-জেনারেটেড বিড়ালের ছবি কেমন হবে?
আমি মনে করি এটা খুব ভালোভাবে পরিচালনা করেছে।
পরবর্তী...
হ্যাঁ, বিগফুট ঠিক আছে। শুধু চিন্তা করুন, সেই সমস্ত বিগফুট "গবেষক" অবসর নিতে পারে এবং তাদের ট্রেল ক্যামগুলিকে এআই-তে সংযুক্ত করতে পারে!
আমি বলতে চাই - আমি মুগ্ধ যে Google শুধুমাত্র ফ্র্যাঞ্চাইজিটিকেই স্বীকৃতি দেয়নি কিন্তু প্রকৃত চরিত্রটিকেও চিনতে পেরেছে, কিন্তু ন্যায্যভাবে বলতে গেলে, Skeletor-এর কাছে তার চেহারা বেশ আলাদা।
এবং পরিশেষে, যেহেতু আমি (অন্যায়ভাবে অবশ্যই) আমার বিড়ালকে জব্বার সাথে তুলনা করেছি, আসুন দেখি কিভাবে এটি পরিচালনা করা হয়:
ওহ, আমি জানি আমি বলেছিলাম আমার কাজ শেষ, কিন্তু অবশ্যই, আমাকে একটি কুকুর পরীক্ষা করতে হবে:
ভাল কাজ, মিথুন. দুর্ভাগ্যবশত, আমি এই ডেমো লাইভ হোস্ট করব না (কোডের আগে ক্লাউডফ্লেয়ার 'লাইভ' URL কাজ করবে না), কিন্তু আমি কোডটি শেয়ার করতে পারি।