أرشفة الصور وتحليلها وإنشاء التقارير في Google Workspace السحابة الإلكترونية من Google

1. نظرة عامة

يتناول هذا الدرس التطبيقي العملي سير عمل محتملاً للمؤسسات: أرشفة الصور وتحليلها وإنشاء التقارير. لنفترض أنّ مؤسستك لديها سلسلة من الصور تشغل مساحة على مورد محدود. عليك أرشفة هذه البيانات وتحليل هذه الصور، والأهم من ذلك، إنشاء تقرير يلخّص المواقع الجغرافية المؤرشفة بالإضافة إلى نتائج التحليل، ويتم تجميعها وتكون جاهزة للاستخدام من قِبل الإدارة. توفّر Google Cloud الأدوات اللازمة لتحقيق ذلك، وذلك باستخدام واجهات برمجة التطبيقات من خطَّي إنتاجها، Google Workspace (المعروفة سابقًا باسم G Suite أو Google Apps) وGoogle Cloud (المعروفة سابقًا باسم GCP).

في السيناريو الذي نقدّمه، سيحصل مستخدم النشاط التجاري على صور في Google Drive. من المنطقي الاحتفاظ بنسخ احتياطية من هذه البيانات في مساحة تخزين "أقل استخدامًا" وأرخص، مثل فئات التخزين المتاحة من Google Cloud Storage. تتيح خدمة Google Cloud Vision للمطوّرين دمج ميزات رصد الصور بسهولة في التطبيقات، بما في ذلك رصد الكائنات والمعالم والتعرّف البصري على الأحرف (OCR) وغير ذلك. وأخيرًا، تُعدّ ورقة بيانات جداول بيانات Google أداة مفيدة لتصوّر البيانات من أجل تلخيص كل ذلك لمديرك.

بعد إكمال هذا الدرس التطبيقي حول الترميز لإنشاء حلّ يستفيد من جميع خدمات Google Cloud، نأمل أن تستوحي أفكارًا لإنشاء حلّ أكثر تأثيرًا لمؤسستك أو لعملائك.

أهداف الدورة التعليمية

  • كيفية استخدام Cloud Shell
  • كيفية مصادقة طلبات البيانات من واجهة برمجة التطبيقات
  • كيفية تثبيت مكتبة برامج Google APIs للغة Python
  • كيفية تفعيل Google APIs
  • كيفية تنزيل الملفات من Google Drive
  • كيفية تحميل الكائنات/البيانات الثنائية الكبيرة إلى Cloud Storage
  • كيفية تحليل البيانات باستخدام Cloud Vision
  • كيفية كتابة صفوف في "جداول بيانات Google"

المتطلبات

  • حساب Google (قد تتطلّب حسابات Google Workspace موافقة المشرف)
  • مشروع على السحابة الإلكترونية من Google Cloud يتضمّن حساب فوترة نشطًا على Google Cloud
  • الإلمام بأوامر المحطة الطرفية/الصدفة لنظام التشغيل
  • مهارات أساسية في Python (الإصدار 2 أو 3)، ولكن يمكنك استخدام أي لغة متوافقة

يُفضّل أن يكون لديك خبرة في منتجات Google Cloud الأربعة المدرَجة أعلاه، ولكنّها ليست شرطًا مطلوبًا. إذا كان لديك الوقت الكافي للتعرّف على كلّ منها بشكل منفصل أولاً، يمكنك الاستفادة من دروس تطبيقية حول الترميز لكلّ منها قبل البدء في التمرين هنا:

استطلاع

كيف ستستخدم هذا البرنامج التعليمي؟

قراءة المحتوى فقط قراءة المحتوى وإكمال التمارين

كيف تقيّم تجربتك مع Python؟

مبتدئ متوسط متمكّن

ما هو تقييمك لتجربة استخدام خدمات Google Cloud؟

مبتدئ متوسط متمكّن

ما هو تقييمك لتجربة استخدام خدمات المطوّرين في Google Workspace؟

مبتدئ متوسط متمكّن

هل تريد الاطّلاع على المزيد من دروس codelab "الموجّهة إلى الأنشطة التجارية" مقارنةً بتلك التي تقدّم ميزات المنتجات؟

نعم لا المزيد من كليهما

2. الإعداد والمتطلبات

إعداد البيئة بوتيرة ذاتية

  1. سجِّل الدخول إلى Google Cloud Console وأنشِئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهي سلسلة أحرف لا تستخدمها Google APIs. ويمكنك تعديله في أي وقت.
  • يجب أن يكون رقم تعريف المشروع فريدًا في جميع مشاريع Google Cloud، كما أنّه غير قابل للتغيير (لا يمكن تغييره بعد ضبطه). تنشئ Cloud Console تلقائيًا سلسلة فريدة، ولا يهمّك عادةً ما هي. في معظم دروس البرمجة، عليك الرجوع إلى رقم تعريف المشروع (يتم تحديده عادةً على أنّه PROJECT_ID). إذا لم يعجبك رقم التعريف الذي تم إنشاؤه، يمكنك إنشاء رقم تعريف عشوائي آخر. يمكنك بدلاً من ذلك تجربة اسم مستخدم من اختيارك لمعرفة ما إذا كان متاحًا. لا يمكن تغيير هذا الخيار بعد هذه الخطوة وسيظل ساريًا طوال مدة المشروع.
  • للعلم، هناك قيمة ثالثة، وهي رقم المشروع الذي تستخدمه بعض واجهات برمجة التطبيقات. يمكنك الاطّلاع على مزيد من المعلومات عن كل هذه القيم الثلاث في المستندات.
  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام موارد/واجهات برمجة تطبيقات Cloud. لن تكلفك تجربة هذا الدرس التطبيقي حول الترميز الكثير من المال، إن لم تكلفك شيئًا على الإطلاق. لإيقاف الموارد كي لا يتم تحصيل رسوم منك بعد هذا البرنامج التعليمي، يمكنك حذف الموارد التي أنشأتها أو حذف المشروع بأكمله. يمكن لمستخدمي Google Cloud الجدد الاستفادة من برنامج الفترة التجريبية المجانية بقيمة 300 دولار أمريكي.

بدء Cloud Shell

ملخّص

على الرغم من إمكانية تطوير الرمز برمجيًا على جهاز الكمبيوتر المحمول، فإنّ الهدف الثانوي من هذا الدرس التطبيقي حول الترميز هو تعليمك كيفية استخدام Google Cloud Shell، وهي بيئة سطر أوامر تعمل على السحابة الإلكترونية من خلال متصفّح الويب الحديث.

تفعيل Cloud Shell

  1. من Cloud Console، انقر على تفعيل Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

