প্রতিদিনের ছবি: ল্যাব 1—ছবি সংরক্ষণ করুন এবং বিশ্লেষণ করুন (জাভা)

1. ওভারভিউ

প্রথম কোড ল্যাবে, আপনি একটি বালতিতে ছবি আপলোড করবেন। এটি একটি ফাইল তৈরির ইভেন্ট তৈরি করবে যা একটি ফাংশন দ্বারা পরিচালিত হবে। ফাংশনটি ছবি বিশ্লেষণ করতে এবং ডেটাস্টোরে ফলাফল সংরক্ষণ করতে Vision API-তে একটি কল করবে।

d650ca5386ea71ad.png

আপনি কি শিখবেন

  • ক্লাউড স্টোরেজ
  • ক্লাউড ফাংশন
  • ক্লাউড ভিশন API
  • ক্লাউড ফায়ারস্টোর

2. সেটআপ এবং প্রয়োজনীয়তা

স্ব-গতিসম্পন্ন পরিবেশ সেটআপ

  1. Google ক্লাউড কনসোলে সাইন-ইন করুন এবং একটি নতুন প্রকল্প তৈরি করুন বা বিদ্যমান একটি পুনরায় ব্যবহার করুন৷ আপনার যদি ইতিমধ্যেই একটি Gmail বা Google Workspace অ্যাকাউন্ট না থাকে, তাহলে আপনাকে অবশ্যই একটি তৈরি করতে হবে।

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • প্রকল্পের নাম এই প্রকল্পের অংশগ্রহণকারীদের জন্য প্রদর্শনের নাম। এটি একটি অক্ষর স্ট্রিং যা Google API দ্বারা ব্যবহৃত হয় না। আপনি যে কোনো সময় এটি আপডেট করতে পারেন.
  • সমস্ত Google ক্লাউড প্রজেক্ট জুড়ে প্রোজেক্ট আইডি অবশ্যই অনন্য হতে হবে এবং অপরিবর্তনীয় (সেট করার পরে পরিবর্তন করা যাবে না)। ক্লাউড কনসোল স্বয়ংক্রিয়ভাবে একটি অনন্য স্ট্রিং তৈরি করে; সাধারণত আপনি এটা কি যত্ন না. বেশিরভাগ কোডল্যাবে, আপনাকে প্রজেক্ট আইডি উল্লেখ করতে হবে (এটি সাধারণত PROJECT_ID হিসাবে চিহ্নিত করা হয়)। আপনি যদি জেনারেট করা আইডি পছন্দ না করেন, তাহলে আপনি অন্য এলোমেলো আইডি তৈরি করতে পারেন। বিকল্পভাবে, আপনি নিজের চেষ্টা করে দেখতে পারেন এবং এটি উপলব্ধ কিনা। এই ধাপের পরে এটি পরিবর্তন করা যাবে না এবং প্রকল্পের সময়কালের জন্য থাকবে।
  • আপনার তথ্যের জন্য, একটি তৃতীয় মান রয়েছে, একটি প্রকল্প নম্বর যা কিছু API ব্যবহার করে। ডকুমেন্টেশনে এই তিনটি মান সম্পর্কে আরও জানুন।
  1. এরপরে, ক্লাউড রিসোর্স/এপিআই ব্যবহার করতে আপনাকে ক্লাউড কনসোলে বিলিং সক্ষম করতে হবে। এই কোডল্যাবের মাধ্যমে চালানোর জন্য খুব বেশি খরচ করা উচিত নয়, যদি কিছু থাকে। রিসোর্স বন্ধ করতে যাতে এই টিউটোরিয়ালের বাইরে আপনার বিলিং খরচ না হয়, আপনি আপনার তৈরি করা রিসোর্স মুছে ফেলতে পারেন বা পুরো প্রোজেক্ট মুছে ফেলতে পারেন। Google ক্লাউডের নতুন ব্যবহারকারীরা $300 USD বিনামূল্যের ট্রায়াল প্রোগ্রামের জন্য যোগ্য৷

ক্লাউড শেল শুরু করুন

যদিও Google ক্লাউড আপনার ল্যাপটপ থেকে দূরবর্তীভাবে পরিচালিত হতে পারে, এই কোডল্যাবে আপনি Google ক্লাউড শেল ব্যবহার করবেন, একটি কমান্ড লাইন পরিবেশ যা ক্লাউডে চলছে।

Google ক্লাউড কনসোল থেকে, উপরের ডানদিকে টুলবারে ক্লাউড শেল আইকনে ক্লিক করুন:

55efc1aaa7a4d3ad.png

পরিবেশের ব্যবস্থা করতে এবং সংযোগ করতে এটি শুধুমাত্র কয়েক মুহূর্ত নিতে হবে। এটি সমাপ্ত হলে, আপনি এই মত কিছু দেখতে হবে:

7ffe5cbb04455448.png

এই ভার্চুয়াল মেশিনটি আপনার প্রয়োজনীয় সমস্ত ডেভেলপমেন্ট টুল দিয়ে লোড করা হয়েছে। এটি একটি ক্রমাগত 5GB হোম ডিরেক্টরি অফার করে এবং Google ক্লাউডে চলে, যা নেটওয়ার্ক কর্মক্ষমতা এবং প্রমাণীকরণকে ব্যাপকভাবে উন্নত করে। এই কোডল্যাবে আপনার সমস্ত কাজ একটি ব্রাউজারে করা যেতে পারে। আপনার কিছু ইন্সটল করার দরকার নেই।

3. API সক্রিয় করুন৷

