การเก็บรูปภาพ การวิเคราะห์ และการสร้างรายงานใน Google Workspace Google Cloud

1. ภาพรวม

Codelab นี้จะมองเวิร์กโฟลว์ที่เป็นไปได้ขององค์กร ไม่ว่าจะเป็นการเก็บรูปภาพ การวิเคราะห์ และการสร้างรายงาน ลองจินตนาการว่าองค์กรของคุณมีชุดรูปภาพที่ใช้พื้นที่ในทรัพยากรที่จำกัด คุณต้องการเก็บถาวรข้อมูลดังกล่าว วิเคราะห์รูปภาพเหล่านั้น และที่สำคัญที่สุดคือ สร้างรายงานที่สรุปข้อมูลสถานที่ที่เก็บถาวร รวมถึงผลการวิเคราะห์ จัดเรียงและทำให้พร้อมใช้งานโดยการจัดการ Google Cloud มีเครื่องมือที่จะทำให้บรรลุเป้าหมายนี้ โดยใช้ API จาก 2 สายผลิตภัณฑ์ ได้แก่ Google Workspace (ก่อนหน้านี้คือ G Suite หรือ Google Apps) และ Google Cloud (ก่อนหน้านี้เรียกว่า GCP)

ในสถานการณ์ของเรา ผู้ใช้แบบธุรกิจจะมีรูปภาพใน Google ไดรฟ์ สมควรที่จะสนับสนุนให้ "เยือกแข็ง" พื้นที่เก็บข้อมูลที่มีราคาถูกกว่า เช่น คลาสพื้นที่เก็บข้อมูลที่มีให้บริการใน Google Cloud Storage Google Cloud Vision ช่วยให้นักพัฒนาซอฟต์แวร์ผสานรวมฟีเจอร์การตรวจจับการมองเห็นภายในแอปพลิเคชันได้อย่างง่ายดาย รวมถึงการตรวจจับวัตถุและจุดสังเกต การรู้จำอักขระด้วยภาพ (OCR) เป็นต้น และสุดท้าย คุณสามารถใช้สเปรดชีต Google ชีตเป็นเครื่องมือแสดงข้อมูลเป็นภาพที่มีประโยชน์สำหรับการสรุปข้อมูลทั้งหมดให้เจ้านายของคุณ

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

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

  • วิธีใช้ Cloud Shell
  • วิธีตรวจสอบสิทธิ์คำขอ API
  • วิธีติดตั้งไลบรารีของไคลเอ็นต์ Google APIs สำหรับ Python
  • วิธีเปิดใช้ Google APIs
  • วิธีดาวน์โหลดไฟล์จาก Google ไดรฟ์
  • วิธีอัปโหลดออบเจ็กต์/BLOB ไปยัง Cloud Storage
  • วิธีวิเคราะห์ข้อมูลด้วย Cloud Vision
  • วิธีเขียนแถวใน Google ชีต

สิ่งที่ต้องมี

  • บัญชี Google (บัญชี Google Workspace อาจต้องได้รับการอนุมัติจากผู้ดูแลระบบ)
  • โปรเจ็กต์ Google Cloud ที่มีบัญชีสำหรับการเรียกเก็บเงิน Google Cloud ที่ใช้งานอยู่
  • ความคุ้นเคยกับคำสั่งของเทอร์มินัล/เชลล์ของระบบปฏิบัติการ
  • ทักษะพื้นฐานด้าน Python (2 หรือ 3) แต่คุณสามารถใช้ภาษาใดก็ได้ที่รองรับ

ประสบการณ์เกี่ยวกับผลิตภัณฑ์ Google Cloud ทั้ง 4 รายการที่ระบุไว้ข้างต้นอาจเป็นประโยชน์กับคุณมากกว่า (ไม่บังคับ) หากคุณมีเวลาเหลือเฟือในการทำความคุ้นเคยก่อน คุณก็สามารถทำ Codelab สำหรับแต่ละบทเรียนก่อนทำแบบฝึกหัดได้ที่นี่

แบบสำรวจ

คุณจะใช้บทแนะนำนี้อย่างไร

อ่านเท่านั้น อ่านและทำแบบฝึกหัด

คุณจะให้คะแนนประสบการณ์การใช้งาน Python อย่างไร

มือใหม่ ระดับกลาง ผู้ชำนาญ

คุณจะให้คะแนนความพึงพอใจในการใช้บริการ Google Cloud อย่างไร

มือใหม่ ระดับกลาง ผู้ชำนาญ

คุณจะให้คะแนนความพึงพอใจสำหรับประสบการณ์การใช้บริการสำหรับนักพัฒนาแอป Google Workspace อย่างไร

มือใหม่ ระดับกลาง ผู้ชำนาญ

คุณต้องการดูหัวข้อ "ธุรกิจ" เพิ่มเติมหรือไม่ Codelab กับส่วนแนะนำฟีเจอร์ผลิตภัณฑ์

ใช่ ไม่ แสดงเพิ่มเติมทั้ง 2 อย่าง

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

สรุป

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

เปิดใช้งาน Cloud Shell

  1. คลิกเปิดใช้งาน Cloud Shell 853e55310c205094.png จาก Cloud Console

55efc1aaa7a4d3ad.png

หากคุณไม่เคยเริ่มต้นใช้งาน Cloud Shell มาก่อน คุณจะเห็นหน้าจอตรงกลาง (ครึ่งหน้าล่าง) ซึ่งอธิบายว่านี่คืออะไร หากเป็นเช่นนั้น ให้คลิกดำเนินการต่อ (คุณจะไม่เห็นการดำเนินการนี้อีก) หน้าจอแบบครั้งเดียวมีลักษณะดังนี้

9c92662c6a846a5c.png

การจัดสรรและเชื่อมต่อกับ Cloud Shell ใช้เวลาเพียงไม่กี่นาที

9f0e51b578fecce5.png

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

เมื่อเชื่อมต่อกับ Cloud Shell คุณควรเห็นว่าได้รับการตรวจสอบสิทธิ์แล้ว และโปรเจ็กต์ได้รับการตั้งค่าเป็นรหัสโปรเจ็กต์แล้ว

  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคุณได้รับการตรวจสอบสิทธิ์แล้ว
gcloud auth list

เอาต์พุตจากคำสั่ง

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคำสั่ง gcloud รู้เกี่ยวกับโปรเจ็กต์ของคุณ
gcloud config list project

เอาต์พุตจากคำสั่ง

[core]
project = <PROJECT_ID>

หากไม่ใช่ ให้ตั้งคำสั่งด้วยคำสั่งนี้

gcloud config set project <PROJECT_ID>

เอาต์พุตจากคำสั่ง

Updated property [core/project].

3. ยืนยันสภาพแวดล้อม Python

Codelab นี้กำหนดให้คุณใช้ภาษา Python (แม้ว่าไลบรารีของไคลเอ็นต์ Google APIs จะรองรับหลายภาษา ดังนั้น คุณสามารถสร้างสิ่งที่เทียบเท่าในเครื่องมือการพัฒนาที่คุณชื่นชอบ และเพียงใช้ Python เป็น Pseudocode) โดย Codelab นี้รองรับ Python 2 และ 3 โดยเฉพาะ แต่เราขอแนะนำให้เปลี่ยนไปใช้ 3.x โดยเร็วที่สุด

Cloud Shell เป็นเครื่องมือที่ใช้งานง่ายสำหรับผู้ใช้โดยตรงจาก Cloud Console และไม่จำเป็นต้องใช้สภาพแวดล้อมการพัฒนาในเครื่อง คุณจึงทำบทแนะนำนี้ได้ในระบบคลาวด์โดยสมบูรณ์ด้วยเว็บเบราว์เซอร์ กล่าวอย่างเจาะจงก็คือ Cloud Shell ได้ติดตั้ง Python ทั้ง 2 เวอร์ชันไว้ล่วงหน้าแล้ว

Cloud Shell ยังติดตั้ง IPython ไว้ด้วย โดยเป็นล่าม Python เชิงโต้ตอบระดับสูงที่เราแนะนำ โดยเฉพาะอย่างยิ่งหากคุณเป็นส่วนหนึ่งของชุมชนวิทยาศาสตร์ข้อมูลหรือแมชชีนเลิร์นนิง หากใช้ IPython จะเป็นล่ามเริ่มต้นสำหรับสมุดบันทึก Jupyter รวมถึง Colab, Jupyter Notebooks ที่โฮสต์โดย Google Research

IPython เลือกใช้ล่าม Python 3 ก่อน แต่กลับไปใช้ Python 2 หากไม่มี 3.x คุณสามารถเข้าถึง IPython ได้จาก Cloud Shell แต่ก็ติดตั้งในสภาพแวดล้อมการพัฒนาภายในได้เช่นกัน ออกด้วย ^D (Ctrl-d) และยอมรับข้อเสนอเพื่อออก เอาต์พุตตัวอย่างของการเริ่ม ipython จะมีลักษณะดังนี้

$ ipython
Python 3.7.3 (default, Mar  4 2020, 23:11:43)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

หากไม่ต้องการใช้ IPython เอง ให้ใช้อินเทอร์แอ็กทีฟของอินเทอร์แอ็กทีฟ Python มาตรฐาน (Cloud Shell หรือสภาพแวดล้อมการพัฒนาในเครื่องของคุณ) ก็เหมาะสมที่สุด (จบด้วย ^D) ดังนี้