إذا لم يسبق لك بدء Cloud Shell، ستظهر لك شاشة وسيطة (الجزء السفلي غير المرئي من الصفحة) توضّح ماهيته. في هذه الحالة، انقر على متابعة (ولن تظهر لك مرة أخرى). في ما يلي الشكل الذي ستظهر به هذه الشاشة لمرة واحدة:

9c92662c6a846a5c.png

يستغرق توفير Cloud Shell والاتصال به بضع لحظات فقط.

9f0e51b578fecce5.png

يتم تحميل هذا الجهاز الافتراضي بجميع أدوات التطوير التي تحتاج إليها. توفّر هذه الخدمة دليلًا رئيسيًا دائمًا بسعة 5 غيغابايت وتعمل في Google Cloud، ما يؤدي إلى تحسين أداء الشبكة والمصادقة بشكل كبير. يمكن إنجاز معظم العمل في هذا الدرس التطبيقي حول الترميز، إن لم يكن كله، باستخدام متصفّح أو جهاز 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

يتطلّب هذا الدرس التطبيقي استخدام لغة Python (مع أنّ مكتبات برامج Google APIs تتيح استخدام العديد من اللغات، لذا يمكنك إنشاء شيء مكافئ باستخدام أداة للمطوّرين المفضّلة لديك واستخدام Python كرمز زائف). على وجه الخصوص، يتوافق هذا الدرس التطبيقي حول الترميز مع الإصدارَين 2 و3 من Python، ولكن ننصحك بالانتقال إلى الإصدار 3.x في أقرب وقت ممكن.

Cloud Shell هي أداة ملائمة متاحة للمستخدمين مباشرةً من Cloud Console ولا تتطلّب بيئة تطوير محلية، لذا يمكن إكمال هذا البرنامج التعليمي بالكامل على السحابة الإلكترونية باستخدام متصفّح ويب. وبشكل أكثر تحديدًا في هذا الدرس العملي، تم تثبيت كلا الإصدارين من Python مسبقًا في Cloud Shell.

يتضمّن Cloud Shell أيضًا IPython مثبّتًا، وهو مترجم Python تفاعلي عالي المستوى ننصح به، خاصةً إذا كنت جزءًا من منتدى علوم البيانات أو تعلُّم الآلة. إذا كان الأمر كذلك، فإنّ IPython هو المترجم التلقائي لأوراق ملاحظات Jupyter بالإضافة إلى Colab، وهي أوراق ملاحظات Jupyter مستضافة بواسطة 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.
>>>

يفترض هذا الدرس التطبيقي حول الترميز أيضًا أنّ لديك أداة التثبيت pip (أداة إدارة حِزم Python وبرنامج التعيين للاعتماديات). يتم تضمينها مع الإصدارات 2.7.9 أو الإصدارات الأحدث أو 3.4 أو الإصدارات الأحدث. إذا كان لديك إصدار أقدم من Python، يمكنك الاطّلاع على دليل هذا للحصول على تعليمات التثبيت. استنادًا إلى أذوناتك، قد تحتاج إلى الحصول على إذن sudo أو إذن مستخدم متميّز، ولكنّ هذا ليس هو الحال عادةً. يمكنك أيضًا استخدام pip2 أو pip3 بشكل صريح لتنفيذ pip لإصدارات معيّنة من Python.

يفترض بقية الدرس التطبيقي العملي أنّك تستخدم الإصدار 3 من Python، وسيتم تقديم تعليمات خاصة بالإصدار 2 من Python إذا كانت تختلف بشكل كبير عن الإصدار 3.x.

[اختياري] إنشاء بيئات افتراضية واستخدامها

هذا القسم اختياري ولا يُطلب إلا من المستخدمين الذين عليهم استخدام بيئة افتراضية لهذا الدرس العملي (وفقًا للشريط الجانبي التحذيري أعلاه). إذا كان لديك الإصدار 3 من Python فقط على جهاز الكمبيوتر، يمكنك ببساطة إصدار هذا الأمر لإنشاء بيئة افتراضية باسم my_env (يمكنك اختيار اسم آخر إذا أردت):

virtualenv my_env

ومع ذلك، إذا كان لديك الإصداران 2 و3 من Python على جهاز الكمبيوتر، ننصحك بتثبيت بيئة افتراضية للإصدار 3 من Python يمكنك إنشاؤها باستخدام -p flag على النحو التالي:

virtualenv -p python3 my_env

أدخِل بيئة virtualenv التي أنشأتها حديثًا من خلال "تفعيلها" على النحو التالي:

source my_env/bin/activate

تأكَّد من أنّك في البيئة من خلال ملاحظة أنّ طلب موجّه الأوامر يسبقه الآن اسم البيئة، أي

(my_env) $ 

من المفترض أن تتمكّن الآن من pip install أي حِزم مطلوبة، وتنفيذ الرمز البرمجي في هذه البيئة، وما إلى ذلك. ومن المزايا الأخرى أنّه في حال حدوث أي خطأ أو تلف في عملية تثبيت Python، يمكنك إزالة هذه البيئة بأكملها بدون التأثير في بقية نظامك.

4. تثبيت مكتبة برامج Google APIs للغة Python

يتطلّب هذا الدرس العملي استخدام مكتبة برامج 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 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.

ملخّص

بما أنّ هذا الدرس التطبيقي حول الترميز متوسّط المستوى، من المفترض أنّ لديك خبرة في إنشاء المشاريع واستخدامها في وحدة التحكّم. إذا كنت جديدًا على Google APIs، وتحديدًا واجهات برمجة التطبيقات في Google Workspace، جرِّب أولاً برنامج التدريب العملي التمهيدي حول Google Workspace APIs. بالإضافة إلى ذلك، إذا كنت تعرف كيفية إنشاء بيانات اعتماد حساب مستخدم (وليس حساب خدمة) (أو إعادة استخدام بيانات اعتماد حالية)، يمكنك وضع ملف client_secret.json في دليل العمل وتخطّي الوحدة التالية والانتقال إلى "تفعيل واجهات Google API".

5- *الموافقة على طلبات واجهة برمجة التطبيقات (تفويض المستخدم)

يمكن تخطّي هذا القسم إذا سبق لك إنشاء بيانات اعتماد تفويض حساب المستخدم وكنت على دراية بالعملية. يختلف ذلك عن تفويض حساب الخدمة الذي تختلف تقنيته، لذا يُرجى مواصلة القراءة أدناه.

مقدمة عن التفويض (بالإضافة إلى بعض المصادقة)

لكي يتمكّن تطبيقك من إرسال طلبات إلى واجهات برمجة التطبيقات، يجب أن يكون لديه الإذن المناسب. تصف كلمة المصادقة المشابهة بيانات اعتماد تسجيل الدخول، إذ يمكنك إثبات هويتك عند تسجيل الدخول إلى حسابك على Google باستخدام اسم مستخدم وكلمة مرور. بعد إتمام عملية المصادقة، تتمثّل الخطوة التالية في تحديد ما إذا كنت مخوَّلاً بالوصول إلى البيانات، مثل ملفات الكائنات الثنائية الكبيرة في Cloud Storage أو الملفات الشخصية للمستخدم على Google Drive، أو ما إذا كان الرمز مخوَّلاً بذلك.

