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

1. ภาพรวม

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

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 ของ Cloud การทำตาม Codelab นี้ไม่ควรมีค่าใช้จ่ายมากนัก หรืออาจไม่มีเลย หากต้องการปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ คุณสามารถลบทรัพยากรที่สร้างขึ้นหรือลบทั้งโปรเจ็กต์ได้ ผู้ใช้ Google Cloud รายใหม่มีสิทธิ์เข้าร่วมโปรแกรมช่วงทดลองใช้ฟรีมูลค่า$300 USD

เริ่มต้น Cloud Shell

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

จาก Google Cloud Console ให้คลิกไอคอน 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. สร้างที่เก็บข้อมูล (คอนโซล)

สร้าง Bucket ของพื้นที่เก็บข้อมูลสำหรับรูปภาพ คุณทำได้จากคอนโซล Google Cloud Platform ( console.cloud.google.com) หรือใช้เครื่องมือบรรทัดคำสั่ง gsutil จาก Cloud Shell หรือสภาพแวดล้อมการพัฒนาในเครื่อง

จากเมนู "แฮมเบอร์เกอร์" (☰) ให้ไปที่หน้า Storage

1930e055d138150a.png

ตั้งชื่อที่เก็บข้อมูล

คลิกปุ่ม CREATE BUCKET

34147939358517f8.png

คลิก CONTINUE

เลือกตำแหน่ง

197817f20be07678.png

สร้าง Bucket แบบหลายภูมิภาคในภูมิภาคที่คุณเลือก (ในที่นี้คือ Europe)

คลิก CONTINUE

เลือกคลาสพื้นที่เก็บข้อมูลเริ่มต้น

53cd91441c8caf0e.png

เลือกคลาสพื้นที่เก็บข้อมูล Standard สำหรับข้อมูล

คลิก CONTINUE

ตั้งค่าการควบคุมการเข้าถึง

8c2b3b459d934a51.png

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

เลือกตัวเลือกการควบคุมการเข้าถึง Uniform

คลิก CONTINUE

ตั้งค่าการปกป้อง/การเข้ารหัส

d931c24c3e705a68.png

คงค่าเริ่มต้น (Google-managed key)) ไว้ เนื่องจากคุณจะไม่ใช้คีย์การเข้ารหัสของคุณเอง

คลิก CREATE เพื่อสร้าง Bucket ให้เสร็จสมบูรณ์

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

ไปที่แท็บ Permissions โดยทำดังนี้

d0ecfdcff730ea51.png

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

e9f25ec1ea0b6cc6.png

คลิก SAVE

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

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

ใน Cloud Shell ให้ตั้งค่าตัวแปรสำหรับชื่อที่เก็บข้อมูลที่ไม่ซ้ำกัน Cloud Shell มี GOOGLE_CLOUD_PROJECT ตั้งค่าเป็นรหัสโปรเจ็กต์ที่ไม่ซ้ำกันของคุณอยู่แล้ว คุณสามารถต่อท้ายชื่อ Bucket ได้

เช่น

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}

สร้างโซนมาตรฐานแบบหลายภูมิภาคในยุโรป

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

ตรวจสอบว่าสิทธิ์เข้าถึงระดับ Bucket เหมือนกัน

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

ทำให้ Bucket เป็นแบบสาธารณะ

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

หากไปที่ส่วน Cloud Storage ของคอนโซล คุณควรมีที่เก็บข้อมูล uploaded-pictures สาธารณะ

a98ed4ba17873e40.png

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

6. ทดสอบการเข้าถึงแบบสาธารณะใน Bucket

เมื่อกลับไปที่เบราว์เซอร์พื้นที่เก็บข้อมูล คุณจะเห็นที่เก็บข้อมูลในรายการที่มีสิทธิ์เข้าถึง "สาธารณะ" (รวมถึงเครื่องหมายเตือนที่แจ้งให้คุณทราบว่าทุกคนมีสิทธิ์เข้าถึงเนื้อหาของที่เก็บข้อมูลนั้น)

89e7a4d2c80a0319.png

ตอนนี้ Bucket พร้อมรับรูปภาพแล้ว

หากคลิกชื่อที่เก็บข้อมูล คุณจะเห็นรายละเอียดที่เก็บข้อมูล

131387f12d3eb2d3.png

