Pic-a-daily: จัดเก็บและวิเคราะห์รูปภาพด้วยไลบรารีของไคลเอ็นต์ Java Native ของ Google

1. ภาพรวม

ใน Code Lab ครั้งแรก คุณจะต้องเก็บรูปภาพไว้ในที่เก็บข้อมูล การดำเนินการนี้จะสร้างเหตุการณ์การสร้างไฟล์ที่จะจัดการโดยบริการที่ทำให้ใช้งานได้ใน Cloud Run บริการจะเรียกใช้ Vision API เพื่อทำการวิเคราะห์รูปภาพและบันทึกผลลัพธ์ในพื้นที่เก็บข้อมูล

427de3100de3a61e.png

สิ่งที่คุณจะได้เรียนรู้

  • Cloud Storage
  • Cloud Run
  • Cloud Vision API
  • Cloud Firestore

2. การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก

  1. ลงชื่อเข้าใช้ Google Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • ชื่อโครงการคือชื่อที่แสดงของผู้เข้าร่วมโปรเจ็กต์นี้ เป็นสตริงอักขระที่ Google APIs ไม่ได้ใช้ โดยคุณจะอัปเดตได้ทุกเมื่อ
  • รหัสโปรเจ็กต์ต้องไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมดและจะเปลี่ยนแปลงไม่ได้ (เปลี่ยนแปลงไม่ได้หลังจากตั้งค่าแล้ว) Cloud Console จะสร้างสตริงที่ไม่ซ้ำกันโดยอัตโนมัติ ปกติแล้วคุณไม่สนว่าอะไรเป็นอะไร ใน Codelab ส่วนใหญ่ คุณจะต้องอ้างอิงรหัสโปรเจ็กต์ (โดยปกติจะระบุเป็น PROJECT_ID) หากคุณไม่ชอบรหัสที่สร้างขึ้น คุณสามารถสร้างรหัสแบบสุ่มอื่นได้ หรือคุณจะลองดำเนินการเองแล้วดูว่าพร้อมให้บริการหรือไม่ และไม่สามารถเปลี่ยนแปลงได้หลังจากขั้นตอนนี้และจะยังคงอยู่ตลอดระยะเวลาของโปรเจ็กต์
  • สำหรับข้อมูลของคุณ ค่าที่ 3 คือหมายเลขโปรเจ็กต์ที่ API บางตัวใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับค่าทั้ง 3 ค่าเหล่านี้ในเอกสารประกอบ
  1. ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร/API ของระบบคลาวด์ การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี หากต้องการปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ คุณสามารถลบทรัพยากรที่คุณสร้างหรือลบทั้งโปรเจ็กต์ได้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD

เริ่มต้น Cloud Shell

แม้ว่าคุณจะดำเนินการ Google Cloud จากระยะไกลได้จากแล็ปท็อป แต่คุณจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมแบบบรรทัดคำสั่งที่ทำงานในระบบคลาวด์ใน Codelab นี้

จากคอนโซล Google Cloud ให้คลิกไอคอน Cloud Shell ในแถบเครื่องมือด้านขวาบน ดังนี้

55efc1aaa7a4d3ad.png

การจัดสรรและเชื่อมต่อกับสภาพแวดล้อมนี้ควรใช้เวลาเพียงครู่เดียว เมื่อเสร็จแล้ว คุณจะเห็นข้อมูลต่อไปนี้

7ffe5cbb04455448.png

เครื่องเสมือนนี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ใช้งานได้ต่อเนื่องและทำงานบน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก งานทั้งหมดใน Codelab นี้ทำได้ในเบราว์เซอร์ คุณไม่จำเป็นต้องติดตั้งอะไรเลย

3. เปิดใช้ API

สำหรับห้องทดลองนี้ คุณจะใช้ Cloud Functions และ Vision API แต่ต้องเปิดใช้ใน Cloud Console หรือด้วย gcloud ก่อน