$ python
Python 2.7.13 (default, Sep 26 2018, 18:42:22)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 
$ python3
Python 3.7.3 (default, Mar 10 2020, 02:33:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Codelab จะถือว่าคุณมีเครื่องมือติดตั้ง pip (เครื่องมือจัดการแพ็กเกจ Python และรีโซลเวอร์ทรัพยากร Dependency ด้วย) ด้วย โดยมาพร้อมกับเวอร์ชัน 2.7.9 ขึ้นไป หรือ 3.4 ขึ้นไป หากคุณมี Python เวอร์ชันเก่า โปรดดูวิธีการติดตั้งจากคู่มือนี้ คุณอาจต้องมีสิทธิ์เข้าถึง sudo หรือผู้ใช้ขั้นสูง ทั้งนี้ขึ้นอยู่กับสิทธิ์ของคุณ แต่โดยทั่วไปแล้วจะไม่เป็นเช่นนั้น คุณยังใช้ pip2 หรือ pip3 อย่างชัดแจ้งเพื่อเรียกใช้ pip สำหรับ Python บางเวอร์ชันได้ด้วย

ส่วนที่เหลือของ Codelab จะถือว่าคุณกำลังใช้ Python 3 โดยคุณจะได้รับคำสั่งเฉพาะสำหรับ Python 2 หากแตกต่างจาก 3.x อย่างมาก

[ไม่บังคับ] สร้างและใช้สภาพแวดล้อมเสมือน

ส่วนนี้ไม่บังคับและมีไว้สำหรับผู้ที่ใช้สภาพแวดล้อมเสมือนสำหรับ Codelab นี้เท่านั้น (ตามแถบด้านข้างคำเตือนด้านบน) หากคุณมี Python 3 ในคอมพิวเตอร์เท่านั้น คุณสามารถใช้คำสั่งนี้เพื่อสร้าง Virtualenv ชื่อ my_env (คุณสามารถเลือกชื่ออื่นได้หากต้องการ)

virtualenv my_env

อย่างไรก็ตาม หากคุณมีทั้ง Python 2 และ 3 ในคอมพิวเตอร์ เราขอแนะนำให้ติดตั้ง Python 3 Virtualenv ซึ่งติดตั้ง -p flag ได้โดยทำดังนี้

virtualenv -p python3 my_env

ป้อน Virtualenv ที่สร้างใหม่โดย "การเปิดใช้งาน" ดังนี้

source my_env/bin/activate

ยืนยันว่าคุณอยู่ในสภาพแวดล้อมโดยสังเกตข้อความแจ้งของ Shell ที่มีชื่อสภาพแวดล้อมนำหน้าแล้ว เช่น

(my_env) $ 

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

4. ติดตั้งไลบรารีของไคลเอ็นต์ Google APIs สำหรับ Python

Codelab นี้กำหนดให้ใช้ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ Python เนื่องจากเป็นขั้นตอนการติดตั้งที่ง่ายดาย หรือคุณอาจไม่ต้องดำเนินการใดๆ เลย

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

*ติดตั้งไลบรารีของไคลเอ็นต์

(ไม่บังคับ) สามารถข้ามได้หากคุณใช้ Cloud Shell หรือสภาพแวดล้อมในเครื่องที่คุณได้ติดตั้งไลบรารีของไคลเอ็นต์ไว้แล้ว คุณต้องดำเนินการนี้เฉพาะเมื่อคุณพัฒนาในเครื่องแต่ยังไม่ได้ (หรือไม่มั่นใจว่าคุณได้) ติดตั้งไว้ วิธีที่ง่ายที่สุดคือการใช้ pip (หรือ pip3) ในการติดตั้ง (รวมถึงอัปเดต pip เองหากจำเป็น) ดังนี้

pip install -U pip google-api-python-client oauth2client

ยืนยันการติดตั้ง

คำสั่งนี้จะติดตั้งไลบรารีของไคลเอ็นต์ รวมถึงแพ็กเกจที่จำเป็นต้องใช้ ไม่ว่าคุณจะใช้ Cloud Shell หรือสภาพแวดล้อมของคุณเอง โปรดตรวจสอบว่าได้ติดตั้งไลบรารีของไคลเอ็นต์แล้วโดยการนำเข้าแพ็กเกจที่จำเป็นและยืนยันว่าไม่มีข้อผิดพลาดในการนำเข้า (ไม่มีเอาต์พุต)

python3 -c "import googleapiclient, httplib2, oauth2client"

หากใช้ Python 2 แทน (จาก Cloud Shell) คุณจะได้รับคำเตือนว่าระบบเลิกใช้งานการรองรับ Python 2 แล้ว ดังนี้

*******************************************************************************
Python 2 is deprecated. Upgrade to Python 3 as soon as possible.
See https://cloud.google.com/python/docs/python2-sunset

To suppress this warning, create an empty ~/.cloudshell/no-python-warning file.
The command will automatically proceed in  seconds or on any key.
*******************************************************************************

เมื่อคุณสามารถเรียกใช้ "การทดสอบ" การนำเข้านั้น คำสั่งสำเร็จแล้ว (ไม่มีข้อผิดพลาด/เอาต์พุต) คุณพร้อมที่จะเริ่มพูดคุยกับ Google APIs แล้ว

สรุป

เนื่องจากโปรแกรมนี้เป็น Codelab ระดับกลาง คุณจึงมีประสบการณ์ในการสร้างและ โดยใช้โปรเจ็กต์ในคอนโซล หากคุณเพิ่งเริ่มใช้ Google APIs และ Google Workspace API โดยเฉพาะ โปรดลองใช้ Codelab แนะนำ Google Workspace API ก่อน นอกจากนี้ หากคุณทราบวิธีสร้าง (หรือนำข้อมูลเข้าสู่ระบบของบัญชีผู้ใช้ที่มีอยู่ (ไม่ใช่ บัญชีบริการ) มาใช้ซ้ำ ให้ส่งไฟล์ client_secret.json ลงในไดเรกทอรีงาน ข้ามโมดูลถัดไป และข้ามไปที่ "เปิดใช้ Google APIs"

5. *ให้สิทธิ์คำขอ API (การให้สิทธิ์ผู้ใช้)

คุณสามารถข้ามส่วนนี้ได้หากสร้างข้อมูลเข้าสู่ระบบการให้สิทธิ์บัญชีผู้ใช้ไว้แล้วและคุ้นเคยกับกระบวนการนี้ ซึ่งแตกต่างจากการให้สิทธิ์บัญชีบริการที่มีเทคนิคที่แตกต่างกัน ดังนั้นโปรดดำเนินการต่อด้านล่าง

ข้อมูลเบื้องต้นเกี่ยวกับการให้สิทธิ์ (รวมถึงการตรวจสอบสิทธิ์บางอย่าง)

ในการส่งคำขอไปยัง API แอปพลิเคชันของคุณต้องมีการให้สิทธิ์ที่เหมาะสม การตรวจสอบสิทธิ์ มีคำอื่นๆ ที่คล้ายกัน อธิบายเกี่ยวกับข้อมูลเข้าสู่ระบบ โดยตรวจสอบสิทธิ์ของตนเองเมื่อเข้าสู่ระบบบัญชี Google ด้วยข้อมูลเข้าสู่ระบบ รหัสผ่าน เมื่อตรวจสอบสิทธิ์แล้ว ขั้นตอนถัดไปคือคุณโค้ดของคุณจะได้รับสิทธิ์ในการเข้าถึงข้อมูล เช่น ไฟล์ BLOB บน Cloud Storage หรือไฟล์ส่วนตัวของผู้ใช้ใน Google ไดรฟ์หรือไม่

Google APIs รองรับการให้สิทธิ์หลายประเภท แต่ประเภทที่พบบ่อยที่สุดสำหรับผู้ใช้ G Suite API คือการให้สิทธิ์ผู้ใช้เนื่องจากแอปพลิเคชันตัวอย่างใน Codelab นี้จะเข้าถึงข้อมูลที่เป็นของผู้ใช้ปลายทาง ผู้ใช้ปลายทางเหล่านั้นต้องให้สิทธิ์แอปของคุณในการเข้าถึงข้อมูลของตน ซึ่งหมายความว่าโค้ดของคุณจะต้องรับข้อมูลเข้าสู่ระบบ OAuth2 ของบัญชีผู้ใช้

หากต้องการรับข้อมูลเข้าสู่ระบบ OAuth2 สำหรับการให้สิทธิ์ผู้ใช้ ให้กลับไปที่ตัวจัดการ API แล้วเลือก "ข้อมูลเข้าสู่ระบบ" แท็บที่การนำทางด้านซ้าย:

635af008256d323.png

เมื่อไปถึงเว็บไซต์ คุณจะเห็นข้อมูลเข้าสู่ระบบทั้งหมดแบ่งออกเป็น 3 ส่วน ดังนี้

fd2f4133b406d572.png

อันแรกคือคีย์ API รหัสไคลเอ็นต์ OAuth 2.0 รายการที่ 2 และบัญชีบริการ OAuth2 อันสุดท้าย ซึ่งเรากำลังใช้รหัสที่อยู่ตรงกลาง

กำลังสร้างข้อมูลเข้าสู่ระบบ

จากหน้าข้อมูลเข้าสู่ระบบ ให้คลิกปุ่ม + สร้างข้อมูลเข้าสู่ระบบ ที่ด้านบนซึ่งจะแสดงกล่องโต้ตอบให้คุณเลือก "รหัสไคลเอ็นต์ OAuth:"

b17b663668e38787.png

ในหน้าจอถัดไป คุณจะมี 2 การดำเนินการ ได้แก่ การกำหนดค่า "หน้าจอคำยินยอม" สำหรับการให้สิทธิ์ของแอป และเลือกประเภทแอปพลิเคชัน

4e0b967c9d70d262.png

หากยังไม่ได้ตั้งค่าหน้าจอขอความยินยอม คุณจะเห็นคำเตือนในคอนโซลและต้องดำเนินการทันที (ข้ามขั้นตอนนี้หากตั้งค่าหน้าจอคำยินยอมไว้แล้ว)

คลิก "กำหนดค่าหน้าจอคำยินยอม" ที่คุณเลือกแท็บ "ภายนอก" แอป (หรือ "ภายใน" หากเป็นลูกค้า G Suite) ให้ทำดังนี้

f17e97b30d994b0c.png

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

b107ab81349bdad2.png

สิ่งเดียวที่คุณต้องมีในขณะนี้มีเพียงชื่อแอปพลิเคชัน ดังนั้นโปรดเลือกบุคคลที่สอดคล้องกับ Codelab ที่คุณกำลังทำ แล้วคลิกบันทึก

กำลังสร้างรหัสไคลเอ็นต์ OAuth (การตรวจสอบสิทธิ์บัญชีผู้ใช้)

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

5ddd365ac0af1e34.png

เรากำลังพัฒนาเครื่องมือบรรทัดคำสั่ง ซึ่งก็คืออื่นๆ ดังนั้นโปรดเลือกเครื่องมือดังกล่าว แล้วคลิกปุ่มสร้าง เลือกชื่อรหัสไคลเอ็นต์ที่แสดงถึงแอปที่คุณกำลังสร้าง หรือใช้ชื่อเริ่มต้นซึ่งมักเป็น "ไคลเอ็นต์อื่น N"

กำลังบันทึกข้อมูลเข้าสู่ระบบ

  1. กล่องโต้ตอบที่มีข้อมูลเข้าสู่ระบบใหม่จะปรากฏขึ้น คลิกตกลงเพื่อปิด

8bec84d82cb104d7.png

  1. กลับไปที่หน้าข้อมูลเข้าสู่ระบบ ให้เลื่อนลงไปที่ "รหัสไคลเอ็นต์ OAuth2" ค้นหาและคลิกไอคอนดาวน์โหลด f54b28417901b3aa.png ที่ด้านล่างขวาของรหัสไคลเอ็นต์ที่สร้างขึ้นใหม่ วันที่ 1b4e8d248274a338.png
  2. การดำเนินการนี้จะเปิดกล่องโต้ตอบเพื่อบันทึกไฟล์ชื่อ client_secret-LONG-HASH-STRING.apps.googleusercontent.com.json ซึ่งมีแนวโน้มที่จะอยู่ในโฟลเดอร์ดาวน์โหลด เราขอแนะนำให้ย่อชื่อให้สั้นลง เช่น client_secret.json (ซึ่งเป็นสิ่งที่แอปตัวอย่างใช้) จากนั้นบันทึกลงในไดเรกทอรี/โฟลเดอร์ที่คุณจะสร้างแอปตัวอย่างใน Codelab นี้

สรุป

ตอนนี้คุณพร้อมแล้วที่จะเปิดใช้งาน Google APIs ที่ใช้ใน Codelab นี้ นอกจากนี้ สำหรับชื่อแอปพลิเคชันในหน้าจอความยินยอม OAuth เราเลือก "การสาธิต API ของ Vision" ดังนั้น โปรดคาดหวังว่าจะเห็นชื่อนี้ในภาพหน้าจอที่กำลังจะมาถึง

6. เปิดใช้ Google APIs

Codelab นี้ใช้ Google Cloud API สี่ (4) รายการ ซึ่งเป็นคู่หนึ่งจาก Google Cloud (Cloud Storage และ Cloud Vision) และอีกคู่หนึ่งจาก Google Workspace (Google ไดรฟ์และ Google ชีต) ด้านล่างนี้เป็นวิธีการทั่วไปในการเปิดใช้ Google API เมื่อคุณรู้วิธีเปิดใช้ API หนึ่งแล้ว API อื่นๆ ก็จะคล้ายกัน

ไม่ว่าจะคุณต้องการใช้ Google API ใดในแอปพลิเคชันของคุณ คุณจะต้องเปิดใช้ API เหล่านั้น คุณจะเปิดใช้ API ได้จากบรรทัดคำสั่งหรือ Cloud Console ขั้นตอนการเปิดใช้ API จะเหมือนกัน ดังนั้นเมื่อคุณเปิด API แล้ว 1 รายการก็จะเปิดใช้งาน API อื่นได้ด้วยวิธีเดียวกัน

ตัวเลือกที่ 1: อินเทอร์เฟซบรรทัดคำสั่ง gcloud (Cloud Shell หรือสภาพแวดล้อมภายใน)

แม้ว่าการเปิดใช้ API จาก Cloud Console จะทำได้มากกว่า แต่นักพัฒนาซอฟต์แวร์บางรายชอบทำทุกอย่างจากบรรทัดคำสั่ง คุณต้องค้นหา "ชื่อบริการ" ของ API ก่อน ซึ่งมีลักษณะคล้ายกับ URL: SERVICE_NAME.googleapis.com คุณดูผลิตภัณฑ์เหล่านี้ได้ในแผนภูมิผลิตภัณฑ์ที่รองรับ หรือจะค้นหาผลิตภัณฑ์ด้วย Google Discovery API โดยใช้โปรแกรม

เมื่อได้รับข้อมูลนี้ คุณสามารถใช้ Cloud Shell (หรือสภาพแวดล้อมการพัฒนาในเครื่องที่มีติดตั้งเครื่องมือบรรทัดคำสั่ง gcloud) แล้วเปิดใช้ API หรือบริการได้ดังนี้

gcloud services enable SERVICE_NAME.googleapis.com

ตัวอย่างที่ 1: เปิดใช้ Cloud Vision API

gcloud services enable vision.googleapis.com

ตัวอย่างที่ 2: เปิดใช้แพลตฟอร์มการประมวลผลแบบ Serverless ของ Google App Engine

gcloud services enable appengine.googleapis.com

ตัวอย่างที่ 3: เปิดใช้ API หลายรายการด้วยคำขอเดียว ตัวอย่างเช่น หาก Codelab นี้มีผู้ดูที่ทำให้แอปใช้งานได้โดยใช้ Cloud Translation API กับ App Engine, Cloud Functions และ Cloud Run บรรทัดคำสั่งจะเป็นดังนี้

gcloud services enable appengine.googleapis.com cloudfunctions.googleapis.com artifactregistry.googleapis.com run.googleapis.com translate.googleapis.com

คำสั่งนี้จะเปิดใช้ App Engine, Cloud Functions, Cloud Run และ Cloud Translation API นอกจากนี้ ยังเปิดใช้ Cloud Artifact Registry เนื่องจากเป็นตำแหน่งที่ระบบ Cloud Build ต้องลงทะเบียนอิมเมจคอนเทนเนอร์เพื่อทำให้ใช้งานได้กับ Cloud Run

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

ตัวอย่างที่ 4: คำค้นหาสำหรับ Google API ที่พร้อมใช้งานสำหรับโปรเจ็กต์ของคุณ

gcloud services list --available --filter="name:googleapis.com"

ตัวอย่างที่ 5: การค้นหา Google APIs ที่เปิดใช้สำหรับโปรเจ็กต์ของคุณ

gcloud services list

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคำสั่งข้างต้น โปรดดูที่เอกสารการเปิดและปิดบริการและบริการข้อมูลรายชื่อ

ตัวเลือกที่ 2: Cloud Console

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

df4a0a5e00d29ffc.png

ด้านล่างแผนภูมิเหล่านี้คือรายการ Google API ที่เปิดใช้งานสำหรับโปรเจ็กต์ของคุณ

5fcf10e5a05cfb97.png

หากต้องการเปิดใช้ (หรือปิดใช้) API ให้คลิกเปิดใช้ API และบริการที่ด้านบน

eef4e5e863f4db66.png

หรือไปที่แถบการนำทางด้านซ้าย แล้วเลือก API และ บริการคลัง

6eda5ba145b30b97.png

ไม่ว่าคุณจะเลือกแบบใด คุณจะเข้าสู่หน้าไลบรารี API ดังนี้

5d4f1c8e7cf8df28.png

ป้อนชื่อ API เพื่อค้นหาและดูผลลัพธ์ที่ตรงกัน:

35bc4b9cf72ce9a4.png

เลือก API ที่ต้องการเปิดใช้แล้วคลิกปุ่มเปิดใช้

9574a69ef8d9e8d2.png

ขั้นตอนการเปิดใช้ API ทั้งหมดจะคล้ายคลึงกัน ไม่ว่าคุณจะต้องการใช้ Google API ใดก็ตาม

ค่าใช้จ่าย

คุณสามารถใช้ Google APIs หลายรายการได้โดยไม่เสียค่าธรรมเนียม แต่การใช้ผลิตภัณฑ์และ API ส่วนใหญ่ของ Google Cloud เมื่อเปิดใช้ Cloud API ระบบอาจขอบัญชีสำหรับการเรียกเก็บเงินที่ใช้งานอยู่ แต่ผลิตภัณฑ์ Google Cloud บางรายการจะมีไอคอน "ฟรีไม่จำกัดเวลา" ซึ่งคุณต้องเกินจึงจะใช้การเรียกเก็บเงินได้

ผู้ใช้ Google Cloud รายใหม่มีสิทธิ์ได้รับช่วงทดลองใช้ฟรี ซึ่งปัจจุบันมีราคาอยู่ที่ $300 USD ในช่วง 90 วันแรก โดยทั่วไป Codelabs ไม่มีการเรียกเก็บเงินหรือการเรียกเก็บเงินใดๆ มากนัก เราจึงขอแนะนำให้คุณรอสายทดลองใช้ฟรีไว้จนกว่าคุณจะพร้อมทดลองใช้ โดยเฉพาะอย่างยิ่งหากเป็นข้อเสนอแบบครั้งเดียว โควต้ารุ่นฟรีจะไม่หมดอายุและนำมาใช้ไม่ว่าคุณจะใช้ช่วงทดลองใช้ฟรีหรือไม่ก็ตาม

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

ผลิตภัณฑ์แต่ละอย่างของ Google จะมีการเรียกเก็บเงินไม่เหมือนกัน ดังนั้นโปรดดูเอกสารที่ถูกต้องสําหรับข้อมูลดังกล่าว

สรุป

เมื่อเปิดใช้ Cloud Vision แล้ว ให้เปิด API อีก 3 รายการ (Google ไดรฟ์, Cloud Storage, Google ชีต) ในลักษณะเดียวกัน จาก Cloud Shell ให้ใช้ gcloud services enable หรือจาก Cloud Console:

  1. กลับไปที่ไลบรารี API
  2. เริ่มการค้นหาโดยพิมพ์ตัวอักษรของชื่อ
  3. เลือก API ที่ต้องการ และ
  4. เปิดใช้

ฟอก ล้าง และทำซ้ำ สำหรับ Cloud Storage จะมีหลายตัวเลือกให้เลือก ได้แก่ "Google Cloud Storage JSON API" นอกจากนี้ Cloud Storage API ยังคาดหวังให้บัญชีสำหรับการเรียกเก็บเงินที่ใช้งานอยู่ด้วย

7. ขั้นตอนที่ 0: ตั้งค่าการนำเข้า & รหัสการให้สิทธิ์

นี่คือจุดเริ่มต้นของโค้ดขนาดกลาง ดังนั้น การปฏิบัติตามแนวทางที่คล่องตัวบางอย่างจะช่วยให้มั่นใจได้ว่าจะมีโครงสร้างพื้นฐานที่เสถียรและมีเสถียรภาพ ก่อนที่จะจัดการกับแอปพลิเคชันหลัก Doublecheck พร้อมใช้งาน client_secret.json อยู่ในไดเรกทอรีปัจจุบันของคุณและเริ่มต้น ipython และป้อนข้อมูลโค้ดต่อไปนี้ หรือบันทึกไว้ใน analyze_gsimg.py และเรียกใช้จาก Shell (ควรใช้แบบหลังเพราะเราจะเพิ่มในตัวอย่างโค้ดต่อไป):

from __future__ import print_function

from googleapiclient import discovery, http
from httplib2 import Http
from oauth2client import file, client, tools

# process credentials for OAuth2 tokens
SCOPES = 'https://www.googleapis.com/auth/drive.readonly'
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
    creds = tools.run_flow(flow, store)

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)

คอมโพเนนต์หลักนี้ประกอบด้วยโค้ดบล็อกสำหรับการนำเข้าโมดูล/แพ็กเกจ การประมวลผลข้อมูลเข้าสู่ระบบการตรวจสอบสิทธิ์ผู้ใช้ และการสร้างปลายทางบริการ API ส่วนสำคัญของโค้ดที่คุณควรตรวจสอบ:

  • การนำเข้าฟังก์ชัน print() ทำให้สามารถใช้ร่วมกับ Python 2-3 ตัวอย่างนี้ได้ และการนำเข้าจากไลบรารีของ Google จะนำเครื่องมือทั้งหมดที่จำเป็นในการสื่อสารกับ Google API มารวมไว้ด้วย
  • ตัวแปร SCOPES แสดงสิทธิ์ที่ขอจากผู้ใช้ โดยตอนนี้มีเพียงสิทธิ์เดียว นั่นคือสิทธิ์ในการอ่านข้อมูลจาก Google ไดรฟ์
  • ส่วนที่เหลือของรหัสการประมวลผลข้อมูลเข้าสู่ระบบจะอ่านในโทเค็น OAuth2 ที่แคชไว้ ซึ่งอาจอัปเดตเป็นโทเค็นเพื่อการเข้าถึงใหม่ด้วยโทเค็นการรีเฟรชหากโทเค็นเพื่อการเข้าถึงเดิมหมดอายุ
  • หากไม่มีการสร้างโทเค็นหรือเรียกโทเค็นเพื่อการเข้าถึงที่ถูกต้องไม่สำเร็จเนื่องจากเหตุผลอื่น ผู้ใช้ต้องทำตามขั้นตอนแบบ 3 ทางของ OAuth2 (3LO) ให้สร้างกล่องโต้ตอบที่มีการขอสิทธิ์และแจ้งให้ผู้ใช้ยอมรับ เมื่อดำเนินการแล้ว แอปจะดำเนินต่อไป มิฉะนั้น tools.run_flow() จะข้ามข้อยกเว้นและการดำเนินการจะหยุดทำงาน
  • เมื่อผู้ใช้ให้สิทธิ์แล้ว ระบบจะสร้างไคลเอ็นต์ HTTP เพื่อสื่อสารกับเซิร์ฟเวอร์ และจะมีการเซ็นชื่อคำขอทั้งหมดด้วยข้อมูลเข้าสู่ระบบของผู้ใช้เพื่อความปลอดภัย จากนั้นระบบจะสร้างปลายทางบริการไปยัง Google Drive API (เวอร์ชัน 3) ด้วยไคลเอ็นต์ HTTP นั้นและมอบหมายให้กับ DRIVE

การเรียกใช้แอปพลิเคชัน

ครั้งแรกที่คุณเรียกใช้สคริปต์ สคริปต์จะไม่มีสิทธิ์เข้าถึงไฟล์ของผู้ใช้ในไดรฟ์ (ของคุณ) เอาต์พุตจะมีลักษณะดังนี้เมื่อการดำเนินการหยุดชั่วคราว

$ python3 ./analyze_gsimg.py
/usr/local/lib/python3.6/site-packages/oauth2client/_helpers.py:255: UserWarning: Cannot access storage.json: No such file or directory
  warnings.warn(_MISSING_FILE_MESSAGE.format(filename))

Your browser has been opened to visit:
    https://accounts.google.com/o/oauth2/auth?client_id=LONG-STRING.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.readonly&access_type=offline&response_type=code

If your browser is on a different machine then exit and re-run this
application with the command-line parameter

  --noauth_local_webserver

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

จากสภาพแวดล้อมการพัฒนาในเครื่อง

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

149241d33871a141.png

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

หลังจากคลิก "ไปที่ "ไม่ปลอดภัย" แอป" คุณจะเห็นกล่องโต้ตอบสิทธิ์ OAuth2 ที่มีลักษณะคล้ายด้านล่างนี้ เรากำลังปรับปรุงอินเทอร์เฟซผู้ใช้ของเราอยู่เสมอ จึงไม่ต้องกังวลหากรายการไม่ตรงกันทั้งหมด

a122eb7468d0d34e.png

กล่องโต้ตอบขั้นตอน OAuth2 แสดงสิทธิ์ที่นักพัฒนาซอฟต์แวร์ขอ (ผ่านตัวแปร SCOPES) ในกรณีนี้ ผู้ใช้จะสามารถดูและดาวน์โหลดจาก Google ไดรฟ์ได้ ในโค้ดของแอปพลิเคชัน ขอบเขตสิทธิ์เหล่านี้จะปรากฏเป็น URI แต่จะมีการแปลเป็นภาษาที่ระบุตามภาษาของผู้ใช้ ในที่นี้ผู้ใช้ต้องให้สิทธิ์ที่ชัดเจนสำหรับสิทธิ์ที่ขอ มิเช่นนั้นระบบจะมีข้อยกเว้น สคริปต์จึงจะไม่ดำเนินการต่อ

คุณอาจได้รับกล่องโต้ตอบอีก 1 ข้อความที่ขอการยืนยัน

bf171080dcd6ec5.png

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

จาก Cloud Shell

จาก Cloud Shell ไม่มีหน้าต่างเบราว์เซอร์ปรากฏขึ้นเพื่อให้คุณติดขัด ตระหนักถึงข้อความการวินิจฉัยที่ด้านล่างที่เหมาะสำหรับคุณ:

If your browser is on a different machine then exit and re-run this
application with the command-line parameter

  --noauth_local_webserver

คุณจะต้อง ^C (Ctrl-C หรือการกดแป้นพิมพ์อื่นๆ เพื่อหยุดการทำงานของสคริปต์) และเรียกใช้จาก Shell ที่มีแฟล็กเพิ่มเติม เมื่อเรียกใช้วิธีนี้ คุณจะได้รับเอาต์พุตต่อไปนี้แทน

$ python3 analyze_gsimg.py --noauth_local_webserver
/usr/local/lib/python3.7/site-packages/oauth2client/_helpers.py:255: UserWarning: Cannot access storage.json: No such file or directory
  warnings.warn(_MISSING_FILE_MESSAGE.format(filename))

Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?client_id=LONG-STRING.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.readonly&access_type=offline&response_type=code

Enter verification code:

(ไม่สนใจคำเตือนเนื่องจากเราทราบว่ายังไม่มีการสร้าง storage.json และ) เมื่อทำตามวิธีการในแท็บเบราว์เซอร์อื่นที่มี URL ดังกล่าว คุณจะได้รับประสบการณ์ใช้งานที่แทบจะเหมือนกับสิ่งที่อธิบายไว้ข้างต้นในสภาพแวดล้อมการพัฒนาในเครื่อง (ดูภาพหน้าจอด้านบน) ที่ตอนท้ายจะเป็นหน้าจอสุดท้ายที่มีรหัสยืนยันสำหรับป้อนใน Cloud Shell:

40a567cda0f31cc9.png

คัดลอกและวางรหัสนี้ในหน้าต่างเทอร์มินัล

สรุป

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

การแก้ปัญหา

หากได้รับข้อผิดพลาดแทนที่จะไม่มีเอาต์พุต อาจเป็นเพราะสาเหตุอย่างน้อย 1 ข้อ ซึ่งอาจเกิดจากสาเหตุต่อไปนี้

8. ขั้นตอนที่ 1: ดาวน์โหลดรูปภาพจาก Google ไดรฟ์

ในขั้นตอนก่อนหน้า เราแนะนำให้สร้างโค้ดเป็น analyze_gsimg.py และแก้ไขจากที่นั่น หรือคุณจะคัดลอกและวางทุกอย่างลงใน iPython หรือเชลล์ Python มาตรฐานโดยตรงก็ได้ แต่จะยุ่งยากมากขึ้นเนื่องจากเราจะสร้างแอปต่อทีละอย่าง

สมมติว่าแอปได้รับอนุญาตและสร้างปลายทางบริการ API แล้ว โดยในโค้ดจะแทนด้วยตัวแปร DRIVE คราวนี้ลองหาไฟล์ภาพใน Google ไดรฟ์ และ

ตั้งค่าเป็นตัวแปรชื่อ NAME ป้อนฟังก์ชัน drive_get_img() ด้านล่างโค้ดจากขั้นตอนที่ 0

FILE = 'YOUR_IMG_ON_DRIVE'  # fill-in with name of your Drive file

def drive_get_img(fname):
    'download file from Drive and return file info & binary if found'

    # search for file on Google Drive
    rsp = DRIVE.files().list(q="name='%s'" % fname,
            fields='files(id,name,mimeType,modifiedTime)'
    ).execute().get('files', [])

    # download binary & return file info if found, else return None
    if rsp:
        target = rsp[0]  # use first matching file
        fileId = target['id']
        fname = target['name']
        mtype = target['mimeType']
        binary = DRIVE.files().get_media(fileId=fileId).execute()
        return fname, mtype, target['modifiedTime'], binary

คอลเล็กชัน files() ของไดรฟ์มีเมธอด list() ซึ่งดำเนินการค้นหา (พารามิเตอร์ q) สำหรับไฟล์ที่ระบุ พารามิเตอร์ fields ใช้เพื่อระบุค่าผลลัพธ์ที่คุณสนใจ เหตุใดจึงต้องรบกวนการนำข้อมูลทุกอย่างกลับคืนมาและทำให้ทุกอย่างช้าลงหากคุณไม่สนใจค่าอื่นๆ หากคุณเพิ่งเริ่มใช้ฟิลด์มาสก์สำหรับการกรองค่าการแสดงผล API โปรดดูบล็อกโพสต์นี้และ วิดีโอ ไม่เช่นนั้นให้เรียกใช้การค้นหาและเก็บแอตทริบิวต์ files ที่ส่งคืนมา โดยกำหนดค่าเริ่มต้นเป็นอาร์เรย์รายการที่ว่างเปล่าหากไม่มีข้อมูลที่ตรงกัน

หากไม่มีผลลัพธ์ ระบบจะข้ามฟังก์ชันที่เหลือและแสดงผล None (โดยนัย) ไม่เช่นนั้น ให้ดึงการตอบกลับที่ตรงกันรายการแรก (rsp[0]) แสดงผลชื่อไฟล์, ประเภท MIME, การประทับเวลาการแก้ไขครั้งล่าสุด และสุดท้ายคือเพย์โหลดแบบไบนารีที่ดึงโดยฟังก์ชัน get_media() (ผ่านรหัสไฟล์) ในคอลเล็กชัน files() ด้วย (ชื่อเมธอดอาจแตกต่างกันเล็กน้อยกับไลบรารีของไคลเอ็นต์ภาษาอื่นๆ)

ส่วนสุดท้ายคือส่วน "หลัก" เนื้อความที่ขับเคลื่อนแอปพลิเคชันทั้งหมด:

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

สมมติว่ารูปภาพชื่อ section-work-card-img_2x.jpg ในไดรฟ์และตั้งค่าเป็น FILE เมื่อดำเนินการสคริปต์แล้ว คุณควรเห็นเอาต์พุตที่ยืนยันว่าสามารถอ่านไฟล์จากไดรฟ์ได้ (แต่บันทึกลงในคอมพิวเตอร์ของคุณไม่ได้)

$ python3 analyze_gsimg.py
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)

