آرشیو تصاویر، تجزیه و تحلیل و تولید گزارش Google Workspace & Google Cloud

۱. مرور کلی

این آزمایشگاه کد، یک گردش کار سازمانی احتمالی را تصور می‌کند: بایگانی تصاویر، تجزیه و تحلیل و تولید گزارش. تصور کنید سازمان شما مجموعه‌ای از تصاویر را دارد که فضایی را در یک منبع محدود اشغال کرده‌اند. شما می‌خواهید آن داده‌ها را بایگانی کنید، آن تصاویر را تجزیه و تحلیل کنید و از همه مهم‌تر، گزارشی تهیه کنید که خلاصه‌ای از مکان‌های بایگانی شده به علاوه نتایج تجزیه و تحلیل را جمع‌آوری و آماده استفاده توسط مدیریت کند. گوگل کلود ابزارهایی را برای تحقق این امر فراهم می‌کند و از APIهای دو خط تولید خود، گوگل ورک اسپیس (قبلاً G Suite یا Google Apps) و گوگل کلود (قبلاً GCP) استفاده می‌کند.

در سناریوی ما، کاربر تجاری تصاویر را در گوگل درایو خواهد داشت. منطقی است که از آنها در فضای ذخیره‌سازی «سردتر» و ارزان‌تر، مانند کلاس‌های ذخیره‌سازی موجود در Google Cloud Storage ، نسخه پشتیبان تهیه کند. Google Cloud Vision به توسعه‌دهندگان اجازه می‌دهد تا به راحتی ویژگی‌های تشخیص بینایی، از جمله تشخیص اشیاء و نقاط دیدنی، تشخیص نوری کاراکتر (OCR) و غیره را در برنامه‌ها ادغام کنند. در نهایت، یک صفحه گسترده Google Sheets یک ابزار تجسم مفید برای خلاصه کردن همه این موارد برای رئیس شما است.

پس از تکمیل این آزمایشگاه کدنویسی برای ساخت راهکاری که از کل فضای ابری گوگل بهره می‌برد، امیدواریم که الهام بگیرید تا چیزی حتی تأثیرگذارتر برای سازمان یا مشتریان خود بسازید.

آنچه یاد خواهید گرفت

  • نحوه استفاده از ابر پوسته
  • نحوه احراز هویت درخواست‌های API
  • نحوه نصب کتابخانه کلاینت Google APIs برای پایتون
  • نحوه فعال کردن API های گوگل
  • نحوه دانلود فایل‌ها از گوگل درایو
  • نحوه آپلود اشیاء/حباب‌ها در فضای ذخیره‌سازی ابری
  • نحوه تجزیه و تحلیل داده‌ها با Cloud Vision
  • نحوه نوشتن ردیف در گوگل شیت

آنچه نیاز دارید

  • یک حساب گوگل (حساب‌های کاربری گوگل ورک‌اسپیس ممکن است نیاز به تأیید مدیر داشته باشند)
  • یک پروژه گوگل کلود با یک حساب پرداخت فعال گوگل کلود
  • آشنایی با دستورات ترمینال/شل سیستم عامل
  • مهارت‌های پایه در پایتون (۲ یا ۳)، اما می‌توانید از هر زبان پشتیبانی‌شده‌ای استفاده کنید

داشتن تجربه با چهار محصول گوگل کلود که در بالا ذکر شد مفید خواهد بود اما الزامی نیست. اگر زمان اجازه می‌دهد که ابتدا به طور جداگانه با آنها آشنا شوید، می‌توانید قبل از پرداختن به تمرین اینجا، برای هر کدام آزمایش کد انجام دهید:

نظرسنجی

چگونه از این آموزش استفاده خواهید کرد؟

فقط تا انتها بخوانید آن را بخوانید و تمرین‌ها را انجام دهید

تجربه خود را با پایتون چگونه ارزیابی می‌کنید؟

تازه کار متوسط ماهر

تجربه خود را در استفاده از خدمات ابری گوگل چگونه ارزیابی می‌کنید؟

تازه کار متوسط ماهر

تجربه خود را در استفاده از خدمات توسعه‌دهندگان Google Workspace چگونه ارزیابی می‌کنید؟

تازه کار متوسط ماهر

آیا مایلید آزمایشگاه‌های کد «کسب‌وکارمحور» بیشتری نسبت به آزمایشگاه‌هایی که صرفاً معرفی ویژگی‌های محصول هستند، ببینید؟

بله خیر بیشتر از هر دو

۲. تنظیمات و الزامات

تنظیم محیط خودتنظیم

  1. وارد کنسول گوگل کلود شوید و یک پروژه جدید ایجاد کنید یا از یک پروژه موجود دوباره استفاده کنید. اگر از قبل حساب جیمیل یا گوگل ورک اسپیس ندارید، باید یکی ایجاد کنید .

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • نام پروژه ، نام نمایشی برای شرکت‌کنندگان این پروژه است. این یک رشته کاراکتری است که توسط APIهای گوگل استفاده نمی‌شود. می‌توانید آن را در هر زمانی به‌روزرسانی کنید.
  • شناسه پروژه باید در تمام پروژه‌های گوگل کلود منحصر به فرد باشد و تغییرناپذیر است (پس از تنظیم، قابل تغییر نیست). کنسول کلود به طور خودکار یک رشته منحصر به فرد تولید می‌کند؛ معمولاً برای شما مهم نیست که چیست. در اکثر آزمایشگاه‌های کد، باید شناسه پروژه را ارجاع دهید (که معمولاً با عنوان PROJECT_ID شناخته می‌شود). اگر شناسه تولید شده را دوست ندارید، می‌توانید یک شناسه تصادفی دیگر ایجاد کنید. به عنوان یک جایگزین، می‌توانید شناسه خودتان را امتحان کنید و ببینید که آیا در دسترس است یا خیر. پس از این مرحله قابل تغییر نیست و در طول پروژه باقی خواهد ماند.
  • برای اطلاع شما، یک مقدار سوم هم وجود دارد، شماره پروژه که برخی از APIها از آن استفاده می‌کنند. برای کسب اطلاعات بیشتر در مورد هر سه این مقادیر، به مستندات مراجعه کنید.
  1. در مرحله بعد، برای استفاده از منابع/API های ابری، باید پرداخت صورتحساب را در کنسول ابری فعال کنید . اجرای این آزمایشگاه کد، اگر اصلاً هزینه‌ای نداشته باشد، هزینه زیادی نخواهد داشت. برای خاموش کردن منابع به طوری که پس از این آموزش متحمل پرداخت صورتحساب نشوید، می‌توانید منابعی را که ایجاد کرده‌اید یا کل پروژه را حذف کنید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان ۳۰۰ دلاری هستند.

