1. खास जानकारी
पहली कोड लैब में, आपको एक बकेट में तस्वीरें स्टोर करनी होंगी. इससे फ़ाइल बनाने का इवेंट जनरेट होगा, जिसे Cloud Run में डिप्लॉय की गई सेवा मैनेज करेगी. सेवा, इमेज का विश्लेषण करने और नतीजों को डेटास्टोर में सेव करने के लिए, Vision API को कॉल करेगी.
आपको क्या सीखने को मिलेगा
- Cloud Storage
- Cloud Run
- क्लाउड विज़न एपीआई
- Cloud Firestore
2. सेटअप और ज़रूरी शर्तें
अपने हिसाब से एनवायरमेंट सेटअप करना
- Google Cloud Console में साइन इन करें और नया प्रोजेक्ट बनाएं या किसी मौजूदा प्रोजेक्ट का फिर से इस्तेमाल करें. अगर आपके पास पहले से Gmail या Google Workspace खाता नहीं है, तो आपको नया खाता बनाना होगा.
- प्रोजेक्ट का नाम, इस प्रोजेक्ट में हिस्सा लेने वाले लोगों का डिसप्ले नेम होता है. यह एक वर्ण स्ट्रिंग है, जिसका इस्तेमाल Google API नहीं करता. इसे कभी भी अपडेट किया जा सकता है.
- प्रोजेक्ट आईडी, Google Cloud के सभी प्रोजेक्ट के लिए यूनीक होता है. साथ ही, इसे बदला नहीं जा सकता. इसे सेट करने के बाद बदला नहीं जा सकता. Cloud Console, एक यूनीक स्ट्रिंग अपने-आप जनरेट करता है; आम तौर पर, आपको उसके होने की कोई परवाह नहीं होती. ज़्यादातर कोडलैब में, आपको अपना प्रोजेक्ट आईडी बताना होगा. आम तौर पर, इसकी पहचान
PROJECT_ID
के रूप में की जाती है. अगर आपको जनरेट किया गया आईडी पसंद नहीं है, तो किसी भी क्रम में एक और आईडी जनरेट किया जा सकता है. दूसरा तरीका यह है कि आप खुद भी आज़माकर देखें कि वह उपलब्ध है या नहीं. इस चरण के बाद, इसे बदला नहीं जा सकता. साथ ही, यह प्रोजेक्ट के खत्म होने तक बना रहता है. - आपकी जानकारी के लिए, प्रोजेक्ट नंबर नाम की एक तीसरी वैल्यू दी गई है. इसका इस्तेमाल कुछ एपीआई करते हैं. दस्तावेज़ में इन तीनों वैल्यू के बारे में ज़्यादा जानें.
- इसके बाद, आपको क्लाउड संसाधनों/एपीआई का इस्तेमाल करने के लिए, Cloud Console में बिलिंग चालू करनी होगी. इस कोडलैब का इस्तेमाल करने पर, आपको ज़्यादा पैसे नहीं चुकाने होंगे. इस ट्यूटोरियल के अलावा, बिलिंग से बचने के लिए संसाधनों को बंद करें. इसके लिए, अपने बनाए गए संसाधनों को मिटाएं या प्रोजेक्ट को मिटाएं. Google Cloud के नए उपयोगकर्ता, 300 डॉलर के मुफ़्त ट्रायल वाले प्रोग्राम में हिस्सा ले सकते हैं.
Cloud Shell शुरू करना
Google Cloud को आपके लैपटॉप से, कहीं से भी ऑपरेट किया जा सकता है. हालांकि, इस कोडलैब में Google Cloud Shell का इस्तेमाल किया जा रहा है. यह क्लाउड में चलने वाला कमांड लाइन एनवायरमेंट है.
Google Cloud Console में जाकर, सबसे ऊपर दाईं ओर मौजूद टूलबार पर क्लाउड शेल आइकॉन पर क्लिक करें:
प्रावधान करने और एनवायरमेंट से कनेक्ट होने में कुछ ही समय लगेगा. उसके पूरा हो जाने पर, आपको कुछ ऐसा दिखाई देगा:
इस वर्चुअल मशीन में ऐसे सभी डेवलपमेंट टूल मौजूद हैं जिनकी आपको ज़रूरत पड़ेगी. यह पांच जीबी की स्थायी होम डायरेक्ट्री उपलब्ध कराता है और Google Cloud पर चलता है. यह नेटवर्क की परफ़ॉर्मेंस और पुष्टि करने की प्रक्रिया को बेहतर बनाता है. इस कोडलैब (कोड बनाना सीखना) में आपका सारा काम ब्राउज़र में किया जा सकता है. आपको कुछ भी इंस्टॉल करने की ज़रूरत नहीं है.
3. एपीआई चालू करें
इस लैब के लिए, आपको Cloud Functions और Vision API का इस्तेमाल करना होगा, लेकिन पहले उन्हें Cloud Console में या gcloud
में चालू करना होगा.
Cloud Console में Vision API को चालू करने के लिए, खोज बार में Cloud Vision API
खोजें:
आपको Cloud Vision API पेज पर ले जाया जाएगा:
ENABLE
बटन पर क्लिक करें.
इसके अलावा, इसे Cloud Shell में चालू भी किया जा सकता है. इसके लिए, gcloud कमांड लाइन टूल इस्तेमाल करें.
Cloud Shell के अंदर, यह कमांड चलाएं:
gcloud services enable vision.googleapis.com
आपको कार्रवाई सफलतापूर्वक खत्म होने के लिए दिखाई देना चाहिए:
Operation "operations/acf.12dba18b-106f-4fd2-942d-fea80ecc5c1c" finished successfully.
Cloud Run और Cloud Build को भी चालू करें:
gcloud services enable cloudbuild.googleapis.com \ run.googleapis.com
4. बकेट बनाना (कंसोल)
तस्वीरों के लिए स्टोरेज बकेट बनाएं. Google Cloud Platform कंसोल ( console.cloud.google.com) से या Cloud Shell से gsutil कमांड लाइन टूल या अपने लोकल डेवलपमेंट एनवायरमेंट की मदद से, ऐसा किया जा सकता है.
स्टोरेज पर जाएं
"हैमबर्गर" से (RECORD) मेन्यू, Storage
पेज पर जाएं.
अपने बकेट को नाम दें
CREATE BUCKET
बटन पर क्लिक करें.
CONTINUE
पर क्लिक करें.
जगह चुनें
अपनी पसंद के क्षेत्र में, एक से ज़्यादा इलाकों के लिए बकेट बनाएं (यहां Europe
).
CONTINUE
पर क्लिक करें.
डिफ़ॉल्ट स्टोरेज क्लास चुनना
अपने डेटा के लिए Standard
स्टोरेज क्लास चुनें.
CONTINUE
पर क्लिक करें.
ऐक्सेस कंट्रोल सेट करना
साथ ही, आपने सार्वजनिक तौर पर उपलब्ध इमेज पर काम किया है. इसलिए, इस बकेट में स्टोर की गई हमारी सभी तस्वीरों का ऐक्सेस कंट्रोल एक जैसा होना चाहिए.
Uniform
ऐक्सेस कंट्रोल का विकल्प चुनें.
CONTINUE
पर क्लिक करें.
सुरक्षा/एन्क्रिप्ट (सुरक्षित) करने का तरीका सेट करना
डिफ़ॉल्ट (Google-managed key)
, क्योंकि आप अपनी एन्क्रिप्शन कुंजियों का इस्तेमाल नहीं करेंगे.) को डिफ़ॉल्ट रखें.
हमारी बकेट बनाने की प्रक्रिया को पूरा करने के लिए, CREATE
पर क्लिक करें.
सभी उपयोगकर्ताओं को स्टोरेज व्यूअर के तौर पर जोड़ना
Permissions
टैब पर जाएं:
बकेट में allUsers
सदस्य को, Storage > Storage Object Viewer
की भूमिका के साथ जोड़ें, ऐसा करने का तरीका:
SAVE
पर क्लिक करें.
5. बकेट बनाएं (gsutil)
बकेट बनाने के लिए, Cloud Shell में gsutil
कमांड-लाइन टूल का इस्तेमाल भी किया जा सकता है.
Cloud Shell में, बकेट के यूनीक नाम के लिए एक वैरिएबल सेट करें. Cloud Shell में पहले से ही आपके यूनीक प्रोजेक्ट आईडी के लिए 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
बकेट होनी चाहिए:
परीक्षण करें कि आप बकेट में चित्र अपलोड कर सकते हैं और पिछले चरण में बताए गए अनुसार अपलोड किए गए चित्र सार्वजनिक रूप से उपलब्ध हैं.
6. बकेट के सार्वजनिक ऐक्सेस की जांच करना
स्टोरेज ब्राउज़र पर वापस जाने पर, आपको सूची में अपना बकेट "सार्वजनिक" के तौर पर दिखेगा ऐक्सेस देना होगा (इसमें चेतावनी का एक निशान शामिल है, जो आपको यह याद दिलाता है कि किसी के पास भी उस बकेट के कॉन्टेंट का ऐक्सेस है).
आपकी बकेट अब चित्र प्राप्त करने के लिए तैयार है.
बकेट के नाम पर क्लिक करने पर, आपको बकेट की जानकारी दिखेगी.
यहां Upload files
बटन का इस्तेमाल करके यह जांच की जा सकती है कि बकेट में कोई तस्वीर जोड़ी जा सकती है या नहीं. फ़ाइल चुनने वाला पॉप-अप आपसे एक फ़ाइल चुनने के लिए कहेगा. चुने जाने के बाद, इसे आपके बकेट में अपलोड कर दिया जाएगा. इसके बाद, आपको public
का वह ऐक्सेस फिर से दिखेगा जो इस नई फ़ाइल के लिए अपने-आप एट्रिब्यूट हो गया है.
Public
ऐक्सेस लेबल के साथ, आपको लिंक का एक छोटा आइकॉन भी दिखेगा. इस पर क्लिक करने पर, आपका ब्राउज़र उस इमेज के सार्वजनिक यूआरएल पर जाएगा, जो इस तरह का होगा:
https://storage.googleapis.com/BUCKET_NAME/PICTURE_FILE.png
जहां आपने अपने बकेट के लिए चुना है वह दुनिया भर में इस्तेमाल होने वाला यूनीक नाम है. इसके बाद, आपकी फ़ोटो का फ़ाइल नाम BUCKET_NAME
है.
चित्र नाम के साथ चेक बॉक्स पर क्लिक करने से, DELETE
बटन सक्षम हो जाएगा और आप इस पहली चित्र को हटा सकते हैं.
7. डेटाबेस तैयार करना
आपको Vision API से मिली तस्वीर की जानकारी को Cloud Firestore के डेटाबेस में सेव करना होगा. यह डेटाबेस, तेज़, पूरी तरह से मैनेज किया गया, सर्वरलेस, क्लाउड-नेटिव NoSQL दस्तावेज़ डेटाबेस है. Cloud Console के Firestore
सेक्शन में जाकर अपना डेटाबेस तैयार करें:
दो विकल्प दिए जाते हैं: Native mode
या Datastore mode
. नेटिव मोड का इस्तेमाल करें. इसमें, ऑफ़लाइन सहायता और रीयल-टाइम सिंक करने जैसी अतिरिक्त सुविधाएं मिलती हैं.
SELECT NATIVE MODE
पर क्लिक करें.
एक से ज़्यादा क्षेत्र चुनें (यहां यूरोप में, लेकिन कम से कम वह क्षेत्र चुनें जो आपका फ़ंक्शन और स्टोरेज बकेट है).
CREATE DATABASE
बटन पर क्लिक करें.
डेटाबेस बन जाने के बाद, आपको यह जानकारी दिखेगी:
+ START COLLECTION
बटन पर क्लिक करके, नया कलेक्शन बनाएं.
नाम संग्रह pictures
.
आपको कोई दस्तावेज़ बनाने की ज़रूरत नहीं है. नई तस्वीरें, Cloud Storage में सेव हो जाती हैं और Vision API इनका विश्लेषण कर सकता है. इसलिए, इन्हें प्रोग्राम के हिसाब से अपने-आप जोड़ा जा सकता है.
Save
पर क्लिक करें.
Firestore, नए कलेक्शन में पहला डिफ़ॉल्ट दस्तावेज़ बनाता है. आपके पास उस दस्तावेज़ को सुरक्षित तरीके से मिटाने का विकल्प होता है, क्योंकि इसमें कोई काम की जानकारी नहीं होती:
हमारे कलेक्शन में, प्रोग्राम के हिसाब से अपने-आप बनने वाले दस्तावेज़ों में चार फ़ील्ड होंगे:
- name (string): अपलोड की गई फ़ोटो की फ़ाइल का नाम, जो दस्तावेज़ की कुंजी भी है
- लेबल (स्ट्रिंग की कैटगरी): Vision API की मदद से पहचाने गए आइटम के लेबल
- color (string): मुख्य रंग का हेक्साडेसिमल रंग कोड (जैसे, #ab12ef)
- बनाया गया (तारीख): इस इमेज के मेटाडेटा को सेव किए जाने के समय का टाइमस्टैंप
- थंबनेल (बूलियन): एक वैकल्पिक फ़ील्ड, जो मौजूद होगी. अगर इस तस्वीर के लिए थंबनेल इमेज जनरेट की गई है, तो यह सही हो जाएगी
हम Firestore में ऐसी तस्वीरें ढूंढने के लिए Firestore में खोज करेंगे जिनमें थंबनेल उपलब्ध होंगे. साथ ही, हम उन्हें बनने की तारीख के हिसाब से क्रम में लगाने का काम करेंगे, इसलिए हमें एक सर्च इंडेक्स बनाना होगा.
Cloud Shell में, इस कमांड का इस्तेमाल करके इंडेक्स बनाया जा सकता है:
gcloud firestore indexes composite create \
--collection-group=pictures \
--field-config field-path=thumbnail,order=descending \
--field-config field-path=created,order=descending
इसके अलावा, Cloud Console में भी ऐसा किया जा सकता है. ऐसा करने के लिए, बाईं ओर नेविगेशन कॉलम में Indexes
पर क्लिक करें. इसके बाद, एक कंपोज़िट इंडेक्स बनाएं, जैसा कि यहां दिखाया गया है:
Create
पर क्लिक करें. इंडेक्स बनाने में कुछ मिनट लग सकते हैं.
8. कोड का क्लोन बनाएं
अगर आपने पिछले कोड लैब में, पहले से कोई काम नहीं किया है, तो कोड का क्लोन बनाएं:
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
इसके बाद लैब बनाने के लिए, सेवा वाली डायरेक्ट्री पर जाएं:
cd serverless-photosharing-workshop/services/image-analysis/java
आपके पास सेवा के लिए यह फ़ाइल लेआउट होगा:
9. सेवा कोड के बारे में ज़्यादा जानें
सबसे पहले यह देखा जाता है कि बीओएम का इस्तेमाल करके, pom.xml
में Java क्लाइंट लाइब्रेरी कैसे चालू होती हैं:
सबसे पहले, pom.xml
फ़ाइल खोलें, जिसमें हमारे Java ऐप्लिकेशन की डिपेंडेंसी दी गई है; हम Vision, Cloud Storage, और Firestore एपीआई के इस्तेमाल पर ध्यान देते हैं
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0-M3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>services</groupId>
<artifactId>image-analysis</artifactId>
<version>0.0.1</version>
<name>image-analysis</name>
<description>Spring App for Image Analysis</description>
<properties>
<java.version>17</java.version>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring-cloud.version>2023.0.0-M2</spring-cloud.version>
<testcontainers.version>1.19.1</testcontainers.version>
</properties>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>26.24.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
—
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-web</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud.functions</groupId>
<artifactId>functions-framework-api</artifactId>
<version>1.1.0</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>
इस सुविधा को EventController
क्लास में लागू किया गया है. बकेट में हर बार नई इमेज अपलोड किए जाने पर, सेवा को प्रोसेस करने के लिए एक सूचना मिलेगी:
@RestController
public class EventController {
private static final Logger logger = Logger.getLogger(EventController.class.getName());
private static final List<String> requiredFields = Arrays.asList("ce-id", "ce-source", "ce-type", "ce-specversion");
@RequestMapping(value = "/", method = RequestMethod.POST)
public ResponseEntity<String> receiveMessage(
@RequestBody Map<String, Object> body, @RequestHeader Map<String, String> headers) throws IOException, InterruptedException, ExecutionException {
...
}
कोड, Cloud Events
हेडर की पुष्टि करने के लिए काम करेगा:
System.out.println("Header elements");
for (String field : requiredFields) {
if (headers.get(field) == null) {
String msg = String.format("Missing expected header: %s.", field);
System.out.println(msg);
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
} else {
System.out.println(field + " : " + headers.get(field));
}
}
System.out.println("Body elements");
for (String bodyField : body.keySet()) {
System.out.println(bodyField + " : " + body.get(bodyField));
}
if (headers.get("ce-subject") == null) {
String msg = "Missing expected header: ce-subject.";
System.out.println(msg);
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
}
अब एक अनुरोध बनाया जा सकता है और कोड इसी तरह के एक अनुरोध को Vision API
पर भेजने के लिए तैयार करेगा:
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);
हम Vision API की तीन मुख्य सुविधाएं मांग रहे हैं:
- लेबल की पहचान: इससे पता चलता है कि उन तस्वीरों में क्या है
- इमेज की प्रॉपर्टी: इससे फ़ोटो के दिलचस्प एट्रिब्यूट दिखाए जा सकते हैं (हम इमेज के मुख्य रंग में दिलचस्पी रखते हैं)
- सुरक्षित खोज: जानें कि इमेज दिखाने के लिए सुरक्षित है या नहीं (इसमें वयस्क / चिकित्सा / वयस्क / हिंसक सामग्री नहीं होनी चाहिए)
अब हम Vision API को कॉल कर सकते हैं:
...
logger.info("Calling the Vision API...");
BatchAnnotateImagesResponse result = vision.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = result.getResponsesList();
...
रेफ़रंस के लिए, Vision 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
}
अगर कोई गड़बड़ी नहीं मिलती है, तो हम आगे की कार्रवाई कर सकते हैं. इसलिए, अगर ब्लॉक है, तो हमारे पास ऐसा क्यों है:
if (responses.size() == 0) {
logger.info("No response received from Vision API.");
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
}
AnnotateImageResponse response = responses.get(0);
if (response.hasError()) {
logger.info("Error: " + response.getError().getMessage());
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
}
हम इमेज में दिखाई गई चीज़ों, कैटगरी या थीम के लेबल बनाएंगे:
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);
}
हम वयस्क / स्पूफ़ / मेडिकल / हिंसा / वयस्क लोगों से जुड़ी विशेषताओं की जांच कर रहे हैं, ताकि यह पता लगाया जा सके कि ऐसे कॉन्टेंट की संभावना ज़्यादा है या इससे ज़्यादा नहीं.
अगर सुरक्षित खोज का नतीजा मिलता है, तो हम Firestore में मेटाडेटा सेव कर सकते हैं:
// Saving result to Firestore
if (isSafe) {
ApiFuture<WriteResult> writeResult =
eventService.storeImage(fileName, labels,
mainColor);
logger.info("Picture metadata saved in Firestore at " +
writeResult.get().getUpdateTime());
}
...
public ApiFuture<WriteResult> storeImage(String fileName,
List<String> labels,
String mainColor) {
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());
return doc.set(data, SetOptions.merge());
}
10. GraalVM की मदद से ऐप्लिकेशन की इमेज बनाएं
इस वैकल्पिक चरण में, आप GraalVM का इस्तेमाल करके JIT based app image
और फिर Native Java app image
बनाएंगे.
बिल्ड चलाने के लिए, आपको यह पक्का करना होगा कि आपके पास सही JDK और नेटिव-इमेज बिल्डर इंस्टॉल और कॉन्फ़िगर किया गया है. यहां कई विकल्प मौजूद हैं.
To start
, GraalVM 22.3.x कम्यूनिटी एडिशन डाउनलोड करें और GraalVM इंस्टॉलेशन पेज पर दिए गए निर्देशों का पालन करें.
इस प्रक्रिया को SDKMAN! की मदद से बहुत ज़्यादा आसान बनाया जा सकता है!
SDKman
के साथ सही JDK डिस्ट्रिब्यूशन को इंस्टॉल करने के लिए, इंस्टॉल करने का निर्देश देकर शुरुआत करें:
sdk install java 17.0.8-graal
SDKमैन को JIT और AOT, दोनों बिल्ड के लिए यह वर्शन इस्तेमाल करने का निर्देश दें:
sdk use java 17.0.8-graal
अपनी सुविधा के लिए, Cloudshell
में इन आसान निर्देशों का इस्तेमाल करके, GraalVM और local-image उपयोगिता को इंस्टॉल किया जा सकता है:
# download GraalVM wget https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_linux-x64_bin.tar.gz tar -xzf graalvm-jdk-17_linux-x64_bin.tar.gz ls -lart # configure Java 17 and GraalVM for Java 17 # note the name of the latest GraalVM version, as unpacked by the tar command echo Existing JVM: $JAVA_HOME cd graalvm-jdk-17.0.8+9.1 export JAVA_HOME=$PWD cd bin export PATH=$PWD:$PATH echo JAVA HOME: $JAVA_HOME echo PATH: $PATH cd ../.. # validate the version with java -version # observe Java(TM) SE Runtime Environment Oracle GraalVM 17.0.8+9.1 (build 17.0.8+9-LTS-jvmci-23.0-b14) Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.8+9.1 (build 17.0.8+9-LTS-jvmci-23.0-b14, mixed mode, sharing)
सबसे पहले, GCP प्रोजेक्ट के एनवायरमेंट वैरिएबल सेट करें:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
इसके बाद लैब बनाने के लिए, सेवा वाली डायरेक्ट्री पर जाएं:
cd serverless-photosharing-workshop/services/image-analysis/java
JIT ऐप्लिकेशन की इमेज बनाएं:
./mvnw package
टर्मिनल में बिल्ड लॉग देखें:
... [INFO] Results: [INFO] [INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ image-analysis --- [INFO] Building jar: /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis-0.0.1.jar [INFO] [INFO] --- spring-boot-maven-plugin:3.2.0-M3:repackage (repackage) @ image-analysis --- [INFO] Replacing main artifact /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. [INFO] The original artifact has been renamed to /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis-0.0.1.jar.original [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 15.335 s [INFO] Finished at: 2023-10-10T19:33:25Z [INFO] ------------------------------------------------------------------------
नेटिव(एओटी का इस्तेमाल करता है) इमेज बनाएं:.
./mvnw native:compile -Pnative
नेटिव इमेज बिल्ड लॉग के साथ-साथ टर्मिनल में बिल्ड लॉग को देखें:
ध्यान दें कि बिल्ड में काफ़ी ज़्यादा समय लगता है. यह इस बात पर निर्भर करता है कि किस मशीन पर टेस्ट किया जा रहा है.
... [2/7] Performing analysis... [*********] (124.5s @ 4.53GB) 29,732 (93.19%) of 31,905 classes reachable 60,161 (70.30%) of 85,577 fields reachable 261,973 (67.29%) of 389,319 methods reachable 2,940 classes, 2,297 fields, and 97,421 methods registered for reflection 81 classes, 90 fields, and 62 methods registered for JNI access 4 native libraries: dl, pthread, rt, z [3/7] Building universe... (11.7s @ 4.67GB) [4/7] Parsing methods... [***] (6.1s @ 5.91GB) [5/7] Inlining methods... [****] (4.5s @ 4.39GB) [6/7] Compiling methods... [******] (35.3s @ 4.60GB) [7/7] Creating image... (12.9s @ 4.61GB) 80.08MB (47.43%) for code area: 190,483 compilation units 73.81MB (43.72%) for image heap: 660,125 objects and 189 resources 14.95MB ( 8.86%) for other data 168.84MB in total ------------------------------------------------------------------------------------------------------------------------ Top 10 packages in code area: Top 10 object types in image heap: 2.66MB com.google.cloud.vision.v1p4beta1 18.51MB byte[] for code metadata 2.60MB com.google.cloud.vision.v1 9.27MB java.lang.Class 2.49MB com.google.protobuf 7.34MB byte[] for reflection metadata 2.40MB com.google.cloud.vision.v1p3beta1 6.35MB byte[] for java.lang.String 2.17MB com.google.storage.v2 5.72MB java.lang.String 2.12MB com.google.firestore.v1 4.46MB byte[] for embedded resources 1.64MB sun.security.ssl 4.30MB c.oracle.svm.core.reflect.SubstrateMethodAccessor 1.51MB i.g.xds.shaded.io.envoyproxy.envoy.config.core.v3 4.27MB byte[] for general heap data 1.47MB com.google.cloud.vision.v1p2beta1 2.50MB com.oracle.svm.core.hub.DynamicHubCompanion 1.34MB i.g.x.shaded.io.envoyproxy.envoy.config.route.v3 1.17MB java.lang.Object[] 58.34MB for 977 more packages 9.19MB for 4667 more object types ------------------------------------------------------------------------------------------------------------------------ 13.5s (5.7% of total time) in 75 GCs | Peak RSS: 9.44GB | CPU load: 6.13 ------------------------------------------------------------------------------------------------------------------------ Produced artifacts: /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis (executable) /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis.build_artifacts.txt (txt) ======================================================================================================================== Finished generating '/home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis' in 3m 57s. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 04:28 min [INFO] Finished at: 2023-10-10T19:53:30Z [INFO] ------------------------------------------------------------------------
11. कंटेनर की इमेज बनाएं और पब्लिश करें
चलिए, दो अलग-अलग वर्शन में कंटेनर इमेज बनाते हैं: एक JIT image
के तौर पर और दूसरी Native Java image
के तौर पर.
सबसे पहले, GCP प्रोजेक्ट के एनवायरमेंट वैरिएबल सेट करें:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
JIT इमेज बनाएं:.
./mvnw spring-boot:build-image -Pji
टर्मिनल में बिल्ड लॉग देखें:
[INFO] [creator] Timer: Saving docker.io/library/image-analysis-maven-jit:latest... started at 2023-10-10T20:00:31Z [INFO] [creator] *** Images (4c84122a1826): [INFO] [creator] docker.io/library/image-analysis-maven-jit:latest [INFO] [creator] Timer: Saving docker.io/library/image-analysis-maven-jit:latest... ran for 6.975913605s and ended at 2023-10-10T20:00:38Z [INFO] [creator] Timer: Exporter ran for 8.068588001s and ended at 2023-10-10T20:00:38Z [INFO] [creator] Timer: Cache started at 2023-10-10T20:00:38Z [INFO] [creator] Reusing cache layer 'paketo-buildpacks/syft:syft' [INFO] [creator] Adding cache layer 'buildpacksio/lifecycle:cache.sbom' [INFO] [creator] Timer: Cache ran for 200.449002ms and ended at 2023-10-10T20:00:38Z [INFO] [INFO] Successfully built image 'docker.io/library/image-analysis-maven-jit:latest' [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 43.887 s [INFO] Finished at: 2023-10-10T20:00:39Z [INFO] ------------------------------------------------------------------------
एओटी(नेटिव) इमेज बनाएं:.
./mvnw spring-boot:build-image -Pnative
टर्मिनल में बिल्ड लॉग के साथ-साथ नेटिव इमेज बिल्ड लॉग भी देखें.
ध्यान दें:
- इस बिल्ड में काफ़ी ज़्यादा समय लगता है. यह इस बात पर निर्भर करता है कि किस मशीन पर टेस्ट किया जा रहा है
- इमेज को UPX की मदद से और ज़्यादा कंप्रेस किया जा सकता है. हालांकि, उसके स्टार्ट-अप की परफ़ॉर्मेंस पर थोड़ा खराब असर पड़ता है. इसलिए, यह बिल्ड UPX का इस्तेमाल नहीं करता - यह हमेशा थोड़े-बहुत काम का होता है
... [INFO] [creator] Saving docker.io/library/image-analysis-maven-native:latest... [INFO] [creator] *** Images (13167702674e): [INFO] [creator] docker.io/library/image-analysis-maven-native:latest [INFO] [creator] Adding cache layer 'paketo-buildpacks/bellsoft-liberica:native-image-svm' [INFO] [creator] Adding cache layer 'paketo-buildpacks/syft:syft' [INFO] [creator] Adding cache layer 'paketo-buildpacks/native-image:native-image' [INFO] [creator] Adding cache layer 'buildpacksio/lifecycle:cache.sbom' [INFO] [INFO] Successfully built image 'docker.io/library/image-analysis-maven-native:latest' [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 03:37 min [INFO] Finished at: 2023-10-10T20:05:16Z [INFO] ------------------------------------------------------------------------
पुष्टि करें कि इमेज बन गई हैं:
docker images | grep image-analysis
दोनों इमेज को GCR में टैग करें और पुश करें:
# JIT image docker tag image-analysis-maven-jit gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-jit docker push gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-jit # Native(AOT) image docker tag image-analysis-maven-native gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-native docker push gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-native
12. Cloud Run पर डिप्लॉय करें
सेवा को लागू करने का समय.
आपको दो बार सेवा डिप्लॉय करनी होगी. पहली बार JIT इमेज का इस्तेमाल करके और दूसरी बार एओटी(नेटिव) इमेज का इस्तेमाल करके. तुलना के मकसद से, दोनों सर्विस डिप्लॉयमेंट में बकेट से एक ही इमेज को साथ-साथ प्रोसेस करेंगे.
सबसे पहले, GCP प्रोजेक्ट के एनवायरमेंट वैरिएबल सेट करें:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) gcloud config set project ${GOOGLE_CLOUD_PROJECT} gcloud config set run/region gcloud config set run/platform managed gcloud config set eventarc/location europe-west1
JIT इमेज को डिप्लॉय करें और कंसोल में डिप्लॉयमेंट लॉग को देखें:
gcloud run deploy image-analysis-jit \ --image gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-jit \ --region europe-west1 \ --memory 2Gi --allow-unauthenticated ... Deploying container to Cloud Run service [image-analysis-jit] in project [...] region [europe-west1] ✓ Deploying... Done. ✓ Creating Revision... ✓ Routing traffic... ✓ Setting IAM Policy... Done. Service [image-analysis-jit] revision [image-analysis-jvm-00009-huc] has been deployed and is serving 100 percent of traffic. Service URL: https://image-analysis-jit-...-ew.a.run.app
नेटिव इमेज को डिप्लॉय करें और कंसोल में डिप्लॉयमेंट लॉग देखें:
gcloud run deploy image-analysis-native \ --image gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-native \ --region europe-west1 \ --memory 2Gi --allow-unauthenticated ... Deploying container to Cloud Run service [image-analysis-native] in project [...] region [europe-west1] ✓ Deploying... Done. ✓ Creating Revision... ✓ Routing traffic... ✓ Setting IAM Policy... Done. Service [image-analysis-native] revision [image-analysis-native-00005-ben] has been deployed and is serving 100 percent of traffic. Service URL: https://image-analysis-native-...-ew.a.run.app
13. Eventarc ट्रिगर सेट अप करें
Eventarc अलग-अलग माइक्रोसेवाओं के बीच, राज्य में होने वाले बदलावों को मैनेज करने के लिए एक स्टैंडर्ड सलूशन उपलब्ध कराता है. इस प्रोसेस को इवेंट कहा जाता है. ट्रिगर किए जाने पर, Eventarc इन इवेंट को Pub/Sub सदस्यताओं के ज़रिए अलग-अलग डेस्टिनेशन (इस दस्तावेज़ में, इवेंट डेस्टिनेशन देखें) पर रूट करता है. साथ ही, यह आपके लिए डिलीवरी, सुरक्षा, अनुमति, निगरानी करने की सुविधा, और गड़बड़ियों को मैनेज करता है.
आप Eventarc ट्रिगर बना सकते हैं, ताकि आपकी Cloud Run सेवा को किसी खास इवेंट या इवेंट के सेट की सूचनाएं मिलें. ट्रिगर के लिए फ़िल्टर तय करके, इवेंट की रूटिंग को कॉन्फ़िगर किया जा सकता है. इसमें इवेंट का सोर्स और टारगेट Cloud Run सेवा भी शामिल है.
सबसे पहले, GCP प्रोजेक्ट के एनवायरमेंट वैरिएबल सेट करें:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) gcloud config set project ${GOOGLE_CLOUD_PROJECT} gcloud config set run/region gcloud config set run/platform managed gcloud config set eventarc/location europe-west1
Cloud Storage सेवा खाते को pubsub.publisher
दें:
SERVICE_ACCOUNT="$(gsutil kms serviceaccount -p ${GOOGLE_CLOUD_PROJECT})" gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:${SERVICE_ACCOUNT}" \ --role='roles/pubsub.publisher'
इमेज प्रोसेस करने के लिए, JIT और नेटिव सेवा इमेज, दोनों के लिए Eventarc ट्रिगर सेट अप करें:
gcloud eventarc triggers list --location=eu gcloud eventarc triggers create image-analysis-jit-trigger \ --destination-run-service=image-analysis-jit \ --destination-run-region=europe-west1 \ --location=eu \ --event-filters="type=google.cloud.storage.object.v1.finalized" \ --event-filters="bucket=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}" \ --service-account=${PROJECT_NUMBER}-compute@developer.gserviceaccount.com gcloud eventarc triggers create image-analysis-native-trigger \ --destination-run-service=image-analysis-native \ --destination-run-region=europe-west1 \ --location=eu \ --event-filters="type=google.cloud.storage.object.v1.finalized" \ --event-filters="bucket=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}" \ --service-account=${PROJECT_NUMBER}-compute@developer.gserviceaccount.com
देखें कि दोनों ट्रिगर बनाए गए हैं:
gcloud eventarc triggers list --location=eu
14. परीक्षण सेवा वर्शन
सेवा के डिप्लॉयमेंट की प्रोसेस पूरी होने के बाद, आपको Cloud Storage में एक तस्वीर पोस्ट करनी होगी. साथ ही, आपको यह पता करना होगा कि हमारी सेवाएं चालू हुई हैं या नहीं, Vision API ने क्या दिखाया है, और क्या डेटा Firestore में सेव हो गया है.
Cloud Storage
पर वापस जाएं और उस बकेट पर क्लिक करें जो हमने लैब की शुरुआत में बनाई थी:
बकेट की ज़्यादा जानकारी वाले पेज पर जाने के बाद, तस्वीर अपलोड करने के लिए Upload files
बटन पर क्लिक करें.
उदाहरण के लिए, /services/image-analysis/java
के तहत आपके कोड बेस के साथ एक GeekHour.jpeg
इमेज दी जाती है. कोई इमेज चुनें और Open button
दबाएं:
अब आपके पास सेवा के लागू होने की जांच करने का विकल्प है. इसकी शुरुआत image-analysis-jit
से होती है और इसके बाद image-analysis-native
आती है.
"हैमबर्गर" से (भरोसेमंद) मेन्यू, Cloud Run > image-analysis-jit
सेवा पर जाएं.
लॉग पर क्लिक करें और आउटपुट देखें:
लॉग की सूची में देखा जा सकता है कि JIT सेवा image-analysis-jit
को शुरू किया गया था.
लॉग, सेवा के चलने और उसके खत्म होने के बारे में बताते हैं. साथ ही, इनके बीच में हम लॉग स्टेटमेंट के साथ उन लॉग को देख सकते हैं जिन्हें हमने फ़ंक्शन में शामिल किया है. यह जानकारी, INFO के स्तर पर देखी जा सकती है. हम देखते हैं:
- हमारे फ़ंक्शन को ट्रिगर करने वाले इवेंट का ब्यौरा,
- Vision API कॉल से मिले रॉ नतीजे,
- हमारी अपलोड की गई तस्वीर में मिले लेबल,
- रंगों की मुख्य जानकारी,
- क्या तस्वीर सुरक्षित है या नहीं,
- आखिर में, तस्वीर से जुड़ा वह मेटाडेटा Firestore में सेव कर दिया जाता है.
image-analysis-native
सेवा के लिए यह प्रोसेस दोहराई जाएगी.
"हैमबर्गर" से (भरोसेमंद) मेन्यू, Cloud Run > image-analysis-native
सेवा पर जाएं.
लॉग पर क्लिक करें और आउटपुट देखें:
अब आपको यह देखना होगा कि इमेज का मेटाडेटा, Fiorestore में स्टोर हुआ है या नहीं.
"हैमबर्गर" से फिर से (RECORD) मेन्यू, Firestore
सेक्शन पर जाएं. Data
सब-सेक्शन (डिफ़ॉल्ट रूप से दिखाया जाता है) में, आपको pictures
कलेक्शन दिखेगा. इसमें एक नया दस्तावेज़ जोड़ा गया है. यह कलेक्शन, आपकी अपलोड की गई तस्वीर से जुड़ा होगा:
15. स्टोरेज खाली करें (ज़रूरी नहीं)
अगर आपको सीरीज़ में मौजूद अन्य लैब का इस्तेमाल जारी नहीं रखना है, तो संसाधनों को इकट्ठा करके खर्च बचाया जा सकता है और क्लाउड पर अच्छा नागरिक बनाया जा सकता है. यहां बताए गए तरीके से, अलग-अलग संसाधनों को खाली किया जा सकता है.
बकेट मिटाना:
gsutil rb gs://${BUCKET_PICTURES}
फ़ंक्शन मिटाएं:
gcloud functions delete picture-uploaded --region europe-west1 -q
कलेक्शन से कलेक्शन मिटाएं को चुनकर, Firestore कलेक्शन मिटाएं:
इसके अलावा, पूरा प्रोजेक्ट मिटाया जा सकता है:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
16. बधाई हो!
बधाई हो! आपने इस प्रोजेक्ट की पहली कुंजी मैनेज करने वाली सेवा को लागू कर दिया है!
इसमें हमने इन विषयों के बारे में बताया
- Cloud Storage
- Cloud Run
- क्लाउड विज़न एपीआई
- Cloud Firestore
- स्थानीय Java इमेज