أرشفة الصور وتحليلها وإنشاء التقارير في 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؟

مبتدئ متوسط متقن

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

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

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

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

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

b35bf95b8bf3d5d8.pnga99b7ace416376c4.pngbd84a6d3004737c5.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 API تتيح استخدام العديد من اللغات، لذا يمكنك إنشاء شيء مماثل باستخدام أداة التطوير المفضّلة لديك واستخدام 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.

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

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

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

virtualenv my_env

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

virtualenv -p python3 my_env

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

source my_env/bin/activate

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

(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 API، وخاصةً واجهات Google Workspace API، جرِّب أولاً برنامج التدريب العملي التمهيدي حول واجهات Google Workspace API. بالإضافة إلى ذلك، إذا كنت تعرف كيفية إنشاء بيانات اعتماد حساب مستخدم (وليس حساب خدمة) (أو إعادة استخدام بيانات اعتماد حالية)، يمكنك وضع ملف 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 APIs المستخدَمة في هذا الدرس التطبيقي حول الترميز. بالنسبة إلى اسم التطبيق في شاشة طلب موافقة OAuth، اخترنا "عرض توضيحي لواجهة برمجة التطبيقات Vision"، لذا من المتوقّع أن يظهر هذا الاسم في بعض لقطات الشاشة القادمة.

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

$ 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

تحتوي مجموعة files() في Drive على طريقة 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 API، ولكن بدلاً من تنزيل ملف، يعرض أول 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، أليس كذلك؟ 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">

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

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

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

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

الترخيص

يخضع هذا العمل لترخيص Creative Commons Attribution 2.0 Generic License.