شروع پوسته ابری

خلاصه

اگرچه می‌توانید کد را به صورت محلی روی لپ‌تاپ خود توسعه دهید، هدف ثانویه این آزمایشگاه کد، آموزش نحوه استفاده از Google Cloud Shell است، یک محیط خط فرمان که از طریق مرورگر وب مدرن شما در فضای ابری اجرا می‌شود.

فعال کردن پوسته ابری

  1. از کنسول ابری، روی فعال کردن پوسته ابری کلیک کنید 853e55310c205094.png .

55efc1aaa7a4d3ad.png

اگر قبلاً Cloud Shell را شروع نکرده‌اید، یک صفحه میانی (در پایین صفحه) به شما نمایش داده می‌شود که توضیح می‌دهد چیست. در این صورت، روی ادامه کلیک کنید (و دیگر هرگز آن را نخواهید دید). آن صفحه یکبار مصرف به این شکل است:

9c92662c6a846a5c.png

آماده‌سازی و اتصال به Cloud Shell فقط چند لحظه طول می‌کشد.

9f0e51b578fecce5.png

این ماشین مجازی با تمام ابزارهای توسعه مورد نیاز شما پر شده است. این ماشین یک دایرکتوری خانگی ۵ گیگابایتی دائمی ارائه می‌دهد و در فضای ابری گوگل اجرا می‌شود که عملکرد شبکه و احراز هویت را تا حد زیادی بهبود می‌بخشد. بخش عمده‌ای از کار شما در این آزمایشگاه کد، اگر نگوییم همه، را می‌توان به سادگی با یک مرورگر یا کروم‌بوک انجام داد.

پس از اتصال به 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].

۳. تأیید محیط پایتون

این آزمایشگاه کد شما را ملزم به استفاده از زبان پایتون می‌کند (اگرچه بسیاری از زبان‌ها توسط کتابخانه‌های کلاینت API گوگل پشتیبانی می‌شوند ، بنابراین می‌توانید چیزی معادل آن را در ابزار توسعه مورد علاقه خود بسازید و به سادگی از پایتون به عنوان شبه کد استفاده کنید). به طور خاص، این آزمایشگاه کد از پایتون ۲ و ۳ پشتیبانی می‌کند، اما توصیه می‌کنیم در اسرع وقت به نسخه ۳.x مهاجرت کنید.

Cloud Shell ابزاری مناسب است که مستقیماً از طریق Cloud Console در دسترس کاربران قرار دارد و نیازی به محیط توسعه محلی ندارد، بنابراین این آموزش را می‌توان به طور کامل در فضای ابری با یک مرورگر وب انجام داد. به طور خاص‌تر برای این آزمایشگاه کد، Cloud Shell از قبل هر دو نسخه پایتون را نصب کرده است.

Cloud Shell همچنین IPython را نصب کرده است: این یک مفسر پایتون تعاملی سطح بالاتر است که ما آن را توصیه می‌کنیم، به خصوص اگر عضوی از جامعه علوم داده یا یادگیری ماشین هستید. اگر عضوی از این جامعه هستید، IPython مفسر پیش‌فرض برای Jupyter Notebooks و همچنین Colab ، Jupyter Notebooks میزبانی شده توسط Google Research است.