หากต้องการเปิดใช้ Vision API ใน Cloud Console ให้ค้นหา Cloud Vision API ในแถบค้นหา

cf48b1747ba6a6fb.png

คุณจะเข้าสู่หน้า Cloud Vision API:

ba4af419e6086fbb.png

คลิกปุ่ม 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) หรือด้วยเครื่องมือบรรทัดคำสั่ง gsutil จาก Cloud Shell หรือสภาพแวดล้อมการพัฒนาในเครื่อง

จาก "แฮมเบอร์เกอร์" (⋮) ให้ไปที่หน้า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 เพื่อสร้างที่เก็บข้อมูลขั้นสุดท้าย

เพิ่ม allUsers เป็นผู้ดูพื้นที่เก็บข้อมูล

ไปที่แท็บ Permissions:

d0ecfdcff730ea51.png

เพิ่มสมาชิก allUsers ไปยังที่เก็บข้อมูล โดยมีบทบาทเป็น Storage > Storage Object Viewer ดังนี้

e9f25ec1ea0b6cc6.png

คลิก SAVE

5. สร้างที่เก็บข้อมูล (gsutil)

คุณยังใช้เครื่องมือบรรทัดคำสั่ง gsutil ใน Cloud Shell เพื่อสร้างที่เก็บข้อมูลได้ด้วย

ใน 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 สาธารณะ

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. เตรียมฐานข้อมูล

คุณจะจัดเก็บข้อมูลเกี่ยวกับรูปภาพที่ได้รับจาก Vision API ไว้ในฐานข้อมูล Cloud Firestore ซึ่งเป็นฐานข้อมูลเอกสาร NoSQL ที่ดำเนินการบนระบบคลาวด์และทำงานได้อย่างรวดเร็ว มีการจัดการครบวงจร เตรียมฐานข้อมูลด้วยการไปที่ส่วน Firestore ของ Cloud Console:

9e4708d2257de058.png

โดยมี 2 ตัวเลือก ได้แก่ Native mode หรือ Datastore mode ใช้โหมดเนทีฟซึ่งมีฟีเจอร์เพิ่มเติม เช่น การรองรับการใช้งานออฟไลน์และการซิงค์ข้อมูลแบบเรียลไทม์

คลิก SELECT NATIVE MODE

9449ace8cc84de43.png

เลือกหลายภูมิภาค (ที่นี่ในยุโรป แต่อย่างน้อยควรเป็นภูมิภาคเดียวกับฟังก์ชันและที่เก็บข้อมูลของพื้นที่เก็บข้อมูล)

คลิกปุ่ม CREATE DATABASE

เมื่อสร้างฐานข้อมูลแล้ว คุณจะเห็นสิ่งต่อไปนี้

56265949a124819e.png

สร้างคอลเล็กชันใหม่โดยคลิกปุ่ม + START COLLECTION

ชื่อคอลเล็กชัน pictures

75806ee24c4e13a7.png

คุณไม่ต้องสร้างเอกสาร คุณจะเพิ่มรูปภาพเหล่านั้นโดยใช้โปรแกรมเมื่อมีการจัดเก็บรูปภาพใหม่ใน Cloud Storage และวิเคราะห์โดย Vision API

คลิก Save

Firestore สร้างเอกสารเริ่มต้นรายการแรกในคอลเล็กชันที่สร้างขึ้นใหม่ คุณลบเอกสารดังกล่าวได้อย่างปลอดภัยเนื่องจากไม่มีข้อมูลที่เป็นประโยชน์ใดๆ ดังต่อไปนี้

5c2f1e17ea47f48f.png