এই ল্যাবের জন্য, আপনি ক্লাউড ফাংশন এবং ভিশন API ব্যবহার করবেন তবে প্রথমে সেগুলিকে ক্লাউড কনসোলে বা gcloud এর সাথে সক্ষম করতে হবে।

ক্লাউড কনসোলে ভিশন API সক্ষম করতে, অনুসন্ধান বারে Cloud Vision API অনুসন্ধান করুন:

cf48b1747ba6a6fb.png

আপনি ক্লাউড ভিশন API পৃষ্ঠায় অবতরণ করবেন:

ba4af419e6086fbb.png

ENABLE বাটনে ক্লিক করুন।

বিকল্পভাবে, আপনি জিক্লাউড কমান্ড লাইন টুল ব্যবহার করে এটি ক্লাউড শেল সক্রিয় করতে পারেন।

ক্লাউড শেলের ভিতরে, নিম্নলিখিত কমান্ডটি চালান:

gcloud services enable vision.googleapis.com

আপনি সফলভাবে শেষ করতে অপারেশন দেখতে হবে:

Operation "operations/acf.12dba18b-106f-4fd2-942d-fea80ecc5c1c" finished successfully.

ক্লাউড ফাংশনগুলিও সক্ষম করুন:

gcloud services enable cloudfunctions.googleapis.com

4. বালতি তৈরি করুন (কনসোল)

ছবির জন্য একটি স্টোরেজ বালতি তৈরি করুন। আপনি Google ক্লাউড প্ল্যাটফর্ম কনসোল ( console.cloud.google.com ) থেকে বা ক্লাউড শেল বা আপনার স্থানীয় উন্নয়ন পরিবেশ থেকে gsutil কমান্ড লাইন টুল দিয়ে এটি করতে পারেন।

"হ্যামবার্গার" (☰) মেনু থেকে, Storage পৃষ্ঠায় নেভিগেট করুন।

1930e055d138150a.png

আপনার বালতি নাম

CREATE BUCKET বাটনে ক্লিক করুন।

34147939358517f8.png

CONTINUE ক্লিক করুন।

অবস্থান নির্বাচন করুন

197817f20be07678.png

আপনার পছন্দের অঞ্চলে একটি বহু-আঞ্চলিক বালতি তৈরি করুন (এখানে Europe )।

CONTINUE ক্লিক করুন।

ডিফল্ট স্টোরেজ ক্লাস বেছে নিন

53cd91441c8caf0e.png

আপনার ডেটার জন্য Standard স্টোরেজ ক্লাস বেছে নিন।

CONTINUE ক্লিক করুন।

অ্যাক্সেস কন্ট্রোল সেট করুন

8c2b3b459d934a51.png

যেহেতু আপনি সর্বজনীনভাবে অ্যাক্সেসযোগ্য চিত্রগুলির সাথে কাজ করবেন, আপনি চান এই বালতিতে সংরক্ষিত আমাদের সমস্ত ছবি একই অভিন্ন অ্যাক্সেস নিয়ন্ত্রণ থাকুক৷

Uniform অ্যাক্সেস কন্ট্রোল বিকল্পটি নির্বাচন করুন।

CONTINUE ক্লিক করুন।

সুরক্ষা/এনক্রিপশন সেট করুন

d931c24c3e705a68.png

ডিফল্ট রাখুন ( Google-managed key) , কারণ আপনি নিজের এনক্রিপশন কী ব্যবহার করবেন না।

শেষ পর্যন্ত আমাদের বালতি তৈরির চূড়ান্ত রূপ দিতে CREATE ক্লিক করুন।

স্টোরেজ ভিউয়ার হিসাবে সমস্ত ব্যবহারকারীদের যোগ করুন

Permissions ট্যাবে যান:

d0ecfdcff730ea51.png

Storage > Storage Object Viewer এর ভূমিকা সহ বালতিতে একজন allUsers সদস্য যোগ করুন, নিম্নরূপ:

e9f25ec1ea0b6cc6.png

SAVE ক্লিক করুন।

5. বালতি তৈরি করুন (gsutil)

আপনি বালতি তৈরি করতে ক্লাউড শেল-এ gsutil কমান্ড লাইন টুল ব্যবহার করতে পারেন।

ক্লাউড শেলে, অনন্য বালতি নামের জন্য একটি পরিবর্তনশীল সেট করুন। ক্লাউড শেল ইতিমধ্যেই আপনার অনন্য প্রকল্প আইডিতে GOOGLE_CLOUD_PROJECT সেট করেছে৷ আপনি বালতি নামের সাথে যে যোগ করতে পারেন.

যেমন:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}

ইউরোপে একটি মানক মাল্টি-রিজিওন জোন তৈরি করুন:

gsutil mb -l EU gs://${BUCKET_PICTURES}

ইউনিফর্ম বালতি স্তর অ্যাক্সেস নিশ্চিত করুন:

gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}

বালতিটি সর্বজনীন করুন:

gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}

আপনি যদি কনসোলের Cloud Storage বিভাগে যান, আপনার কাছে একটি সর্বজনীন uploaded-pictures থাকা উচিত:

a98ed4ba17873e40.png

পরীক্ষা করুন যে আপনি বালতিতে ছবি আপলোড করতে পারেন এবং আপলোড করা ছবিগুলি সর্বজনীনভাবে উপলব্ধ, যেমনটি পূর্ববর্তী ধাপে ব্যাখ্যা করা হয়েছে।

6. বালতিতে পাবলিক অ্যাক্সেস পরীক্ষা করুন

স্টোরেজ ব্রাউজারে ফিরে গেলে, আপনি "পাবলিক" অ্যাক্সেস সহ তালিকায় আপনার বালতি দেখতে পাবেন (একটি সতর্কতা চিহ্ন সহ আপনাকে মনে করিয়ে দেয় যে সেই বালতির সামগ্রীতে যে কারও অ্যাক্সেস রয়েছে)।