การแก้ปัญหา

หากคุณไม่ได้รับผลลัพธ์ที่สำเร็จดังเช่นข้างต้น อาจเป็นเพราะสาเหตุอย่างน้อย 1 ข้อซึ่งอาจเกิดจากสาเหตุต่อไปนี้

สรุป

ในส่วนนี้ คุณได้เรียนรู้วิธี (ในการเรียก API แยกกัน 2 ครั้ง) ในการเชื่อมต่อกับการค้นหา API ของไดรฟ์สำหรับไฟล์ใดไฟล์หนึ่งแล้วทำการดาวน์โหลดไฟล์นั้น กรณีการใช้งานทางธุรกิจ: เก็บข้อมูลในไดรฟ์ของคุณและอาจวิเคราะห์ข้อมูล เช่น ด้วยเครื่องมือ Google Cloud โค้ดสำหรับแอปในขั้นตอนนี้ควรตรงกับในที่เก็บที่step1-drive/analyze_gsimg.py

อ่านเพิ่มเติมเกี่ยวกับการดาวน์โหลดไฟล์บน Google ไดรฟ์ ที่นี่ หรือดูบล็อกโพสต์นี้และ วิดีโอ ส่วนนี้ของ Codelab แทบจะเหมือนกันทุกประการกับข้อมูลเบื้องต้นเกี่ยวกับ Codelab ของ Google Workspace API ทั้งหมด โดยจะแสดงไฟล์/โฟลเดอร์ 100 รายการแรกใน Google ไดรฟ์ของผู้ใช้และใช้ขอบเขตที่จำกัดกว่าแทนการดาวน์โหลดไฟล์