تتيح واجهات Google API عدة أنواع من التفويض، ولكن النوع الأكثر شيوعًا لمستخدمي G Suite API هو تفويض المستخدم لأنّ التطبيق النموذجي في هذا الدرس التطبيقي حول الترميز يتيح الوصول إلى البيانات الخاصة بالمستخدمين النهائيين. يجب أن يمنح هؤلاء المستخدمون النهائيون تطبيقك الإذن بالوصول إلى بياناتهم. وهذا يعني أنّ الرمز البرمجي يجب أن يحصل على بيانات اعتماد OAuth2 الخاصة بحساب المستخدم.

للحصول على بيانات اعتماد OAuth2 لتفويض المستخدم، ارجع إلى "إدارة واجهات برمجة التطبيقات" وانقر على علامة التبويب "بيانات الاعتماد" في شريط التنقّل الأيمن:

635af008256d323.png

عند الوصول إلى هناك، ستظهر لك جميع بيانات الاعتماد في ثلاثة أقسام منفصلة:

fd2f4133b406d572.png

الأول مخصّص لمفاتيح واجهة برمجة التطبيقات، والثاني لمعرّفات عملاء OAuth 2.0، والأخير لحسابات خدمة OAuth2، ونحن نستخدم الخيار الأوسط.

إنشاء بيانات اعتماد

من صفحة "بيانات الاعتماد"، انقر على الزر + إنشاء بيانات اعتماد في أعلى الصفحة، ما يفتح لك مربّع حوار يمكنك من خلاله اختيار "معرّف عميل OAuth":

b17b663668e38787.png

في الشاشة التالية، يمكنك تنفيذ إجراءَين: ضبط "شاشة طلب الموافقة" الخاصة بتفويض تطبيقك واختيار نوع التطبيق:

4e0b967c9d70d262.png

إذا لم تكن قد أعددت شاشة طلب الموافقة، سيظهر لك التحذير في وحدة التحكّم وعليك إعدادها الآن. (يمكنك تخطّي الخطوات التالية إذا سبق لك إعداد شاشة طلب الموافقة).

انقر على "ضبط شاشة طلب الموافقة" حيث يمكنك اختيار تطبيق "خارجي" (أو "داخلي" إذا كنت من عملاء G Suite):

f17e97b30d994b0c.png

يُرجى العِلم أنّه لأغراض هذا التمرين، لا يهمّ أيًّا من الخيارَين ستختار لأنّك لن تنشر نموذج درس تطبيقي حول الترميز. سيختار معظم المستخدمين "خارجي" للانتقال إلى شاشة أكثر تعقيدًا، ولكن ما عليك سوى ملء حقل "اسم التطبيق" في أعلى الصفحة:

b107ab81349bdad2.png

كل ما تحتاج إليه في هذا الوقت هو اسم تطبيق، لذا اختَر اسمًا يعكس الدرس التطبيقي حول الترميز الذي تجريه، ثم انقر على حفظ.

إنشاء معرّف عميل 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 (وهو الاسم الذي يستخدمه نموذج التطبيق)، ثم حفظه في الدليل أو المجلد الذي ستنشئ فيه نموذج التطبيق في هذا الدرس التطبيقي حول الترميز.

ملخّص

أنت الآن مستعد لتفعيل واجهات Google API المستخدَمة في هذا الدرس التطبيقي حول الترميز. بالنسبة إلى اسم التطبيق في شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth، اخترنا "إصدار تجريبي لواجهة Vision API"، لذا من المتوقّع أن يظهر هذا الاسم في بعض لقطات الشاشة القادمة.

6. تفعيل واجهات Google APIs

يستخدم هذا الدرس العملي أربع (4) واجهات برمجة تطبيقات من Google Cloud، وهما زوجان من Google Cloud (Cloud Storage وCloud Vision) وزوجان آخران من Google Workspace (Google Drive وجداول بيانات Google). في ما يلي تعليمات عامة حول تفعيل واجهات Google API. بعد معرفة كيفية تفعيل إحدى واجهات برمجة التطبيقات، ستجد أنّ طريقة تفعيل الواجهات الأخرى مشابهة.

بغض النظر عن واجهة Google API التي تريد استخدامها في تطبيقك، يجب تفعيلها. يمكن تفعيل واجهات برمجة التطبيقات من سطر الأوامر أو من وحدة تحكّم Cloud. إنّ عملية تفعيل واجهات برمجة التطبيقات متطابقة، لذا بعد تفعيل إحدى واجهات برمجة التطبيقات، يمكنك تفعيل غيرها بطريقة مماثلة.

الخيار 1: واجهة سطر الأوامر gcloud (Cloud Shell أو البيئة المحلية)

على الرغم من أنّ تفعيل واجهات برمجة التطبيقات من Cloud Console هو الإجراء الأكثر شيوعًا، يفضّل بعض المطوّرين تنفيذ كل شيء من سطر الأوامر. لإجراء ذلك، عليك البحث عن "اسم الخدمة" لواجهة برمجة التطبيقات. يبدو أنّها عنوان URL: SERVICE_NAME.googleapis.com. يمكنك العثور على هذه المنتجات في مخطط المنتجات المتوافقة، أو يمكنك طلبها آليًا باستخدام Google Discovery API.

باستخدام هذه المعلومات، يمكنك تفعيل واجهة برمجة تطبيقات أو خدمة باستخدام Cloud Shell (أو بيئة التطوير المحلية مع تثبيت أداة سطر الأوامر gcloud)، وذلك باتّباع الخطوات التالية:

gcloud services enable SERVICE_NAME.googleapis.com

المثال 1: تفعيل Cloud Vision API

gcloud services enable vision.googleapis.com

المثال 2: تفعيل منصة الحوسبة بدون خادم Google App Engine

gcloud services enable appengine.googleapis.com

المثال 3: تفعيل عدة واجهات برمجة تطبيقات بطلب واحد على سبيل المثال، إذا كان هذا الدرس التطبيقي حول الترميز يتضمّن مشاهدين ينشرون تطبيقًا باستخدام 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. بالإضافة إلى ذلك، يتيح هذا الإذن استخدام Artifact Registry لأنّ نظام التصميم Cloud Build يجب أن يسجّل فيه صور الحاويات حتى يتمكّن من نشرها على Cloud Run.

تتوفّر أيضًا بعض الأوامر للاستعلام عن واجهات برمجة التطبيقات التي يجب تفعيلها أو واجهات برمجة التطبيقات التي تم تفعيلها بالفعل لمشروعك.