IPython ابتدا از مفسر پایتون ۳ استفاده می‌کند، اما اگر پایتون ۳.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 مورد نظر شما نیست، استفاده از یک مفسر تعاملی استاندارد پایتون (یا 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.
>>>

کدلب همچنین فرض می‌کند که شما ابزار نصب pip (مدیر بسته پایتون و حل‌کننده وابستگی) را دارید. این ابزار همراه با نسخه‌های ۲.۷.۹+ یا ۳.۴+ ارائه می‌شود. اگر نسخه پایتون قدیمی‌تری دارید، برای دستورالعمل‌های نصب به این راهنما مراجعه کنید. بسته به مجوزهای شما، ممکن است نیاز به دسترسی sudo یا superuser داشته باشید، اما معمولاً اینطور نیست. همچنین می‌توانید به طور صریح pip2 یا pip3 برای اجرای pip برای نسخه‌های خاص پایتون استفاده کنید.

بقیه‌ی کدها فرض می‌کنند که شما از پایتون ۳ استفاده می‌کنید - اگر دستورالعمل‌های پایتون ۲ تفاوت قابل توجهی با ۳.x داشته باشند، برای آنها دستورالعمل‌های خاصی ارائه خواهد شد.

[اختیاری] ایجاد و استفاده از محیط‌های مجازی

این بخش اختیاری است و فقط برای کسانی که باید از یک محیط مجازی برای این آزمایشگاه کد استفاده کنند (طبق نوار کناری هشدار بالا) واقعاً ضروری است. اگر فقط پایتون ۳ را روی رایانه خود دارید، می‌توانید به سادگی این دستور را برای ایجاد یک محیط مجازی به نام my_env صادر کنید (در صورت تمایل می‌توانید نام دیگری انتخاب کنید):

virtualenv my_env

با این حال، اگر هر دو نسخه پایتون ۲ و ۳ را روی رایانه خود دارید، توصیه می‌کنیم یک محیط مجازی پایتون ۳ نصب کنید که می‌توانید با استفاده از -p flag مانند این عمل کنید:

virtualenv -p python3 my_env

با فعال کردن آن به صورت زیر، وارد محیط مجازی (virtualenv) تازه ایجاد شده خود شوید:

source my_env/bin/activate

با مشاهده‌ی اینکه نام محیط شما قبل از اعلان پوسته آمده است، تأیید کنید که در محیط هستید، یعنی

(my_env) $ 

حالا باید بتوانید بسته‌های مورد نیاز را pip install ، کد را درون این eivonment اجرا کنید و غیره. مزیت دیگر این است که اگر کاملاً آن را خراب کنید، در شرایطی قرار بگیرید که نصب پایتون شما خراب شود و غیره، می‌توانید کل این محیط را بدون تأثیر بر بقیه سیستم خود از بین ببرید.

۴. کتابخانه کلاینت APIهای گوگل برای پایتون را نصب کنید

این آزمایشگاه کد نیاز به استفاده از کتابخانه کلاینت APIهای گوگل برای پایتون دارد، بنابراین یا یک فرآیند نصب ساده است، یا ممکن است اصلاً لازم نباشد کاری انجام دهید.

ما قبلاً برای راحتی شما استفاده از 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"

اگر به جای آن از پایتون ۲ (از Cloud Shell) استفاده کنید، هشداری دریافت خواهید کرد که پشتیبانی از آن منسوخ شده است:

*******************************************************************************
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.
*******************************************************************************

وقتی بتوانید دستور import "test" را با موفقیت اجرا کنید (بدون خطا/خروجی)، آماده‌اید تا با APIهای گوگل کار کنید!

خلاصه

از آنجایی که این یک آزمایشگاه کد سطح متوسط ​​است، فرض بر این است که شما از قبل تجربه ایجاد و استفاده از پروژه‌ها در کنسول را دارید. اگر با APIهای گوگل و به طور خاص APIهای گوگل ورک‌اسپیس آشنا نیستید، ابتدا آزمایشگاه کد مقدماتی APIهای گوگل ورک‌اسپیس را امتحان کنید. علاوه بر این، اگر می‌دانید چگونه اعتبارنامه‌های حساب کاربری ( نه حساب سرویس ) را ایجاد کنید (یا از اعتبارنامه‌های موجود استفاده مجدد کنید)، فایل client_secret.json را در دایرکتوری کار خود قرار دهید، ماژول بعدی را رد کنید و به بخش «فعال کردن APIهای گوگل» بروید.

۵. *مجوز دادن به درخواست‌های API (مجوز کاربر)

اگر قبلاً اعتبارنامه‌های مجوز حساب کاربری را ایجاد کرده‌اید و با فرآیند آن آشنا هستید، می‌توانید از این بخش صرف نظر کنید. این بخش با مجوز حساب سرویس که تکنیک آن متفاوت است، متفاوت است، بنابراین لطفاً در ادامه ادامه دهید.

مقدمه‌ای بر مجوزدهی (به‌علاوه‌ی برخی احراز هویت‌ها)

برای ارسال درخواست به APIها، برنامه شما باید مجوز مناسب را داشته باشد. Authentication ، کلمه‌ای مشابه، اعتبارنامه‌های ورود به سیستم را توصیف می‌کند - شما هنگام ورود به حساب گوگل خود با نام کاربری و رمز عبور، خود را تأیید می‌کنید. پس از تأیید اعتبار، مرحله بعدی این است که آیا شما - یا بهتر بگوییم، کد شما - مجاز به دسترسی به داده‌ها، مانند فایل‌های blob در Cloud Storage یا فایل‌های شخصی کاربر در Google Drive هستید یا خیر.

APIهای گوگل از چندین نوع مجوز پشتیبانی می‌کنند، اما رایج‌ترین نوع آن برای کاربران APIهای G Suite، مجوز کاربر است، زیرا برنامه‌ی نمونه در این آزمایشگاه کد به داده‌های متعلق به کاربران نهایی دسترسی دارد. این کاربران نهایی باید به برنامه‌ی شما اجازه دسترسی به داده‌هایشان را بدهند. این بدان معناست که کد شما باید اعتبارنامه‌های حساب کاربری OAuth2 را دریافت کند.

برای دریافت اعتبارنامه‌های OAuth2 برای مجوزدهی کاربر، به مدیریت API برگردید و تب «اعتبارنامه‌ها» را در منوی سمت چپ انتخاب کنید:

635af008256d323.png

وقتی به آنجا رسیدید، تمام اعتبارنامه‌های خود را در سه بخش جداگانه مشاهده خواهید کرد:

fd2f4133b406d572.png

اولی برای کلیدهای API ، دومی برای شناسه‌های کلاینت OAuth 2.0 و آخری برای حساب‌های سرویس OAuth2 است - ما از وسطی استفاده می‌کنیم.

ایجاد اعتبارنامه‌ها

از صفحه اعتبارنامه‌ها، روی دکمه + ایجاد اعتبارنامه‌ها در بالا کلیک کنید، که سپس یک کادر محاوره‌ای به شما می‌دهد که در آن «OAuth client ID:» را انتخاب می‌کنید.

b17b663668e38787.png

در صفحه بعد، دو اقدام پیش رو دارید: پیکربندی «صفحه رضایت» برای مجوز برنامه‌تان و انتخاب نوع برنامه:

4e0b967c9d70d262.png

اگر صفحه رضایت‌نامه تنظیم نکرده باشید، هشدار را در کنسول مشاهده خواهید کرد و باید همین حالا این کار را انجام دهید. (اگر صفحه رضایت‌نامه شما از قبل تنظیم شده است، از این مراحل بعدی صرف نظر کنید.)

روی «صفحه پیکربندی رضایت» کلیک کنید و در آنجا یک برنامه «خارجی» (یا اگر مشتری G Suite هستید «داخلی») را انتخاب کنید:

f17e97b30d994b0c.png

توجه داشته باشید که برای اهداف این تمرین، فرقی نمی‌کند کدام را انتخاب کنید زیرا نمونه کد آزمایشگاه خود را منتشر نمی‌کنید. اکثر افراد برای رفتن به یک صفحه پیچیده‌تر، گزینه "External" را انتخاب می‌کنند، اما شما فقط باید فیلد "Application name" را در بالا تکمیل کنید:

b107ab81349bdad2.png

تنها چیزی که در حال حاضر نیاز دارید، یک نام برای برنامه است، بنابراین نامی را انتخاب کنید که منعکس کننده آزمایشگاه کدی باشد که شما انجام می‌دهید، سپس روی ذخیره کلیک کنید.

ایجاد شناسه کلاینت OAuth (احراز هویت کاربر)

حالا به تب Credentials برگردید تا یک شناسه کلاینت OAuth2 ایجاد کنید. در اینجا می‌توانید انواع شناسه‌های کلاینت OAuth را که می‌توانید ایجاد کنید، مشاهده کنید:

5ddd365ac0af1e34.png

ما در حال توسعه یک ابزار خط فرمان هستیم که Other نام دارد، بنابراین آن را انتخاب کنید و سپس روی دکمه Create کلیک کنید. یک نام برای شناسه کلاینت انتخاب کنید که منعکس کننده برنامه‌ای باشد که در حال ایجاد آن هستید یا به سادگی نام پیش‌فرض را که معمولاً "Other client N " است، در نظر بگیرید.

ذخیره اعتبارنامه‌های شما

  1. یک کادر محاوره‌ای با اطلاعات کاربری جدید ظاهر می‌شود؛ برای بستن، روی تأیید کلیک کنید.

8bec84d82cb104d7.png

  1. به صفحه اعتبارنامه‌ها برگردید، به پایین اسکرول کنید تا به بخش «OAuth2 Client IDs» برسید، آیکون دانلود را پیدا کرده و روی آن کلیک کنید. f54b28417901b3aa.png در پایین سمت راست شناسه کلاینت تازه ایجاد شده شما. ۱b4e8d248274a338.png
  2. این کار یک پنجره محاوره‌ای برای ذخیره فایلی با نام client_secret- LONG-HASH-STRING .apps.googleusercontent.com.json باز می‌کند که احتمالاً در پوشه دانلودهای شما قرار دارد. توصیه می‌کنیم آن را به نامی ساده‌تر مانند client_secret.json (که برنامه نمونه از آن استفاده می‌کند) کوتاه کنید، سپس آن را در دایرکتوری/پوشه‌ای که برنامه نمونه را در این آزمایشگاه کد ایجاد خواهید کرد، ذخیره کنید.

خلاصه

اکنون آماده‌اید تا APIهای گوگل به کار رفته در این آزمایشگاه کد را فعال کنید. همچنین، برای نام برنامه در صفحه رضایت OAuth، ما "Vision API demo" را انتخاب کردیم، بنابراین انتظار داشته باشید که این نام را در برخی از تصاویر آینده ببینید.

۶. فعال کردن APIهای گوگل

این آزمایشگاه کد از چهار (4) API گوگل کلود استفاده می‌کند، یک جفت از گوگل کلود (Cloud Storage و Cloud Vision) و یک جفت دیگر از گوگل ورک‌اسپیس (Google Drive و Google Sheets). در زیر دستورالعمل‌های کلی برای فعال‌سازی APIهای گوگل آمده است. وقتی نحوه فعال‌سازی یک API را بدانید، بقیه نیز مشابه هستند.

صرف نظر از اینکه می‌خواهید از کدام API گوگل در برنامه خود استفاده کنید، باید آنها را فعال کنید . APIها را می‌توان از خط فرمان یا از کنسول Cloud فعال کرد. فرآیند فعال‌سازی APIها یکسان است، بنابراین پس از فعال کردن یک API، می‌توانید بقیه را نیز به روشی مشابه فعال کنید.

گزینه ۱: رابط خط فرمان gcloud (Cloud Shell یا محیط محلی)

اگرچه فعال کردن APIها از طریق کنسول ابری رایج‌تر است، برخی از توسعه‌دهندگان ترجیح می‌دهند همه کارها را از طریق خط فرمان انجام دهند. برای انجام این کار، باید «نام سرویس» یک API را جستجو کنید. این نام شبیه یک URL است: SERVICE_NAME .googleapis.com . می‌توانید این موارد را در نمودار محصولات پشتیبانی‌شده پیدا کنید، یا می‌توانید با استفاده از API کشف گوگل، به صورت برنامه‌نویسی شده آنها را جستجو کنید.

با استفاده از این اطلاعات، با استفاده از Cloud Shell (یا محیط توسعه محلی خود که ابزار خط فرمان gcloud روی آن نصب شده است )، می‌توانید یک API یا سرویس را به شرح زیر فعال کنید:

gcloud services enable SERVICE_NAME.googleapis.com

مثال ۱: فعال کردن API مربوط به Cloud Vision

gcloud services enable vision.googleapis.com

مثال ۲: فعال کردن پلتفرم محاسباتی بدون سرور Google App Engine

gcloud services enable appengine.googleapis.com

مثال ۳: فعال کردن چندین 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 مستقر شوند.

همچنین چند دستور برای جستجو و فعال کردن APIها یا APIهایی که قبلاً برای پروژه شما فعال شده‌اند، وجود دارد.

مثال ۴: جستجوی APIهای گوگل موجود برای فعال‌سازی در پروژه شما

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

مثال ۵: جستجوی APIهای گوگل برای پروژه شما فعال شده است

gcloud services list

برای اطلاعات بیشتر در مورد دستورات فوق، به مستندات فعال و غیرفعال کردن سرویس‌ها و فهرست کردن سرویس‌ها مراجعه کنید.

گزینه ۲: کنسول ابری

همچنین می‌توانید APIهای گوگل را در API Manager فعال کنید. از Cloud Console، به API Manager بروید. در این صفحه داشبورد، اطلاعات ترافیک برنامه خود، نمودارهایی که درخواست‌های برنامه، خطاهای ایجاد شده توسط برنامه و زمان پاسخگویی برنامه را نشان می‌دهند، مشاهده خواهید کرد:

df4a0a5e00d29ffc.png

در زیر این نمودارها لیستی از API های گوگل که برای پروژه شما فعال شده‌اند، آمده است:

5fcf10e5a05cfb97.png

برای فعال (یا غیرفعال) کردن APIها، روی گزینه‌ی «فعال کردن APIها و خدمات» در بالا کلیک کنید:

eef4e5e863f4db66.png

روش دیگر این است که به نوار ناوبری سمت چپ بروید و APIها و خدماتکتابخانه را انتخاب کنید:

6eda5ba145b30b97.png

در هر صورت، به صفحه کتابخانه API خواهید رسید:

5d4f1c8e7cf8df28.png

برای جستجو و مشاهده نتایج منطبق، نام API را وارد کنید:

35bc4b9cf72ce9a4.png

API مورد نظر برای فعال‌سازی را انتخاب کنید و روی دکمه‌ی فعال‌سازی کلیک کنید:

۹۵۷۴a۶۹ef۸d۹e۸d۲.png

فرآیند فعال‌سازی همه APIها مشابه است، صرف نظر از اینکه از کدام API گوگل می‌خواهید استفاده کنید.

هزینه

بسیاری از APIهای گوگل را می‌توان بدون هزینه استفاده کرد، با این حال، استفاده از اکثر محصولات و APIهای گوگل کلود هزینه‌هایی دارد. هنگام فعال کردن APIهای ابری، ممکن است از شما یک حساب صورتحساب فعال خواسته شود. با این حال، برخی از محصولات گوگل کلود دارای یک سطح «همیشه رایگان» هستند که برای متحمل شدن هزینه‌های صورتحساب، باید از آن سطح فراتر بروید.

کاربران جدید گوگل کلود واجد شرایط دوره آزمایشی رایگان هستند که در حال حاضر برای ۹۰ روز اول ۳۰۰ دلار آمریکا هزینه دارد. Codelabs معمولاً هزینه زیادی یا هیچ هزینه‌ای ندارد، بنابراین پیشنهاد می‌کنیم تا زمانی که واقعاً آماده امتحان کردن آن نیستید، از دوره آزمایشی رایگان صرف نظر کنید، به خصوص که این یک پیشنهاد یک‌باره است. سهمیه‌های سطح رایگان منقضی نمی‌شوند و صرف نظر از اینکه از دوره آزمایشی رایگان استفاده کنید یا خیر، اعمال می‌شوند.

کاربران باید قبل از فعال کردن هر API، به اطلاعات قیمت آن مراجعه کنند (مثلاً: صفحه قیمت‌گذاری Cloud Vision API )، به خصوص توجه داشته باشند که آیا سطح رایگان دارد یا خیر، و اگر دارد، چیست. تا زمانی که در مجموع در محدوده مشخص شده روزانه یا ماهانه باقی بمانید، نباید هیچ هزینه‌ای متحمل شوید. قیمت‌گذاری و سطوح رایگان بین APIهای گروه‌های محصولات گوگل متفاوت است. مثال‌ها:

محصولات مختلف گوگل به صورت متفاوتی صورتحساب می‌شوند، بنابراین حتماً برای این اطلاعات به اسناد مربوطه مراجعه کنید.

خلاصه

حالا که Cloud Vision فعال شده است، سه API دیگر (Google Drive، Cloud Storage، Google Sheets) را به همین روش فعال کنید. از Cloud Shell، از gcloud services enable یا از کنسول Cloud استفاده کنید:

  1. بازگشت به کتابخانه API
  2. با تایپ چند حرف از نام آن، جستجو را شروع کنید
  3. API مورد نظر را انتخاب کنید، و
  4. فعال کردن

کف کنید، آبکشی کنید و تکرار کنید. برای فضای ذخیره‌سازی ابری، چندین انتخاب وجود دارد: "Google Cloud Storage JSON API" را انتخاب کنید. رابط برنامه‌نویسی کاربردی فضای ذخیره‌سازی ابری همچنین انتظار یک حساب صورتحساب فعال را دارد.

۷. مرحله ۰: تنظیم واردات و کد مجوز

این آغاز یک قطعه کد با اندازه متوسط ​​است، بنابراین پیروی از شیوه‌های چابک تا حدودی به تضمین یک زیرساخت رایج، پایدار و کارآمد قبل از پرداختن به برنامه اصلی کمک می‌کند. بررسی مجدد کنید که آیا client_secret.json در دایرکتوری فعلی شما موجود است یا خیر و یا ipython را اجرا کنید و قطعه کد زیر را وارد کنید، یا آن را در analyze_gsimg.py ذخیره کنید و آن را از پوسته اجرا کنید (مورد دوم ترجیح داده می‌شود زیرا ما به اضافه کردن به نمونه کد ادامه خواهیم داد):

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() این نمونه را با پایتون ۲-۳ سازگار می‌کند و کتابخانه گوگل تمام ابزارهای لازم برای ارتباط با APIهای گوگل را وارد می‌کند.
  • متغیر SCOPES نشان‌دهنده مجوزهای درخواستی از کاربر است - در حال حاضر فقط یکی وجود دارد: مجوز خواندن داده‌ها از گوگل درایو آنها
  • باقی‌مانده‌ی کد پردازش اعتبارنامه‌ها، توکن‌های OAuth2 ذخیره‌شده را می‌خواند و احتمالاً اگر توکن دسترسی اصلی منقضی شده باشد، آن را با توکن به‌روزرسانی به یک توکن دسترسی جدید به‌روزرسانی می‌کند.
  • اگر هیچ توکنی ایجاد نشده باشد یا بازیابی یک توکن دسترسی معتبر به دلیل دیگری ناموفق باشد، کاربر باید از جریان سه مرحله‌ای OAuth2 (3LO) عبور کند: یک کادر محاوره‌ای با مجوزهای درخواستی ایجاد کند و از کاربر بخواهد که آن را بپذیرد. پس از انجام این کار، برنامه ادامه می‌یابد، در غیر این صورت tools.run_flow() یک استثنا ایجاد می‌کند و اجرا متوقف می‌شود.
  • پس از اعطای مجوز توسط کاربر، یک کلاینت HTTP برای ارتباط با سرور ایجاد می‌شود و تمام درخواست‌ها برای امنیت با اعتبارنامه‌های کاربر امضا می‌شوند. سپس یک نقطه پایانی سرویس برای API گوگل درایو (نسخه ۳) با آن کلاینت 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 اجرا می‌کنید، به بخش «From Cloud Shell» بروید و سپس در صورت لزوم به عقب برگردید تا صفحات مربوطه را در «From local development environment» مرور کنید.

از محیط توسعه محلی

اسکریپت خط فرمان با باز شدن پنجره مرورگر متوقف می‌شود. ممکن است یک صفحه هشدار ترسناک مانند این دریافت کنید:

۱۴۹۲۴۱d۳۳۸۷۱a۱۴۱.png

این یک نگرانی مشروع است، زیرا شما در حال تلاش برای اجرای برنامه‌ای هستید که به داده‌های کاربر دسترسی دارد. از آنجایی که این فقط یک برنامه آزمایشی است و شما توسعه‌دهنده آن هستید ، امیدواریم که به اندازه کافی به خودتان اعتماد داشته باشید تا ادامه دهید. برای درک بهتر این موضوع، خود را جای کاربر خود قرار دهید: از شما خواسته می‌شود که به کد شخص دیگری اجازه دسترسی به داده‌های خود را بدهید. اگر قصد انتشار برنامه‌ای مانند این را دارید، فرآیند تأیید را طی خواهید کرد تا کاربران شما این صفحه را نبینند.

پس از کلیک روی پیوند «برو به برنامه «ناامن»، یک کادر محاوره‌ای مجوزهای OAuth2 دریافت خواهید کرد که چیزی شبیه به تصویر زیر است - ما همیشه در حال بهبود رابط کاربری خود هستیم، بنابراین اگر دقیقاً مطابق تصویر زیر نیست، نگران نباشید:

a122eb7468d0d34e.png

دیالوگ جریان OAuth2 مجوزهایی را که توسعه‌دهنده درخواست می‌کند (از طریق متغیر SCOPES ) منعکس می‌کند. در این مورد، این مجوز، امکان مشاهده و دانلود از گوگل درایو کاربر است. در کد برنامه، این محدوده‌های مجوز به صورت URI ظاهر می‌شوند، اما به زبانی که توسط زبان محلی کاربر مشخص شده است، ترجمه می‌شوند. در اینجا کاربر باید مجوز صریحی برای مجوز(های) درخواستی بدهد، در غیر این صورت یک استثنا ایجاد می‌شود، بنابراین اسکریپت ادامه نمی‌یابد.

حتی ممکن است یک کادر محاوره‌ای دیگر برای درخواست تأیید شما نمایش داده شود:

bf171080dcd6ec5.png

توجه : برخی از افراد از چندین مرورگر وب استفاده می‌کنند و با حساب‌های کاربری مختلف وارد سیستم می‌شوند، بنابراین ممکن است این درخواست مجوز به تب/پنجره مرورگر اشتباهی برود و شما مجبور شوید لینک این درخواست را در مرورگری که با حساب کاربری صحیح وارد سیستم شده است، کپی و پیست کنید.

از پوسته ابری

از 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 یا کلیدهای دیگر برای متوقف کردن اجرای اسکریپت) را فشار دهید و آن را از پوسته خود با پرچم اضافی اجرا کنید. وقتی آن را به این روش اجرا می‌کنید، به جای آن خروجی زیر را دریافت خواهید کرد:

$ 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 »، انتظار خروجی دیگری نداشته باشید. به یاد داشته باشید که این فقط تنظیمات اولیه است... شما هنوز کاری انجام نداده‌اید. کاری که انجام داده‌اید این است که با موفقیت سفر خود را به سمت چیزی که احتمال اجرای صحیح آن در اولین بار بیشتر است، آغاز کرده‌اید. (بهترین بخش این است که فقط یک بار از شما درخواست مجوز شد؛ همه اجراهای بعدی از آن صرف نظر می‌کنند زیرا مجوزهای شما ذخیره شده‌اند.) حالا بیایید کاری کنیم که کد کار واقعی انجام دهد و منجر به خروجی واقعی شود.

عیب‌یابی

اگر به جای عدم خروجی، خطایی دریافت کردید، ممکن است به دلیل یک یا چند دلیل باشد، شاید این یکی:

۸. مرحله ۱: دانلود تصویر از گوگل درایو

در مرحله قبل، توصیه کردیم کد را با نام analyze_gsimg.py ایجاد کرده و از آنجا ویرایش کنید. همچنین می‌توان همه چیز را مستقیماً در iPython یا پوسته استاندارد پایتون کپی و پیست کرد، با این حال، این کار دشوارتر است زیرا قرار است ساخت برنامه را قطعه قطعه ادامه دهیم.