เอกสารที่จะสร้างขึ้นแบบเป็นโปรแกรมในคอลเล็กชันของเราประกอบด้วย 4 ฟิลด์ ดังนี้

  • name (สตริง): ชื่อไฟล์ของรูปภาพที่อัปโหลด ซึ่งเป็นคีย์ของเอกสาร
  • labels (อาร์เรย์ของสตริง): ป้ายกำกับของรายการที่รู้จักโดย Vision API
  • color (สตริง): รหัสสีเลขฐาน 16 ของสีหลัก (เช่น #ab12ef)
  • สร้าง (วันที่): การประทับเวลาที่เก็บข้อมูลเมตาของรูปภาพนี้
  • ภาพขนาดย่อ (บูลีน): ช่องที่ไม่บังคับซึ่งจะแสดงและเป็น "จริง" หากมีการสร้างภาพขนาดย่อสำหรับรูปภาพนี้

เนื่องจากเราจะค้นหาใน 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 ในคอลัมน์การนำทางด้านซ้าย แล้วสร้างดัชนีผสมดังที่แสดงด้านล่างก็ได้

ecb8b95e3c791272.png

คลิก Create การสร้างดัชนีอาจใช้เวลาสักครู่

8. โคลนโค้ด

โคลนโค้ดหากยังไม่ได้ทำใน Code Lab ก่อนหน้านี้:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

จากนั้นคุณสามารถไปที่ไดเรกทอรีที่มีบริการเพื่อเริ่มสร้าง Lab:

cd serverless-photosharing-workshop/services/image-analysis/java

คุณจะมีการจัดวางไฟล์ดังต่อไปนี้สำหรับบริการ:

f79613aff479d8ad.png

9. สำรวจรหัสบริการ

คุณเริ่มต้นด้วยการดูวิธีเปิดใช้ไลบรารีไคลเอ็นต์ Java ใน pom.xml โดยใช้ BOM ดังนี้

ก่อนอื่น ให้แก้ไขไฟล์ pom.xml ซึ่งแสดงรายการทรัพยากร Dependency ของฟังก์ชัน Java อัปเดตโค้ดเพื่อเพิ่มทรัพยากร Dependency ของ Cloud Vision 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>

มีการติดตั้งใช้งานฟังก์ชันนี้ในคลาส 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);
} 

สร้างคำขอได้แล้ว โค้ดจะเตรียมคำขอดังกล่าว 1 รายการให้ส่งไปยัง 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);

เราขอแนะนำความสามารถหลัก 3 อย่างของ 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) {
    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());
}

10. สร้างรูปภาพแอปด้วย GraalVM (ไม่บังคับ)

ในขั้นตอนที่ไม่บังคับนี้ คุณจะสร้าง JIT(JVM) based app image แล้วตามด้วย AOT(Native) Java app image โดยใช้ GraalVM

หากต้องการเรียกใช้บิลด์ คุณจะต้องตรวจสอบว่าได้ติดตั้งและกําหนดค่า JDK และเครื่องมือสร้างรูปภาพเนทีฟที่เหมาะสมแล้ว ซึ่งมีหลายตัวเลือกให้ใช้งาน

To start ให้ดาวน์โหลด GraalVM 22.2.x Community Edition และทำตามวิธีการในหน้าการติดตั้ง GraalVM

ขั้นตอนนี้สามารถทำได้ง่ายมากด้วยความช่วยเหลือของ SDKMAN!

หากต้องการติดตั้งการกระจาย JDK ที่เหมาะสมด้วย SDKman ให้เริ่มต้นโดยใช้คำสั่งติดตั้ง ดังนี้

sdk install java 22.2.r17-grl

สั่งให้ SDKman ใช้เวอร์ชันนี้สำหรับทั้งบิลด์ JIT และ AOT:

sdk use java 22.2.0.r17-grl

ติดตั้ง native-image utility สำหรับ GraalVM:

gu install native-image

เพื่อความสะดวกของคุณ คุณสามารถติดตั้ง GraalVM และยูทิลิตีรูปภาพแบบเนทีฟใน Cloudshell ด้วยคำสั่งง่ายๆ ต่อไปนี้

# install GraalVM in your home directory
cd ~

# download GraalVM
wget https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.2.0/graalvm-ce-java17-linux-amd64-22.2.0.tar.gz
ls
tar -xzvf graalvm-ce-java17-linux-amd64-22.2.0.tar.gz

