1. סקירה כללית
ה-Codelab הזה מדמה תהליך עבודה אפשרי בארגון: העברת תמונות לארכיון, ניתוח ויצירת דוחות. נניח שלארגון שלכם יש סדרה של תמונות שתופסות מקום של משאב מוגבל. אתם רוצים להעביר את הנתונים האלה לארכיון, לנתח את התמונות האלה, והכי חשוב, ליצור דוח שמסכם את המיקומים שהועברו לארכיון ואת תוצאות הניתוח, כשהם מוכנים לשימוש על ידי הניהול. כדי לעשות זאת, Google Cloud מספק כלים באמצעות ממשקי API משני קווי המוצרים שלו, Google Workspace (לשעבר G Suite או Google Apps) ו-Google Cloud (לשעבר GCP).
בתרחיש שלנו, למשתמש העסקי יהיו תמונות ב-Google Drive. הגיוני לגבות אותם ל"קולר", נפח אחסון זול יותר, כמו סוגי האחסון (storage classes) שזמינים ב-Google Cloud Storage. בעזרת Google Cloud Vision, מפתחים יכולים לשלב בקלות תכונות של זיהוי ראייה באפליקציות, כולל זיהוי אובייקטים וציוני דרך, זיהוי תווים אופטי (OCR). לבסוף, גיליון אלקטרוני ב-Google Sheets הוא כלי שימושי להמחשה חזותית, לסיכום של כל המידע הזה בשביל הבוס.
אחרי שתשלימו את תהליך ה-Codelab הזה ותבנה פתרון שממנף את כל Google Cloud, אנחנו מקווים לקבל השראה לבנות משהו שישפיע עוד יותר על הארגון או הלקוחות שלך.
מה תלמדו
- איך משתמשים ב-Cloud Shell?
- איך לאמת בקשות API
- איך להתקין את ספריית הלקוח של Google APIs ל-Python
- איך מפעילים את ממשקי ה-API של Google
- איך מורידים קבצים מ-Google Drive
- איך מעלים אובייקטים או blobs ל-Cloud Storage
- איך מנתחים נתונים באמצעות Cloud Vision
- איך כותבים שורות ב-Google Sheets
למה תזדקק?
- חשבון Google (חשבונות Google Workspace עשויים לדרוש אישור אדמין)
- פרויקט ב-Google Cloud עם חשבון פעיל לחיוב ב-Google Cloud
- היכרות עם פקודות טרמינל/מעטפת של מערכת הפעלה
- מיומנויות בסיסיות ב-Python (2 או 3), אבל אפשר להשתמש בכל שפה נתמכת
ניסיון בארבעת מוצרי Google Cloud המפורטים למעלה יכול לעזור, אבל לא חובה. אם הזמן יאפשר לכם להכיר אותם בנפרד, תוכלו לבצע ערכות Codelabs לכל אחת מהפלטפורמות לפני שתתחילו את התרגיל כאן:
- הקדמה ל-Google Drive (שימוש ב-Google Workspace APIs) (Python)
- שימוש ב-Cloud Vision עם Python (Python)
- יצירת כלי דיווח מותאמים אישית באמצעות Sheets API (JS/Node)
- העלאת אובייקטים ל-Google Cloud Storage (ללא צורך בכתיבת קוד)
סקר
איך תשתמשו במדריך הזה?
איזה דירוג מגיע לדעתך לחוויה שלך עם Python?
איזה דירוג מגיע לדעתך לחוויית השימוש שלך בשירותי Google Cloud?
איזה דירוג מגיע לדעתך לחוויית השימוש בשירותים למפתחים של Google Workspace?
האם ברצונך לראות יותר מודעות 'עסקיות' Codelabs לעומת אלה מהם מבוא לפיצ'רים של המוצר?
2. הגדרה ודרישות
הגדרת סביבה בקצב אישי
- נכנסים למסוף Google Cloud ויוצרים פרויקט חדש או עושים שימוש חוזר בפרויקט קיים. אם אין לכם עדיין חשבון Gmail או חשבון Google Workspace, עליכם ליצור חשבון.
- Project name הוא השם המוצג של המשתתפים בפרויקט. זו מחרוזת תווים שלא משמשת את Google APIs. אפשר לעדכן אותו בכל שלב.
- Project ID חייב להיות ייחודי בכל הפרויקטים ב-Google Cloud ואי אפשר לשנות אותו (אי אפשר לשנות אותו אחרי שמגדירים אותו). מסוף Cloud יוצר מחרוזת ייחודית באופן אוטומטי; בדרך כלל לא מעניין אותך מה זה. ברוב ה-Codelabs תצטרכו להפנות אל מזהה הפרויקט (בדרך כלל הוא מזוהה כ-
PROJECT_ID
). אם המזהה שנוצר לא מוצא חן בעיניך, יש לך אפשרות ליצור מזהה אקראי אחר. לחלופין, אפשר לנסות תבנית משלך ולבדוק אם היא זמינה. לא ניתן לשנות אותו אחרי השלב הזה, והוא יישאר למשך הפרויקט. - לידיעתך, יש ערך שלישי – Project Number (מספר פרויקט), שחלק מממשקי ה-API משתמשים בו. מידע נוסף על כל שלושת הערכים האלה זמין במסמכי התיעוד.
- בשלב הבא צריך להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבים או בממשקי API של Cloud. מעבר ב-Codelab הזה לא אמור לעלות הרבה, אם בכלל. כדי להשבית את המשאבים ולא לצבור חיובים מעבר למדריך הזה, אתם יכולים למחוק את המשאבים שיצרתם או למחוק את הפרויקט כולו. משתמשים חדשים ב-Google Cloud זכאים להצטרף לתוכנית תקופת ניסיון בחינם בשווי 1,200 ש"ח.
הפעלת Cloud Shell
סיכום
אפשר לפתח קוד באופן מקומי במחשב הנייד, אבל מטרה משנית ב-Codelab הזה היא ללמד איך להשתמש ב-Google Cloud Shell, סביבת שורת פקודה שפועלת בענן דרך דפדפן האינטרנט המודרני שלכם.
הפעלת Cloud Shell
- במסוף Cloud, לוחצים על Activate Cloud Shell .
אם לא הפעלתם את Cloud Shell בעבר, יוצג לכם מסך ביניים (בחלק הנגלל) שמתאר מהו. במקרה כזה, לוחצים על המשך (וזה לא יקרה שוב). כך נראה המסך החד-פעמי:
ההקצאה וההתחברות ל-Cloud Shell נמשכת כמה דקות.
במכונה הווירטואלית הזו משולבת כל כלי הפיתוח שדרושים לכם. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר משמעותית את ביצועי הרשת והאימות. אם לא את כולן, ניתן לבצע חלק גדול מהעבודה ב-Codelab הזה באמצעות דפדפן או Chromebook.
אחרי ההתחברות ל-Cloud Shell, אתם אמורים לראות שכבר בוצע אימות ושהפרויקט כבר מוגדר למזהה הפרויקט שלכם.
- מריצים את הפקודה הבאה ב-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`
- מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שהפקודה ב-gcloud יודעת על הפרויקט שלכם:
gcloud config list project
פלט הפקודה
[core] project = <PROJECT_ID>
אם היא לא נמצאת שם, תוכלו להגדיר אותה באמצעות הפקודה הבאה:
gcloud config set project <PROJECT_ID>
פלט הפקודה
Updated property [core/project].
3. אישור סביבת Python
ה-Codelab הזה מחייב אותך להשתמש בשפת Python (למרות ששפות רבות נתמכות על ידי ספריות הלקוח של Google APIs, לכן אל תהססו לפתח משהו מקביל בכלי הפיתוח המועדף עליכם ופשוט להשתמש ב-Python כ-pseudocode). באופן ספציפי, ה-Codelab הזה תומך ב-Python 2 וב-Python 2, אבל אנחנו ממליצים לעבור ל-3.x בהקדם האפשרי.
Cloud Shell הוא כלי נוח למשתמשים שזמין ישירות מ-Cloud Console ולא נדרשת סביבת פיתוח מקומית, כך שאפשר לבצע את המדריך הזה בענן באופן מלא באמצעות דפדפן אינטרנט. באופן ספציפי יותר ב-Codelab הזה, Cloud Shell כבר התקין מראש את שתי הגרסאות של Python.
ב-Cloud Shell מותקן גם IPython: זהו כלי תרגום אינטראקטיבי ב-Python ברמה גבוהה יותר, ואנחנו ממליצים להשתמש בו, במיוחד אם אתם חברים בקהילה של מדעי הנתונים או למידת המכונה. אם כן, IPython הוא כלי התרגום המוגדר כברירת מחדל ב-Notebooks של Jupyter וגם ב-Colab, Jupyter Notebooks באירוח של Google Research.
ב-IPython יש עדיפות למפענח Python 3, אבל הוא יחזור ל-Python 2 אם אין גרסה 3.x. אפשר לגשת ל-IPython מ-Cloud Shell, אבל אפשר להתקין אותו גם בסביבת פיתוח מקומית. צאו עם ^D (Ctrl-d) ומאשרים את ההצעה כדי לצאת. פלט לדוגמה של התחלת ipython
ייראה כך:
$ ipython Python 3.7.3 (default, Mar 4 2020, 23:11:43) Type 'copyright', 'credits' or 'license' for more information IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help. In [1]:
אם אתם לא מעדיפים להשתמש ב-IPython, השימוש במפענח אינטראקטיבי סטנדרטי של Python (ב-Cloud Shell או בסביבת הפיתוח המקומית שלכם) מקובל עליכם (לצאת גם באמצעות ^D):
$ python Python 2.7.13 (default, Sep 26 2018, 18:42:22) [GCC 6.3.0 20170516] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> $ python3 Python 3.7.3 (default, Mar 10 2020, 02:33:39) [GCC 6.3.0 20170516] on linux Type "help", "copyright", "credits" or "license" for more information. >>>
המערכת של Codelab גם יוצאת מנקודת הנחה שיש לכם את כלי ההתקנה pip
(מנהל החבילות Python ומקודד התלות). הוא מגיע עם גרסאות 2.7.9 ומעלה או 3.4 ומעלה. אם אתם משתמשים בגרסה ישנה יותר של Python, תוכלו לעיין במדריך הזה כדי לקבל הוראות להתקנה. בהתאם להרשאות שלכם, יכול להיות שתצטרכו להיות sudo
או גישה של משתמש-על, אבל בדרך כלל זה לא המצב. אפשר גם להשתמש במפורש ב-pip2
או ב-pip3
כדי להריץ את pip
בגרסאות Python ספציפיות.
המשך השיעור ב-Codelab מבוסס על ההנחה שאתם משתמשים ב-Python 3. הוראות ספציפיות יסופקו עבור Python 2 אם הן שונות באופן משמעותי מ- 3.x.
[אופציונלי] יצירה של סביבות וירטואליות ושימוש בהן
הקטע הזה הוא אופציונלי ונדרש רק עבור מי שחייבים להשתמש בסביבה וירטואלית עבור ה-Codelab הזה (בהתאם לסרגל הצד של האזהרה שלמעלה). אם במחשב שלכם יש רק Python 3, אתם יכולים פשוט להפיק את הפקודה הבאה וליצור Virtualenv בשם my_env
(אם תרצו, תוכלו לבחור שם אחר):
virtualenv my_env
אבל אם יש לכם גם את Python 2 וגם 3 במחשב, אנחנו ממליצים להתקין וירטואליה של Python 3. אפשר לעשות זאת באמצעות -p flag
באופן הבא:
virtualenv -p python3 my_env
צריך להיכנס ל-Virtualenv החדש שנוצר על ידי "Activate" (הפעלה) כך:
source my_env/bin/activate
כדי לוודא שאתם נמצאים בסביבה, בודקים את הנחיית המעטפת לפני שם הסביבה, כלומר,
(my_env) $
עכשיו אמורה להיות לך אפשרות pip install
את כל החבילות הנדרשות, להפעיל קוד בתוך ההפעלה הזו וכו'. יתרון נוסף הוא שאם תגרום לבלגן לגמרי, תקבל מצב שבו התקנת Python שלך נפגמה וכו', תוכל לפוצץ את כל הסביבה בלי להשפיע על שאר המערכת.
4. התקנה של ספריית הלקוח של Google APIs ל-Python
הקוד של Codelab הזה מחייב שימוש בספריית הלקוח של Google APIs ל-Python. לכן, התהליך פשוט להתקנה ואם לא צריך לעשות שום דבר.
קודם אנחנו ממליצים להשתמש ב-Cloud Shell כדי שיהיה נוח יותר. אפשר להשלים את המדריך כולו מדפדפן אינטרנט בענן. עוד סיבה להשתמש ב-Cloud Shell היא שהרבה ספריות וכלי פיתוח פופולריים וספריות נחוצות כבר מותקנות מראש.
*התקנת ספריות לקוח
(אופציונלי) אפשר לדלג על השלב הזה אם משתמשים ב-Cloud Shell או בסביבה מקומית שבה כבר התקנתם את ספריות הלקוח. צריך לעשות את זה רק אם אתם מפתחים באופן מקומי ועדיין לא התקנתם אותם (או אם אתם לא בטוחים שהתקנתם אותם). הדרך הקלה ביותר היא להשתמש ב-pip
(או ב-pip3
) לביצוע ההתקנה (כולל עדכון של pip
עצמו במקרה הצורך):
pip install -U pip google-api-python-client oauth2client
אישור ההתקנה
הפקודה הזו מתקינה את ספריית הלקוח וגם את החבילות שהיא תלויה בה. לא משנה אם אתם משתמשים ב-Cloud Shell או בסביבה שלכם, חשוב לוודא שספריית הלקוח מותקנת על ידי ייבוא החבילות הנדרשות, ומוודאים שאין שגיאות בייבוא (וגם אין פלט):
python3 -c "import googleapiclient, httplib2, oauth2client"
אם אתם משתמשים ב-Python 2 במקום זאת (מ-Cloud Shell), תוצג לכם אזהרה על כך שהתמיכה בו הוצאה משימוש:
******************************************************************************* Python 2 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. *******************************************************************************
ברגע שניתן להריץ את הייבוא "test" הפקודה הושלמה בהצלחה (ללא שגיאות/פלט), אתם מוכנים להתחיל לדבר עם ממשקי ה-API של Google!
סיכום
מאחר שמדובר ב-Codelab, ההנחה היא שכבר יש לך ניסיון ביצירה וב- באמצעות פרויקטים במסוף. אם זו הפעם הראשונה שאתם משתמשים ב-Google APIs וב-Google Workspace APIs באופן ספציפי, כדאי לנסות קודם את קוד Lab המבוא של Google Workspace APIs. בנוסף, אם יודעים איך ליצור (או לעשות שימוש חוזר) פרטי כניסה של חשבון משתמש (לא בחשבון שירות) כדי לדלג על קובץ ה-API של המודול הבא, משחררים את קובץ client_secret.json
5. *אישור בקשות API (הרשאת משתמש)
אפשר לדלג על הקטע הזה אם כבר יצרתם פרטי כניסה להרשאת חשבון משתמש ואתם מכירים את התהליך. היא שונה מהרשאה באמצעות חשבון שירות שהשיטה שלה שונה, ולכן יש להמשיך בהמשך.
מבוא להרשאה (בתוספת אימות חלק)
כדי לשלוח בקשות לממשקי ה-API, האפליקציה שלכם צריכה את ההרשאה המתאימה. אימות, מילה דומה, מתאר את פרטי הכניסה – אתם מאמתים את הזהות כשאתם מתחברים לחשבון Google באמצעות התחברות סיסמה. אחרי האימות, השלב הבא הוא אם אתם מורשים לגשת לנתונים, כמו קובצי blob ב-Cloud Storage או קבצים אישיים של משתמש ב-Google Drive, או אם לקוד שלכם.
Google APIs תומכים בכמה סוגי הרשאות, אבל הסוג הנפוץ ביותר בקרב משתמשי G Suite API הוא הרשאת משתמש, כי האפליקציה לדוגמה ב-Codelab הזו ניגשת לנתונים ששייכים למשתמשי קצה. משתמשי הקצה האלה חייבים לתת לאפליקציה שלכם הרשאת גישה לנתונים שלהם. המשמעות היא שהקוד צריך לקבל פרטי כניסה מסוג OAuth2 של חשבון משתמש.
כדי לקבל פרטי כניסה של OAuth2 להרשאות משתמש, חוזרים למנהל ה-API ובוחרים באפשרות 'פרטי כניסה' שבתפריט הניווט הימני:
שם תראו את כל פרטי הכניסה בשלושה קטעים נפרדים:
הראשונה היא למפתחות API, למזהי לקוח ב-OAuth 2.0 ולחשבונות שירות OAuth2 האחרונים – אנחנו משתמשים בזה שנמצא באמצע.
יצירת פרטי כניסה
בחלק העליון של הדף Credentials (פרטי כניסה), לוחצים על הלחצן + Create Credentials (+ יצירת פרטי כניסה), ואז תופיע תיבת דו-שיח שבה בוחרים באפשרות OAuth client ID:
במסך הבא יש שתי פעולות: הגדרת ההרשאה 'מסך ההסכמה' באפליקציה ובחירת סוג האפליקציה:
אם לא הגדרתם מסך הסכמה, האזהרה תופיע במסוף ויהיה עליכם לעשות זאת עכשיו. (אם מסך ההסכמה כבר הוגדר, אפשר לדלג על השלבים הבאים).
מסך ההסכמה ל-OAuth
לוחצים על 'Configure consent screen' (הגדרת מסך ההסכמה) שבו בוחרים באפשרות 'חיצוני' אפליקציה (או 'פנימית', אם אתם לקוחות G Suite):
שימו לב: לצורך התרגיל הזה, לא משנה באיזו שיטה תבחרו, כי אתם לא מפרסמים את דוגמת ה-Codelab. רוב האנשים יבחרו באפשרות 'חיצוני' יוצג במסך מורכב יותר, אבל תצטרך רק להשלים את "שם האפליקציה" השדה בחלק העליון:
בשלב הזה רק צריך שם של אפליקציה, אז בחרו מישהו שמשקף את ה-Codelab שאתם עושים ואז לוחצים על Save (שמירה).
יצירת מזהה לקוח ב-OAuth (אימות חשבון משתמש)
עכשיו חוזרים לכרטיסייה Credentials כדי ליצור מזהה לקוח OAuth2. כאן אפשר למצוא מגוון מזהי לקוח ב-OAuth שאפשר ליצור:
אנחנו מפתחים כלי שורת פקודה, שהוא אחר, אז בוחרים באפשרות הזו ולוחצים על הלחצן יצירה. בוחרים שם למזהה הלקוח שמשקף את האפליקציה שיוצרים, או פשוט משתמשים בשם ברירת המחדל, שהוא בדרך כלל "N של לקוח אחר".
המערכת שומרת את פרטי הכניסה שלך
- תופיע תיבת דו-שיח עם פרטי הכניסה החדשים. לוחצים על OK כדי לסגור
- חוזרים לדף Credentials, גוללים למטה לקטע 'מזהי לקוחות של OAuth2' מוצאים את סמל ההורדה ולוחצים עליו בקצה השמאלי של מזהה הלקוח החדש שיצרתם.
- תיפתח תיבת דו-שיח לשמירת קובץ בשם
client_secret-
LONG-HASH-STRING
.apps.googleusercontent.com.json
, כנראה בתיקייה הורדות. מומלץ לקצר את השם לשם קל יותר, כמוclient_secret.json
(כלומר, השימוש של האפליקציה לדוגמה), ואז לשמור אותו בספרייה או בתיקייה שבה תיצרו את האפליקציה לדוגמה ב-Codelab הזה.
סיכום
עכשיו אתם מוכנים להפעיל את ממשקי ה-API של Google שבהם אתם משתמשים ב-Codelab הזה. בנוסף, עבור שם האפליקציה במסך ההסכמה ל-OAuth, בחרנו באפשרות Vision APIdemo (הדגמה של Vision API), כך שאפשר לראות את זה בחלק מצילומי המסך שצפויים בקרוב.
6. הפעלת Google APIs
ב-Codelab הזה נעשה שימוש בארבעה (4) ממשקי API של Google Cloud, צמד מ-Google Cloud (Cloud Storage ו-Cloud Vision) וצמד נוסף מ-Google Workspace (Google Drive ו-Google Sheets). בהמשך מפורטות הוראות כלליות להפעלת Google APIs. ברגע שאתם יודעים איך להפעיל ממשק API אחד, שאר ממשקי ה-API דומים.
ללא קשר ל-Google API שבו אתם רוצים להשתמש באפליקציה, עליכם להפעיל אותם. את ממשקי ה-API אפשר להפעיל משורת הפקודה או ממסוף Cloud. תהליך ההפעלה של ממשקי API זהה, לכן לאחר שמפעילים ממשק API אחד, ניתן להפעיל ממשקי API אחרים באופן דומה.
אפשרות 1: gcloud
ממשק שורת הפקודה (Cloud Shell או בסביבה מקומית)
אומנם התהליך של הפעלת ממשקי API ממסוף Cloud הוא נפוץ יותר, אבל יש מפתחים שמעדיפים לעשות הכול משורת הפקודה. לשם כך, צריך לחפש את 'שם השירות' של API. נראה שכתובת ה-URL היא: SERVICE_NAME
.googleapis.com
. תוכלו למצוא את המוצרים האלה בתרשים המוצרים הנתמכים או לשלוח שאילתה עליהם באופן פרוגרמטי באמצעות Google Discovery API.
כשכוללים את המידע הזה, באמצעות Cloud Shell (או סביבת הפיתוח המקומית שבה מותקן כלי שורת הפקודה gcloud
), אפשר להפעיל API או שירות באופן הבא:
gcloud services enable SERVICE_NAME.googleapis.com
דוגמה 1: הפעלה של Cloud Vision API
gcloud services enable vision.googleapis.com
דוגמה 2: הפעלה של פלטפורמת המחשוב ללא שרת (serverless) של Google App Engine
gcloud services enable appengine.googleapis.com
דוגמה 3: הפעלה של מספר ממשקי API בבקשה אחת. לדוגמה, אם ב-Codelab הזה יש צופים שפורסים אפליקציה באמצעות Cloud Translation API ל-App Engine, Cloud Functions ו-Cloud Run, שורת הפקודה תהיה:
gcloud services enable appengine.googleapis.com cloudfunctions.googleapis.com artifactregistry.googleapis.com run.googleapis.com translate.googleapis.com
הפקודה הזו מפעילה את App Engine, Cloud Functions, Cloud Run ואת Cloud Translation API. בנוסף, היא מפעילה את Cloud Artifact Registry כי מערכת Cloud Build צריכה לרשום קובצי אימג' של קונטיינרים כדי לפרוס אותם ב-Cloud Run.
יש גם כמה פקודות לשליחת שאילתות לגבי ממשקי API להפעלה, או לגבי ממשקי API שכבר הופעלו בפרויקט שלכם.
דוגמה 4: שאילתה לגבי ממשקי ה-API של Google שאפשר להפעיל בפרויקט שלכם
gcloud services list --available --filter="name:googleapis.com"
דוגמה 5: שאילתה להפעלת Google APIs בפרויקט שלך
gcloud services list
למידע נוסף על הפקודות שלמעלה, עיינו במשאבי העזרה בנושא הפעלה והשבתה של שירותים ושירותי רישום.
אפשרות 2: מסוף Cloud
אפשר להפעיל את Google APIs גם דרך מנהל ה-API. ממסוף Cloud, נכנסים אל API Manager. בדף זה של מרכז השליטה, מופיע מידע על התנועה של האפליקציה, תרשימים שמציגים בקשות של אפליקציות, שגיאות שנוצרו על ידי האפליקציה וזמני התגובה של האפליקציה:
למטה מופיעה רשימה של ממשקי Google API שהופעלו בפרויקט שלכם:
כדי להפעיל (או להשבית) ממשקי API, לוחצים על הפעלת ממשקי API ושירותים בחלק העליון של הדף:
לחלופין, עוברים לסרגל הניווט הימני ובוחרים באפשרות APIs & שירותים ← ספרייה:
בכל מקרה, תגיעו לדף API Library:
צריך להזין שם API שרוצים לחפש ולראות תוצאות תואמות:
בוחרים את ממשק ה-API שרוצים להפעיל ולוחצים על הלחצן Enable (הפעלה):
תהליך ההפעלה של כל ממשקי ה-API דומה, בלי קשר ל-Google API שבו רוצים להשתמש.
עלות
אפשר להשתמש בהרבה ממשקי API של Google ללא עמלות, אבל השימוש ברוב המוצרים וממשקי ה-API של Google Cloud כרוך בעלויות. כשמפעילים את Cloud APIs, יכול להיות שתתבקשו ליצור חשבון פעיל לחיוב. עם זאת, בחלק ממוצרי Google Cloud יש התכונה "חינם תמיד" [tier], שעליכם לחרוג ממנה כדי לצבור חיובי חיוב.
משתמשים חדשים ב-Google Cloud זכאים לתקופת הניסיון בחינם, שנכון לעכשיו היא 1,200 ש"ח למשך 90 הימים הראשונים. בדרך כלל, Codelabs לא כרוך בחיובים רבים או בחיובים כלשהם, ולכן אנו ממליצים להמתין את תקופת הניסיון בחינם עד שתהיה מוכנים באמת להתנסות, במיוחד מפני שמדובר במבצע חד-פעמי. המכסות של תוכנית ללא תשלום לא פג תוקף והן חלות גם אם לא משתמשים בתקופת הניסיון בחינם.
המשתמשים צריכים לעיין במידע על התמחור של כל API לפני שהם מפעילים אותו (לדוגמה: דף תמחור של Cloud Vision API ), ובמיוחד לציין אם יש לו תוכנית ללא תשלום, ואם כן, מה שלה. כל עוד לא תצברו חיובים במסגרת המגבלות היומיות או החודשיות שצוינו, לא תצברו חיובים. יש הבדלים בתמחור ובתוכניות ללא תשלום בין ממשקי ה-API של קבוצות המוצרים ב-Google. דוגמאות:
- Google Cloud – החיוב על כל מוצר מתבצע באופן שונה ובדרך כלל התשלום לפי שימוש. אפשר לעיין למעלה במידע על התוכנית ללא תשלום.
- מפות Google — כולל חבילה של ממשקי API ומציע למשתמשים קרדיט בסך 200 דולר ארה"ב בחודש בחינם.
- ממשקי Google Workspace (לשעבר G Suite APIs) – מספקים את השימוש (עד מגבלות מסוימות) שמכוסה בדמי מינוי חודשיים ל-Google Workspace, כך שאין חיוב ישיר על השימוש בממשקי API של אפליקציות כמו Gmail , Google Drive, יומן, Docs , Sheets או Slides.
מוצרים שונים של Google מחויבים בצורה שונה, לכן חשוב לעיין בתיעוד המתאים למידע הזה.
סיכום
עכשיו, אחרי ש-Cloud Vision הופעל, אפשר להפעיל את שלושת ממשקי ה-API האחרים (Google Drive , Cloud Storage , Google Sheets) באותה הדרך. ב-Cloud Shell, משתמשים ב-gcloud services enable
או ממסוף Cloud:
- חזרה לספריית ה-API
- אפשר להתחיל חיפוש על ידי הקלדת כמה אותיות מהשם שלו
- בוחרים את ה-API הרצוי.
- הפעלה
מחלצים, מנקים וחוזרים על הפעולה. ב-Cloud Storage יש כמה אפשרויות: בחירה ב-'Google Cloud Storage JSON API'. בנוסף, ב-Cloud Storage API צריך להיות חשבון פעיל לחיוב.
7. שלב 0: מגדירים ייבוא ו קוד הרשאה
זו ההתחלה של קטע קוד בגודל בינוני, לכן אם תקפידו על כמה נוהלים גמישים, תוכלו ליצור תשתית משותפת, יציבה ותקינה לפני שנאלצת להתמודד עם האפליקציה הראשית. ודאו ש-client_secret.json
זמין בספרייה הנוכחית שלכם וגם בהפעלה ipython
ומזינים את קטע הקוד הבא, או שומרים אותו ב-analyze_gsimg.py
ומריצים אותו מהמעטפת (עדיף להשתמש באפשרות השנייה כי נמשיך להוסיף לדוגמת הקוד):
from __future__ import print_function
from googleapiclient import discovery, http
from httplib2 import Http
from oauth2client import file, client, tools
# process credentials for OAuth2 tokens
SCOPES = 'https://www.googleapis.com/auth/drive.readonly'
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
creds = tools.run_flow(flow, store)
# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE = discovery.build('drive', 'v3', http=HTTP)
רכיב הליבה הזה כולל בלוקים של קוד לייבוא של מודולים/חבילות, לעיבוד פרטי כניסה של אימות משתמשים וליצירת נקודות קצה של שירות API. החלקים העיקריים בקוד שצריך לבדוק:
- ייבוא הפונקציה
print()
הופך את הדוגמה ל-Python 2-3 תואמת ל-Python 2-3, והייבוא של ספריית Google כולל את כל הכלים הדרושים לתקשורת עם Google APIs. - המשתנה
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". ואז גוללים חזרה כדי לעיין במסכים הרלוונטיים בקטע "מסביבת פיתוח מקומית" כשיש צורך.
מסביבת פיתוח מקומית
הסקריפט של שורת הפקודה מושהה כשחלון הדפדפן נפתח. יכול להיות שיופיע דף אזהרה מפחיד, שנראה כך:
זהו חשש לגיטימי כי ניסית להפעיל אפליקציה עם גישה לנתוני משתמשים. מכיוון שזו רק אפליקציית הדגמה, ואתם המפתחים, אנחנו מקווים שאתם יכולים לסמוך על עצמכם מספיק כדי להמשיך. כדי להבין זאת טוב יותר, חשוב להיכנס לנעליים של המשתמשים: תתבקשו לאפשר לקוד של מישהו אחר לגשת לנתונים שלכם. אם בכוונתך לפרסם אפליקציה כזו, תבוצע תהליך אימות שיאפשר למשתמשים שלך לראות את המסך הזה.
לאחר הלחיצה על 'מעבר אל 'לא בטוח' app" תופיע תיבת דו-שיח להרשאות OAuth2 שנראית בערך כך: אנחנו תמיד משפרים את ממשק המשתמש שלנו, אז אל תדאגו אם זו לא התאמה מדויקת:
בתיבת הדו-שיח לתהליך OAuth2 מוצגות ההרשאות שהמפתח מבקש (באמצעות המשתנה SCOPES
). במקרה הזה, מדובר באפשרות להציג ולהוריד מ-Google Drive של המשתמש. בקוד האפליקציה, היקפי ההרשאות האלה מופיעים כמזהי URI, אבל הם מתורגמים לשפה שצוינה על ידי הלוקאל של המשתמש. כאן המשתמש חייב להעניק הרשאה מפורשת להרשאות המבוקשות, אחרת תירשם חריג כך שהסקריפט לא ימשיך הלאה.
יכול להיות שתופיע אפילו תיבת דו-שיח אחת נוספת שבה תתבקשו לאשר את הבקשה:
הערה: חלק מהם משתמשים בכמה דפדפני אינטרנט שמחוברים לחשבונות שונים, כך שבקשת ההרשאה הזו עשויה להישלח לכרטיסייה או בחלון שגויים בדפדפן. כתוצאה מכך, ייתכן שיהיה צורך לחתוך ולהדביק את הקישור של הבקשה הזו בדפדפן שמחובר לחשבון הנכון.
מ-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:
מעתיקים את הקוד הזה ומדביקים אותו בחלון הטרמינל.
סיכום
מלבד 'Authentication successful
', לא צפוי פלט נוסף. חשוב לזכור שזו רק ההגדרה... עדיין לא עשית כלום. מה שעשיתם כבר התחיל בהצלחה את התהליך, בדרך להשגת פעולה שיש סיכוי גבוה יותר שהיא תתבצע כמו שצריך בפעם הראשונה. (הכי טוב הוא שהוצג לך בקשה להרשאה רק פעם אחת; כל ההפעלות הבאות מדלגות עליה כי ההרשאות שלך נשמרו במטמון). עכשיו נשנה את הקוד לעשות עבודה אמיתית שמובילה לפלט בפועל.
פתרון בעיות
אם קיבלתם שגיאה במקום שלא קיבלתם פלט, יכול להיות שהדבר נובע מאחת או יותר מהסיבות הבאות:
8. שלב 1: מורידים תמונה מ-Google Drive
בשלב הקודם המלצנו ליצור את הקוד בתור analyze_gsimg.py
ולערוך אותו משם. ניתן גם פשוט לחתוך ולהדביק הכול ישירות ב-iPython או במעטפת Python רגילה, אבל זה דבר מסורבל יותר כי אנחנו נמשיך לפתח את האפליקציה שלב אחרי שלב.
נניח שהאפליקציה שלכם קיבלה הרשאה ונוצרה נקודת קצה (endpoint) של שירות API. בקוד שלכם הוא מיוצג על ידי המשתנה 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
משמש כדי לציין את הערכים המוחזרים שמעניינים אתכם – למה לטרוח להחזיר את הכול ולהאט אם לא חשובים לכם הערכים האחרים? אם זו הפעם הראשונה שאתם משתמשים במסכות שדות לסינון ערכי החזרה של API, עיינו בפוסט הזה בבלוג וידאו. אחרת, מריצים את השאילתה ומוצאים את המאפיין files
שהוחזר, כשברירת המחדל היא מערך רשימה ריק אם אין התאמות.
אם אין תוצאות, המערכת מדלגת על שאר הפונקציה ומוחזרת None
(באופן מרומז). לחלופין, אפשר לשלוף את התגובה התואמת הראשונה (rsp[0]
), להחזיר את שם הקובץ, את סוג ה-MIME שלו, את חותמת הזמן של השינוי האחרון, ולבסוף את המטען הייעודי (payload) הבינארי, שאוחזר על ידי הפונקציה get_media()
(באמצעות מזהה הקובץ), גם באוסף files()
. (שמות השיטות עשויים להיות שונים מעט מאלה של ספריות לקוח אחרות של שפות).
החלק האחרון הוא החלק ה"ראשי" שהפעיל את כל האפליקציה:
if __name__ == '__main__':
# download img file & info from Drive
rsp = drive_get_img(FILE)
if rsp:
fname, mtype, ftime, data = rsp
print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))
else:
print('ERROR: Cannot download %r from Drive' % fname)
בהנחה שתמונה בשם section-work-card-img_2x.jpg
ב-Drive מוגדרת ל-FILE
, לאחר ביצוע מוצלח של הסקריפט אמור להופיע פלט שמאשר שהיא הצליחה לקרוא את הקובץ מ-Drive (אבל לא נשמר במחשב):
$ python3 analyze_gsimg.py Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
פתרון בעיות
אם לא הצלחתם להשיג את התוצאות שצוינו למעלה, יכולות להיות לכך כמה סיבות, למשל:
סיכום
בחלק הזה למדתם איך (ב-2 קריאות נפרדות ל-API) להתחבר ל-Drive API באמצעות שליחת שאילתות לגבי קובץ ספציפי, ולאחר מכן להוריד אותו. תרחיש עסקי לדוגמה: ניתן להעביר את נתוני Drive לארכיון ואז לנתח אותם, למשל באמצעות הכלים של Google Cloud. הקוד של האפליקציה בשלב הזה צריך להתאים לקוד במאגר שבstep1-drive/analyze_gsimg.py
.
אפשר לקרוא מידע נוסף על הורדת קבצים ב-Google Drive כאן או לקרוא את הפוסט בבלוג הזה וידאו. החלק הזה ב-Codelab הוא כמעט זהה לכל המבוא ל-Google Workspace APIs Codelab – במקום להוריד קובץ, הוא מציג את 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 מספק אחסון blob אמורפי. כשמעלים קבצים לקובץ, הוא לא מבין את המושג של סוגי קבצים, סיומות וכו', כמו ב-Google Drive. הם פשוט 'blobs' ל-Cloud Storage. בנוסף, אין רעיון של תיקיות או ספריות משנה ב-Cloud Storage.
כן, אפשר להשתמש בלוכסנים (/
) בשמות הקבצים כדי לייצג את ההפשטה של כמה תיקיות משנה, אבל בסוף היום, כל פריטי ה-blob שלכם יתווספו לקטגוריה, ושמות של '/
' יהיו רק תווים בשמות הקבצים שלהם. תוכלו למצוא מידע נוסף בדף המוסכמות למתן שמות של קטגוריות ואובייקטים.
שלב 1 שלמעלה ביקש היקף לקריאה בלבד ב-Drive. באותו זמן, זה כל מה שצריך. עכשיו נדרשת הרשאת העלאה (קריאה-כתיבה) ל-Cloud Storage. משנים את SCOPES
ממשתנה מסוג מחרוזת יחידה למערך (tuple [או list] של Python) את היקפי ההרשאות כך שייראה כך:
SCOPES = (
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/devstorage.full_control',
)
עכשיו אפשר ליצור ל-Cloud Storage נקודת קצה (endpoint) של שירות, מתחת לנקודת הקצה של 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()
נדרשים שם הקטגוריה, המטא-נתונים של הקובץ וה-blob הבינארי עצמו. כדי לסנן את הערכים המוחזרים, המשתנה fields
מבקש רק את שמות הקטגוריות והאובייקטים שהוחזרו מה-API. למידע נוסף על מסכות השדה האלה בבקשות קריאה ל-API, כדאי לקרוא את הפוסט הזה וידאו.
עכשיו צריך לשלב את השימוש ב-gcs_blob_upload()
באפליקציה הראשית:
# upload file to GCS
gcsname = '%s/%s'% (PARENT, fname)
rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
if rsp:
print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
else:
print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
המשתנה gcsname
ממזג כל 'ספריית משנה ראשית' שמות שמוצמדים לשם הקובץ עצמו, וכשלפניהם שם הקטגוריה, מתקבלת החשיפה להעברה לארכיון של הקובץ ב-'/bucket/parent.../filename
'. מחליקים את המקטע הזה מיד אחרי הפונקציה print()
הראשונה ממש מעל התנאי else
, כך שכל ה-'main' (ראשי) נראה כך:
if __name__ == '__main__':
# download img file & info from Drive
rsp = drive_get_img(FILE)
if rsp:
fname, mtype, ftime, data = rsp
print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))
# upload file to GCS
gcsname = '%s/%s'% (PARENT, fname)
rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
if rsp:
print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
else:
print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
else:
print('ERROR: Cannot download %r from Drive' % fname)
נניח שנציין קטגוריה בשם 'vision-demo
' עם "analyzed_imgs
" כ'ספריית משנה ראשית'. אחרי שמגדירים את המשתנים האלה ומריצים שוב את הסקריפט, תתבצע הורדה של section-work-card-img_2x.jpg
מ-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',
)
עכשיו יוצרים נקודת קצה (endpoint) של שירות ל-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)
עכשיו מוסיפים את הפונקציה הבאה ששולחת את המטען הייעודי (payload) של התמונה ל-Cloud Vision:
def vision_label_img(img, top):
'send image to Vision API for label annotation'
# build image metadata and call Vision API to process
body = {'requests': [{
'image': {'content': img},
'features': [{'type': 'LABEL_DETECTION', 'maxResults': top}],
}]}
rsp = VISION.images().annotate(body=body).execute().get('responses', [{}])[0]
# return top labels for image as CSV for Sheet (row)
if 'labelAnnotations' in rsp:
return ', '.join('(%.2f%%) %s' % (
label['score']*100., label['description']) \
for label in rsp['labelAnnotations'])
כדי להפעיל את הקריאה images().annotate()
צריך את הנתונים ואת תכונות ה-API הרצויות. גם המכסה של 5 התוויות המובילות היא חלק מהמטען הייעודי (Payload) (אבל אופציונלי). אם הקריאה תתבצע בהצלחה, המטען הייעודי (payload) מחזיר את 5 התוויות העליונות של האובייקטים בתוספת ציון סמך שאובייקט נמצא בתמונה. (אם לא תתקבל תשובה, מקצים מילון Python ריק כדי שההצהרה הבאה של if
לא תיכשל). הפונקציה הזו פשוט אוספת את הנתונים האלה למחרוזת CSV כדי לאפשר שימוש סופי בדוח.
צריך למקם את 5 השורות הבאות שקוראות ל-vision_label_img()
מיד אחרי שההעלאה בוצעה ל-Cloud Storage:
# process w/Vision
rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), TOP)
if rsp:
print('Top %d labels from Vision API: %s' % (TOP, rsp))
else:
print('ERROR: Vision API cannot analyze %r' % fname)
במקרה כזה, הנהג הראשי כולו אמור להיראות כך:
if __name__ == '__main__':
# download img file & info from Drive
rsp = drive_get_img(FILE)
if rsp:
fname, mtype, ftime, data = rsp
print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))
# upload file to GCS
gcsname = '%s/%s'% (PARENT, fname)
rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
if rsp:
print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
# process w/Vision
rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), TOP)
if rsp:
print('Top %d labels from Vision API: %s' % (TOP, rsp))
else:
print('ERROR: Vision API cannot analyze %r' % fname)
else:
print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
else:
print('ERROR: Cannot download %r from Drive' % fname)
מחיקה של storage.json
כדי לרענן את היקפי ההרשאות והרצה מחדש של האפליקציה המעודכנת אמורה להניב פלט דומה לפלט הבא, עם התייחסות לניתוח של Cloud Vision:
$ python3 analyze_gsimg.py . . . Authentication successful. Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781) Uploaded 'analyzed_imgs/section-work-card-img_2x.jpg' to GCS bucket 'vision-demo' Top 5 labels from Vision API: (89.94%) Sitting, (86.09%) Interior design, (82.08%) Furniture, (81.52%) Table, (80.85%) Room
סיכום
לא לכל אחד יש מומחיות בלמידת מכונה כדי ליצור ולאמן מודלים של למידת מכונה משלו לנתח את הנתונים שלהם. צוות Google Cloud פרסם חלק מהמודלים שעברו אימון מראש של Google לשימוש כללי, והציב אותם מאחורי ממשקי API, כדי להעניק ל-AI דמוקרטיות למידת מכונה לכולם.
אם אתם מפתחים ויכולים לשלוח קריאה ל-API, אתם יכולים להשתמש בלמידת מכונה. Cloud Vision הוא רק אחד משירותי ה-API שבאמצעותם אפשר לנתח את הנתונים. כאן תוכלו לקבל מידע נוסף על שאר החשבונות. הקוד צריך עכשיו להתאים למה שמופיע במאגר בכתובתstep3-vision/analyze_gsimg.py
.
11. שלב 4: יצירת דוח באמצעות Google Sheets
בשלב הזה יכולתם להעביר לארכיון נתונים ארגוניים ולנתח אותם, אבל חסר סיכום של הפעילות הזו. נארגן את כל התוצאות בדוח אחד שתוכל להעביר לבוס. מה מתאים יותר לניהול מגיליון אלקטרוני?
לא נדרש ייבוא נוסף ל-Google Sheets API, והמידע החדש היחיד שנדרש הוא מזהה הקובץ של גיליון אלקטרוני קיים שכבר מעוצב וממתין לשורת נתונים חדשה – כך הקבוע SHEET
. מומלץ ליצור גיליון אלקטרוני חדש שנראה כך:
כתובת ה-URL של הגיליון האלקטרוני תיראה כך: https://docs.google.com/spreadsheets/d/
FILE_ID
/edit
. קחו את FILE_ID
והקצו אותו כעוקץ ל-SHEET
.
הצטרפנו גם לפונקציה קטנטנה בשם k_ize()
שממירה בייטים לקילובייט (KB), ומגדירה אותה כ-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
את כל 4 השדות הדרושים:
SCOPES = (
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/cloud-vision',
'https://www.googleapis.com/auth/spreadsheets',
)
עכשיו יוצרים נקודת קצה (endpoint) של שירות ל-Google Sheets ליד האחרים, כך שהיא תיראה כך:
# 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()
מחייבת את מזהה הקובץ של Sheets, טווח של תאים, אופן הזנת הנתונים והנתונים עצמם. מזהה הקובץ הוא פשוט, טווח התאים מצוין בסימון A1. טווח של "Sheet1
" הוא כל הגיליון – האותות ל-API מצרפים את השורה אחרי כל הנתונים בגיליון. יש שתי אפשרויות: איך מוסיפים את הנתונים לגיליון – 'RAW
' (צריך להזין את נתוני המחרוזת מילה במילה) או "USER_ENTERED
" (כתבו את הנתונים כאילו המשתמש הזין אותם במקלדת באמצעות אפליקציית Google Sheets, תוך שמירה על תכונות עיצוב התאים).
אם הקריאה מצליחה, לערך המוחזר אין שום דבר שימושי במיוחד, לכן בחרנו לעדכן את מספר התאים המעודכנים על ידי בקשת ה-API. בהמשך מופיע הקוד שקורא לפונקציה:
# push results to Sheet, get cells-saved count
fsize = k_ize(len(data))
row = [PARENT,
'=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
BUCKET, gcsname, fname), mtype, ftime, fsize, rsp
]
rsp = sheet_append_row(SHEET, row)
if rsp:
print('Updated %d cells in Google Sheet' % rsp)
else:
print('ERROR: Cannot write row to Google Sheets')
בגיליון האלקטרוני ב-Google Sheets יש עמודות שמייצגות נתונים, כמו כל 'ספריית משנה' הורה, המיקום של הקובץ שהועבר לארכיון ב-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 Sheets. השורה האחרונה (שורה 7 בדוגמה שלמטה) נוספה למערך הנתונים הקיים שנוספה קודם:
סיכום
ב-3 השלבים הראשונים במדריך הזה התחברתם לממשקי ה-API של Google Workspace ושל Google Cloud כדי להעביר נתונים ולנתח אותם – 80% מכלל העבודה. עם זאת, בסופו של דבר אין לכך כל משמעות, אם לא תהיה לך אפשרות להציג להנהלה את כל מה שהשגת. כדי להמחיש את התוצאות בצורה טובה יותר, סיכום כל התוצאות בדוח שנוצר מייצג את כמות הנתונים הרצויה.
כדי לשפר עוד יותר את התועלת של הניתוח, בנוסף לכתיבת התוצאות בגיליון אלקטרוני, שיפור אפשרי הוא הוספה לאינדקס של 5 התוויות המובילות האלה לכל תמונה, כך שניתן יהיה לבנות מסד נתונים פנימי שיאפשר לעובדים מורשים לשלוח שאילתות על תמונות לפי צוות החיפוש, אבל נשאיר את זה בשם תרגיל לקוראים.
בינתיים, התוצאות שלנו מוצגות בגיליון אלקטרוני ואפשר לנהל אותן. הקוד של האפליקציה בשלב הזה צריך להתאים לקוד במאגר שבstep4-sheets/analyze_gsimg.py
. השלב האחרון הוא למחוק את הקוד ולהפוך אותו לסקריפט שאפשר להשתמש בו.
12. *השלב האחרון: ארגון מחדש
(אופציונלי) כדאי להשתמש באפליקציה פעילה, אבל אפשר לשפר אותה? כן, במיוחד האפליקציה הראשית שנראית מבולגנת. נשתמש בפונקציה הזו בפונקציה משלה כדי לאפשר קלט של משתמשים במקום קבועים קבועים. נעשה זאת באמצעות המודול argparse
. בנוסף, נשיק כרטיסייה בדפדפן אינטרנט שבה יוצג הגיליון לאחר שנכתב בו את שורת הנתונים. אפשר לעשות זאת באמצעות המודול 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 ומזהי קבצים של גיליונות אלקטרוניים (Sheets). בעקבות העדכונים האחרונים האלה, הגרסה הסופית של הקוד אמורה עכשיו להתאים במלואה למאגר שבמאגר final/analyze_gsimg.py
וגם כאן:
'''
analyze_gsimg.py - analyze Google Workspace image processing workflow
Download image from Google Drive, archive to Google Cloud Storage, send
to Google Cloud Vision for processing, add results row to Google Sheet.
'''
from __future__ import print_function
import argparse
import base64
import io
import webbrowser
from googleapiclient import discovery, http
from httplib2 import Http
from oauth2client import file, client, tools
k_ize = lambda b: '%6.2fK' % (b/1000.) # bytes to kBs
FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = '' # YOUR IMG FILE PREFIX
SHEET = 'YOUR_SHEET_ID'
TOP = 5 # TOP # of VISION LABELS TO SAVE
DEBUG = False
# process credentials for OAuth2 tokens
SCOPES = (
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/cloud-vision',
'https://www.googleapis.com/auth/spreadsheets',
)
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
creds = tools.run_flow(flow, store)
# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE = discovery.build('drive', 'v3', http=HTTP)
GCS = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision', 'v1', http=HTTP)
SHEETS = discovery.build('sheets', 'v4', http=HTTP)
def drive_get_img(fname):
'download file from Drive and return file info & binary if found'
# search for file on Google Drive
rsp = DRIVE.files().list(q="name='%s'" % fname,
fields='files(id,name,mimeType,modifiedTime)'
).execute().get('files', [])
# download binary & return file info if found, else return None
if rsp:
target = rsp[0] # use first matching file
fileId = target['id']
fname = target['name']
mtype = target['mimeType']
binary = DRIVE.files().get_media(fileId=fileId).execute()
return fname, mtype, target['modifiedTime'], binary
def gcs_blob_upload(fname, bucket, media, mimetype):
'upload an object to a Google Cloud Storage bucket'
# build blob metadata and upload via GCS API
body = {'name': fname, 'uploadType': 'multipart', 'contentType': mimetype}
return GCS.objects().insert(bucket=bucket, body=body,
media_body=http.MediaIoBaseUpload(io.BytesIO(media), mimetype),
fields='bucket,name').execute()
def vision_label_img(img, top):
'send image to Vision API for label annotation'
# build image metadata and call Vision API to process
body = {'requests': [{
'image': {'content': img},
'features': [{'type': 'LABEL_DETECTION', 'maxResults': top}],
}]}
rsp = VISION.images().annotate(body=body).execute().get('responses', [{}])[0]
# return top labels for image as CSV for Sheet (row)
if 'labelAnnotations' in rsp:
return ', '.join('(%.2f%%) %s' % (
label['score']*100., label['description']) \
for label in rsp['labelAnnotations'])
def sheet_append_row(sheet, row):
'append row to a Google Sheet, return #cells added'
# call Sheets API to write row to Sheet (via its ID)
rsp = SHEETS.spreadsheets().values().append(
spreadsheetId=sheet, range='Sheet1',
valueInputOption='USER_ENTERED', body={'values': [row]}
).execute()
if rsp:
return rsp.get('updates').get('updatedCells')
def main(fname, bucket, sheet_id, folder, top, debug):
'"main()" drives process from image download through report generation'
# download img file & info from Drive
rsp = drive_get_img(fname)
if not rsp:
return
fname, mtype, ftime, data = rsp
if debug:
print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))
# upload file to GCS
gcsname = '%s/%s'% (folder, fname)
rsp = gcs_blob_upload(gcsname, bucket, data, mtype)
if not rsp:
return
if debug:
print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
# process w/Vision
rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), top)
if not rsp:
return
if debug:
print('Top %d labels from Vision API: %s' % (top, rsp))
# push results to Sheet, get cells-saved count
fsize = k_ize(len(data))
row = [folder,
'=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
bucket, gcsname, fname), mtype, ftime, fsize, rsp
]
rsp = sheet_append_row(sheet_id, row)
if not rsp:
return
if debug:
print('Added %d cells to Google Sheet' % rsp)
return True
if __name__ == '__main__':
# args: [-hv] [-i imgfile] [-b bucket] [-f folder] [-s Sheet ID] [-t top labels]
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--imgfile", action="store_true",
default=FILE, help="image file filename")
parser.add_argument("-b", "--bucket_id", action="store_true",
default=BUCKET, help="Google Cloud Storage bucket name")
parser.add_argument("-f", "--folder", action="store_true",
default=PARENT, help="Google Cloud Storage image folder")
parser.add_argument("-s", "--sheet_id", action="store_true",
default=SHEET, help="Google Sheet Drive file ID (44-char str)")
parser.add_argument("-t", "--viz_top", action="store_true",
default=TOP, help="return top N (default %d) Vision API labels" % TOP)
parser.add_argument("-v", "--verbose", action="store_true",
default=DEBUG, help="verbose display output")
args = parser.parse_args()
print('Processing file %r... please wait' % args.imgfile)
rsp = main(args.imgfile, args.bucket_id,
args.sheet_id, args.folder, args.viz_top, args.verbose)
if rsp:
sheet_url = 'https://docs.google.com/spreadsheets/d/%s/edit' % args.sheet_id
print('DONE: opening web browser to it, or see %s' % sheet_url)
webbrowser.open(sheet_url, new=1, autoraise=True)
else:
print('ERROR: could not process %r' % args.imgfile)
נעשה כל ניסיון לשמור על עדכניות התוכן של המדריך הזה, אבל יהיו מקרים שבהם במאגר תהיה הגרסה העדכנית ביותר של הקוד.
13. מעולה!
הייתה בהחלט הרבה למידה ב-Codelab הזה, והצלחתם להשיג את זה, גם אחרי ששרדתם את אחת משיעורי ה-Codelabs הארוכים יותר. כתוצאה מכך, התמודדתם עם תרחיש ארגוני אפשרי שכולל כ-130 שורות של Python, תוך שימוש בכל Google Cloud ו-Google Workspace והעברת נתונים ביניהן כדי לפתח פתרון עבודה. אפשר לעיין במאגר הקוד הפתוח שמיועד לכל הגרסאות של האפליקציה הזו (מידע נוסף מופיע בהמשך).
הסרת המשאבים
- השימוש ב-Google Cloud APIs לא כרוך בתשלום, כל עוד Google Workspace APIs מכוסה בדמי המינוי החודשיים ל-Google Workspace (למשתמשי Gmail פרטיים יש תשלום חודשי של אפס). לכן אין צורך בניקוי או בהסרה של ממשקי API עבור משתמשי Google Workspace. ב-Google Cloud, אפשר להיכנס למרכז הבקרה של מסוף Cloud ולבדוק את כרטיס 'חיוב'. לחיובים משוערים.
- ב-Cloud Vision, אתם יכולים לקבל מספר קבוע של קריאות ל-API בחודש בחינם. כל עוד לא חורגים מהמגבלות, אין צורך להשבית שום דבר ולא להשבית או למחוק את הפרויקט. מידע נוסף על החיוב והמכסה בחינם ב-Vision API זמין בדף התמחור.
- חלק ממשתמשי Cloud Storage מקבלים נפח אחסון בחינם בחודש. אם התמונות שיועברו לארכיון באמצעות ה-Codelab הזה לא יגרמו לחריגה מהמכסה הזו, לא תצברו חיובים. מידע נוסף על חיובים ומכסות בחינם ב-GCS זמין בדף התמחור. אפשר להציג ולמחוק blobs בקלות בדפדפן של Cloud Storage.
- יכול להיות שלמשתמשים שלכם ב-Google Drive יש גם מכסת אחסון. אם תחרגו ממנה (או אם תחרגו ממנו), כדאי לשקול להשתמש בכלי שיצרתם ב-Codelab הזה כדי להעביר את התמונות האלה לארכיון ל-Cloud Storage כדי לפנות מקום ב-Drive. מידע נוסף על נפח האחסון ב-Google Drive מופיע בדף התמחור המתאים למשתמשי Google Workspace Basic או למשתמשי Gmail/consumer.
ברוב התוכניות העסקיות וה-Enterprise של Google Workspace יש נפח אחסון ללא הגבלה, אבל התיקיות ב-Drive עשויות להיות עמוסות ו/או מסובכות. האפליקציה שיצרתם במדריך הזה היא דרך מצוינת להעביר לארכיון קבצים מיותרים ולנקות את Google Drive.
גרסאות חלופיות
אבל final/analyze_gsimg.py
הוא "האחרון" בגרסה הרשמית שעליה אתם עובדים במדריך הזה, זה לא סוף הסיפור. אחת הבעיות בגרסה הסופית של האפליקציה היא שנעשה בה שימוש בספריות האימות הישנות יותר שהוצאו משימוש. בחרנו בנתיב הזה כי ספריות האימות החדשות יותר לא תמכו בכמה אלמנטים מרכזיים: ניהול אחסון של אסימוני OAuth ובטיחות שרשורים.
ספריות אימות נוכחיות (חדשות יותר)
עם זאת, בשלב מסוים לא תהיה יותר תמיכה בספריות האימות הישנות, לכן מומלץ לבדוק גרסאות שמשתמשות בספריות האימות (הנוכחיות) החדשות יותר בתיקייה alt
של המאגר, גם אם הן לא מתאימות ל-threads (אבל אפשר ליצור פתרון משלך). מחפשים קבצים שהשם שלהם כולל את *newauth*
.
ספריות הלקוח של המוצרים ב-Google Cloud
ההמלצה של Google Cloud לכל המפתחים היא להשתמש בספריות הלקוח של המוצרים כשהם משתמשים בממשקי Google Cloud API. לצערנו, לממשקי API שאינם של Google Cloud אין כרגע ספריות כאלה. שימוש בספריות ברמה נמוכה יותר מאפשר שימוש עקבי ב-API ושימוש בתכונות קריאות טובות יותר. בדומה להמלצה שלמעלה, גרסאות חלופיות שמתבססות על ספריות לקוח של מוצרי Google Cloud זמינות לעיון בתיקייה alt
של המאגר. מחפשים קבצים שהשם שלהם כולל את *-gcp*
.
הרשאה באמצעות חשבון שירות
כשעובדים בענן בלבד, בדרך כלל אין מידע אנושי או נתונים בבעלות המשתמש (לבני אדם), ולכן אנחנו משתמשים בחשבונות שירות ובהרשאה באמצעות חשבון שירות בעיקר ב-Google Cloud. עם זאת, בדרך כלל מסמכי Google Workspace הם בבעלות משתמשים (בני אדם), ולכן המדריך הזה משתמש בהרשאה באמצעות חשבון משתמש. זה לא אומר שאי אפשר להשתמש בממשקי Google Workspace API עם חשבונות שירות. כל עוד לחשבונות האלה יש רמת גישה מתאימה, אפשר בהחלט להשתמש בהם באפליקציות. בדומה למה שמתואר למעלה, גרסאות חלופיות שמתבססות על הרשאה באמצעות חשבון שירות זמינות בתיקייה alt
של המאגר לעיונך. מחפשים קבצים שהשם שלהם כולל את *-svc*
.
קטלוג גרסאות חלופיות
בהמשך מוצגות כל הגרסאות החלופיות של final/analyze_gsimg.py
. לכל גרסה יש לפחות אחד מהנכסים שמפורטים למעלה. בכל שם קובץ של גרסה, מחפשים את הפרטים הבאים:
oldauth
לגרסאות שמשתמשות בספריות האימות הישנות (בנוסף ל-final/analyze_gsimg.py
)newauth
למשתמשים שמשתמשים בספריות האימות הנוכחיות/החדשות יותרgcp
למשתמשים שמשתמשים בספריות לקוח של מוצרי Google Cloud, כמו google-cloud-storage וכו'.svc
למשתמשים שמשתמשים בהרשאה של חשבון שירות ('חשבון svc') במקום בחשבון משתמש
אלה כל הגרסאות:
שם קובץ | תיאור |
| המדגם הראשי; משתמש בספריות האימות הישנות יותר |
| זהה למשתמש |
| כמו |
| כמו |
| כמו |
| כמו |
| כמו |
| זהה למשתמש |
בשילוב עם הפתרון final/analyze_gsimg.py
המקורי , תוכלו ליהנות מכל השילובים האפשריים של הפתרון הסופי, ללא קשר לסביבת הפיתוח של Google API, ותוכלו לבחור את זה שהכי מתאים לצרכים שלכם. אפשר למצוא הסבר דומה גם ב-alt/README.md
.
מחקר נוסף
בהמשך מופיעות כמה רעיונות שיעזרו לכם להמשיך את התרגיל צעד אחד או שניים. ניתן להרחיב את הבעיה להגדיר שהפתרון הנוכחי יכול לטפל בה, וכך תוכלו לבצע את השיפורים הבאים:
- (מספר תמונות בתיקיות) במקום לעבד תמונה אחת, נניח שיש לכם תמונות בתיקיות ב-Google Drive.
- (מספר תמונות בקובצי ZIP) במקום תיקייה של תמונות, מה לגבי ארכיוני ZIP שמכילים קובצי תמונה? אם אתם משתמשים ב-Python, מומלץ להשתמש במודול
zipfile
. - (ניתוח תוויות חזותיות) ניתן לקבץ יחד תמונות דומות, אולי כדאי להתחיל בחיפוש של התוויות הנפוצות ביותר, לאחר מכן התווית השנייה הנפוצה ביותר וכן הלאה.
- (יצירת תרשימים) מעקב מס' 3, יצירת תרשימים באמצעות Sheets API על סמך הניתוח והסיווג של Vision API
- (סיווג מסמכים) במקום לנתח תמונות באמצעות Cloud Vision API, נניח שיש לכם קובצי PDF לסווג באמצעות Cloud Natural Language API. בעזרת הפתרונות שלמעלה, קובצי ה-PDF האלה יכולים להיות בתיקיות Drive או בארכיוני ZIP ב-Drive.
- (ליצור מצגות) משתמשים ב-API של Slides כדי ליצור מצגת מכירות מהתוכן של הדוח ב-Google Sheets. לקבלת השראה, מומלץ לקרוא את הפוסט הזה בבלוג סרטון על יצירת שקפים מנתונים של גיליון אלקטרוני.
- (ייצוא כקובץ PDF) מייצאים את הגיליון האלקטרוני ו/או המצגת כ-PDF, אבל האפשרות הזו לא קיימת בממשקי ה-API של Sheets או של Slides. רמז: Google Drive API. קרדיט נוסף: ממזגים את קובצי ה-PDF של Sheets ו-Slides לקובץ PDF ראשי אחד באמצעות כלים כמו Ghostscript (Linux, Windows) או
Combine PDF Pages.action
(Mac OS X).
מידע נוסף
Codelabs
- מבוא לממשקי ה-API של Google Workspace (Google Drive API) (Python)
- שימוש ב-Cloud Vision עם Python (Python)
- יצירת כלי דיווח בהתאמה אישית (Google Sheets API) (JS/Node)
- העלאת אובייקטים ל-Google Cloud Storage (ללא צורך בכתיבת קוד)
כללי
Google Workspace
- דף הבית של Google Drive API
- דף הבית של Google Sheets API
- סקירה כללית למפתחים ב-Google Workspace תיעוד
Google Cloud
- דף הבית של Google Cloud Storage
- דף הבית של Google Cloud Vision הדגמה (דמו) בזמן אמת
- מאמרי העזרה של Cloud Vision API
- מסמכים בנושא תוויות תמונה ב-Vision API
- Python ב-Google Cloud
- ספריות הלקוח של מוצרי Google Cloud
- משאבי עזרה ל-Google Cloud
רישיון
היצירה הזו בשימוש ברישיון Creative Commons Attribution 2.0 גנרי.