فرض کنید برنامه شما مجاز شده و نقطه پایانی سرویس API ایجاد شده است. در کد شما، این نقطه پایانی با متغیر DRIVE نمایش داده می‌شود. حالا بیایید یک فایل تصویری در گوگل درایو شما پیدا کنیم و

آن را روی متغیری به نام 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 آن، آخرین برچسب زمانی تغییر و در نهایت، payload دودویی آن را که توسط تابع 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)

عیب‌یابی

اگر خروجی موفقیت‌آمیزی مانند موارد فوق دریافت نکردید، ممکن است به دلیل یک یا چند دلیل باشد، شاید این یکی:

خلاصه

در این بخش، یاد گرفتید که چگونه (در دو فراخوانی API جداگانه) به API درایو متصل شوید و برای یک فایل خاص کوئری بگیرید و سپس آن را دانلود کنید. مورد استفاده تجاری: بایگانی داده‌های درایو خود و شاید تجزیه و تحلیل آنها، مانند ابزارهای Google Cloud. کد برنامه شما در این مرحله باید با آنچه در مخزن step1-drive/analyze_gsimg.py وجود دارد، مطابقت داشته باشد.

برای اطلاعات بیشتر در مورد دانلود فایل‌ها در گوگل درایو اینجا را بخوانید یا این پست و ویدیوی وبلاگ را ببینید. این بخش از codelab تقریباً مشابه کل مقدمه‌ی codelab برای رابط‌های برنامه‌نویسی کاربردی گوگل ورک‌اسپیس است - به جای دانلود یک فایل، ۱۰۰ فایل/پوشه اول را در گوگل درایو کاربر نمایش می‌دهد و از دامنه‌ی محدودتری استفاده می‌کند.