9. ขั้นตอนที่ 2: เก็บไฟล์ไปยัง Cloud Storage

ขั้นตอนต่อไปคือการเพิ่มการสนับสนุนสำหรับ Google Cloud Storage เราจำเป็นต้องนำเข้าแพ็กเกจ Python อีกรายการหนึ่งคือ io ตรวจสอบว่าส่วนบนสุดของการนำเข้ามีลักษณะดังนี้

from __future__ import print_function                   
import io

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

FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''     # YOUR IMG FILE PREFIX                  

คำศัพท์เกี่ยวกับที่เก็บข้อมูล: Cloud Storage ให้พื้นที่เก็บข้อมูล BLOB ในรูปแบบอสัณฐาน เมื่อทำการอัปโหลดไฟล์ในนั้น โปรแกรมดังกล่าวไม่เข้าใจแนวคิดของประเภทไฟล์ นามสกุลไฟล์ ฯลฯ แบบเดียวกับการทำงานของ Google ไดรฟ์ พวกเขาเป็นเพียง "BLOB" ไปยัง Cloud Storage นอกจากนี้ เรายังไม่ทราบเกี่ยวกับโฟลเดอร์หรือไดเรกทอรีย่อยใน Cloud Storage

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

ขั้นตอนที่ 1 ข้างต้นขอขอบเขตแบบอ่านอย่างเดียวของไดรฟ์ เท่านี้แหละที่คุณจำเป็นต้องทำ ตอนนี้ ต้องมีสิทธิ์อัปโหลด (อ่านและเขียน) ไปยัง Cloud Storage เปลี่ยน SCOPES จากตัวแปรสตริงเดียวเป็นอาร์เรย์ (Python tuple [or list]) ของขอบเขตสิทธิ์เพื่อให้มีลักษณะดังนี้

SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
)                  

จากนั้นสร้างปลายทางบริการไปยัง Cloud Storage ใต้ปลายทางสำหรับไดรฟ์ โปรดทราบว่าเราปรับเปลี่ยนการเรียกใช้เล็กน้อยเพื่อให้นำออบเจ็กต์ไคลเอ็นต์ HTTP เดียวกันมาใช้ซ้ำ เนื่องจากไม่จำเป็นต้องสร้างออบเจ็กต์ใหม่เมื่อเป็นทรัพยากรที่แชร์ได้

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)                  

ตอนนี้ให้เพิ่มฟังก์ชันนี้ (หลัง drive_get_img()) ซึ่งจะอัปโหลดไปยัง Cloud Storage:

def gcs_blob_upload(fname, bucket, media, mimetype):
    'upload an object to a Google Cloud Storage bucket'

    # build blob metadata and upload via GCS API
    body = {'name': fname, 'uploadType': 'multipart', 'contentType': mimetype}
    return GCS.objects().insert(bucket=bucket, body=body,
            media_body=http.MediaIoBaseUpload(io.BytesIO(media), mimetype),
            fields='bucket,name').execute()

การเรียก objects.().insert() ต้องใช้ชื่อที่เก็บข้อมูล ข้อมูลเมตาของไฟล์ และ Branch ของไบนารีเอง ในการกรองค่าที่ส่งกลับออก ตัวแปร fields จะขอเฉพาะที่เก็บข้อมูลและชื่อออบเจ็กต์ที่แสดงผลจาก API ดูข้อมูลเพิ่มเติมเกี่ยวกับฟิลด์มาสก์ในคำขออ่าน API ได้ที่โพสต์นี้และ วิดีโอ

ตอนนี้ได้ผสานรวมการใช้ gcs_blob_upload() เข้ากับแอปพลิเคชันหลักแล้ว:

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)

ตัวแปร gcsname จะรวม "ไดเรกทอรีย่อยหลัก" ทั้งหมด จะต่อท้ายด้วยชื่อไฟล์ และเมื่อขึ้นต้นด้วยชื่อที่เก็บข้อมูล จะทำให้ทราบว่าคุณกำลังเก็บไฟล์ที่ "/bucket/parent.../filename" แทรกส่วนนี้หลังฟังก์ชัน print() แรกเหนือวลี else เพื่อให้ "main" ทั้งหมด ซึ่งมีลักษณะดังนี้

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

สมมติว่าเราระบุที่เก็บข้อมูลชื่อ "vision-demo" กับ "analyzed_imgs" เป็น "ไดเรกทอรีย่อยระดับบนสุด" เมื่อคุณตั้งค่าตัวแปรเหล่านั้นและเรียกใช้สคริปต์อีกครั้งแล้ว ระบบจะดาวน์โหลด section-work-card-img_2x.jpg จากไดรฟ์และอัปโหลดไปยัง Cloud Storage ใช่ไหม ไม่ใช่

$ python3 analyze_gsimg.py 
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Traceback (most recent call last):
  File "analyze_gsimg.py", line 85, in <module>
    io.BytesIO(data), mimetype=mtype), mtype)
  File "analyze_gsimg.py", line 72, in gcs_blob_upload
    media_body=media, fields='bucket,name').execute()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/googleapiclient/_helpers.py", line 134, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/googleapiclient/http.py", line 898, in execute
    raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://storage.googleapis.com/upload/storage/v1/b/PROJECT_ID/o?fields=bucket%2Cname&alt=json&uploadType=multipart returned "Insufficient Permission">

โปรดดูอย่างละเอียดขณะที่ดาวน์โหลดไดรฟ์สำเร็จ แต่อัปโหลดไปยัง Cloud Storage ไม่สำเร็จ เหตุผล

เหตุผลก็คือเมื่อเราให้สิทธิ์แอปพลิเคชันนี้ในขั้นตอนที่ 1 ไปแล้ว แต่เดิมเราให้สิทธิ์การเข้าถึงแบบอ่านอย่างเดียวแก่ Google ไดรฟ์เท่านั้น แม้ว่าเราได้เพิ่มขอบเขตแบบอ่าน-เขียนสำหรับ Cloud Storage แต่เราไม่เคยแจ้งให้ผู้ใช้ให้สิทธิ์เข้าถึงดังกล่าว เพื่อให้ใช้งานได้ เราต้องทำลายไฟล์ storage.json ที่ไม่มีขอบเขตนี้ออกไป แล้วเรียกใช้อีกครั้ง

หลังจากให้สิทธิ์อีกครั้ง (ยืนยันโดยดูภายใน storage.json และดูขอบเขตทั้ง 2 แบบ) จากนั้นเอาต์พุตของคุณจะเป็นไปตามที่คาดไว้

$ python3 analyze_gsimg.py

    . . .

Authentication successful.
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Uploaded 'analyzed_imgs/section-work-card-img_2x.jpg' to GCS bucket 'vision-demo'

สรุป

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

แน่นอนว่านักพัฒนาซอฟต์แวร์มักจะถามเราอยู่เรื่อยๆ ว่าทำไมทั้ง Google ไดรฟ์และ Cloud Storage ท้ายที่สุดแล้ว พวกเขาไม่ได้ใช้พื้นที่เก็บข้อมูลทั้งคู่ในระบบคลาวด์ใช่ไหม เราจึงได้จัดทำวิดีโอนี้ขึ้น โค้ดในขั้นตอนนี้ควรตรงกับสิ่งที่อยู่ในที่เก็บที่step2-gcs/analyze_gsimg.py

10. ขั้นตอนที่ 3: วิเคราะห์ด้วย Cloud Vision

แม้ว่าตอนนี้เราจะทราบแล้วว่าคุณสามารถย้ายข้อมูลระหว่าง Google Cloud และ Google Workspace ได้ แต่เรายังไม่ได้ทำการวิเคราะห์ ดังนั้นขอให้เวลาส่งรูปภาพไปยัง Cloud Vision สำหรับคำอธิบายประกอบป้ายกำกับหรือการตรวจหาวัตถุ ในการทำเช่นนั้น เราต้องเข้ารหัสข้อมูลด้วย Base64 ซึ่งหมายถึงโมดูล Python อีกรายการหนึ่งซึ่งก็คือ base64 ตรวจสอบว่าส่วนการนำเข้าด้านบนสุดมีลักษณะดังนี้

from __future__ import print_function
import base64
import io

โดยค่าเริ่มต้น Vision API จะแสดงป้ายกำกับทั้งหมดที่พบ เพื่อให้ทุกอย่างสอดคล้องกัน โปรดส่งคำขอเฉพาะ 5 อันดับแรก (ผู้ใช้ปรับได้แน่นอน) โดยเราจะใช้ตัวแปรคงที่ TOP สำหรับกรณีนี้ เพิ่มภายใต้ค่าคงที่อื่นๆ ทั้งหมด ดังนี้

FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''   # YOUR IMG FILE PREFIX 
TOP = 5       # TOP # of VISION LABELS TO SAVE                 

เช่นเดียวกับขั้นตอนก่อนหน้านี้ เราต้องการขอบเขตสิทธิ์อื่นสำหรับ Vision API ในครั้งนี้ อัปเดต SCOPES ด้วยสตริงของตัวเอง:

SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
    'https://www.googleapis.com/auth/cloud-vision',
)                  

จากนั้นสร้างปลายทางบริการไปยัง Cloud Vision ให้สอดคล้องกับบริการอื่นๆ ดังนี้

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision',  'v1', http=HTTP)

จากนั้นเพิ่มฟังก์ชันนี้ที่ส่งเพย์โหลดรูปภาพไปยัง Cloud Vision ดังนี้

def vision_label_img(img, top):
    'send image to Vision API for label annotation'

    # build image metadata and call Vision API to process
    body = {'requests': [{
                'image':     {'content': img},
                'features': [{'type': 'LABEL_DETECTION', 'maxResults': top}],
    }]}
    rsp = VISION.images().annotate(body=body).execute().get('responses', [{}])[0]

    # return top labels for image as CSV for Sheet (row)
    if 'labelAnnotations' in rsp:
        return ', '.join('(%.2f%%) %s' % (
                label['score']*100., label['description']) \
                for label in rsp['labelAnnotations'])

การเรียกใช้ images().annotate() ต้องใช้ข้อมูลและฟีเจอร์ API ที่ต้องการ ป้ายกำกับสูงสุด 5 อันดับแรกเป็นส่วนหนึ่งของเพย์โหลดด้วย (แต่ไม่บังคับ) หากเรียกใช้ได้สำเร็จ เพย์โหลดจะแสดงป้ายกำกับออบเจ็กต์ 5 อันดับแรกของออบเจ็กต์ รวมถึงคะแนนความเชื่อมั่นที่ออบเจ็กต์อยู่ในอิมเมจ (หากไม่มีการตอบกลับ ให้กำหนดพจนานุกรม Python ที่ว่างเปล่าเพื่อให้คำสั่ง if ต่อไปนี้ทำงานไม่สำเร็จ) ฟังก์ชันนี้จะเรียงข้อมูลดังกล่าวเป็นสตริง CSV เพื่อใช้ในรายงานของเราในท้ายที่สุด

คุณควรวาง 5 บรรทัดที่เรียก vision_label_img() ทันทีหลังจากที่อัปโหลดไปยัง Cloud Storage สำเร็จ

            # process w/Vision
            rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), TOP)
            if rsp:
                print('Top %d labels from Vision API: %s' % (TOP, rsp))
            else:
                print('ERROR: Vision API cannot analyze %r' % fname)

นอกจากนี้ ไดรเวอร์หลักทั้งหมดควรมีลักษณะดังนี้

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

            # process w/Vision
            rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), TOP)
            if rsp:
                print('Top %d labels from Vision API: %s' % (TOP, rsp))
            else:
                print('ERROR: Vision API cannot analyze %r' % fname)
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

การลบ storage.json เพื่อรีเฟรชขอบเขตและเรียกใช้แอปพลิเคชันที่อัปเดตแล้วอีกครั้งควรทำให้ได้เอาต์พุตที่คล้ายกับผลลัพธ์ต่อไปนี้ ซึ่งระบุถึงการเพิ่มการวิเคราะห์ Cloud Vision

$ python3 analyze_gsimg.py

    . . .

Authentication successful.
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Uploaded 'analyzed_imgs/section-work-card-img_2x.jpg' to GCS bucket 'vision-demo'
Top 5 labels from Vision API: (89.94%) Sitting, (86.09%) Interior design, (82.08%) Furniture, (81.52%) Table, (80.85%) Room

สรุป

ไม่ใช่ทุกคนที่มีความเชี่ยวชาญด้านแมชชีนเลิร์นนิงในการสร้างและฝึกโมเดล ML ของตนเพื่อวิเคราะห์ข้อมูล ทีม Google Cloud ได้เผยแพร่โมเดลก่อนการฝึกของ Google บางส่วนสำหรับการใช้งานทั่วไปและอยู่เบื้องหลัง API เพื่อช่วยให้ทุกคนเข้าถึง AI และได้อย่างเสมอภาค ML สำหรับทุกคน

คุณจะใช้แมชชีนเลิร์นนิงได้หากเป็นนักพัฒนาซอฟต์แวร์และเรียกใช้ API ได้ Cloud Vision เป็นเพียงหนึ่งในบริการ API ที่คุณใช้วิเคราะห์ข้อมูลได้ ดูข้อมูลเกี่ยวกับแอปอื่นๆ ที่นี่ ตอนนี้โค้ดควรตรงกับในที่เก็บที่step3-vision/analyze_gsimg.py

11. ขั้นตอนที่ 4: สร้างรายงานด้วย Google ชีต

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

Google Sheets API ไม่ต้องมีการนำเข้าเพิ่มเติม และข้อมูลเดียวใหม่ที่จำเป็นก็คือรหัสไฟล์ของสเปรดชีตที่มีอยู่แล้วซึ่งจัดรูปแบบแล้วและรอข้อมูลแถวใหม่ ด้วยเหตุนี้จึงมีค่าคงที่ที่ SHEET เราขอแนะนำให้คุณสร้างสเปรดชีตใหม่ที่มีลักษณะคล้ายกับรายการต่อไปนี้

4def78583d05300.png

URL ของสเปรดชีตจะมีลักษณะดังนี้: https://docs.google.com/spreadsheets/d/FILE_ID/edit รับ FILE_ID แล้วมอบหมายให้ SHEET