المثال 4: طلب البحث عن Google APIs المتاحة للتفعيل في مشروعك

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

المثال 5: طلب البحث عن واجهات Google APIs المفعّلة لمشروعك

gcloud services list

لمزيد من المعلومات حول الأوامر أعلاه، يُرجى الاطّلاع على المستندات حول تفعيل الخدمات وإيقافها وإدراج الخدمات.

الخيار 2: Cloud Console

يمكنك أيضًا تفعيل واجهات Google APIs في "أداة إدارة واجهات برمجة التطبيقات". من Cloud Console، انتقِل إلى إدارة واجهة برمجة التطبيقات. في صفحة لوحة البيانات هذه، ستظهر لك بعض معلومات الزيارات لتطبيقك، ورسوم بيانية تعرض طلبات التطبيق، والأخطاء التي أنشأها تطبيقك، وأوقات استجابة تطبيقك:

df4a0a5e00d29ffc.png

أسفل هذه الرسوم البيانية، تظهر قائمة بواجهات Google API المفعّلة لمشروعك:

5fcf10e5a05cfb97.png

لتفعيل واجهات برمجة التطبيقات (أو إيقافها)، انقر على تفعيل واجهات برمجة التطبيقات والخدمات في أعلى الصفحة:

eef4e5e863f4db66.png

بدلاً من ذلك، انتقِل إلى شريط التنقّل الأيمن وانقر على واجهات برمجة التطبيقات والخدماتالمكتبة:

6eda5ba145b30b97.png

في كلتا الحالتين، ستصل إلى صفحة مكتبة واجهة برمجة التطبيقات:

5d4f1c8e7cf8df28.png

أدخِل اسم واجهة برمجة تطبيقات للبحث عنها والاطّلاع على النتائج المطابقة:

35bc4b9cf72ce9a4.png

اختَر واجهة برمجة التطبيقات التي تريد تفعيلها وانقر على الزر تفعيل:

9574a69ef8d9e8d2.png

تتشابه عملية تفعيل جميع واجهات برمجة التطبيقات، بغض النظر عن واجهة برمجة التطبيقات من Google التي تريد استخدامها.

التكلفة

يمكن استخدام العديد من واجهات Google API بدون رسوم، ولكن هناك تكاليف عند استخدام معظم منتجات وواجهات Google Cloud API. عند تفعيل Cloud APIs، قد يُطلب منك تقديم حساب فوترة نشط. ومع ذلك، تتضمّن بعض منتجات Google Cloud فئة"دائمًا مجانية"، ويجب تجاوزها من أجل تكبُّد رسوم الفوترة.

يمكن لمستخدمي Google Cloud الجدد الاستفادة من الفترة التجريبية المجانية التي تبلغ قيمتها حاليًا 300 دولار أمريكي (أو ما يعادله بالعملة المحلية) لمدة أول 90 يومًا. لا تتكبّد Codelabs عادةً تكلفة كبيرة أو أي تكلفة، لذا نقترح عليك تأجيل الاستفادة من الفترة التجريبية المجانية إلى أن تكون مستعدًا لتجربتها، خاصةً أنّها عرض لمرة واحدة. لا تنتهي صلاحية حصص "الإصدار المجاني"، وهي تسري بغض النظر عمّا إذا كنت تستخدم "الفترة التجريبية المجانية" أم لا.

على المستخدمين الرجوع إلى معلومات التسعير الخاصة بأي واجهة برمجة تطبيقات قبل تفعيلها (مثال: صفحة أسعار Cloud Vision API )، مع الانتباه بشكل خاص إلى ما إذا كانت تتضمّن طبقة مجانية، وإذا كان الأمر كذلك، ما هي هذه الطبقة. وطالما أنّك تلتزم بالحدود اليومية أو الشهرية المحدّدة بشكل إجمالي، لن يتم تحصيل أي رسوم منك. تختلف الأسعار والمستويات المجانية بين واجهات برمجة التطبيقات لمجموعات منتجات Google. أمثلة:

تختلف طريقة فوترة منتجات Google المختلفة، لذا احرص على الرجوع إلى المستندات المناسبة للحصول على هذه المعلومات.

ملخّص

بعد تفعيل Cloud Vision، فعِّل واجهات برمجة التطبيقات الثلاث الأخرى (Google Drive وCloud Storage و"جداول بيانات Google") بالطريقة نفسها. من Cloud Shell، استخدِم gcloud services enable، أو من Cloud Console:

  1. الرجوع إلى "مكتبة واجهة برمجة التطبيقات"
  2. بدء البحث عن طريق كتابة بضعة أحرف من اسمه
  3. اختَر واجهة برمجة التطبيقات المطلوبة، ثم
  4. تفعيل

يُرجى وضع الصابون ثم شطف اليدين وتكرار العملية. بالنسبة إلى Cloud Storage، هناك العديد من الخيارات: اختَر "Google Cloud Storage JSON API". سيتطلّب Cloud Storage API أيضًا حساب فوترة نشطًا.

7. الخطوة 0: إعداد عمليات الاستيراد ورمز التفويض

هذه هي بداية جزء متوسط الحجم من الرمز، لذا فإنّ اتّباع بعض الممارسات المرنة يساعد في ضمان توفّر جزء شائع ومستقر وعامل من البنية الأساسية قبل معالجة التطبيق الرئيسي. تأكَّد من توفّر 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)

يتضمّن هذا المكوّن الأساسي رموزًا برمجية لاستيراد الوحدات أو الحِزم، ومعالجة بيانات اعتماد مصادقة المستخدم، وإنشاء نقاط نهاية لخدمة واجهة برمجة التطبيقات. في ما يلي الأجزاء الرئيسية من الرمز التي يجب مراجعتها:

  • يؤدي استيراد الدالة print() إلى جعل نموذج Python هذا متوافقًا مع الإصدارين 2 و3، كما أنّ عمليات استيراد مكتبة Google توفّر جميع الأدوات اللازمة للتواصل مع واجهات Google API.
  • يمثّل المتغيّر SCOPES الأذونات المطلوب الحصول عليها من المستخدم، ولا يتوفّر حاليًا سوى إذن واحد، وهو الإذن بقراءة البيانات من Google Drive.
  • يتم قراءة بقية رمز معالجة بيانات الاعتماد في الرموز المميزة المخزَّنة مؤقتًا لبروتوكول OAuth2، وربما يتم تعديلها إلى رمز دخول جديد باستخدام الرمز المميز لإعادة التحميل إذا انتهت صلاحية رمز الدخول الأصلي.
  • إذا لم يتم إنشاء أي رموز مميزة أو تعذّر استرداد رمز دخول صالح لسبب آخر، على المستخدم اتّباع مسار OAuth2 الثلاثي الأطراف (3LO): إنشاء مربّع الحوار مع الأذونات المطلوبة ومطالبة المستخدم بقبولها. وبعد ذلك، يواصل التطبيق عمله، وإلا سيُظهر tools.run_flow() استثناءً ويتوقف التنفيذ.
  • بعد أن يمنح المستخدم الإذن، يتم إنشاء برنامج HTTP للتعامل مع الخادم، ويتم توقيع جميع الطلبات باستخدام بيانات اعتماد المستخدم لأغراض الأمان. بعد ذلك، يتم إنشاء نقطة نهاية خدمة لواجهة برمجة التطبيقات Google Drive API (الإصدار 3) باستخدام برنامج HTTP، ثم يتم تعيينها إلى DRIVE.