۹. مرحله ۲: بایگانی فایل در فضای ذخیره‌سازی ابری

مرحله بعدی اضافه کردن پشتیبانی از فضای ذخیره‌سازی ابری گوگل (Google Cloud Storage ) است. برای این کار باید یک بسته پایتون دیگر به io را وارد کنیم. مطمئن شوید که بخش بالای فایل‌های وارد شده به این شکل باشد:

from __future__ import print_function                   
import io

علاوه بر نام فایل درایو، به اطلاعاتی در مورد محل ذخیره این فایل در فضای ابری، به ویژه نام «سطل» که می‌خواهید آن را در آن قرار دهید و هرگونه پیشوند «پوشه والد» نیاز داریم. اطلاعات بیشتر در این مورد به زودی:

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

A word on buckets: Cloud Storage provides amorphous blob storage. When uploading files there, it doesn't understand the concept of file types, extensions, etc., like the way Google Drive does. They're just "blobs" to Cloud Storage. Furthermore, there's no concept of folders or subdirectories in Cloud Storage.

Yes, you can have slashes ( / ) in filenames to represent the abstraction of multiple sub-folders, but at the end of the day, all your blobs go into a bucket, and " / "s are just characters in their filenames. Check out the bucket and object naming conventions page for more info.

Step 1 above requested the Drive read-only scope. At the time, that's all you needed. Now, upload (read-write) permission to Cloud Storage is required. Change SCOPES from a single string variable to an array (Python tuple [or list]) of permission scopes so it looks like this:

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

Now create a service endpoint to Cloud Storage right below the one for Drive. Note we slightly altered the call to reuse the same HTTP client object as there's no need to make a new one when it can be a shared resource.

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

Now add this function (after drive_get_img() ) which uploads to 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()

The objects.().insert() call requires the bucket name, file metadata, and the binary blob itself. To filter out the return values, the fields variable requests just the bucket and object names returned from the API. To learn more about these field masks on API read requests, check out this post & video .

Now integrate the use of gcs_blob_upload() into the main application:

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

The gcsname variable merges any "parent subdirectory" name(s) appended with the filename itself, and when prefixed with the bucket name, gives off the impression you're archiving the file at " /bucket/parent.../filename ". Slip this chunk right after the first print() function just above the else clause so the entire "main" looks like this:

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)

Let's say we specify a bucket named " vision-demo " with " analyzed_imgs " as a "parent subdirectory". Once you set those variables and run the script again, section-work-card-img_2x.jpg will be downloaded from Drive then uploaded to Cloud Storage, right? NOT!

$ 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">

Look carefully, while the Drive download succeeded, the upload to Cloud Storage failed. Why?

The reason is that when we authorized this application originally for Step 1, we only authorized the read-only access to Google Drive. While we added the read-write scope for Cloud Storage, we never prompted the user to authorize that access. To make it work, we need to blow away the storage.json file which is missing this scope and re-run.

After you re-authorize (confirm this by looking inside storage.json and see both scopes there), your output will then be as expected:

$ 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'

خلاصه

This is a big deal, showing you, in relatively few lines of code, how to transfer files between both Cloud-based storage systems. The business use-case here is to backup a possibly constrained resource to "colder," cheaper storage as mentioned earlier. Cloud Storage offers different storage classes depending on whether you access your data regularly, monthly, quarterly, or annually.

Of course, developers do ask us from time-to-time why both Google Drive and Cloud Storage exist. After all, aren't they both file storage in the cloud? That's why we made this video . Your code at this stage should match what's in the repo at step2-gcs/analyze_gsimg.py .

10. Step 3: Analyze with Cloud Vision