นอกจากนี้เรายังเข้าไปในฟังก์ชันขนาดเล็กที่ชื่อ k_ize() ซึ่งแปลงไบต์เป็นกิโลไบต์ โดยกำหนดให้เป็น Python lambda เนื่องจากเป็นฟังก์ชัน 1 บรรทัดที่เรียบง่าย การรวมทั้งสองค่านี้เข้ากับค่าคงที่อื่นๆ มีลักษณะดังนี้

k_ize =  lambda b: '%6.2fK' % (b/1000.)  # bytes to kBs
FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''     # YOUR IMG FILE PREFIX
SHEET = 'YOUR_SHEET_ID'
TOP = 5       # TOP # of VISION LABELS TO SAVE                 

เช่นเดียวกับขั้นตอนก่อนหน้านี้ เราต้องการขอบเขตสิทธิ์อื่น ซึ่งคราวนี้เป็นแบบอ่านและเขียนสำหรับ Sheets API ตอนนี้ SCOPES มีข้อมูลที่จำเป็นครบทั้ง 4 อย่างแล้ว:

SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
    'https://www.googleapis.com/auth/cloud-vision',
    'https://www.googleapis.com/auth/spreadsheets',
)                  

จากนั้นสร้างปลายทางบริการไปยัง Google ชีตใกล้กับปลายทางอื่นๆ ซึ่งมีลักษณะดังนี้

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision',  'v1', http=HTTP)
SHEETS = discovery.build('sheets',  'v4', http=HTTP)

ฟังก์ชันของ sheet_append_row() นั้นไม่ซับซ้อน โดยนำแถวข้อมูลและรหัสของชีต แล้วเพิ่มแถวนั้นลงในชีตรายการนั้น

def sheet_append_row(sheet, row):
    'append row to a Google Sheet, return #cells added'

    # call Sheets API to write row to Sheet (via its ID)
    rsp = SHEETS.spreadsheets().values().append(
            spreadsheetId=sheet, range='Sheet1',
            valueInputOption='USER_ENTERED', body={'values': [row]}
    ).execute()
    if rsp:
        return rsp.get('updates').get('updatedCells')

การเรียก spreadsheets().values().append() ต้องใช้รหัสไฟล์ของชีต ช่วงของเซลล์ วิธีป้อนข้อมูล และตัวข้อมูลเอง รหัสไฟล์ไม่ซับซ้อน มีการระบุช่วงของเซลล์ในรูปแบบ A1 ช่วงของ "Sheet1" หมายถึงชีตทั้งหมด ซึ่งจะส่งสัญญาณไปยัง API เพื่อเพิ่มแถวต่อท้ายข้อมูลทั้งหมดในชีต มี 2 ตัวเลือกด้วยกันสำหรับวิธีเพิ่มข้อมูลลงในชีต, "RAW" (ป้อนข้อมูลสตริงแบบคำต่อคำ) หรือ "USER_ENTERED" (เขียนข้อมูลให้เหมือนกับที่ผู้ใช้ป้อนข้อมูลลงในแป้นพิมพ์ด้วยแอปพลิเคชัน Google ชีต โดยเก็บฟีเจอร์การจัดรูปแบบเซลล์ไว้)

หากการเรียกใช้สำเร็จ ค่าที่ส่งกลับจะไม่มีข้อมูลที่เป็นประโยชน์มากนัก เราจึงเลือกใช้จำนวนเซลล์ที่อัปเดตโดยคำขอ API ด้านล่างนี้คือโค้ดที่เรียกใช้ฟังก์ชันดังกล่าว

                # push results to Sheet, get cells-saved count
                fsize = k_ize(len(data))
                row = [PARENT,
                        '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
                        BUCKET, gcsname, fname), mtype, ftime, fsize, rsp
                ]
                rsp = sheet_append_row(SHEET, row)
                if rsp:
                    print('Updated %d cells in Google Sheet' % rsp)
                else:
                    print('ERROR: Cannot write row to Google Sheets')

สเปรดชีตใน Google ชีตมีคอลัมน์ที่แสดงข้อมูล เช่น "ไดเรกทอรีย่อย" ระดับบนสุด ตำแหน่งของไฟล์ที่เก็บถาวรบน Cloud Storage (ที่เก็บข้อมูล + ชื่อไฟล์), ประเภท MIME ของไฟล์, ขนาดไฟล์ (เดิมเป็นไบต์ แต่แปลงเป็นกิโลไบต์ด้วย k_ize()) และสตริงป้ายกำกับ Cloud Vision นอกจากนี้ โปรดทราบว่าตำแหน่งที่เก็บถาวรคือไฮเปอร์ลิงก์เพื่อให้ผู้จัดการสามารถคลิกเพื่อยืนยันว่ามีการสำรองข้อมูลอย่างปลอดภัยแล้ว

การเพิ่มบล็อกโค้ดด้านบนทันทีหลังจากแสดงผลการค้นหาจาก Cloud Vision ซึ่งเป็นส่วนหลักที่ขับเคลื่อนแอปเสร็จสมบูรณ์แล้ว แม้ว่าโครงสร้างจะซับซ้อนเล็กน้อยก็ตาม

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

            # process w/Vision
            rsp = vision_label_img(base64.b64encode(data).decode('utf-8'))
            if rsp:
                print('Top %d labels from Vision API: %s' % (TOP, rsp))

                # push results to Sheet, get cells-saved count
                fsize = k_ize(len(data))
                row = [PARENT,
                        '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
                        BUCKET, gcsname, fname), mtype, ftime, fsize, rsp
                ]
                rsp = sheet_append_row(SHEET, row)
                if rsp:
                    print('Updated %d cells in Google Sheet' % rsp)
                else:
                    print('ERROR: Cannot write row to Google Sheets')
            else:
                print('ERROR: Vision API cannot analyze %r' % fname)
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

การลบ storage.json เป็นครั้งสุดท้ายและเรียกใช้แอปพลิเคชันที่อัปเดตแล้วอีกครั้งควรทำให้ได้เอาต์พุตที่คล้ายกับข้อความต่อไปนี้ ซึ่งแสดงการวิเคราะห์ Cloud Vision เพิ่มเติม

$ python3 analyze_gsimg.py

    . . .

Authentication successful.
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Uploaded 'analyzed_imgs/section-work-card-img_2x.jpg' to GCS bucket 'vision-demo'
Top 5 labels from Vision API: (89.94%) Sitting, (86.09%) Interior design, (82.08%) Furniture, (81.52%) Table, (80.85%) Room
Updated 6 cells in Google Sheet

แม้จะมีประโยชน์ แต่บรรทัดนี้ก็ช่วยให้เห็นภาพได้มากขึ้นโดยดู Google ชีตที่อัปเดตแล้ว โดยเพิ่มบรรทัดสุดท้าย (แถว 7 ในตัวอย่างด้านล่าง) ในชุดข้อมูลที่มีอยู่ซึ่งเพิ่มเข้ามาก่อนหน้า

b53a5bc944734652.png

สรุป

ใน 3 ขั้นตอนแรกของบทแนะนำนี้ คุณได้เชื่อมต่อกับ Google Workspace และ Google Cloud API เพื่อย้ายข้อมูลและวิเคราะห์ ซึ่งคิดเป็น 80% ของงานทั้งหมด แต่ในท้ายที่สุดแล้ว ทุกอย่างก็จะไม่มีประโยชน์ใดๆ หากคุณนำเสนอต่อฝ่ายจัดการทุกอย่างที่คุณทำสำเร็จไม่ได้ เพื่อให้เห็นภาพผลลัพธ์ได้ดีขึ้น การสรุปผลลัพธ์ทั้งหมดในรายงานที่สร้างขึ้นกล่าวถึงปริมาณ

เพื่อปรับปรุงให้การวิเคราะห์มีประโยชน์ยิ่งขึ้น นอกเหนือจากการเขียนผลลัพธ์ลงในสเปรดชีต การเพิ่มประสิทธิภาพที่เป็นไปได้คือการจัดทำดัชนีป้ายกำกับ 5 อันดับแรกสำหรับแต่ละรูปภาพ เพื่อให้สามารถสร้างฐานข้อมูลภายในขึ้นเพื่อให้พนักงานที่ได้รับอนุญาตสามารถค้นหารูปภาพด้วยทีมค้นหาได้ แต่เราก็ปล่อยให้เป็นแบบฝึกหัดสำหรับผู้อ่าน

ในตอนนี้ ผลการค้นหาของเราอยู่ในชีตและพร้อมให้ฝ่ายจัดการใช้งานแล้ว โค้ดสำหรับแอปในขั้นตอนนี้ควรตรงกับในที่เก็บที่step4-sheets/analyze_gsimg.py ขั้นตอนสุดท้ายคือล้างโค้ดและเปลี่ยนโค้ดให้เป็นสคริปต์ที่ใช้งานได้

12. *ขั้นตอนสุดท้าย: เปลี่ยนโครงสร้างภายในโค้ด

(ไม่บังคับ) การมีแอปที่ใช้งานได้จริงเป็นสิ่งที่ดี แต่เราสามารถปรับปรุงได้หรือไม่ ใช่ โดยเฉพาะแอปพลิเคชันหลักที่ดูยุ่งเหยิง มาลองใส่ฟังก์ชันดังกล่าวและกระตุ้นให้มอบอินพุตของผู้ใช้แทนค่าคงที่ที่คงที่ ซึ่งเราจะดำเนินการดังกล่าวด้วยโมดูล argparse นอกจากนี้ ลองเปิดแท็บเว็บเบราว์เซอร์เพื่อแสดงชีตเมื่อเราเขียนแถวข้อมูลลงในชีตแล้ว ซึ่งทำได้ด้วยโมดูล webbrowser รวมการนำเข้าเหล่านี้กับรายการอื่นๆ เพื่อให้การนำเข้ายอดนิยมมีลักษณะดังนี้:

from __future__ import print_function
import argparse
import base64
import io
import webbrowser

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

DEBUG = False

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

โดยทำตามแนวทางปฏิบัติแนะนำนี้ เรามาจัดระเบียบส่วนหลักของแอปใหม่เป็นฟังก์ชันและ return ที่แต่ละ "จุดพัก" กัน แทนการซ้อน (จะแสดง None หากขั้นตอนใดล้มเหลว และ True หากทั้งหมดสำเร็จ):

def main(fname, bucket, sheet_id, folder, top, debug):
    '"main()" drives process from image download through report generation'

    # download img file & info from Drive
    rsp = drive_get_img(fname)
    if not rsp:
        return
    fname, mtype, ftime, data = rsp
    if debug:
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

    # upload file to GCS
    gcsname = '%s/%s'% (folder, fname)
    rsp = gcs_blob_upload(gcsname, bucket, data, mtype)
    if not rsp:
        return
    if debug:
        print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

    # process w/Vision
    rsp = vision_label_img(base64.b64encode(data).decode('utf-8'))
    if not rsp:
        return
    if debug:
        print('Top %d labels from Vision API: %s' % (top, rsp))

    # push results to Sheet, get cells-saved count
    fsize = k_ize(len(data))
    row = [folder,
            '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
            bucket, gcsname, fname), mtype, ftime, fsize, rsp
    ]
    rsp = sheet_append_row(sheet_id, row)
    if not rsp:
        return
    if debug:
        print('Added %d cells to Google Sheet' % rsp)
    return True

ซึ่งทำงานอย่างเป็นระเบียบและสะอาดตาขึ้น ทำให้ทิ้งความรู้สึกของเชน if-else ที่เกิดซ้ำไปพร้อมๆ กับการลดความซับซ้อนของโค้ดดังที่อธิบายไว้ข้างต้น ปริศนาข้อสุดท้ายคือการสร้าง ไดรเวอร์หลัก ซึ่งช่วยให้ผู้ใช้สามารถปรับแต่งได้ และลดเอาต์พุต (เว้นแต่ต้องการ)