تشغيل التطبيق

في المرة الأولى التي تنفّذ فيها البرنامج النصي، لن يكون لديك الإذن بالوصول إلى ملفات المستخدم على 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 Drive الخاص بالمستخدم. في الرمز البرمجي للتطبيق، تظهر نطاقات الأذونات هذه كمعرّفات موارد موحّدة (URI)، ولكن يتم ترجمتها إلى اللغة المحدّدة حسب اللغة المحلية للمستخدم. في هذه الحالة، يجب أن يمنح المستخدم إذنًا صريحًا بالأذونات المطلوبة، وإلا سيتم عرض استثناء حتى لا يستمر النص البرمجي في التنفيذ.

قد يظهر لك مربّع حوار آخر يطلب منك التأكيد:

bf171080dcd6ec5.png

NOTE: يستخدم بعض الأشخاص متصفّحات ويب متعددة تم تسجيل الدخول إليها باستخدام حسابات مختلفة، لذا قد ينتقل طلب التفويض هذا إلى علامة تبويب المتصفّح/نافذة المتصفّح الخاطئة، وقد تحتاج إلى قص الرابط الخاص بهذا الطلب ولصقه في متصفّح تم تسجيل الدخول إليه باستخدام الحساب الصحيح.

من 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"، لا تتوقّع أي نتائج إضافية. تذكَّر أنّ هذه مجرّد عملية إعداد، ولم تتّخذ أي إجراء بعد. ما فعلته هو أنّك بدأت بنجاح رحلتك نحو تحقيق نتائج صحيحة من المرة الأولى. (أفضل ما في الأمر أنّه سيُطلب منك الحصول على إذن مرة واحدة فقط، وسيتم تخطّي هذه الخطوة في جميع عمليات التنفيذ اللاحقة لأنّه تم تخزين أذوناتك مؤقتًا). لننتقل الآن إلى جعل الرمز البرمجي يؤدي بعض المهام الحقيقية التي تؤدي إلى مخرجات فعلية.

تحديد المشاكل وحلّها

إذا ظهرت لك رسالة خطأ بدلاً من عدم ظهور أي نتائج، قد يرجع ذلك إلى سبب واحد أو أكثر، ربما السبب التالي:

8. الخطوة 1: تنزيل الصورة من Google Drive

في الخطوة السابقة، نصحنا بإنشاء الرمز البرمجي كـ analyze_gsimg.py ثم تعديله. يمكن أيضًا قص كل شيء ولصقه مباشرةً في iPython أو واجهة Python العادية، ولكنّ هذه الطريقة أكثر صعوبة لأنّنا سنواصل إنشاء التطبيق جزءًا جزءًا.

لنفترض أنّه تم منح تطبيقك الإذن وتم إنشاء نقطة نهاية لخدمة واجهة برمجة التطبيقات. في الرمز، يتم تمثيله بالمتغيّر DRIVE. لنبحث الآن عن ملف صورة في Google 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

تحتوي مجموعة Drive files() على طريقة list() تُجري طلب بحث (المَعلمة q) عن الملف المحدّد. تُستخدَم المَعلمة fields لتحديد قيم العرض التي تهمّك، فما الفائدة من استرجاع كل شيء وإبطاء العملية إذا لم تكن تهتم بالقيم الأخرى؟ إذا كنت جديدًا في استخدام أقنعة الحقول لفلترة القيم المعروضة من واجهة برمجة التطبيقات، يمكنك الاطّلاع على مشاركة المدوّنة والفيديو. بخلاف ذلك، نفِّذ طلب البحث واحصل على السمة 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 على Drive وتم ضبطها على FILE، بعد تنفيذ النص البرمجي بنجاح، من المفترض أن يظهر لك ناتج يؤكّد أنّه تمكّن من قراءة الملف من Drive (ولكن لم يتم حفظه على الكمبيوتر):

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

تحديد المشاكل وحلّها

إذا لم تحصل على الناتج المطلوب كما هو موضّح أعلاه، قد يرجع ذلك إلى سبب واحد أو أكثر، ربما السبب التالي:

ملخّص

في هذا القسم، تعرّفت على كيفية الربط بواجهة Drive API (في طلبَي بيانات منفصلَين) للاستعلام عن ملف معيّن ثم تنزيله. حالة الاستخدام في النشاط التجاري: أرشفة بيانات Drive وربما تحليلها، مثلاً باستخدام أدوات Google Cloud يجب أن يتطابق الرمز البرمجي لتطبيقك في هذه المرحلة مع الرمز البرمجي في المستودع علىstep1-drive/analyze_gsimg.py.

يمكنك الاطّلاع على مزيد من المعلومات حول تنزيل الملفات على Google Drive هنا أو مشاهدة منشور المدونة والفيديو هذا. هذا الجزء من الدرس التطبيقي مطابق تقريبًا للدرس التطبيقي الكامل حول مقدّمة عن واجهات برمجة التطبيقات في Google Workspace، ولكن بدلاً من تنزيل ملف، يعرض أول 100 ملف أو مجلد في Google Drive الخاص بالمستخدم ويستخدم نطاقًا أكثر تقييدًا.

9- الخطوة 2: أرشفة الملف في Cloud Storage

الخطوة التالية هي إضافة إمكانية استخدام Google Cloud Storage. لإجراء ذلك، علينا استيراد حزمة Python أخرى، وهي io. تأكَّد من أنّ القسم العلوي من عمليات الاستيراد يبدو الآن على النحو التالي:

from __future__ import print_function                   
import io

بالإضافة إلى اسم ملف Drive، نحتاج إلى بعض المعلومات حول مكان تخزين هذا الملف على Cloud Storage، وتحديدًا اسم "الحزمة" التي ستضع الملف فيها وأي بادئات "المجلد الرئيسي". المزيد حول هذا الموضوع بعد قليل:

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