# configure Java 17 and GraalVM 22.2
echo Existing JVM: $JAVA_HOME
cd graalvm-ce-java17-22.2.0
export JAVA_HOME=$PWD
cd bin
export PATH=$PWD:$PATH

echo JAVA HOME: $JAVA_HOME
echo PATH: $PATH

# install the native image utility
java -version
gu install native-image

cd ../..

ขั้นแรก ให้ตั้งค่าตัวแปรสภาพแวดล้อมโปรเจ็กต์ GCP ดังนี้

export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)

จากนั้นคุณสามารถไปที่ไดเรกทอรีที่มีบริการเพื่อเริ่มสร้าง Lab:

cd serverless-photosharing-workshop/services/image-analysis/java

สร้างอิมเมจแอปพลิเคชัน JIT(JVM) ด้วยคำสั่งต่อไปนี้

./mvnw package -Pjvm

สังเกตบันทึกของบิลด์ในเทอร์มินัลด้วยคำสั่งต่อไปนี้

...
[INFO] --- spring-boot-maven-plugin:2.7.3:repackage (repackage) @ image-analysis ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  24.009 s
[INFO] Finished at: 2022-09-26T22:17:32-04:00
[INFO] ------------------------------------------------------------------------

สร้างอิมเมจ AOT(เนทีฟ)

./mvnw package -Pnative -DskipTests

สังเกตบันทึกของบิลด์ในเทอร์มินัล รวมถึงบันทึกของบิลด์อิมเมจในเครื่อง

โปรดทราบว่าบิลด์จะใช้เวลานานกว่าเล็กน้อย ทั้งนี้ขึ้นอยู่กับเครื่องที่คุณกำลังทดสอบ

...
[2/7] Performing analysis...  [**********]                                                              (95.4s @ 3.57GB)
  23,346 (94.42%) of 24,725 classes reachable
  44,625 (68.71%) of 64,945 fields reachable
 163,759 (70.79%) of 231,322 methods reachable
     989 classes, 1,402 fields, and 11,032 methods registered for reflection
      63 classes,    69 fields, and    55 methods registered for JNI access
       5 native libraries: -framework CoreServices, -framework Foundation, dl, pthread, z
[3/7] Building universe...                                                                              (10.0s @ 5.35GB)
[4/7] Parsing methods...      [***]                                                                      (9.7s @ 3.13GB)
[5/7] Inlining methods...     [***]                                                                      (4.5s @ 3.29GB)
[6/7] Compiling methods...    [[6/7] Compiling methods...    [********]                                                                (67.6s @ 5.72GB)
[7/7] Creating image...                                                                                  (8.7s @ 4.59GB)
  62.21MB (54.80%) for code area:   100,371 compilation units
  50.98MB (44.91%) for image heap:  465,035 objects and 365 resources
 337.09KB ( 0.29%) for other data
 113.52MB in total
------------------------------------------------------------------------------------------------------------------------
Top 10 packages in code area:                               Top 10 object types in image heap:
   2.36MB com.google.protobuf                                 12.70MB byte[] for code metadata
   1.90MB i.g.xds.shaded.io.envoyproxy.envoy.config.core.v3    6.66MB java.lang.Class
   1.73MB i.g.x.shaded.io.envoyproxy.envoy.config.route.v3     6.47MB byte[] for embedded resources
   1.67MB sun.security.ssl                                     4.61MB byte[] for java.lang.String
   1.54MB com.google.cloud.vision.v1                           4.37MB java.lang.String
   1.46MB com.google.firestore.v1                              3.38MB byte[] for general heap data
   1.37MB io.grpc.xds.shaded.io.envoyproxy.envoy.api.v2.core   1.96MB com.oracle.svm.core.hub.DynamicHubCompanion
   1.32MB i.g.xds.shaded.io.envoyproxy.envoy.api.v2.route      1.80MB byte[] for reflection metadata
   1.09MB java.util                                          911.80KB java.lang.String[]
   1.08MB com.google.re2j                                    826.48KB c.o.svm.core.hub.DynamicHub$ReflectionMetadata
  45.91MB for 772 more packages                                6.45MB for 3913 more object types
------------------------------------------------------------------------------------------------------------------------
                        15.1s (6.8% of total time) in 56 GCs | Peak RSS: 7.72GB | CPU load: 4.37
------------------------------------------------------------------------------------------------------------------------
Produced artifacts:
 /Users/ddobrin/work/dan/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis (executable)
 /Users/ddobrin/work/dan/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis.build_artifacts.txt (txt)
========================================================================================================================
Finished generating 'image-analysis' in 3m 41s.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  03:56 min
[INFO] Finished at: 2022-09-26T22:22:29-04:00
[INFO] ------------------------------------------------------------------------

11. สร้างและเผยแพร่อิมเมจคอนเทนเนอร์

ลองสร้างอิมเมจคอนเทนเนอร์ใน 2 เวอร์ชันที่แตกต่างกัน ได้แก่ เวอร์ชันหนึ่งเป็น JIT(JVM) image และอีกเวอร์ชันเป็น AOT(Native) Java image

ขั้นแรก ให้ตั้งค่าตัวแปรสภาพแวดล้อมโปรเจ็กต์ GCP ดังนี้

export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)