if __name__ == '__main__':
    # args: [-hv] [-i imgfile] [-b bucket] [-f folder] [-s Sheet ID] [-t top labels]
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", "--imgfile", action="store_true",
            default=FILE, help="image file filename")
    parser.add_argument("-b", "--bucket_id", action="store_true",
            default=BUCKET, help="Google Cloud Storage bucket name")
    parser.add_argument("-f", "--folder", action="store_true",
            default=PARENT, help="Google Cloud Storage image folder")
    parser.add_argument("-s", "--sheet_id", action="store_true",
            default=SHEET, help="Google Sheet Drive file ID (44-char str)")
    parser.add_argument("-t", "--viz_top", action="store_true",
            default=TOP, help="return top N (default %d) Vision API labels" % TOP)
    parser.add_argument("-v", "--verbose", action="store_true",
            default=DEBUG, help="verbose display output")
    args = parser.parse_args()

    print('Processing file %r... please wait' % args.imgfile)
    rsp = main(args.imgfile, args.bucket_id,
            args.sheet_id, args.folder, args.viz_top, args.verbose)
    if rsp:
        sheet_url = 'https://docs.google.com/spreadsheets/d/%s/edit' % args.sheet_id
        print('DONE: opening web browser to it, or see %s' % sheet_url)
        webbrowser.open(sheet_url, new=1, autoraise=True)
    else:
        print('ERROR: could not process %r' % args.imgfile)

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

สรุป

ไม่จำเป็นต้องลบ storage.json เนื่องจากไม่มีการเปลี่ยนแปลงขอบเขต เรียกใช้แอปพลิเคชันที่อัปเดตอีกครั้งจะแสดงหน้าต่างเบราว์เซอร์ใหม่ซึ่งเปิดไปยังชีตที่แก้ไขแล้ว ลดจำนวนบรรทัดเอาต์พุต และการออกตัวเลือก -h จะแสดงตัวเลือกให้แก่ผู้ใช้ ซึ่งรวมถึง -v ในการคืนค่าบรรทัดเอาต์พุตที่ระงับไว้ซึ่งเห็นก่อนหน้านี้

$ python3 analyze_gsimg.py
Processing file 'section-work-card-img_2x.jpg'... please wait
DONE: opening web browser to it, or see https://docs.google.com/spreadsheets/d/SHEET_ID/edit

$ python3 analyze_gsimg.py -h
usage: analyze_gsimg.py [-h] [-i] [-t] [-f] [-b] [-s] [-v]

optional arguments:
  -h, --help       show this help message and exit
  -i, --imgfile    image file filename
  -t, --viz_top    return top N (default 5) Vision API labels
  -f, --folder     Google Cloud Storage image folder
  -b, --bucket_id  Google Cloud Storage bucket name
  -s, --sheet_id   Google Sheet Drive file ID (44-char str)
  -v, --verbose    verbose display output

ตัวเลือกอื่นๆ ช่วยให้ผู้ใช้เลือกชื่อไฟล์ไดรฟ์ที่แตกต่างกัน เช่น "ไดเรกทอรีย่อย" ของ Cloud Storage ได้ และชื่อที่เก็บข้อมูลด้านบน "N" ผลลัพธ์จาก Cloud Vision และรหัสไฟล์สเปรดชีต (ชีต) จากการอัปเดตล่าสุดเหล่านี้ โค้ดเวอร์ชันสุดท้ายของคุณควรตรงกับสิ่งที่อยู่ในที่เก็บที่ final/analyze_gsimg.py และที่นี่ทั้งหมด

'''
analyze_gsimg.py - analyze Google Workspace image processing workflow

Download image from Google Drive, archive to Google Cloud Storage, send
to Google Cloud Vision for processing, add results row to Google Sheet.
'''

from __future__ import print_function
import argparse
import base64
import io
import webbrowser

from googleapiclient import discovery, http
from httplib2 import Http
from oauth2client import file, client, tools

k_ize = lambda b: '%6.2fK' % (b/1000.) # bytes to kBs
FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''     # YOUR IMG FILE PREFIX
SHEET = 'YOUR_SHEET_ID'
TOP = 5       # TOP # of VISION LABELS TO SAVE
DEBUG = False

# process credentials for OAuth2 tokens
SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
    'https://www.googleapis.com/auth/cloud-vision',
    'https://www.googleapis.com/auth/spreadsheets',
)
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
    creds = tools.run_flow(flow, store)

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision',  'v1', http=HTTP)
SHEETS = discovery.build('sheets',  'v4', http=HTTP)


def drive_get_img(fname):
    'download file from Drive and return file info & binary if found'

    # search for file on Google Drive
    rsp = DRIVE.files().list(q="name='%s'" % fname,
            fields='files(id,name,mimeType,modifiedTime)'
    ).execute().get('files', [])

    # download binary & return file info if found, else return None
    if rsp:
        target = rsp[0]  # use first matching file
        fileId = target['id']
        fname = target['name']
        mtype = target['mimeType']
        binary = DRIVE.files().get_media(fileId=fileId).execute()
        return fname, mtype, target['modifiedTime'], binary


def gcs_blob_upload(fname, bucket, media, mimetype):
    'upload an object to a Google Cloud Storage bucket'

    # build blob metadata and upload via GCS API
    body = {'name': fname, 'uploadType': 'multipart', 'contentType': mimetype}
    return GCS.objects().insert(bucket=bucket, body=body,
            media_body=http.MediaIoBaseUpload(io.BytesIO(media), mimetype),
            fields='bucket,name').execute()


def vision_label_img(img, top):
    'send image to Vision API for label annotation'

    # build image metadata and call Vision API to process
    body = {'requests': [{
                'image':     {'content': img},
                'features': [{'type': 'LABEL_DETECTION', 'maxResults': top}],
    }]}
    rsp = VISION.images().annotate(body=body).execute().get('responses', [{}])[0]

    # return top labels for image as CSV for Sheet (row)
    if 'labelAnnotations' in rsp:
        return ', '.join('(%.2f%%) %s' % (
                label['score']*100., label['description']) \
                for label in rsp['labelAnnotations'])


def sheet_append_row(sheet, row):
    'append row to a Google Sheet, return #cells added'

    # call Sheets API to write row to Sheet (via its ID)
    rsp = SHEETS.spreadsheets().values().append(
            spreadsheetId=sheet, range='Sheet1',
            valueInputOption='USER_ENTERED', body={'values': [row]}
    ).execute()
    if rsp:
        return rsp.get('updates').get('updatedCells')


def main(fname, bucket, sheet_id, folder, top, debug):
    '"main()" drives process from image download through report generation'

    # download img file & info from Drive
    rsp = drive_get_img(fname)
    if not rsp:
        return
    fname, mtype, ftime, data = rsp
    if debug:
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

    # upload file to GCS
    gcsname = '%s/%s'% (folder, fname)
    rsp = gcs_blob_upload(gcsname, bucket, data, mtype)
    if not rsp:
        return
    if debug:
        print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

    # process w/Vision
    rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), top)
    if not rsp:
        return
    if debug:
        print('Top %d labels from Vision API: %s' % (top, rsp))

    # push results to Sheet, get cells-saved count
    fsize = k_ize(len(data))
    row = [folder,
            '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
            bucket, gcsname, fname), mtype, ftime, fsize, rsp
    ]
    rsp = sheet_append_row(sheet_id, row)
    if not rsp:
        return
    if debug:
        print('Added %d cells to Google Sheet' % rsp)
    return True


if __name__ == '__main__':
    # args: [-hv] [-i imgfile] [-b bucket] [-f folder] [-s Sheet ID] [-t top labels]
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", "--imgfile", action="store_true",
            default=FILE, help="image file filename")
    parser.add_argument("-b", "--bucket_id", action="store_true",
            default=BUCKET, help="Google Cloud Storage bucket name")
    parser.add_argument("-f", "--folder", action="store_true",
            default=PARENT, help="Google Cloud Storage image folder")
    parser.add_argument("-s", "--sheet_id", action="store_true",
            default=SHEET, help="Google Sheet Drive file ID (44-char str)")
    parser.add_argument("-t", "--viz_top", action="store_true",
            default=TOP, help="return top N (default %d) Vision API labels" % TOP)
    parser.add_argument("-v", "--verbose", action="store_true",
            default=DEBUG, help="verbose display output")
    args = parser.parse_args()

    print('Processing file %r... please wait' % args.imgfile)
    rsp = main(args.imgfile, args.bucket_id,
            args.sheet_id, args.folder, args.viz_top, args.verbose)
    if rsp:
        sheet_url = 'https://docs.google.com/spreadsheets/d/%s/edit' % args.sheet_id
        print('DONE: opening web browser to it, or see %s' % sheet_url)
        webbrowser.open(sheet_url, new=1, autoraise=True)
    else:
        print('ERROR: could not process %r' % args.imgfile)

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

13. ยินดีด้วย

Codelab นี้มีการเรียนรู้อีกมากมาย คุณจึงทำได้สำเร็จ แต่ก็ผ่าน Codelab ที่ยาวกว่า 1 รายการมาได้ คุณจึงได้จัดการกับสถานการณ์ขององค์กรที่เป็นไปได้ด้วยบรรทัด Python ประมาณ 130 บรรทัด โดยใช้ประโยชน์จาก Google Cloud และ Google Workspace ทั้งหมด รวมถึงย้ายข้อมูลระหว่าง 2 แหล่งนี้เพื่อสร้างโซลูชันที่ใช้งานได้ สำรวจพื้นที่เก็บข้อมูลโอเพนซอร์สของแอปนี้ทุกเวอร์ชัน (ดูข้อมูลเพิ่มเติมด้านล่าง)

ล้างข้อมูล

  1. การใช้ Google Cloud APIs ไม่เสียค่าใช้จ่าย แม้ว่า Google Workspace API จะเป็นผู้รับผิดชอบค่าธรรมเนียมการสมัครใช้บริการ Google Workspace รายเดือน (ผู้ใช้ Gmail ของผู้บริโภคจะมีค่าธรรมเนียมรายเดือนอยู่ที่ 0) จึงไม่ต้องชำระ/เลิกใช้งาน API สำหรับผู้ใช้ Google Workspace สำหรับ Google Cloud ให้ไปที่หน้าแดชบอร์ด Cloud Console และตรวจสอบ "การ์ด" การเรียกเก็บเงิน สำหรับค่าบริการโดยประมาณ
  2. สำหรับ Cloud Vision คุณสามารถเรียก API ได้ฟรีตามจำนวนครั้งที่กำหนดต่อเดือน ตราบใดที่คุณยังอยู่ภายใต้ขีดจำกัดดังกล่าว ก็ไม่จำเป็นต้องปิดการทำงานหรือปิดใช้/ลบโปรเจ็กต์ ดูข้อมูลเพิ่มเติมเกี่ยวกับการเรียกเก็บเงินและโควต้าฟรีของ Vision API ได้ในหน้าราคา
  3. ผู้ใช้ Cloud Storage บางรายจะได้รับพื้นที่เก็บข้อมูลฟรีต่อเดือน หากรูปภาพที่คุณเก็บถาวรโดยใช้ Codelab นี้ไม่ได้ทำให้เกินโควต้าดังกล่าว คุณจะไม่เสียค่าใช้จ่ายใดๆ ดูข้อมูลเพิ่มเติมเกี่ยวกับการเรียกเก็บเงินของ GCS และโควต้าฟรีได้ในหน้าราคา คุณสามารถดูและลบ Blob ได้อย่างง่ายดายจากเบราว์เซอร์ Cloud Storage
  4. การใช้งาน Google ไดรฟ์ อาจมีโควต้าพื้นที่เก็บข้อมูลด้วย และหากคุณใช้พื้นที่เก็บข้อมูลเกินโควต้า (หรือใกล้เคียงกับพื้นที่นั้น) คุณอาจพิจารณาใช้เครื่องมือที่สร้างไว้ใน Codelab นี้เพื่อเก็บรูปภาพเหล่านั้นไปยัง Cloud Storage เพื่อเพิ่มพื้นที่ในไดรฟ์ ดูข้อมูลเพิ่มเติมเกี่ยวกับพื้นที่เก็บข้อมูล Google ไดรฟ์ได้ในหน้าราคาที่เหมาะสมสำหรับผู้ใช้ Google Workspace Basic หรือผู้ใช้ Gmail/ผู้ใช้ทั่วไป