89e7a4d2c80a0319.png

আপনার বালতি এখন ছবি গ্রহণ করার জন্য প্রস্তুত.

আপনি যদি বালতির নামের উপর ক্লিক করেন, আপনি বালতির বিবরণ দেখতে পাবেন।

131387f12d3eb2d3.png

সেখানে, আপনি বালতিতে একটি ছবি যোগ করতে পারেন তা পরীক্ষা করতে আপনি Upload files বোতামটি চেষ্টা করতে পারেন। একটি ফাইল চয়নকারী পপআপ আপনাকে একটি ফাইল নির্বাচন করতে বলবে। একবার নির্বাচিত হলে, এটি আপনার বালতিতে আপলোড করা হবে, এবং আপনি আবার দেখতে পাবেন public অ্যাক্সেস যা এই নতুন ফাইলটিতে স্বয়ংক্রিয়ভাবে দায়ী করা হয়েছে।

e87584471a6e9c6d.png

Public অ্যাক্সেস লেবেল বরাবর, আপনি একটি ছোট লিঙ্ক আইকনও দেখতে পাবেন। এটিতে ক্লিক করার সময়, আপনার ব্রাউজার সেই চিত্রটির সর্বজনীন URL-এ নেভিগেট করবে, যা ফর্মের হবে:

https://storage.googleapis.com/BUCKET_NAME/PICTURE_FILE.png

BUCKET_NAME হল বিশ্বব্যাপী অনন্য নাম যা আপনি আপনার বাকেটের জন্য বেছে নিয়েছেন এবং তারপরে আপনার ছবির ফাইলের নাম৷

ছবির নামের পাশে চেক বক্সে ক্লিক করে, DELETE বোতামটি সক্রিয় হবে এবং আপনি এই প্রথম ছবিটি মুছতে পারবেন।

7. ফাংশন তৈরি করুন

এই ধাপে, আপনি একটি ফাংশন তৈরি করুন যা ছবি আপলোড ইভেন্টগুলিতে প্রতিক্রিয়া জানায়।

Google ক্লাউড কনসোলের Cloud Functions বিভাগে যান। এটি পরিদর্শন করে, ক্লাউড ফাংশন পরিষেবা স্বয়ংক্রিয়ভাবে সক্ষম হবে৷

9d29e8c026a7a53f.png

Create function এ ক্লিক করুন।

একটি নাম (যেমন picture-uploaded ) এবং অঞ্চল (বালতির জন্য অঞ্চল পছন্দের সাথে সামঞ্জস্যপূর্ণ মনে রাখবেন):

4bb222633e6f278.png

দুটি ধরনের ফাংশন আছে:

  • HTTP ফাংশন যা একটি URL এর মাধ্যমে আহ্বান করা যেতে পারে (যেমন একটি ওয়েব API),
  • ব্যাকগ্রাউন্ড ফাংশন যা কিছু ইভেন্ট দ্বারা ট্রিগার হতে পারে।

আপনি একটি পটভূমি ফাংশন তৈরি করতে চান যা আমাদের Cloud Storage বালতিতে একটি নতুন ফাইল আপলোড করার সময় ট্রিগার হয়:

d9a12fcf58f4813c.png

আপনি ইভেন্টের প্রকার Finalize/Create আগ্রহী, যেটি ইভেন্ট যা ট্রিগার হয় যখন একটি ফাইল তৈরি বা বালতিতে আপডেট করা হয়:

b30c8859b07dc4cb.png

এই নির্দিষ্ট বালতিতে একটি ফাইল তৈরি/আপডেট করার সময় ক্লাউড ফাংশনগুলিকে জানানোর জন্য আগে তৈরি করা বালতি নির্বাচন করুন:

cb15a1f4c7a1ca5f.png

আপনি আগে তৈরি করা বালতি চয়ন করতে Select ক্লিক করুন এবং তারপর Save

c1933777fac32c6a.png

আপনি পরবর্তী ক্লিক করার আগে, আপনি রানটাইম, বিল্ড, সংযোগ এবং নিরাপত্তা সেটিংসের অধীনে ডিফল্ট (256 MB মেমরি) প্রসারিত এবং সংশোধন করতে পারেন এবং এটি 1GB-তে আপডেট করতে পারেন।

83d757e6c38e10.png

Next ক্লিক করার পর, আপনি রানটাইম , সোর্স কোড এবং এন্ট্রি পয়েন্ট টিউন করতে পারেন।

এই ফাংশনের জন্য Inline editor রাখুন:

b6646ec646082b32.png

জাভা রানটাইমগুলির একটি নির্বাচন করুন, উদাহরণস্বরূপ জাভা 11:

f85b8a6f951f47a7.png

সোর্স কোডে একটি Java ফাইল এবং একটি pom.xml Maven ফাইল রয়েছে যা বিভিন্ন মেটাডেটা এবং নির্ভরতা প্রদান করে।

কোডের ডিফল্ট স্নিপেট ছেড়ে দিন: এটি আপলোড করা ছবির ফাইলের নাম লগ করে:

9b7b9801b42f6ca6.png

আপাতত, পরীক্ষার উদ্দেশ্যে Example এ এক্সিকিউট করার জন্য ফাংশনের নাম রাখুন।

ফাংশন তৈরি এবং স্থাপন করতে Deploy এ ক্লিক করুন। একবার স্থাপনা সফল হলে, আপনি ফাংশনের তালিকায় একটি সবুজ-বৃত্তাকার চেক চিহ্ন দেখতে পাবেন:

3732fdf409eefd1a.png

8. ফাংশন পরীক্ষা করুন

এই ধাপে, পরীক্ষা করুন যে ফাংশন স্টোরেজ ইভেন্টগুলিতে সাড়া দেয়।

"হ্যামবার্গার" (☰) মেনু থেকে, Storage পৃষ্ঠায় ফিরে যান।

ছবি আপলোড করতে ইমেজ বাকেট, এবং তারপর Upload files ক্লিক করুন।

21767ec3cb8b18de.png

Logging > Logs Explorer পৃষ্ঠায় যেতে ক্লাউড কনসোলের মধ্যে আবার নেভিগেট করুন।

Log Fields সিলেক্টরে, আপনার ফাংশনের জন্য উৎসর্গীকৃত লগগুলি দেখতে Cloud Function নির্বাচন করুন। লগ ফিল্ডগুলির মাধ্যমে নীচে স্ক্রোল করুন এবং আপনি ফাংশন সম্পর্কিত লগগুলির একটি সূক্ষ্ম-দানাযুক্ত দৃশ্য পেতে একটি নির্দিষ্ট ফাংশন নির্বাচন করতে পারেন। picture-uploaded ফাংশন নির্বাচন করুন.

আপনার লগ আইটেমগুলি দেখতে হবে যাতে ফাংশন তৈরি করা, ফাংশনের শুরু এবং শেষের সময় এবং আমাদের প্রকৃত লগ স্টেটমেন্ট উল্লেখ করা উচিত:

e8ba7d39c36df36c.png

আমাদের লগ স্টেটমেন্টটি পড়ে: Processing file: pic-a-daily-architecture-events.png , যার অর্থ এই ছবিটি তৈরি এবং স্টোরেজ সম্পর্কিত ইভেন্টটি প্রকৃতপক্ষে প্রত্যাশিত হিসাবে ট্রিগার হয়েছে৷

9. ডাটাবেস প্রস্তুত করুন

আপনি ক্লাউড ফায়ারস্টোর ডাটাবেস, একটি দ্রুত, সম্পূর্ণরূপে পরিচালিত, সার্ভারহীন, ক্লাউড-নেটিভ NoSQL ডকুমেন্ট ডাটাবেসে ভিশন API দ্বারা প্রদত্ত ছবি সম্পর্কে তথ্য সংরক্ষণ করবেন। ক্লাউড কনসোলের Firestore বিভাগে গিয়ে আপনার ডাটাবেস প্রস্তুত করুন:

9e4708d2257de058.png

দুটি বিকল্প দেওয়া হয়: Native mode বা Datastore mode । নেটিভ মোড ব্যবহার করুন, যা অফলাইন সমর্থন এবং রিয়েল-টাইম সিঙ্ক্রোনাইজেশনের মতো অতিরিক্ত বৈশিষ্ট্যগুলি অফার করে৷

SELECT NATIVE MODE ক্লিক করুন।

9449ace8cc84de43.png

একটি বহু-অঞ্চল বেছে নিন (এখানে ইউরোপে, তবে আদর্শভাবে অন্তত একই অঞ্চলে আপনার ফাংশন এবং স্টোরেজ বালতি)।

CREATE DATABASE বোতামে ক্লিক করুন।

একবার ডাটাবেস তৈরি হয়ে গেলে, আপনাকে নিম্নলিখিতগুলি দেখতে হবে:

56265949a124819e.png

+ START COLLECTION বোতামে ক্লিক করে একটি নতুন সংগ্রহ তৈরি করুন৷

নাম সংগ্রহের pictures

75806ee24c4e13a7.png

আপনি একটি নথি তৈরি করতে হবে না. নতুন ছবিগুলি ক্লাউড স্টোরেজে সংরক্ষণ করা এবং Vision API দ্বারা বিশ্লেষণ করা হলে আপনি সেগুলিকে প্রোগ্রাম্যাটিকভাবে যুক্ত করবেন৷

Save ক্লিক করুন।

Firestore নতুন তৈরি সংগ্রহে একটি প্রথম ডিফল্ট নথি তৈরি করে, আপনি নিরাপদে সেই দস্তাবেজটি মুছে ফেলতে পারেন কারণ এতে কোনও দরকারী তথ্য নেই:

5c2f1e17ea47f48f.png