สร้างอิมเมจ JIT(JVM)

./mvnw package -Pjvm-image

สังเกตบันทึกของบิลด์ในเทอร์มินัลด้วยคำสั่งต่อไปนี้

[INFO]     [creator]     Adding layer 'process-types'
[INFO]     [creator]     Adding label 'io.buildpacks.lifecycle.metadata'
[INFO]     [creator]     Adding label 'io.buildpacks.build.metadata'
[INFO]     [creator]     Adding label 'io.buildpacks.project.metadata'
[INFO]     [creator]     Adding label 'org.opencontainers.image.title'
[INFO]     [creator]     Adding label 'org.opencontainers.image.version'
[INFO]     [creator]     Adding label 'org.springframework.boot.version'
[INFO]     [creator]     Setting default process type 'web'
[INFO]     [creator]     Saving docker.io/library/image-analysis-jvm:r17...
[INFO]     [creator]     *** Images (03a44112456e):
[INFO]     [creator]           docker.io/library/image-analysis-jvm:r17
[INFO]     [creator]     Adding cache layer 'paketo-buildpacks/syft:syft'
[INFO]     [creator]     Adding cache layer 'cache.sbom'
[INFO] 
[INFO] Successfully built image 'docker.io/library/image-analysis-jvm:r17'
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:11 min
[INFO] Finished at: 2022-09-26T13:09:34-04:00
[INFO] ------------------------------------------------------------------------

สร้างอิมเมจ AOT(เนทีฟ)

./mvnw package -Pnative-image

สังเกตบันทึกของบิลด์ในเทอร์มินัล รวมถึงบันทึกบิลด์ของรูปภาพในเครื่องและการบีบอัดรูปภาพโดยใช้ UPX

โปรดทราบว่าบิลด์จะใช้เวลานานกว่าเล็กน้อย ทั้งนี้ขึ้นอยู่กับเครื่องที่คุณกำลังทดสอบ