แม้ว่าแพ็กเกจ Google Workspace Business และ Enterprise ส่วนใหญ่จะมีพื้นที่เก็บข้อมูลไม่จำกัด แต่การดำเนินการนี้อาจทำให้โฟลเดอร์ในไดรฟ์รกรุงรังและ/หรือรกตาได้ และแอปที่คุณสร้างขึ้นในบทแนะนำนี้ก็เป็นวิธีที่ยอดเยี่ยมในการเก็บไฟล์ส่วนเกินและล้างข้อมูลใน Google ไดรฟ์

เวอร์ชันอื่น

ขณะที่ final/analyze_gsimg.py เป็น "สุดท้าย" เวอร์ชันที่เป็นทางการที่คุณกำลังทำอยู่ในบทแนะนำนี้ ยังไม่จบเพียงเท่านี้ ปัญหาหนึ่งของแอปเวอร์ชันสุดท้ายคือแอปใช้ไลบรารีการตรวจสอบสิทธิ์เวอร์ชันเก่าซึ่งเลิกใช้งานแล้ว เราเลือกเส้นทางนี้เนื่องจากในขณะที่เขียนบทความนี้ ไลบรารีการตรวจสอบสิทธิ์รุ่นใหม่ไม่รองรับองค์ประกอบหลักหลายอย่าง ได้แก่ การจัดการพื้นที่เก็บข้อมูลโทเค็น OAuth และความปลอดภัยของชุดข้อความ

ไลบรารีการตรวจสอบสิทธิ์ปัจจุบัน (ใหม่)

อย่างไรก็ตาม ในบางสถานการณ์ ระบบจะไม่รองรับไลบรารีการตรวจสอบสิทธิ์แบบเก่าอีกต่อไป เราจึงขอแนะนําให้คุณตรวจสอบเวอร์ชันที่ใช้ไลบรารีการตรวจสอบสิทธิ์ที่ใหม่กว่า (ปัจจุบัน) ในโฟลเดอร์ alt ของที่เก็บ แม้ว่าไฟล์เหล่านั้นจะไม่ปลอดภัย Thread (แต่คุณสามารถสร้างโซลูชันของตัวเองได้) มองหาไฟล์ที่มี *newauth* ในชื่อ

ไลบรารีของไคลเอ็นต์ผลิตภัณฑ์ของ Google Cloud

Google Cloud ขอแนะนำให้นักพัฒนาซอฟต์แวร์ทั้งหมดใช้ไลบรารีของไคลเอ็นต์ผลิตภัณฑ์เมื่อใช้ Google Cloud API ขออภัย API ที่ไม่ใช่ Google Cloud ไม่มีไลบรารีดังกล่าวในขณะนี้ การใช้ไลบรารีระดับล่างช่วยให้ใช้ API ที่สอดคล้องกันและใช้ฟีเจอร์ให้อ่านง่ายขึ้น เวอร์ชันอื่นที่ใช้ไลบรารีไคลเอ็นต์ผลิตภัณฑ์ของ Google Cloud จะอยู่ในโฟลเดอร์ alt ของที่เก็บเพื่อให้คุณตรวจสอบ เช่นเดียวกับคำแนะนำข้างต้น มองหาไฟล์ที่มี *-gcp* ในชื่อ

การให้สิทธิ์บัญชีบริการ

เมื่อทำงานในระบบคลาวด์เพียงอย่างเดียว มักจะไม่มีข้อมูลที่เป็นมนุษย์หรือมนุษย์ (มนุษย์) ผู้ใช้ จึงเป็นเหตุผลที่บัญชีบริการและการให้สิทธิ์บัญชีบริการใช้กับ Google Cloud เป็นหลัก อย่างไรก็ตาม โดยทั่วไปแล้ว เอกสาร Google Workspace จะเป็นของผู้ใช้ (ที่เป็นมนุษย์) บทแนะนำนี้จึงใช้การให้สิทธิ์บัญชีผู้ใช้ แต่นั่นไม่ได้หมายความว่าจะใช้ Google Workspace API กับบัญชีบริการไม่ได้ ตราบใดที่บัญชีเหล่านั้นมีระดับการเข้าถึงที่เหมาะสม ก็นำไปใช้ในแอปพลิเคชันได้อย่างแน่นอน เช่นเดียวกับด้านบน เวอร์ชันอื่นที่ใช้การให้สิทธิ์บัญชีบริการจะมีอยู่ในโฟลเดอร์ alt ของที่เก็บเพื่อให้คุณตรวจสอบ มองหาไฟล์ที่มี *-svc* ในชื่อ

แคตตาล็อกเวอร์ชันทางเลือก

คุณจะเห็นเวอร์ชันทางเลือกทั้งหมดของ final/analyze_gsimg.py ด้านล่าง โดยแต่ละเวอร์ชันมีพร็อพเพอร์ตี้ด้านบนอย่างน้อย 1 รายการ ในชื่อไฟล์ของแต่ละเวอร์ชัน ให้มองหา:

  • "oldauth" สำหรับเวอร์ชันที่ใช้ไลบรารีการตรวจสอบสิทธิ์แบบเก่า (นอกเหนือจาก final/analyze_gsimg.py)
  • "newauth" สำหรับผู้ที่ใช้ไลบรารีการตรวจสอบสิทธิ์ปัจจุบัน/ใหม่
  • "gcp" สำหรับผู้ที่ใช้ไลบรารีของไคลเอ็นต์ผลิตภัณฑ์ Google Cloud เช่น google-cloud-storage ฯลฯ
  • "svc" สำหรับผู้ที่ใช้การตรวจสอบสิทธิ์บัญชีบริการ ("svc acct") แทนบัญชีผู้ใช้

นี่คือเวอร์ชันทั้งหมด

ชื่อไฟล์

คำอธิบาย

final/analyze_gsimg.py

ตัวอย่างหลัก ใช้ไลบรารีการตรวจสอบสิทธิ์แบบเก่า

alt/analyze_gsimg-newauth.py

เหมือนกับ final/analyze_gsimg.py แต่ใช้ไลบรารีการตรวจสอบสิทธิ์ที่ใหม่กว่า

alt/analyze_gsimg-oldauth-gcp.py

เหมือนกับ final/analyze_gsimg.py แต่ใช้ไลบรารีของไคลเอ็นต์ผลิตภัณฑ์ Google Cloud

alt/analyze_gsimg-newauth-gcp.py

เหมือนกับ alt/analyze_gsimg-newauth.py แต่ใช้ไลบรารีของไคลเอ็นต์ผลิตภัณฑ์ Google Cloud

alt/analyze_gsimg-oldauth-svc.py

เหมือนกับ final/analyze_gsimg.py แต่ใช้บัญชี SVG แทนบัญชีผู้ใช้

alt/analyze_gsimg-newauth-svc.py

เหมือนกับ alt/analyze_gsimg-newauth.py แต่ใช้การตรวจสอบสิทธิ์บัญชี SVG แทนบัญชีผู้ใช้

alt/analyze_gsimg-oldauth-svc-gcp.py

เหมือนกับ alt/analyze_gsimg-oldauth-svc.py แต่ใช้ไลบรารีของไคลเอ็นต์ผลิตภัณฑ์ Google Cloud และเหมือนกับ alt/analyze_gsimg-oldauth-gcp.py แต่ใช้การตรวจสอบสิทธิ์บัญชี SVG แทนบัญชีผู้ใช้

alt/analyze_gsimg-newauth-svc-gcp.py

เหมือนกับ alt/analyze_gsimg-oldauth-svc-gcp.py แต่ใช้ไลบรารีการตรวจสอบสิทธิ์ที่ใหม่กว่า

เมื่อใช้ร่วมกับ final/analyze_gsimg.py เดิม คุณก็จะสามารถใช้โซลูชันขั้นสุดท้ายทั้งหมด โดยไม่คำนึงถึงสภาพแวดล้อมในการพัฒนาซอฟต์แวร์ Google API ของคุณ และยังเลือกโซลูชันที่เหมาะกับความต้องการของคุณมากที่สุดได้ ดู alt/README.md สำหรับคำอธิบายที่คล้ายกันด้วย

การศึกษาเพิ่มเติม

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

  1. (รูปภาพหลายรูปในโฟลเดอร์) แทนที่จะประมวลผลรูปภาพ 1 รูป สมมติว่าคุณมีรูปภาพในโฟลเดอร์ Google ไดรฟ์
  2. (รูปภาพหลายรูปในไฟล์ ZIP) แทนที่จะใช้โฟลเดอร์รูปภาพ เรามาลองเก็บไฟล์ ZIP ที่มีไฟล์ภาพแทนโฟลเดอร์รูปภาพไหม หากใช้ Python ให้พิจารณาโมดูล zipfile
  3. (วิเคราะห์ป้ายกำกับ Vision) จัดกลุ่มรูปภาพที่คล้ายกันไว้ด้วยกัน โดยอาจเริ่มด้วยการมองหาป้ายกำกับที่พบบ่อยที่สุด แล้วป้ายกำกับลำดับที่ 2 และลำดับที่ 2 ต่อไปเรื่อยๆ
  4. (สร้างแผนภูมิ) ติดตามผล #3 สร้างแผนภูมิด้วย Sheets API โดยอิงจากการวิเคราะห์และการจัดหมวดหมู่ Vision API
  5. (จัดหมวดหมู่เอกสาร) สมมติว่าคุณมีไฟล์ PDF ที่จะจัดหมวดหมู่ด้วย Cloud Natural Language API แทนที่จะวิเคราะห์รูปภาพด้วย Cloud Vision API เมื่อใช้โซลูชันข้างต้น ไฟล์ PDF เหล่านี้อาจอยู่ในโฟลเดอร์ไดรฟ์หรือที่เก็บถาวร ZIP ในไดรฟ์
  6. (สร้างงานนำเสนอ) ใช้ Slides API เพื่อสร้างชุดสไลด์จากเนื้อหาของรายงานสเปรดชีตใน Google ชีต หากต้องการแรงบันดาลใจ โปรดดูบล็อกโพสต์นี้และ วิดีโอเกี่ยวกับการสร้างสไลด์จากข้อมูลสเปรดชีต
  7. (ส่งออกเป็น PDF) ส่งออกสเปรดชีตและ/หรือชุดสไลด์เป็น PDF แต่จะไม่เป็นฟีเจอร์ของ API ของชีตและสไลด์ คำแนะนำ: Google Drive API เครดิตเพิ่มเติม: รวม PDF ของชีตและสไลด์ไว้ใน PDF หลักไฟล์เดียวด้วยเครื่องมืออย่าง Ghostscript (Linux, Windows) หรือ Combine PDF Pages.action (Mac OS X)

ดูข้อมูลเพิ่มเติม

Codelabs

ทั่วไป

Google Workspace

Google Cloud

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้ใบอนุญาตทั่วไปครีเอทีฟคอมมอนส์แบบระบุแหล่งที่มา 2.0