ملاحظة حول الحِزم: توفّر خدمة Cloud Storage مساحة تخزين غير محدودة للبيانات الثنائية الكبيرة. عند تحميل الملفات هناك، لا يفهم مفهوم أنواع الملفات والامتدادات وما إلى ذلك، كما يفعل Google Drive. هي مجرد "كائنات ثنائية كبيرة" بالنسبة إلى Cloud Storage. بالإضافة إلى ذلك، لا يتوفّر مفهوم المجلدات أو الدلائل الفرعية في Cloud Storage.

نعم، يمكنك استخدام شرطات مائلة (/) في أسماء الملفات لتمثيل تجريد المجلدات الفرعية المتعددة، ولكن في نهاية المطاف، يتم وضع جميع الكائنات الثنائية الكبيرة في حزمة، وتكون الشرطات المائلة (/) مجرد أحرف في أسماء الملفات. يمكنك الاطّلاع على صفحة اصطلاحات تسمية الحِزم والعناصر لمزيد من المعلومات.

طلبت الخطوة 1 أعلاه نطاق القراءة فقط في Drive. في ذلك الوقت، كان هذا كل ما تحتاجه. يجب الآن الحصول على إذن التحميل (القراءة والكتابة) إلى Cloud Storage. غيِّر SCOPES من متغيّر سلسلة واحد إلى صفيف (مجموعة Python [أو قائمة]) لنطاقات الأذونات لكي يبدو على النحو التالي:

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

الآن، أنشئ نقطة نهاية خدمة في Cloud Storage أسفل نقطة نهاية خدمة Drive مباشرةً. يُرجى العِلم أنّنا عدّلنا الطلب قليلاً لإعادة استخدام كائن عميل 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() اسم الحزمة والبيانات الوصفية للملف والثنائي الكبير نفسه. لاستبعاد القيم المعروضة، يطلب المتغيّر fields أسماء الحزمة والعناصر فقط التي تعرضها واجهة برمجة التطبيقات. لمزيد من المعلومات حول أقنعة الحقول هذه في طلبات القراءة من واجهة برمجة التطبيقات، يمكنك الاطّلاع على هذه المشاركة والفيديو.

الآن، ادمِج استخدام 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 لكي يبدو "الرئيسي" بالكامل على النحو التالي:

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 من Drive ثم تحميله إلى 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">

انتبه جيدًا، فمع أنّ عملية التنزيل من Drive تمت بنجاح، تعذّر تحميل الملف إلى Cloud Storage. لماذا؟

والسبب هو أنّه عند السماح لهذا التطبيق في الخطوة 1، سمحنا له بالوصول إلى Google Drive في وضع القراءة فقط. على الرغم من أنّنا أضفنا نطاق القراءة والكتابة إلى Cloud Storage، لم نطلب من المستخدم أبدًا منح هذا الإذن. لإنجاح ذلك، علينا حذف ملف storage.json الذي لا يتضمّن هذا النطاق وإعادة التشغيل.

بعد إعادة التفويض (يمكنك التأكّد من ذلك من خلال البحث داخل storage.json والعثور على النطاقَين)، ستكون النتيجة كما هو متوقّع:

$ 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 Drive و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() البيانات بالإضافة إلى ميزات واجهة برمجة التطبيقات المطلوبة. يشكّل الحدّ الأقصى لعدد التصنيفات البالغ 5 جزءًا من الحمولة أيضًا (ولكنّه اختياري تمامًا). في حال نجاح الطلب، تعرض الحمولة أهم 5 تصنيفات للعناصر بالإضافة إلى درجة الثقة في أنّ العنصر يظهر في الصورة. (في حال عدم تلقّي أي ردّ، عليك تعيين قاموس بايثون فارغ حتى لا يتعذّر تنفيذ عبارة if التالية). تجمع هذه الدالة هذه البيانات ببساطة في سلسلة CSV لاستخدامها في النهاية في تقريرنا.

يجب وضع هذه الأسطر الخمسة التي تستدعي 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

ملخّص

لا يمتلك الجميع الخبرة في مجال تعلُّم الآلة لإنشاء نماذج تعلُّم الآلة وتدريبها بأنفسهم من أجل تحليل بياناتهم. أتاح فريق Google Cloud بعض نماذج Google المدرَّبة مسبقًا للاستخدام العام، كما أتاحها من خلال واجهات برمجة التطبيقات، ما ساعد في إتاحة الذكاء الاصطناعي وتعلُّم الآلة للجميع.

إذا كنت مطوّرًا ويمكنك استدعاء واجهة برمجة تطبيقات، يمكنك استخدام تعلُّم الآلة. ‫Cloud Vision هي مجرد واحدة من خدمات واجهة برمجة التطبيقات التي يمكنك استخدامها لتحليل بياناتك. يمكنك الاطّلاع على المزيد من المعلومات بشأنها هنا. من المفترض أن يتطابق الرمز الآن مع الرمز الموجود في المستودع على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() تحوّل البايت إلى كيلوبايت، مع تعريفها على أنّها lambda في Python لأنّها تتألف من سطر واحد بسيط. يبدو كلا هذين المتغيرين المدمجين مع الثوابت الأخرى على النحو التالي:

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 الآن جميع العناصر الأربعة المطلوبة:

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() معرّف ملف "جداول بيانات Google" ونطاقًا من الخلايا وطريقة إدخال البيانات والبيانات نفسها. رقم تعريف الملف واضح، ويتم تقديم نطاق الخلايا في تنسيق A1. يعني النطاق "Sheet1" ورقة Google بأكملها، ويشير ذلك إلى واجهة برمجة التطبيقات لإلحاق الصف بعد كل البيانات في ورقة Google. هناك خياران بشأن كيفية إضافة البيانات إلى ورقة Google، وهما "RAW" (إدخال بيانات السلسلة حرفيًا) أو "USER_ENTERED" (كتابة البيانات كما لو أنّ المستخدم أدخلها على لوحة المفاتيح باستخدام تطبيق "جداول بيانات Google"، مع الحفاظ على أي ميزات لتنسيق الخلايا).

إذا كان الطلب ناجحًا، لن تكون القيمة المعروضة مفيدة جدًا، لذا اخترنا الحصول على عدد الخلايا التي تم تعديلها من خلال طلب البيانات من واجهة برمجة التطبيقات. في ما يلي الرمز الذي يستدعي هذه الدالة:

                # 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

ملخّص

في الخطوات الثلاث الأولى من هذا البرنامج التعليمي، ربطت واجهات برمجة التطبيقات في Google Workspace وCloud APIs لنقل البيانات وتحليلها، ما يمثّل% 80 من جميع الأعمال. ومع ذلك، في نهاية اليوم، لن يكون لأي من ذلك أي معنى إذا لم تتمكّن من تقديم كل ما أنجزته إلى الإدارة. للحصول على تصور أفضل للنتائج، من المفيد تلخيص جميع النتائج في تقرير يتم إنشاؤه.