ที่นั่น คุณสามารถลองใช้ปุ่ม Upload files เพื่อทดสอบว่าคุณเพิ่มรูปภาพลงใน Bucket ได้ ป๊อปอัปตัวเลือกไฟล์จะขอให้คุณเลือกไฟล์ เมื่อเลือกแล้ว ระบบจะอัปโหลดไปยังที่เก็บข้อมูลของคุณ และคุณจะเห็นpublicสิทธิ์เข้าถึงที่ระบบกำหนดให้กับไฟล์ใหม่นี้โดยอัตโนมัติอีกครั้ง

e87584471a6e9c6d.png

นอกจากป้ายกำกับสิทธิ์เข้าถึง Public แล้ว คุณยังจะเห็นไอคอนลิงก์เล็กๆ ด้วย เมื่อคลิกที่รูปภาพ เบราว์เซอร์จะนำคุณไปยัง URL สาธารณะของรูปภาพนั้น ซึ่งจะมีรูปแบบดังนี้

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

โดย BUCKET_NAME คือชื่อที่ไม่ซ้ำกันทั่วโลกที่คุณเลือกสำหรับ Bucket และตามด้วยชื่อไฟล์ของรูปภาพ

การคลิกช่องทำเครื่องหมายข้างชื่อรูปภาพจะทำให้ปุ่ม DELETE เปิดใช้ และคุณจะลบรูปภาพแรกนี้ได้

7. เตรียมฐานข้อมูล

คุณจะจัดเก็บข้อมูลเกี่ยวกับรูปภาพที่ Vision API ให้ไว้ในฐานข้อมูล Cloud Firestore ซึ่งเป็นฐานข้อมูลเอกสาร NoSQL ที่ดำเนินการบนระบบคลาวด์แบบ Serverless ที่มีการจัดการครบวงจรและรวดเร็ว เตรียมฐานข้อมูลโดยไปที่ส่วน 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 (สตริง): ชื่อไฟล์ของรูปภาพที่อัปโหลด ซึ่งเป็นคีย์ของเอกสารด้วย
  • ป้ายกำกับ (อาร์เรย์ของสตริง): ป้ายกำกับของรายการที่ Vision API รู้จัก
  • color (สตริง): รหัสสีเลขฐานสิบหกของสีหลัก (เช่น #ab12ef)
  • created (วันที่): การประทับเวลาเมื่อจัดเก็บข้อมูลเมตาของรูปภาพนี้
  • thumbnail (บูลีน): ฟิลด์ที่ไม่บังคับซึ่งจะแสดงและมีค่าเป็นจริงหากมีการสร้างภาพขนาดย่อสำหรับรูปภาพนี้

เนื่องจากเราจะค้นหาใน 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. โคลนโค้ด

โคลนโค้ด หากคุณยังไม่ได้ทำในโค้ดแล็บก่อนหน้า

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

จากนั้นคุณสามารถไปที่ไดเรกทอรีที่มีบริการเพื่อเริ่มสร้างห้องทดลองได้โดยทำดังนี้

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

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

f79613aff479d8ad.png

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

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

ก่อนอื่น ให้แก้ไขไฟล์ pom.xml ซึ่งแสดงรายการการอ้างอิงของฟังก์ชัน 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);
} 

ตอนนี้คุณสร้างคำขอได้แล้ว และโค้ดจะเตรียมคำขอดังกล่าวเพื่อส่งไปยัง 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 นี้

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 และตัวสร้าง Native Image ที่เหมาะสมแล้ว โดยมีตัวเลือกหลายอย่างให้เลือก

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

ใน Cloudshell คุณสามารถติดตั้ง GraalVM และยูทิลิตี native-image ได้อย่างสะดวกด้วยคำสั่งง่ายๆ ดังนี้

# 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)

จากนั้นคุณสามารถไปที่ไดเรกทอรีที่มีบริการเพื่อเริ่มสร้างห้องทดลองได้โดยทำดังนี้

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 มีโซลูชันที่ได้มาตรฐานในการจัดการโฟลว์ของการเปลี่ยนแปลงสถานะที่เรียกว่าเหตุการณ์ระหว่างไมโครเซอร์วิสที่แยกออกจากกัน เมื่อมีการทริกเกอร์ 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 แล้วคลิกที่ Bucket ที่เราสร้างไว้ตอนต้นของแล็บ

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 หรือไม่

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

933a20a9709cb006.png

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

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

ลบ Bucket

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 ดั้งเดิม

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