While we now know you can move data between Google Cloud and Google Workspace, we haven't done any analysis yet, so time to send the image to Cloud Vision for label annotation aka object detection. To do so, we need to Base64-encode the data, meaning another Python module, base64 . Ensure your top import section now looks like this:

from __future__ import print_function
import base64
import io

By default, the Vision API returns all the labels it finds. To keep things consistent, let's request just the top 5 (adjustable by the user of course). We'll use a constant variable TOP for this; add it under all the other constants:

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

As with earlier steps, we need another permission scope, this time for the Vision API. Update SCOPES with its string:

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

Now create a service endpoint to Cloud Vision so it lines up with the others like this:

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

Now add this function that sends the image payload to 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'])

The images().annotate() call requires the data plus desired API features. The top 5 label cap is part of the payload too (but completely optional). If the call is successful, the payload returns the top 5 labels of objects plus a confidence score an object is in the image. (If no response comes back, assign an empty Python dictionary so the following if statement doesn't fail.) This function simply collates that data into a CSV string for eventual use in our report.

These 5 lines that call vision_label_img() should be placed right after the successful upload to 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)

With that addition, the entire main driver should look like this:

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)

Deleting storage.json to refresh the scopes and re-running the updated application should result in output similar to the following, noting the addition of Cloud Vision analysis:

$ 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

خلاصه

Not everyone has the machine learning expertise to create and train their own ML models to analyze their data. The Google Cloud team has made available some of Google's pre-trained models for general use and put them behind APIs, helping democratize AI & ML for everyone.

If you're a developer and can call an API, you can use machine learning. Cloud Vision is just one of the API services you can use to analyze your data with. Learn about the others here . Your code should now match what's in the repo at step3-vision/analyze_gsimg.py .

11. Step 4: Generate a report with Google Sheets

At this point, you've been able to archive corporate data and analyze it, but what's lacking is a summary of this work. Let's organize all results into a single report you can hand to your boss. What's more presentable to management than a spreadsheet?

No additional imports are needed for the Google Sheets API, and the only new piece of information needed is the file ID of an existing spreadsheet already formatted and awaiting a new row of data, hence the SHEET constant. We recommend you create a new spreadsheet that looks similar to the following:

4def78583d05300.png

The URL for that spreadsheet will look like the following: https://docs.google.com/spreadsheets/d/ FILE_ID /edit . Grab that FILE_ID and assign it as a sting to SHEET .

We also snuck in a tiny function named k_ize() which converts bytes to kilobytes, defining it as a Python lambda since it's a simple 1-liner. Both of these integrated with the other constants looks like this:

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                 

As with earlier steps, we need another permission scope, this time read-write for the Sheets API. SCOPES now has all 4 needed:

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',
)                  

Now create a service endpoint to Google Sheets near the others, so it looks like this:

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

The functionality of sheet_append_row() is straightforward: take a row of data and a Sheet's ID, then add that row to that Sheet:

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

The spreadsheets().values().append() call requires Sheet's file ID, a range of cells, how the data should be entered, and the data itself. The file ID is straightforward, the range of cells is given in A1 notation . A range of " Sheet1 " means the entire Sheet—this signals to the API to append the row after all the data in the Sheet. There are a pair of choices on how the data should be added to the Sheet , " RAW " (enter the string data verbatim) or " USER_ENTERED " (write the data as if a user entered it on their keyboard with the Google Sheets application, preserving any cell formatting features).

If the call is successful, the return value doesn't really have anything super useful, so we opted for getting the number of cells updated by the API request. Below is the code that calls that function:

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

The Google Sheet has columns representing data such as any parent "subdirectory," the location of the archived file on Cloud Storage (bucket + filename), the file's MIMEtype, the file size (originally in bytes, but converted to kilobytes with k_ize() ), and the Cloud Vision labels string. Also note the archived location is a hyperlink so your manager can click to confirm it's been backed up safely.

Adding the block of code above right after displaying the results from Cloud Vision, the main portion driving the app is now complete, although structurally a bit complex:

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)

Deleting storage.json one last time and re-running the updated application should result in output similar to the following, noting the addition of Cloud Vision analysis:

$ 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

The extra line of output, while useful, is better visualized by taking a peek at the updated Google Sheet, with the last line (row 7 in the example below) added to the existing data set added prior:

b53a5bc944734652.png

خلاصه

In the first 3 steps of this tutorial, you connected with Google Workspace and Google Cloud APIs to move data and to analyze it, representing 80% of all the work. However at the end of day, none of this means anything if you can't present to management all you've accomplished. To better visualize the results, summarizing all the results in a generated report speaks volumes.

To further enhance the usefulness of the analysis, in addition to writing the results into a spreadsheet, one possible enhancement would be to index these top 5 labels for each image so that an internal database can be built allowing authorized employees to query for images by search team, but we leave that as an exercise for readers.

For now, our results are in a Sheet and accessible to management. The code for your app at this stage should match what's in the repo at step4-sheets/analyze_gsimg.py . The final step is to clean-up the code and turn it into a usable script.

12. *Final step: refactor

(optional) It's good to have a working app, however can we improve it? Yes, especially the main application which seems like a jumbled mess. Let's put that into its own function and drive it allowing for user input rather than fixed constants. We'll do that with the argparse module. Furthermore, let's launch a web browser tab to display the Sheet once we've written our row of data to it. This is doable with the webbrowser module. Weave these imports with the others so the top imports look like this:

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

To be able to use this code in other applications, we need the ability to suppress the output, so let's add a DEBUG flag to make that happen, adding this line to end of the constants section near the top:

DEBUG = False

Now, about the main body. As we were building this sample, you should've begun to feel "uncomfortable" as our code adds another level of nesting with each service added. If you felt that way, you're not alone, as this adds to code complexity as described in this Google Testing Blog post .

Following this best practice, let's reorganize the main part of the app into a function and return at each "break point" instead of nesting (returning None if any step fails and True if all succeed):

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

It's neater and cleaner, leaving behind that recursive if-else chain feeling along with reducing code complexity as described above. The last piece of the puzzle is to create a "real" main driver, allowing for user customization, and minimizing output (unless desired):

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)

If all steps are successful, the script launches a web browser to the spreadsheet specified where the new data row was added.

خلاصه

No need to delete storage.json since no scope changes occurred. Re-run the updated application reveals a new browser window opened to the modified Sheet, fewer lines of output, and issuing a -h option shows users their options, including -v to restore the now-suppressed lines of output seen earlier:

$ 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

The other options let users choose different Drive file names, Cloud Storage "subdirectory" and bucket names, top "N" results from Cloud Vision, and spreadsheet (Sheets) file IDs. With these last updates, the final version of your code should now match what's in the repo at final/analyze_gsimg.py as well as here, in its entirety:

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