لتعزيز فائدة التحليل، بالإضافة إلى كتابة النتائج في جدول بيانات، يمكن إجراء تحسين محتمل من خلال فهرسة أهم 5 تصنيفات لكل صورة، ما يتيح إنشاء قاعدة بيانات داخلية تسمح للموظفين المفوّضين بالبحث عن الصور حسب فريق البحث، ولكن نترك ذلك كتمرين للقراء.

في الوقت الحالي، تتوفر نتائجنا في "جدول بيانات Google" ويمكن لفريق الإدارة الوصول إليها. يجب أن يتطابق الرمز البرمجي لتطبيقك في هذه المرحلة مع الرمز البرمجي في المستودع علىstep4-sheets/analyze_gsimg.py. الخطوة الأخيرة هي تنظيف الرمز البرمجي وتحويله إلى نص برمجي قابل للاستخدام.

12. *الخطوة الأخيرة: إعادة تصميم الرمز

(اختياري) من الجيد أن يكون لديك تطبيق يعمل، ولكن هل يمكننا تحسينه؟ نعم، لا سيما التطبيق الرئيسي الذي يبدو وكأنه فوضى عارمة. لنضع ذلك في دالة خاصة وننفّذها مع السماح ببيانات أدخلها المستخدم بدلاً من الثوابت الثابتة. سننفّذ ذلك باستخدام الوحدة التدريبية argparse. علاوةً على ذلك، لنطلق علامة تبويب متصفّح لعرض "جدول Google" بعد أن نكتب صف البيانات فيه. يمكن إجراء ذلك باستخدام الوحدة webbrowser. اربط عمليات الاستيراد هذه بعمليات الاستيراد الأخرى لتبدو عمليات الاستيراد الأعلى على النحو التالي:

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

لكي نتمكّن من استخدام هذا الرمز في تطبيقات أخرى، نحتاج إلى إمكانية إيقاف الإخراج، لذا لنضِف العلامة DEBUG لتحقيق ذلك، وذلك بإضافة هذا السطر إلى نهاية قسم الثوابت بالقرب من أعلى الصفحة:

DEBUG = False

والآن، سنتحدث عن النص الأساسي. أثناء إنشاء هذا النموذج، من المفترض أنّك بدأت تشعر "بالضيق" لأنّ الرمز البرمجي يضيف مستوى آخر من التداخل مع كل خدمة تتم إضافتها. إذا شعرت بذلك، لا تقلق، فهذا يزيد من تعقيد الرمز البرمجي كما هو موضّح في منشور مدوّنة Google Testing هذا.

باتّباع أفضل الممارسات هذه، لنعيد تنظيم الجزء الرئيسي من التطبيق في دالة و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

تتيح الخيارات الأخرى للمستخدمين اختيار أسماء ملفات مختلفة في Drive، وأسماء "المجلدات الفرعية" والحِزم في Cloud Storage، وأفضل "N" نتائج من Cloud Vision، ومعرّفات ملفات جداول البيانات (جداول بيانات Google). بعد إجراء هذه التعديلات الأخيرة، من المفترض أن يتطابق الإصدار النهائي من الرمز مع ما هو متوفّر في المستودع على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. تهانينا!

لقد تعلّمت الكثير في هذا الدرس التطبيقي حول الترميز، ونجحت في إكماله، وهو من الدروس التطبيقية الأطول. نتيجةً لذلك، تمكّنت من معالجة سيناريو محتمل للمؤسسات باستخدام حوالي 130 سطرًا من لغة Python، والاستفادة من جميع خدمات Google Cloud وGoogle Workspace، ونقل البيانات بينهما لإنشاء حلّ عملي. يمكنك الاطّلاع على مستودع المصدر المفتوح لجميع إصدارات هذا التطبيق (مزيد من المعلومات أدناه).

تَنظيم

  1. إنّ استخدام واجهات Google Cloud API ليس مجانيًا، بينما يتم تضمين واجهات برمجة التطبيقات في Google Workspace في رسوم اشتراك Google Workspace الشهرية (لا يدفع مستخدمو Gmail رسومًا شهرية)، لذا لا يلزم إجراء أي عملية تنظيف أو إيقاف لواجهات برمجة التطبيقات لمستخدمي Google Workspace. بالنسبة إلى Google Cloud، يمكنك الانتقال إلى لوحة بيانات Cloud Console والتحقّق من "بطاقة" الفوترة لمعرفة الرسوم المقدّرة.
  2. بالنسبة إلى Cloud Vision، يُسمح لك بعدد ثابت من طلبات البيانات من واجهة برمجة التطبيقات شهريًا مجانًا. لذلك، طالما أنّك لا تتجاوز هذه الحدود، لن تحتاج إلى إيقاف أي شيء أو إيقاف مشروعك أو حذفه. يمكنك الاطّلاع على مزيد من المعلومات حول الفوترة والحصة المجانية في Vision API على صفحة الأسعار.
  3. يحصل بعض مستخدمي Cloud Storage على مساحة تخزين مجانية كل شهر. إذا لم تتجاوز الحصة المحددة عند أرشفة الصور باستخدام هذا الدرس التطبيقي حول الترميز، لن يتم تحصيل أي رسوم منك. يمكنك الاطّلاع على مزيد من المعلومات حول فوترة GCS والحصة المجانية على صفحة الأسعار. يمكنك عرض وحذف الكائنات الثنائية الكبيرة بسهولة من متصفّح Cloud Storage.
  4. قد يكون لاستخدامك Google Drive أيضًا مساحة التخزين المتوفّرة، وإذا تجاوزتها (أو كنت قريبًا منها)، يمكنك استخدام الأداة التي أنشأتها في هذا الدرس العملي لتأرشف هذه الصور في Cloud Storage من أجل توفير مساحة أكبر على Drive. يمكنك العثور على مزيد من المعلومات حول مساحة التخزين في Google Drive على صفحة الأسعار المناسبة لمستخدمي Google Workspace Basic أو مستخدمي Gmail/المستهلكين.

على الرغم من أنّ معظم خطط Google Workspace Business وEnterprise توفّر مساحة تخزين غير محدودة، قد يؤدي ذلك إلى ازدحام مجلدات Drive و/أو صعوبة إدارتها، ويُعدّ التطبيق الذي أنشأته في هذا البرنامج التعليمي طريقة رائعة لأرشفة الملفات غير الضرورية وتنظيف Google Drive.

إصدارات بديلة

على الرغم من أنّ final/analyze_gsimg.py هي "آخر" نسخة رسمية تعمل عليها في هذا البرنامج التعليمي، إلا أنّها ليست نهاية القصة. إحدى المشاكل في الإصدار النهائي من التطبيق هي أنّه يستخدم مكتبات المصادقة القديمة التي تم إيقافها نهائيًا. لقد اخترنا هذا المسار لأنّه في وقت كتابة هذا المستند، لم تكن مكتبات المصادقة الأحدث متوافقة مع العديد من العناصر الأساسية: إدارة تخزين رموز OAuth المميزة وأمان سلاسل المحادثات.