...
[INFO]     [creator]     [2/7] Performing analysis...  [***********]                    (147.6s @ 3.10GB)
[INFO]     [creator]       23,362 (94.34%) of 24,763 classes reachable
[INFO]     [creator]       44,657 (68.67%) of 65,029 fields reachable
[INFO]     [creator]      163,926 (70.76%) of 231,656 methods reachable
[INFO]     [creator]          981 classes, 1,402 fields, and 11,026 methods registered for reflection
[INFO]     [creator]           63 classes,    68 fields, and    55 methods registered for JNI access
[INFO]     [creator]            4 native libraries: dl, pthread, rt, z
[INFO]     [creator]     [3/7] Building universe...                                      (21.1s @ 2.66GB)
[INFO]     [creator]     [4/7] Parsing methods...      [****]                            (13.7s @ 4.16GB)
[INFO]     [creator]     [5/7] Inlining methods...     [***]                              (9.6s @ 4.20GB)
[INFO]     [creator]     [6/7] Compiling methods...    [**********]                     (107.6s @ 3.36GB)
[INFO]     [creator]     [7/7] Creating image...                                         (14.7s @ 4.87GB)
[INFO]     [creator]       62.24MB (51.35%) for code area:   100,499 compilation units
[INFO]     [creator]       51.99MB (42.89%) for image heap:  473,948 objects and 473 resources
[INFO]     [creator]        6.98MB ( 5.76%) for other data
[INFO]     [creator]      121.21MB in total
[INFO]     [creator]     --------------------------------------------------------------------------------
[INFO]     [creator]     Top 10 packages in code area:           Top 10 object types in image heap:
[INFO]     [creator]        2.36MB com.google.protobuf             12.71MB byte[] for code metadata
[INFO]     [creator]        1.90MB i.g.x.s.i.e.e.config.core.v3     7.59MB byte[] for embedded resources
[INFO]     [creator]        1.73MB i.g.x.s.i.e.e.config.route.v3    6.66MB java.lang.Class
[INFO]     [creator]        1.67MB sun.security.ssl                 4.62MB byte[] for java.lang.String
[INFO]     [creator]        1.54MB com.google.cloud.vision.v1       4.39MB java.lang.String
[INFO]     [creator]        1.46MB com.google.firestore.v1          3.66MB byte[] for general heap data
[INFO]     [creator]        1.37MB i.g.x.s.i.e.envoy.api.v2.core    1.96MB c.o.s.c.h.DynamicHubCompanion
[INFO]     [creator]        1.32MB i.g.x.s.i.e.e.api.v2.route       1.80MB byte[] for reflection metadata
[INFO]     [creator]        1.09MB java.util                      910.41KB java.lang.String[]
[INFO]     [creator]        1.08MB com.google.re2j                826.95KB c.o.s.c.h.DynamicHu~onMetadata
[INFO]     [creator]       45.94MB for 776 more packages            6.69MB for 3916 more object types
[INFO]     [creator]     --------------------------------------------------------------------------------
[INFO]     [creator]         20.4s (5.6% of total time) in 81 GCs | Peak RSS: 6.75GB | CPU load: 4.53
[INFO]     [creator]     --------------------------------------------------------------------------------
[INFO]     [creator]     Produced artifacts:
[INFO]     [creator]      /layers/paketo-buildpacks_native-image/native-image/services.ImageAnalysisApplication (executable)
[INFO]     [creator]      /layers/paketo-buildpacks_native-image/native-image/services.ImageAnalysisApplication.build_artifacts.txt (txt)
[INFO]     [creator]     ================================================================================
[INFO]     [creator]     Finished generating '/layers/paketo-buildpacks_native-image/native-image/services.ImageAnalysisApplication' in 5m 59s.
[INFO]     [creator]         Executing upx to compress native image
[INFO]     [creator]                            Ultimate Packer for eXecutables
[INFO]     [creator]                               Copyright (C) 1996 - 2020
[INFO]     [creator]     UPX 3.96        Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 23rd 2020
[INFO]     [creator]     
[INFO]     [creator]             File size         Ratio      Format      Name
[INFO]     [creator]        --------------------   ------   -----------   -----------
 127099880 ->  32416676   25.50%   linux/amd64   services.ImageAnalysisApplication
...
[INFO]     [creator]     ===> EXPORTING
...
[INFO]     [creator]     Adding cache layer 'paketo-buildpacks/native-image:native-image'
[INFO]     [creator]     Adding cache layer 'cache.sbom'
[INFO] 
[INFO] Successfully built image 'docker.io/library/image-analysis-native:r17'
------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  05:28 min
[INFO] Finished at: 2022-09-26T13:19:53-04:00
[INFO] ------------------------------------------------------------------------

ตรวจสอบว่ารูปภาพสร้างขึ้นแล้วโดยทำดังนี้