We will make every attempt to keep this tutorial's contents up-to-date, but there will be occasions where the repo will have the most recent version of the code.

۱۳. تبریک می‌گویم!

There was certainly a lot of learning in this codelab, and you achieved that, surviving one of the longer codelabs. As a result, you tackled a possible enterprise scenario with about ~130 lines of Python, leveraging all of Google Cloud and Google Workspace, and moving data between them to build a working solution. Feel free to explore the open source repo for all versions of this app (more info below).

تمیز کردن

  1. Use of Google Cloud APIs are not free while Google Workspace APIs are covered by your monthly Google Workspace subscription fee (consumer Gmail users have a monthly fee of zero), so there's no API clean-up/turndown required for Google Workspace users. For Google Cloud, you can go to your Cloud console dashboard and check the Billing "card" for estimated charges.
  2. For Cloud Vision , you're allowed a fixed number of API calls per month for free. So as long as you stay under those limits, there's no need to shut anything down nor must you disable/delete your project. More information on the Vision API's billing and free quota can be found on its pricing page .
  3. Some Cloud Storage users receive a free amount of storage per month. If the images you archive using this codelab do not cause you to exceed that quota, you will not incur any charges. More information on GCS billing and free quota can be found on its pricing page . You can view and easily delete blobs from the Cloud Storage browser .
  4. Your use of Google Drive may also have a storage quota, and if you exceed it (or are close to it), you may actually consider using the tool you built in this codelab to archive those images to Cloud Storage to give yourself more space on Drive. More information on Google Drive storage can be found on the appropriate pricing page for Google Workspace Basic users or Gmail/consumer users.

While most Google Workspace Business and Enterprise plans have unlimited storage, this could cause your Drive folders to be cluttered and/or overwhelming, and the app you built in this tutorial is a great way to archive extraneous files and clean-up your Google Drive.

نسخه‌های جایگزین

While final/analyze_gsimg.py is the "last" official version you're working on in this tutorial, it's not the end of the story. One issue with the final version of the app is that it uses the older auth libraries which have been deprecated. We chose this path because, at the time of this writing, the newer auth libraries did not support several key elements: OAuth token storage management and thread safety.

Current (newer) auth libraries

However, at some point, the older auth libraries will no longer be supported, so we encourage you to review versions that use the newer (current) auth libraries in the repo's alt folder even if they aren't threadsafe (but you can build your own solution that is). Look for files with *newauth* in their names.

Google Cloud product client libraries

Google Cloud recommends all developers use the product client libraries when using Google Cloud APIs. Unfortunately non-Google Cloud APIs don't have such libraries at this time. Use of the lower-level libraries allow for consistent API usage and features better readability. Similar to the recommendation above, alternative versions using Google Cloud product client libraries are available in the repo's alt folder for you to review. Look for files with *-gcp* in their names.

Service account authorization

When working purely in the cloud, there generally aren't humans nor (human) user-owned data, so that's why service accounts and service account authorization are primarily used with Google Cloud. However, Google Workspace documents are generally owned by (human) users, so that's why this tutorial uses user account authorization. That doesn't mean it's not possible to use Google Workspace APIs with service accounts. As long as those accounts have the appropriate access level, they can certainly be used in applications. Similar to the above, alternative versions using service account authorization are available in the repo's alt folder for you to review. Look for files with *-svc* in their names.

Alternative version catalog

Below, you'll find all alternative versions of final/analyze_gsimg.py , each having one or more of the properties above. In each version's filename, look for:

  • " oldauth " for versions using the older auth libraries (in addition to final/analyze_gsimg.py )
  • " newauth " for those using the current/newer auth libraries
  • " gcp " for those using Google Cloud product client libraries, ie, google-cloud-storage, etc.
  • " svc " for those using a service account ("svc acct") auth instead of a user account

Here are all the versions:

نام فایل

توضیحات

final/analyze_gsimg.py

The primary sample; uses the older auth libraries

alt/analyze_gsimg-newauth.py

Same as final/analyze_gsimg.py but uses the newer auth libraries

alt/analyze_gsimg-oldauth-gcp.py

Same as final/analyze_gsimg.py but uses the Google Cloud product client libraries

alt/analyze_gsimg-newauth-gcp.py

Same as alt/analyze_gsimg-newauth.py but uses the Google Cloud product client libraries

alt/analyze_gsimg-oldauth-svc.py

Same as final/analyze_gsimg.py but uses svc acct instead of user acct

alt/analyze_gsimg-newauth-svc.py

Same as alt/analyze_gsimg-newauth.py but uses svc acct auth instead of user acct

alt/analyze_gsimg-oldauth-svc-gcp.py

Same as alt/analyze_gsimg-oldauth-svc.py but uses the Google Cloud product client libraries and same as alt/analyze_gsimg-oldauth-gcp.py but uses svc acct auth instead of user acct

alt/analyze_gsimg-newauth-svc-gcp.py

Same as alt/analyze_gsimg-oldauth-svc-gcp.py but uses the newer auth libraries

Coupled with the original final/analyze_gsimg.py , you have all possible combinations of the final solution, regardless of your Google API development environment, and can choose the one which best suits your needs. Also see alt/README.md for a similar explanation.

Additional Study

Below are a few ideas of how you can take this exercise a step or two further. The problem set the current solution can handle can be expanded allowing you to make these enhancements:

  1. ( multiple images in folders ) Instead of processing one image, let's say you had images in Google Drive folders .
  2. ( multiple images in ZIP files ) Instead of a folder of images, how about ZIP archives containing image files? If using Python, consider the zipfile module .
  3. ( analyze Vision labels ) Cluster similar images together, perhaps start by looking for the most common labels, then the 2nd most common, and so on.
  4. ( create charts ) Follow-up #3, generate charts with the Sheets API based on the Vision API analysis and categorization
  5. ( categorize documents ) Instead of analyzing images with the Cloud Vision API, let's say you have PDF files to categorize with the Cloud Natural Language API . Using your solutions above, these PDFs can be in Drive folders or ZIP archives on Drive.
  6. ( create presentations ) Use the Slides API to generate a slide deck from the contents of the Google Sheet report. For inspiration, check out this blog post & video on generating slides from spreadsheet data.
  7. ( export as PDF ) Export the spreadsheet and/or slide deck as PDF, however this isn't a feature of either the Sheets nor Slides APIs. Hint : Google Drive API. Extra credit : merge both the Sheets and Slides PDFs into one master PDF with tools like Ghostscript (Linux, Windows) or Combine PDF Pages.action (Mac OS X).

اطلاعات بیشتر

Codelabs

عمومی

فضای کاری گوگل

گوگل کلود

مجوز

این اثر تحت مجوز عمومی Creative Commons Attribution 2.0 منتشر شده است.