مكتبات المصادقة الحالية (الأحدث)

ومع ذلك، في مرحلة ما، لن تعود مكتبات المصادقة القديمة متوافقة، لذا ننصحك بمراجعة الإصدارات التي تستخدم مكتبات المصادقة الأحدث (الحالية) في مجلد alt في المستودع حتى إذا لم تكن آمنة للاستخدام المتزامن (ولكن يمكنك إنشاء حلّ خاص بك يكون آمنًا للاستخدام المتزامن). ابحث عن الملفات التي تتضمّن *newauth* في أسمائها.

مكتبات برامج المنتجات على Google Cloud

تنصح Google Cloud جميع المطوّرين باستخدام مكتبات برامج العميل الخاصة بالمنتج عند استخدام واجهات Google Cloud API. في الوقت الحالي، لا تتوفّر مثل هذه المكتبات لواجهات برمجة التطبيقات غير التابعة لـ Google Cloud. يسمح استخدام المكتبات ذات المستوى الأدنى باستخدام واجهة برمجة التطبيقات بشكل متّسق، كما يتيح قراءة أفضل. على غرار الاقتراح أعلاه، تتوفّر إصدارات بديلة تستخدم مكتبات برامج Google Cloud في مجلد alt في المستودع لتراجعها. ابحث عن الملفات التي تتضمّن *-gcp* في أسمائها.

تفويض حساب الخدمة

عند العمل في السحابة الإلكترونية فقط، لا يكون هناك عادةً أشخاص أو بيانات يملكها مستخدم (بشري)، ولهذا السبب يتم استخدام حسابات الخدمة وتفويض حسابات الخدمة بشكل أساسي مع Google Cloud. ومع ذلك، يملك المستخدمون (البشر) بشكل عام مستندات Google Workspace، ولهذا السبب يستخدم هذا البرنامج التعليمي تفويض حساب المستخدم. وهذا لا يعني أنّه لا يمكن استخدام واجهات برمجة التطبيقات في Google Workspace مع حسابات الخدمة. ما دامت هذه الحسابات تتضمّن مستوى الوصول المناسب، يمكن استخدامها بالتأكيد في التطبيقات. على غرار ما ورد أعلاه، تتوفّر إصدارات بديلة تستخدم تفويض حساب الخدمة في مجلد alt في المستودع لتراجعها. ابحث عن الملفات التي تتضمّن *-svc* في أسمائها.

قائمة الإصدارات البديلة

في ما يلي جميع الإصدارات البديلة من final/analyze_gsimg.py، وكلّ منها يتضمّن واحدة أو أكثر من الخصائص المذكورة أعلاه. في اسم ملف كل إصدار، ابحث عن:

  • ‫"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 ولكن يستخدم حساب خدمة بدلاً من حساب مستخدم

alt/analyze_gsimg-newauth-svc.py

هي نفسها alt/analyze_gsimg-newauth.py ولكنها تستخدم مصادقة حساب الخدمة بدلاً من حساب المستخدم

alt/analyze_gsimg-oldauth-svc-gcp.py

كما هو الحال مع alt/analyze_gsimg-oldauth-svc.py، ولكنّه يستخدم مكتبات برامج Google Cloud API، وكما هو الحال مع alt/analyze_gsimg-oldauth-gcp.py، ولكنّه يستخدم مصادقة حساب الخدمة بدلاً من حساب المستخدم

alt/analyze_gsimg-newauth-svc-gcp.py

هي نفسها alt/analyze_gsimg-oldauth-svc-gcp.py ولكنها تستخدم مكتبات المصادقة الأحدث

بالإضافة إلى final/analyze_gsimg.py الأصلي، تتوفّر لك جميع المجموعات الممكنة للحل النهائي، بغض النظر عن بيئة تطوير Google API، ويمكنك اختيار المجموعة الأنسب لاحتياجاتك. راجِع أيضًا alt/README.md للحصول على شرح مشابه.

دراسة إضافية

في ما يلي بعض الأفكار حول كيفية تطوير هذا التمرين خطوة أو خطوتين إضافيتين. يمكن توسيع مجموعة المشاكل التي يمكن للحل الحالي التعامل معها، ما يتيح لك إجراء التحسينات التالية:

  1. (صور متعددة في مجلدات) بدلاً من معالجة صورة واحدة، لنفترض أنّ لديك صورًا في مجلدات Google Drive.
  2. (صور متعددة في ملفات ZIP) بدلاً من مجلد صور، ماذا عن أرشيفات ZIP تحتوي على ملفات صور؟ إذا كنت تستخدم Python، ننصحك باستخدام وحدة zipfile.
  3. (تحليل تصنيفات Vision) تجميع الصور المتشابهة معًا، ربما البدء بالبحث عن التصنيفات الأكثر شيوعًا، ثم التصنيفات الأكثر شيوعًا في المرتبة الثانية، وهكذا
  4. (إنشاء رسومات بيانية) المتابعة رقم 3، إنشاء رسومات بيانية باستخدام Sheets API استنادًا إلى تحليل Vision API وتصنيفاته
  5. (تصنيف المستندات) بدلاً من تحليل الصور باستخدام Cloud Vision API، لنفترض أنّ لديك ملفات PDF لتصنيفها باستخدام Cloud Natural Language API. باستخدام الحلول المذكورة أعلاه، يمكن أن تكون ملفات PDF هذه في مجلدات Drive أو أرشيفات ZIP على Drive.
  6. (إنشاء عروض تقديمية) استخدِم Slides API لإنشاء مجموعة شرائح من محتوى تقرير "جداول بيانات Google". للحصول على أفكار جديدة، يمكنك الاطّلاع على منشور المدوّنة والفيديو هذا حول إنشاء شرائح من بيانات جدول بيانات.
  7. (التصدير كملف PDF) تصدير جدول البيانات و/أو مجموعة الشرائح كملف PDF، ولكن هذه ليست ميزة في واجهات برمجة التطبيقات لكل من "جداول بيانات Google" و"العروض التقديمية من Google". تلميح: Google Drive API. ميزة إضافية: يمكنك دمج ملفَي PDF الخاصَين بـ "جداول بيانات Google" و"العروض التقديمية من Google" في ملف PDF رئيسي واحد باستخدام أدوات مثل Ghostscript (Linux وWindows) أو Combine PDF Pages.action (نظام التشغيل Mac OS X).

مزيد من المعلومات

Codelabs

للجمهور العام

Google Workspace

Google Cloud

الترخيص

يخضع هذا العمل لترخيص المشاع الإبداعي مع نسب العمل إلى مؤلفه 2.0 Generic License.