docker images | grep image-analysis

ติดแท็กและพุชรูปภาพ 2 รูปไปยัง GCR ดังนี้

# JIT(JVM) image
docker tag image-analysis-jvm:r17 gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-jvm:r17
docker push gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-jvm:r17

# AOT(Native) image
docker tag image-analysis-native:r17 gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-native:r17
docker push  gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-native:r17

12. ทำให้ใช้งานได้กับ Cloud Run

ได้เวลาทำให้บริการใช้งานได้แล้ว

คุณจะต้องติดตั้งใช้งานบริการ 2 ครั้ง โดยครั้งแรกใช้อิมเมจ JIT(JVM) และครั้งที่ 2 ใช้อิมเมจ AOT(เนทีฟ) การทำให้บริการใช้งานได้ทั้ง 2 รายการจะประมวลผลอิมเมจเดียวกันจากที่เก็บข้อมูลพร้อมกัน เพื่อจุดประสงค์ในการเปรียบเทียบ

ขั้นแรก ให้ตั้งค่าตัวแปรสภาพแวดล้อมโปรเจ็กต์ 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(JVM) ใช้งานได้และสังเกตบันทึกการทำให้ใช้งานได้ในคอนโซล โดยทำดังนี้

gcloud run deploy image-analysis-jvm \
     --image gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-jvm:r17 \
     --region europe-west1 \
     --memory 2Gi --allow-unauthenticated

...
Deploying container to Cloud Run service [image-analysis-jvm] in project [...] region [europe-west1]
✓ Deploying... Done.                                                                                                                                                               
  ✓ Creating Revision...                                                                                                                                                           
  ✓ Routing traffic...                                                                                                                                                             
  ✓ Setting IAM Policy...                                                                                                                                                          
Done.                                                                                                                                                                              
Service [image-analysis-jvm] revision [image-analysis-jvm-00009-huc] has been deployed and is serving 100 percent of traffic.
Service URL: https://image-analysis-jvm-...-ew.a.run.app

ทำให้อิมเมจ AOT(เนทีฟ) ใช้งานได้และสังเกตบันทึกการทำให้ใช้งานได้ในคอนโซล โดยทำดังนี้

gcloud run deploy image-analysis-native \
     --image gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-native:r17 \
     --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 นำเสนอโซลูชันที่เป็นมาตรฐานเพื่อจัดการโฟลว์ของการเปลี่ยนแปลงสถานะ ซึ่งเรียกว่าเหตุการณ์ ระหว่าง Microservice ที่แยกส่วนออกจากกัน เมื่อทริกเกอร์ 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

ให้สิทธิ์ pubsub.publisher แก่บัญชีบริการ Cloud Storage:

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'

ตั้งค่าทริกเกอร์ Eventarc สำหรับทั้งอิมเมจบริการ JVM(JIT) และ AOT(เนทีฟ) เพื่อประมวลผลอิมเมจ ดังนี้

gcloud eventarc triggers list --location=eu

gcloud eventarc triggers create image-analysis-jvm-trigger \
     --destination-run-service=image-analysis-jvm \
     --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    

สังเกตว่ามีการสร้างทริกเกอร์ 2 ตัว ดังนี้

gcloud eventarc triggers list --location=eu

14. เวอร์ชันบริการทดสอบ

เมื่อการทำให้บริการใช้งานได้เสร็จสมบูรณ์แล้ว คุณจะโพสต์รูปภาพไปยัง Cloud Storage, ดูว่ามีการเรียกใช้บริการของเราหรือไม่, Vision API แสดงผลใดบ้าง และข้อมูลเมตาเก็บไว้ใน Firestore หรือไม่

กลับไปที่ Cloud Storage แล้วคลิกที่เก็บข้อมูลที่เราสร้างไว้เมื่อเริ่มต้นห้องทดลอง

ff8a6567afc76235.png