আমাদের সংগ্রহে প্রোগ্রাম্যাটিকভাবে তৈরি করা নথিগুলিতে 4টি ক্ষেত্র থাকবে:

  • নাম (স্ট্রিং): আপলোড করা ছবির ফাইলের নাম, যা তিনি নথির কীও
  • লেবেল (স্ট্রিংগুলির অ্যারে): ভিশন API দ্বারা স্বীকৃত আইটেমগুলির লেবেল৷
  • রঙ (স্ট্রিং): প্রভাবশালী রঙের হেক্সাডেসিমেল রঙের কোড (যেমন #ab12ef)
  • তৈরি করা হয়েছে (তারিখ): এই ছবির মেটাডেটা কখন সংরক্ষণ করা হয়েছিল তার টাইমস্ট্যাম্প
  • থাম্বনেইল (বুলিয়ান): একটি ঐচ্ছিক ক্ষেত্র যা উপস্থিত থাকবে এবং এই ছবির জন্য একটি থাম্বনেইল চিত্র তৈরি করা হলে তা সত্য হবে

থাম্বনেইল উপলব্ধ ছবিগুলি খুঁজে পেতে এবং তৈরির তারিখ বরাবর সাজানোর জন্য আমরা Firestore-এ অনুসন্ধান করব, আমাদের একটি অনুসন্ধান সূচক তৈরি করতে হবে।

আপনি ক্লাউড শেলে নিম্নলিখিত কমান্ড দিয়ে সূচক তৈরি করতে পারেন:

gcloud firestore indexes composite create \
  --collection-group=pictures \
  --field-config field-path=thumbnail,order=descending \
  --field-config field-path=created,order=descending

অথবা আপনি ক্লাউড কনসোল থেকেও এটি করতে পারেন, বাম দিকের নেভিগেশন কলামে Indexes এ ক্লিক করে, এবং তারপরে নীচে দেখানো হিসাবে একটি যৌগিক সূচক তৈরি করুন:

ecb8b95e3c791272.png

Create ক্লিক করুন। সূচক তৈরিতে কয়েক মিনিট সময় লাগতে পারে।

10. ফাংশন আপডেট করুন

Functions পৃষ্ঠায় ফিরে যান, আমাদের ছবিগুলি বিশ্লেষণ করতে Vision API-কে আহ্বান করতে এবং Firestore-এ মেটাডেটা সংরক্ষণ করতে ফাংশন আপডেট করতে।

"হ্যামবার্গার" (☰) মেনু থেকে, Cloud Functions বিভাগে নেভিগেট করুন, ফাংশনের নামের উপর ক্লিক করুন, Source ট্যাবটি নির্বাচন করুন এবং তারপরে EDIT বোতামে ক্লিক করুন৷

প্রথমে, pom.xml ফাইলটি সম্পাদনা করুন যা আমাদের জাভা ফাংশনের নির্ভরতা তালিকাভুক্ত করে। ক্লাউড ভিশন API Maven নির্ভরতা যোগ করতে কোড আপডেট করুন:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cloudfunctions</groupId>
  <artifactId>gcs-function</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>libraries-bom</artifactId>
        <version>26.1.1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.google.cloud.functions</groupId>
      <artifactId>functions-framework-api</artifactId>
      <version>1.0.4</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-firestore</artifactId>
    </dependency>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-vision</artifactId>
    </dependency>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-storage</artifactId>
    </dependency>
  </dependencies>

  <!-- Required for Java 11 functions in the inline editor -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <excludes>
            <exclude>.google/</exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

এখন যেহেতু নির্ভরতাগুলি আপ-টু-ডেট, আপনি আমাদের কাস্টম কোডের সাথে Example.java ফাইলটি আপডেট করে আমাদের ফাংশনের কোডে কাজ করতে যাচ্ছেন।

Example.java ফাইলের উপর মাউস সরান এবং পেন্সিল ক্লিক করুন। প্যাকেজের নাম এবং ফাইলের নাম src/main/java/fn/ImageAnalysis.java এ প্রতিস্থাপন করুন।

ImageAnalysis.java এর কোডটি নিচের কোড দিয়ে প্রতিস্থাপন করুন। এটি পরবর্তী ধাপে ব্যাখ্যা করা হবে।

package fn;

import com.google.cloud.functions.*;
import com.google.cloud.vision.v1.*;
import com.google.cloud.vision.v1.Feature.Type;
import com.google.cloud.firestore.*;
import com.google.api.core.ApiFuture;

import java.io.*;
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
import java.util.logging.Logger;

import fn.ImageAnalysis.GCSEvent;

public class ImageAnalysis implements BackgroundFunction<GCSEvent> {
    private static final Logger logger = Logger.getLogger(ImageAnalysis.class.getName());

    @Override
    public void accept(GCSEvent event, Context context) 
            throws IOException, InterruptedException, ExecutionException {
        String fileName = event.name;
        String bucketName = event.bucket;

        logger.info("New picture uploaded " + fileName);

        try (ImageAnnotatorClient vision = ImageAnnotatorClient.create()) {
            List<AnnotateImageRequest> requests = new ArrayList<>();
            
            ImageSource imageSource = ImageSource.newBuilder()
                .setGcsImageUri("gs://" + bucketName + "/" + fileName)
                .build();

            Image image = Image.newBuilder()
                .setSource(imageSource)
                .build();

            Feature featureLabel = Feature.newBuilder()
                .setType(Type.LABEL_DETECTION)
                .build();
            Feature featureImageProps = Feature.newBuilder()
                .setType(Type.IMAGE_PROPERTIES)
                .build();
            Feature featureSafeSearch = Feature.newBuilder()
                .setType(Type.SAFE_SEARCH_DETECTION)
                .build();
                
            AnnotateImageRequest request = AnnotateImageRequest.newBuilder()
                .addFeatures(featureLabel)
                .addFeatures(featureImageProps)
                .addFeatures(featureSafeSearch)
                .setImage(image)
                .build();
            
            requests.add(request);

            logger.info("Calling the Vision API...");
            BatchAnnotateImagesResponse result = vision.batchAnnotateImages(requests);
            List<AnnotateImageResponse> responses = result.getResponsesList();

            if (responses.size() == 0) {
                logger.info("No response received from Vision API.");
                return;
            }

            AnnotateImageResponse response = responses.get(0);
            if (response.hasError()) {
                logger.info("Error: " + response.getError().getMessage());
                return;
            }

            List<String> labels = response.getLabelAnnotationsList().stream()
                .map(annotation -> annotation.getDescription())
                .collect(Collectors.toList());
            logger.info("Annotations found:");
            for (String label: labels) {
                logger.info("- " + label);
            }

            String mainColor = "#FFFFFF";
            ImageProperties imgProps = response.getImagePropertiesAnnotation();
            if (imgProps.hasDominantColors()) {
                DominantColorsAnnotation colorsAnn = imgProps.getDominantColors();
                ColorInfo colorInfo = colorsAnn.getColors(0);

                mainColor = rgbHex(
                    colorInfo.getColor().getRed(), 
                    colorInfo.getColor().getGreen(), 
                    colorInfo.getColor().getBlue());

                logger.info("Color: " + mainColor);
            }

            boolean isSafe = false;
            if (response.hasSafeSearchAnnotation()) {
                SafeSearchAnnotation safeSearch = response.getSafeSearchAnnotation();

                isSafe = Stream.of(
                    safeSearch.getAdult(), safeSearch.getMedical(), safeSearch.getRacy(),
                    safeSearch.getSpoof(), safeSearch.getViolence())
                .allMatch( likelihood -> 
                    likelihood != Likelihood.LIKELY && likelihood != Likelihood.VERY_LIKELY
                );

                logger.info("Safe? " + isSafe);
            }

            // Saving result to Firestore
            if (isSafe) {
                FirestoreOptions firestoreOptions = FirestoreOptions.getDefaultInstance();
                Firestore pictureStore = firestoreOptions.getService();

                DocumentReference doc = pictureStore.collection("pictures").document(fileName);

                Map<String, Object> data = new HashMap<>();
                data.put("labels", labels);
                data.put("color", mainColor);
                data.put("created", new Date());

                ApiFuture<WriteResult> writeResult = doc.set(data, SetOptions.merge());

                logger.info("Picture metadata saved in Firestore at " + writeResult.get().getUpdateTime());
            }
        }
    }

    private static String rgbHex(float red, float green, float blue) {
        return String.format("#%02x%02x%02x", (int)red, (int)green, (int)blue);
    }

    public static class GCSEvent {
        String bucket;
        String name;
    }
}

968749236c3f01da.png

11. ফাংশন অন্বেষণ

আসুন বিভিন্ন আকর্ষণীয় অংশগুলি ঘনিষ্ঠভাবে দেখে নেওয়া যাক।

প্রথমত, আমরা Maven pom.xml ফাইলে নির্দিষ্ট নির্ভরতা অন্তর্ভুক্ত করছি। Google জাভা ক্লায়েন্ট লাইব্রেরি কোনো নির্ভরতা দ্বন্দ্ব দূর করতে একটি Bill-of-Materials(BOM) প্রকাশ করে। এটি ব্যবহার করে, আপনাকে পৃথক Google ক্লায়েন্ট লাইব্রেরির জন্য কোনো সংস্করণ উল্লেখ করতে হবে না

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>libraries-bom</artifactId>
        <version>26.1.1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

তারপর, আমরা ভিশন API এর জন্য একটি ক্লায়েন্ট প্রস্তুত করি:

...
try (ImageAnnotatorClient vision = ImageAnnotatorClient.create()) {
...

এখন আমাদের ফাংশন গঠন আসে. আমরা ইনকামিং ইভেন্ট থেকে আমাদের আগ্রহী ক্ষেত্রগুলি ক্যাপচার করি এবং সেগুলিকে আমাদের সংজ্ঞায়িত GCSEvent কাঠামোতে ম্যাপ করি:

...
public class ImageAnalysis implements BackgroundFunction<GCSEvent> {
    @Override
    public void accept(GCSEvent event, Context context) 
            throws IOException, InterruptedException,     
    ExecutionException {
...

    public static class GCSEvent {
        String bucket;
        String name;
    }

স্বাক্ষরটি লক্ষ্য করুন, তবে আমরা কীভাবে ফাইল এবং বাকেটের নাম পুনরুদ্ধার করি যা ক্লাউড ফাংশনটি ট্রিগার করেছে।

রেফারেন্সের জন্য, ইভেন্ট পেলোড দেখতে কেমন তা এখানে:

{
  "bucket":"uploaded-pictures",
  "contentType":"image/png",
  "crc32c":"efhgyA==",
  "etag":"CKqB956MmucCEAE=",
  "generation":"1579795336773802",
  "id":"uploaded-pictures/Screenshot.png/1579795336773802",
  "kind":"storage#object",
  "md5Hash":"PN8Hukfrt6C7IyhZ8d3gfQ==",
  "mediaLink":"https://www.googleapis.com/download/storage/v1/b/uploaded-pictures/o/Screenshot.png?generation=1579795336773802&alt=media",
  "metageneration":"1",
  "name":"Screenshot.png",
  "selfLink":"https://www.googleapis.com/storage/v1/b/uploaded-pictures/o/Screenshot.png",
  "size":"173557",
  "storageClass":"STANDARD",
  "timeCreated":"2020-01-23T16:02:16.773Z",
  "timeStorageClassUpdated":"2020-01-23T16:02:16.773Z",
  "updated":"2020-01-23T16:02:16.773Z"
}

আমরা ভিশন ক্লায়েন্টের মাধ্যমে পাঠানোর জন্য একটি অনুরোধ প্রস্তুত করি:

ImageSource imageSource = ImageSource.newBuilder()
    .setGcsImageUri("gs://" + bucketName + "/" + fileName)
    .build();

Image image = Image.newBuilder()
    .setSource(imageSource)
    .build();

Feature featureLabel = Feature.newBuilder()
    .setType(Type.LABEL_DETECTION)
    .build();
Feature featureImageProps = Feature.newBuilder()
    .setType(Type.IMAGE_PROPERTIES)
    .build();
Feature featureSafeSearch = Feature.newBuilder()
    .setType(Type.SAFE_SEARCH_DETECTION)
    .build();
    
AnnotateImageRequest request = AnnotateImageRequest.newBuilder()
    .addFeatures(featureLabel)
    .addFeatures(featureImageProps)
    .addFeatures(featureSafeSearch)
    .setImage(image)
    .build();

আমরা ভিশন API এর 3টি মূল ক্ষমতার জন্য জিজ্ঞাসা করছি:

  • লেবেল সনাক্তকরণ : সেই ছবিগুলিতে কী রয়েছে তা বোঝার জন্য
  • ছবির বৈশিষ্ট্য : ছবির আকর্ষণীয় বৈশিষ্ট্য দিতে (আমরা ছবির প্রভাবশালী রঙে আগ্রহী)
  • নিরাপদ অনুসন্ধান : ছবিটি দেখানোর জন্য নিরাপদ কিনা তা জানার জন্য (এতে প্রাপ্তবয়স্ক / চিকিৎসা / জাতিগত / সহিংস বিষয়বস্তু থাকা উচিত নয়)

এই মুহুর্তে, আমরা ভিশন API এ কল করতে পারি:

...
logger.info("Calling the Vision API...");
BatchAnnotateImagesResponse result = 
                            vision.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = result.getResponsesList();
...

রেফারেন্সের জন্য, ভিশন API থেকে প্রতিক্রিয়া কেমন দেখায় তা এখানে:

{
  "faceAnnotations": [],
  "landmarkAnnotations": [],
  "logoAnnotations": [],
  "labelAnnotations": [
    {
      "locations": [],
      "properties": [],
      "mid": "/m/01yrx",
      "locale": "",
      "description": "Cat",
      "score": 0.9959855675697327,
      "confidence": 0,
      "topicality": 0.9959855675697327,
      "boundingPoly": null
    },
     - - - 
  ],
  "textAnnotations": [],
  "localizedObjectAnnotations": [],
  "safeSearchAnnotation": {
    "adult": "VERY_UNLIKELY",
    "spoof": "UNLIKELY",
    "medical": "VERY_UNLIKELY",
    "violence": "VERY_UNLIKELY",
    "racy": "VERY_UNLIKELY",
    "adultConfidence": 0,
    "spoofConfidence": 0,
    "medicalConfidence": 0,
    "violenceConfidence": 0,
    "racyConfidence": 0,
    "nsfwConfidence": 0
  },
  "imagePropertiesAnnotation": {
    "dominantColors": {
      "colors": [
        {
          "color": {
            "red": 203,
            "green": 201,
            "blue": 201,
            "alpha": null
          },
          "score": 0.4175916016101837,
          "pixelFraction": 0.44456374645233154
        },
         - - - 
      ]
    }
  },
  "error": null,
  "cropHintsAnnotation": {
    "cropHints": [
      {
        "boundingPoly": {
          "vertices": [
            { "x": 0, "y": 118 },
            { "x": 1177, "y": 118 },
            { "x": 1177, "y": 783 },
            { "x": 0, "y": 783 }
          ],
          "normalizedVertices": []
        },
        "confidence": 0.41695669293403625,
        "importanceFraction": 1
      }
    ]
  },
  "fullTextAnnotation": null,
  "webDetection": null,
  "productSearchResults": null,
  "context": null
}

যদি কোনো ত্রুটি ফিরে না আসে, তাহলে আমরা এগিয়ে যেতে পারি, তাই কেন আমাদের কাছে এটি যদি ব্লক থাকে:

AnnotateImageResponse response = responses.get(0);
if (response.hasError()) {
     logger.info("Error: " + response.getError().getMessage());
     return;
}

আমরা ছবিতে স্বীকৃত জিনিস, বিভাগ বা থিমগুলির লেবেল পেতে যাচ্ছি:

List<String> labels = response.getLabelAnnotationsList().stream()
    .map(annotation -> annotation.getDescription())
    .collect(Collectors.toList());

logger.info("Annotations found:");
for (String label: labels) {
    logger.info("- " + label);
}

আমরা ছবির প্রভাবশালী রঙ জানতে আগ্রহী:

String mainColor = "#FFFFFF";
ImageProperties imgProps = response.getImagePropertiesAnnotation();
if (imgProps.hasDominantColors()) {
    DominantColorsAnnotation colorsAnn = 
                               imgProps.getDominantColors();
    ColorInfo colorInfo = colorsAnn.getColors(0);

    mainColor = rgbHex(
        colorInfo.getColor().getRed(), 
        colorInfo.getColor().getGreen(), 
        colorInfo.getColor().getBlue());

    logger.info("Color: " + mainColor);
}

আমরা লাল/সবুজ/নীল মানগুলিকে হেক্সাডেসিমেল রঙের কোডে রূপান্তর করতে একটি ইউটিলিটি ফাংশন ব্যবহার করছি যা আমরা CSS স্টাইলশীটে ব্যবহার করতে পারি।

ছবি দেখানোর জন্য নিরাপদ কিনা তা পরীক্ষা করা যাক:

boolean isSafe = false;
if (response.hasSafeSearchAnnotation()) {
    SafeSearchAnnotation safeSearch = 
                      response.getSafeSearchAnnotation();

    isSafe = Stream.of(
        safeSearch.getAdult(), safeSearch.getMedical(), safeSearch.getRacy(),
        safeSearch.getSpoof(), safeSearch.getViolence())
    .allMatch( likelihood -> 
        likelihood != Likelihood.LIKELY && likelihood != Likelihood.VERY_LIKELY
    );

    logger.info("Safe? " + isSafe);
}

আমরা প্রাপ্তবয়স্ক / স্পুফ / চিকিৎসা / সহিংসতা / জাতিগত বৈশিষ্ট্যগুলি পরীক্ষা করে দেখছি যে সেগুলি সম্ভবত বা খুব সম্ভব নয়৷

নিরাপদ অনুসন্ধানের ফলাফল ঠিক থাকলে, আমরা Firestore-এ মেটাডেটা সংরক্ষণ করতে পারি:

if (isSafe) {
    FirestoreOptions firestoreOptions = FirestoreOptions.getDefaultInstance();
    Firestore pictureStore = firestoreOptions.getService();

    DocumentReference doc = pictureStore.collection("pictures").document(fileName);

    Map<String, Object> data = new HashMap<>();
    data.put("labels", labels);
    data.put("color", mainColor);
    data.put("created", new Date());

    ApiFuture<WriteResult> writeResult = doc.set(data, SetOptions.merge());

    logger.info("Picture metadata saved in Firestore at " + writeResult.get().getUpdateTime());
}

12. ফাংশন স্থাপন করুন

ফাংশন স্থাপন করার সময়।

604f47aa11fbf8e.png

DEPLOY বোতাম টিপুন এবং নতুন সংস্করণ স্থাপন করা হবে, আপনি অগ্রগতি দেখতে পারেন:

13da63f23e4dbbdd.png

13. ফাংশনটি আবার পরীক্ষা করুন

একবার ফাংশনটি সফলভাবে স্থাপন করা হলে, আপনি ক্লাউড স্টোরেজে একটি ছবি পোস্ট করবেন, দেখুন আমাদের ফাংশন চালু করা হয়েছে কিনা, ভিশন API কী রিটার্ন করে এবং মেটাডেটা Firestore এ সংরক্ষণ করা হয় কিনা।

Cloud Storage -এ ফিরে যান এবং ল্যাবের শুরুতে আমরা যে বালতি তৈরি করেছি তাতে ক্লিক করুন:

d44c1584122311c7.png

একবার বালতি বিবরণ পৃষ্ঠায়, একটি ছবি আপলোড করতে Upload files বোতামে ক্লিক করুন৷

26bb31d35fb6aa3d.png

"হ্যামবার্গার" (☰) মেনু থেকে, Logging > Logs এক্সপ্লোরার-এ নেভিগেট করুন।

Log Fields সিলেক্টরে, আপনার ফাংশনের জন্য উৎসর্গীকৃত লগগুলি দেখতে Cloud Function নির্বাচন করুন। লগ ফিল্ডগুলির মাধ্যমে নীচে স্ক্রোল করুন এবং আপনি ফাংশন সম্পর্কিত লগগুলির একটি সূক্ষ্ম-দানাযুক্ত দৃশ্য পেতে একটি নির্দিষ্ট ফাংশন নির্বাচন করতে পারেন। picture-uploaded ফাংশন নির্বাচন করুন.

b651dca7e25d5b11.png

এবং প্রকৃতপক্ষে, লগের তালিকায়, আমি দেখতে পাচ্ছি যে আমাদের ফাংশনটি আহ্বান করা হয়েছিল:

d22a7f24954e4f63.png

লগগুলি ফাংশন সম্পাদনের শুরু এবং শেষ নির্দেশ করে। এবং এর মধ্যে, আমরা console.log() স্টেটমেন্টের সাথে আমাদের ফাংশনে যে লগগুলি রাখি তা দেখতে পারি। আমরা দেখি:

  • আমাদের ফাংশন ট্রিগার ইভেন্টের বিশদ বিবরণ,
  • ভিশন API কল থেকে কাঁচা ফলাফল,
  • আমাদের আপলোড করা ছবিতে যে লেবেলগুলি পাওয়া গেছে,
  • প্রভাবশালী রং তথ্য,
  • ছবি দেখানো নিরাপদ কিনা,
  • এবং অবশেষে ছবি সম্পর্কে সেই মেটাডেটা Firestore এ সংরক্ষণ করা হয়েছে।

9ff7956a215c15da.png

আবার "হ্যামবার্গার" (☰) মেনু থেকে, Firestore বিভাগে যান। Data সাবসেকশনে (ডিফল্টভাবে দেখানো হয়েছে), আপনি একটি নতুন ডকুমেন্ট যোগ করার সাথে pictures সংগ্রহ দেখতে পাবেন, আপনার এইমাত্র আপলোড করা ছবির সাথে মিল রয়েছে:

a6137ab9687da370.png

14. পরিষ্কার করুন (ঐচ্ছিক)

আপনি যদি সিরিজের অন্যান্য ল্যাবগুলির সাথে চালিয়ে যেতে চান না, তাহলে খরচ বাঁচাতে এবং সামগ্রিকভাবে ভাল ক্লাউড নাগরিক হতে আপনি সংস্থানগুলি পরিষ্কার করতে পারেন। আপনি নিম্নরূপ পৃথকভাবে সম্পদ পরিষ্কার করতে পারেন.

বালতি মুছুন:

gsutil rb gs://${BUCKET_PICTURES}

ফাংশন মুছুন:

gcloud functions delete picture-uploaded --region europe-west1 -q

সংগ্রহ থেকে সংগ্রহ মুছুন নির্বাচন করে Firestore সংগ্রহ মুছুন:

410b551c3264f70a.png

বিকল্পভাবে, আপনি পুরো প্রকল্প মুছে ফেলতে পারেন:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT} 

15. অভিনন্দন!

অভিনন্দন! আপনি সফলভাবে প্রকল্পের প্রথম মূল পরিষেবা বাস্তবায়ন করেছেন!

আমরা কভার করেছি কি

  • ক্লাউড স্টোরেজ
  • ক্লাউড ফাংশন
  • ক্লাউড ভিশন API
  • ক্লাউড ফায়ারস্টোর

পরবর্তী পদক্ষেপ