เมื่ออยู่ในหน้ารายละเอียดที่เก็บข้อมูล ให้คลิกปุ่ม Upload files เพื่ออัปโหลดรูปภาพ

เช่น รูปภาพ GeekHour.jpeg จะมาพร้อมกับฐานของโค้ดภายใต้ /services/image-analysis/java เลือกรูปภาพแล้วกด Open button:

347b76e8b775f2f5.png

ตอนนี้คุณตรวจสอบการดำเนินการของบริการได้แล้ว โดยเริ่มจาก image-analysis-jvm ตามด้วย image-analysis-native

จาก "แฮมเบอร์เกอร์" (⋮) ให้ไปที่บริการ Cloud Run > image-analysis-jvm

คลิกบันทึกและสังเกตผลลัพธ์ ดังนี้

810a8684414ceafa.png

อันที่จริง ในรายการของบันทึก เราพบว่ามีการเรียกใช้บริการ JIT(JVM) image-analysis-jvm

บันทึกจะระบุการเริ่มต้นและสิ้นสุดการเรียกใช้บริการ และระหว่างนั้น เราจะเห็นบันทึกที่เราใส่ไว้ในฟังก์ชันพร้อมด้วยคำสั่งบันทึกที่ระดับ INFO เราพบว่า

  • รายละเอียดของเหตุการณ์ที่ทริกเกอร์ฟังก์ชันของเรา
  • ผลลัพธ์ดิบจากการเรียก Vision API
  • ป้ายกำกับที่พบในภาพที่เราอัปโหลด
  • ข้อมูลสีที่โดดเด่น
  • รูปภาพปลอดภัยที่จะแสดงหรือไม่
  • และท้ายที่สุดแล้วระบบได้จัดเก็บข้อมูลเมตาเกี่ยวกับรูปภาพไว้ใน Firestore

คุณจะทำขั้นตอนนี้ซ้ำสำหรับบริการ image-analysis-native

จาก "แฮมเบอร์เกอร์" (⋮) ให้ไปที่บริการ Cloud Run > image-analysis-native

คลิกบันทึกและสังเกตผลลัพธ์ ดังนี้

b80308c7d0f55a3.png

คุณจะต้องตรวจสอบว่าข้อมูลเมตาของรูปภาพจัดเก็บอยู่ใน Fiorestore หรือไม่

อีกครั้งจาก "แฮมเบอร์เกอร์" (src) ไปที่ส่วน Firestore ในส่วนย่อย Data (แสดงโดยค่าเริ่มต้น) คุณจะเห็นคอลเล็กชัน pictures ที่มีเอกสารใหม่เพิ่มเข้ามา ซึ่งจะสอดคล้องกับภาพที่คุณเพิ่งอัปโหลด

933a20a9709cb006.png

15. ล้างข้อมูล (ไม่บังคับ)

หากไม่ต้องการใช้ห้องทดลองอื่นๆ ในชุดนี้ต่อ คุณสามารถล้างทรัพยากรเพื่อประหยัดต้นทุนและเป็นพลเมืองระบบคลาวด์ที่ดีโดยรวม คุณสามารถล้างทรัพยากรแต่ละรายการได้ดังนี้

ลบที่เก็บข้อมูล

gsutil rb gs://${BUCKET_PICTURES}

ลบฟังก์ชัน

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

ลบคอลเล็กชัน Firestore โดยเลือก "ลบคอลเล็กชัน" ออกจากคอลเล็กชัน ดังนี้

410b551c3264f70a.png

หรือจะลบทั้งโปรเจ็กต์ก็ได้ โดยทำดังนี้

gcloud projects delete ${GOOGLE_CLOUD_PROJECT} 

16. ยินดีด้วย

ยินดีด้วย คุณใช้งานบริการจัดการคีย์แรกของโปรเจ็กต์เรียบร้อยแล้ว

หัวข้อที่ครอบคลุม

  • Cloud Storage
  • Cloud Run
  • Cloud Vision API
  • Cloud Firestore
  • รูปภาพ Java เนทีฟ

ขั้นตอนถัดไป