ממשק קצה להתקשרות של ממשק API של Call Vision ב-Android

1. לפני שמתחילים

bd8c01b2f8013c6d.png

ראית את ההדגמה של Google Lens, איפה אפשר לכוון את מצלמת הטלפון לאובייקט ולמצוא איפה אפשר לקנות אותה באינטרנט? אם אתם רוצים ללמוד איך להוסיף את אותה תכונה לאפליקציה שלכם, מעבדת הקוד הזו תתאים לכם. זהו חלק מנתיב לימוד שמלמד איך ליצור תכונת חיפוש תמונות של מוצרים באפליקציה לנייד.

במעבד הקוד הזה, תלמדו איך לקרוא לקצה העורפי שנוצר באמצעות Vision API לחיפוש מוצרים מאפליקציה לנייד. הקצה העורפי הזה יכול לצלם תמונת שאילתה ולחפש מוצרים דומים מבחינה חזותית מקטלוג מוצרים.

במסלול הלימוד אפשר למצוא מידע נוסף על השלבים הנותרים של יצירת תכונה של חיפוש מוצרים ויזואלי, כולל איך להשתמש בזיהוי אובייקטים של ML ערכת ומעקב אחר פריטים, ולאפשר למשתמשים לבחור את המוצר שהם רוצים לחפש.

מה תיצור

  • במעבדה זו, אתם מתחילים באפליקציית Android לזיהוי אובייקטים מתמונת קלט. יש לכתוב קוד כדי לקחת את האובייקט שהמשתמש בוחר, לשלוח אותו לקצה העורפי של חיפוש המוצרים ולהציג את תוצאת החיפוש במסך.
  • בסופו של דבר, אמור להופיע משהו דומה לתמונה שמשמאל.

מה תלמדו

  • איך להתקשר ולנתח את ה-API של חיפוש המוצרים של Vision API מאפליקציה ל-Android

מה צריך?

  • גרסה עדכנית של Android Studio (גרסה 4.1.2 ומעלה)
  • אמולטור Android Studio או מכשיר Android פיזי
  • הקוד לדוגמה
  • ידע בסיסי על פיתוח Android בקוטלין

שיעור Lab זה מתמקד ב-Vision API של חיפוש מוצרים. קונספטים ובלוקים של קוד שאינם רלוונטיים לא נבדקים, והם ניתנים להעתקה ולהדבקה בלבד.

2. מידע על Vision Product Search

Vision API של חיפוש מוצרים הוא תכונה ב-Google Cloud שמאפשרת למשתמשים לחפש מוצרים דומים מבחינה חזותית מקטלוג מוצרים. קמעונאים יכולים ליצור מוצרים, שכל אחד מהם מכיל תמונות עזר שמתארות את המוצר בצורה חזותית מתוך נקודות מבט. לאחר מכן אפשר להוסיף את המוצרים האלה לקבוצות מוצרים (כלומר, קטלוג מוצרים). בשלב זה, חיפוש המוצרים של Vision API תומך בקטגוריות המוצרים הבאות: מוצרי בית, ביגוד, צעצועים, מוצרים ארוזים וכלל.

כשמשתמשים מבצעים שאילתה על קבוצת מוצרים עם תמונות משלהם, ממשק ה-API של חיפוש המוצרים שלVision מחיל למידה חישובית כדי להשוות את המוצר בתמונת השאילתה של המשתמש לבין התמונות בקבוצת המוצרים של הקמעונאי. לאחר מכן הוא מחזיר רשימה מדורגת של תוצאות דומות מבחינה סמנטית.

3. הורדה והפעלה של האפליקציה למתחילים

להורדת הקוד

כדי להוריד את כל הקוד של Lablab זה, צריך ללחוץ על הקישור הבא:

פותחים את הקובץ הדחוס. פעולה זו תשחרר תיקיית בסיס (odml-pathways-main) עם כל המשאבים הדרושים לך. עבור קוד Lab זה תצטרכו את המקורות רק בספריית המשנה product-search/codelab2/android.

ספריית המשנה codelab2 במאגר odml-pathways מכילה שתי ספריות:

  • android_studio_folder.pngהתחלה — קוד בסיס שעליו תבססו על מעבדת קוד זו.
  • android_studio_folder.pngסופי – הושלם הקוד לאפליקציה לדוגמה שהושלמה.

האפליקציה למתחילים כאן היא זו שיצרתם בזיהוי אובייקטים בתמונות כדי ליצור חיפוש מוצרים ויזואלי: Android. היא משתמשת בזיהוי אובייקטים ובמעקב אחר אובייקטים של ML כדי לזהות אובייקטים מתמונה ולהציג אותם במסך.

ייבוא האפליקציה ל-Android Studio

בשלב הראשון, מייבאים את האפליקציה Starter אל Android Studio.

נכנסים ל-Android Studio, בוחרים באפשרות ייבוא פרויקט (גראדל, Eclipse ADT וכו') ובוחרים את התיקייה starter בקוד המקור שהורדתם בעבר.

7c0f27882a2698ac.png

הפעלת האפליקציה למתחילים

עכשיו, אחרי שייבאתם את הפרויקט ל-Android Studio, אתם מוכנים להריץ את האפליקציה בפעם הראשונה. מחברים את מכשיר ה-Android באמצעות USB למארח או מתחילים את האמולטור של Android Studio,ולוחצים על הפעלה ( exe.png) בסרגל הכלים של Android Studio.

(אם הלחצן הזה מושבת, יש להקפיד לייבא רק את הסימן Starter/app/build.gradle, ולא את כל המאגר).

עכשיו האפליקציה אמורה לפעול במכשיר Android שלכם. התכונה כבר כוללת את היכולת לזיהוי אובייקטים: מזהה פריטי אופנה מהתמונה ומציגה לך את מיקומם. יש לנסות להשתמש בתמונות שהוגדרו מראש כדי לאשר.

c6102a808fdfcb11.png

צילום מסך של האפליקציה למתחילים שיכול לזהות אובייקטים בתמונה

בשלב הבא, תרחיבו את האפליקציה כדי לשלוח את האובייקטים שזוהו לקצה העורפי של Product API לחיפוש מוצרים, ותציג את תוצאות החיפוש במסך.

4. ניהול בחירת אובייקט

משתמשים יכולים להקיש על אובייקט שזוהה כדי לבחור אותו

עכשיו צריך להוסיף קוד כדי לאפשר למשתמשים לבחור אובייקט מהתמונה ולהתחיל את חיפוש המוצר. האפליקציה למתחילים כבר יכולה לזהות אובייקטים בתמונה. ייתכן שיש כמה אובייקטים בתמונה או שהאובייקט שזוהה מכיל רק חלק קטן מהתמונה. לכן, צריך לבקש מהמשתמש להקיש על אחד מהאובייקטים שזוהו כדי לציין את האובייקט שבו הוא רוצה להשתמש לחיפוש מוצרים.

9cdfcead6d95a87.png

צילום מסך של פריטי האופנה שזוהו מהתמונה

כדי לקודד את הקוד באופן פשוט ולהתמקד בלמידה חישובית, חלק מהקודים של מכשירי Android מיושמים באפליקציה למתחילים, כדי לעזור לכם לזהות על איזה אובייקט המשתמש לחץ. התצוגה שמציגה את התמונה בפעילות הראשית (ObjectDetectorActivity) היא למעשה תצוגה מותאמת אישית (ImageClickableView) שמרחיבה את ברירת המחדל של ImageView ב-Android OS. היא מיישמת כמה שיטות שירות נוחות, כולל:

  • fun setOnObjectClickListener(listener: ((objectImage: Bitmap) -> Unit)) זוהי קריאה חוזרת (callback) לקבלת התמונה החתוכה שמכילה רק את האובייקט שעליו המשתמש הקש. התמונה החתוכה תישלח לקצה העורפי של חיפוש המוצרים.

צריך להוסיף קוד כדי לטפל כשהמשתמש מקיש על האובייקטים שזוהו.

עוברים לשיטה initViews בכיתה ObjectDetectorActivity ומוסיפים את השורות הבאות בסוף השיטה: (Android Studio יציין שלא ניתן למצוא את השיטה startProductImageSearch . אל דאגה, תוכלו להטמיע אותו מאוחר יותר.)

// Callback received when the user taps on any of the detected objects.
ivPreview.setOnObjectClickListener { objectImage ->
    startProductImageSearch(objectImage)
}

מתבצעת קריאה ל-onObjectClickListener בכל פעם שהמשתמש מקיש על אחד מהאובייקטים שזוהו במסך. היא מקבלת את התמונה החתוכה שמכילה רק את האובייקט שנבחר. לדוגמה: אם המשתמש מקיש על האדם שלובשת את השמלה בצד ימין, ההאזנה תופעל עם objectImage למטה.

9cac8458d0f326e6.png

דוגמה לתמונה שנחתכת הועברה ל-onObjectClickListener

שליחת התמונה החתוכה לפעילות החיפוש של מוצרים

עכשיו עליך ליישם את הלוגיקה של שליחת תמונת השאילתה לקצה העורפי של Product Search Search בפעילות מופרדת (ProductSearchActivity).

כל רכיבי ממשק המשתמש הוטמעו מראש, כדי שתוכלו להתמקד בכתיבת הקוד ליצירת קשר עם הקצה העורפי של חיפוש המוצרים.

25939f5a13eeb3c3.png

צילום מסך של רכיבי ממשק המשתמש ב-ProductSearchActivity

יש להוסיף קוד כדי לשלוח את תמונת האובייקט שהמשתמש בחר אל ProductSearchActivity.

יש לחזור ל-Android Studio ולהוסיף את השיטה startProductImageSearch הזו לכיתה ObjectDetectorActivity:

private fun startProductImageSearch(objectImage: Bitmap) {
    try {
        // Create file based Bitmap. We use PNG to preserve the image quality
        val savedFile = createImageFile(ProductSearchActivity.CROPPED_IMAGE_FILE_NAME)
        objectImage.compress(Bitmap.CompressFormat.PNG, 100, FileOutputStream(savedFile))

        // Start the product search activity (using Vision Product Search API.).
        startActivity(
            Intent(
                    this,
                    ProductSearchActivity::class.java
            ).apply {
                // As the size limit of a bundle is 1MB, we need to save the bitmap to a file
                // and reload it in the other activity to support large query images.
                putExtra(
                    ProductSearchActivity.REQUEST_TARGET_IMAGE_PATH,
                    savedFile.absolutePath
                )
            })
    } catch (e: Exception) {
        // IO Exception, Out Of memory ....
        Toast.makeText(this, e.message, Toast.LENGTH_SHORT).show()
        Log.e(TAG, "Error starting the product image search activity.", e)
    }
}

קטע הקוד מבצע 3 פעולות:

  • לוקחת את התמונה שנחתכה וסדרת אותה לקובץ PNG.
  • מפעיל את ProductSearchActivity כדי להפעיל את רצף חיפוש המוצרים.
  • כולל URI של התמונה החתוכה בכוונת הפעילות, כדי שProductSearchActivity יוכל לאחזר אותה מאוחר יותר לשימוש כתמונת שאילתה.

יש כמה נקודות שכדאי לזכור:

  • הלוגיקה לזיהוי אובייקטים ושליחת שאילתות בקצה העורפי פוצלה לשתי פעילויות רק כדי שיהיה קל יותר להבין את הקוד. אתם מחליטים איך ליישם אותם באפליקציה שלכם.
  • יש לכתוב את תמונת השאילתה בקובץ ולהעביר את ה-URI של התמונה בין פעילויות, כי תמונת השאילתה יכולה להיות גדולה ממגבלת הגודל של 1MB של כוונת Android.
  • אפשר לשמור את תמונת השאילתה בפורמט PNG מכיוון שהיא בפורמט ללא אובדן.

אחזור של תמונת השאילתה בפעילות החיפוש של המוצר

ב-ProductSearchActivity, הקוד לאחזור תמונת השאילתה והצגתו במסך כבר יושם באפליקציה למתחילים.

יש לעבור לשיטה onCreate ולוודא שהקוד הזה כבר קיים:

// Receive the query image and show it on the screen
intent.getStringExtra(REQUEST_TARGET_IMAGE_PATH)?.let { absolutePath ->
    viewBinding.ivQueryImage.setImageBitmap(BitmapFactory.decodeFile(absolutePath))
}

הפעלת האפליקציה

עכשיו לוחצים על הפעלה ( exe.png) בסרגל הכלים של Android Studio.

אחרי שהאפליקציה נטענת, מקישים על אחת מהתמונות שהוגדרו מראש ובוחרים באחד מהאובייקטים שזוהו.

מוודאים שהשדה ProductSearchActivity מופיע עם התמונה שעליה הקשתם. הלחצן חיפוש עדיין לא עושה דבר, אבל ניישם אותו בשלב הבא.

fed40f81b8b43801.png

המסך אמור להופיע לאחר הקשה על אחד מהאובייקטים שזוהו.

5. קצה עורפי בחיפוש המוצרים

יצירה של הקצה העורפי לחיפוש תמונות של מוצרים

ב-codelab זה נדרש קצה עורפי לחיפוש מוצרים שנבנה עם Vision API של חיפוש מוצרים. ניתן לעשות זאת בשתי דרכים:

אפשרות 1: שימוש בקצה העורפי שלהדמיה

אתם יכולים להמשיך בשיעור הקוד הזה באמצעות הקצה העורפי לחיפוש מוצרים ש-Google כבר פרסה עבורכם. ניתן לשכפל את הקצה העורפי של ההדגמה על ידי ביצוע האתחול המהיר של חיפוש מוצרים ב-Vision API.

אפשרות 2: יצירת קצה עורפי על ידי ביצוע ההתחלה המהירה של חיפוש המוצרים של Vision API

האפשרות הזו מומלצת למי שמעוניין ללמוד לעומק איך ליצור קצה עורפי בחיפוש מוצרים, כדי שתוכלו לבנות אותו בעצמכם עבור קטלוג המוצרים. אתם צריכים:

  • חשבון ב-Google Cloud שבו החיוב מופעל. (זה יכול להיות חשבון של תקופת ניסיון בחינם).
  • ידע מסוים בקונספטים של Google Cloud, כולל פרויקטים, חשבונות שירות וכו'.

אפשר למצוא מידע נוסף על כך במסלול הלימוד.

העקרונות החשובים

הרעיון הבא מתקיים במהלך אינטראקציה עם קצה עורפי בחיפוש מוצרים:

  • קבוצת מוצרים: קבוצת מוצרים היא מאגר פשוט של קבוצת מוצרים. קטלוג מוצרים יכול להיות מיוצג כקבוצת מוצרים ובמוצרים שלה.
  • מוצר: אחרי שיוצרים קבוצת מוצרים, אפשר ליצור אותם ולהוסיף אותם לקבוצת המוצרים.
  • תמונות עזר: אלה תמונות שמכילות תצוגות שונות של המוצרים. תמונות עזר משמשות לחיפוש מוצרים דומים מבחינה חזותית.
  • חיפוש מוצרים: אחרי שיוצרים את קבוצת המוצרים ומוסיפים את קבוצת המוצרים לאינדקס, אפשר להריץ שאילתות על קבוצת המוצרים באמצעות ה-Cloud Vision API.

הסבר על קטלוג המוצרים המוגדר מראש

הקצה העורפי של חיפוש המוצרים המשמש ב-codelab זה נוצר באמצעות Vision API לחיפוש מוצרים וקטלוג מוצרים של כמאה נעליים ותמונות של שמלות. הנה כמה תמונות מהקטלוג:

4f1a8507b74ab178.png 79a5fc6c829eca77.png 3528c872f813826e.png

דוגמאות מקטלוג המוצרים המוגדר מראש

קריאה לקצה העורפי של הדגמה של חיפוש המוצרים

אתם יכולים לקרוא ל-Vision API של חיפוש מוצרים ישירות מאפליקציה לנייד, על ידי הגדרת מפתח של Google Cloud API והגבלת הגישה למפתח ה-API לאפליקציה שלכם בלבד.

כדי לפשט את השימוש ב-codelab הזה, הוגדרה נקודת קצה שמאפשרת לך לגשת לקצה העורפי של ההדגמה בלי לדאוג למפתח ולאימות של ה-API. היא מקבלת את בקשת ה-HTTP מהאפליקציה לנייד, מצרפת את מפתח ה-API ומעבירה את הבקשה לקצה העורפי של Vision API לחיפוש מוצרים. לאחר מכן, שרת ה-proxy מקבל את התגובה מהקצה העורפי ומחזיר אותו לאפליקציה לנייד.

במעבדת קוד זו תשתמשו בשני ממשקי API של חיפוש מוצרים של Vision API:

  • projects.locations.images.annotate: שליחת תמונת השאילתה לשרת וקבלת רשימה של מוצרים מקטלוג מוצרים מוגדר מראש שדומה לתמונה של השאילתה.
  • projects.locations.products.referenceImage.get: המערכת מקבלת את ה-URI של התמונות של המוצרים שהוחזרו בקריאת ה-API שלמעלה כדי להציג אותן למשתמשים.

6. הטמעה של לקוח ה-API

הסבר על תהליך העבודה של חיפוש מוצרים

תהליך העבודה הזה מאפשר לבצע חיפוש מוצרים באמצעות הקצה העורפי:

  • קידוד של תמונת השאילתה כמחרוזת base64
  • יש להתקשר אל נקודת הקצה projects.locations.images.annotate עם תמונת השאילתה
  • יש לקבל את מזהי תמונות המוצר מקריאת ה-API הקודמת ולשלוח אותם לנקודות הקצה projects.locations.products.referenceImage.get כדי לקבל את ה-URI של תמונות המוצרים בתוצאת החיפוש.

הטמעה של מחלקת לקוחות של ה-API

עכשיו צריך להטמיע את הקוד כדי להתקשר לקצה העורפי של חיפוש מוצרים בכיתה ייעודית שנקראת ProductSearchAPIClient. חלק מהקודים של כללים סטנדרטיים נוספו לאפליקציה למתחילים:

  • class ProductSearchAPIClient: הכיתה הזו ריקה ברובה, אבל יש בה כמה שיטות להטמעה בשלב מאוחר יותר של שיעור ה-Lab.
  • fun convertBitmapToBase64(bitmap: Bitmap): אפשר להמיר מופע של Bitmap לייצוג base64 כדי לשלוח אותו לקצה העורפי של חיפוש המוצרים
  • fun annotateImage(image: Bitmap): Task<List<ProductSearchResult>>: יש להתקשר ל-projects.locations.images.annotate API ולנתח את התגובה.
  • fun fetchReferenceImage(searchResult: ProductSearchResult): Task<ProductSearchResult>: יש להתקשר ל-projects.locations.products.referenceImage.get API ולנתח את התגובה.
  • SearchResult.kt: הקובץ הזה מכיל כמה מחלקות נתונים שמייצגות את הסוגים שמוחזרים על ידי הקצה העורפי של Search API.

ציון תצורות ה-API

יש לעבור לכיתת ProductSearchAPIClient כדי לראות כמה מההגדרות של הקצה העורפי של חיפוש המוצרים שכבר הוגדרו:

// Define the product search backend
// Option 1: Use the demo project that we have already deployed for you
const val VISION_API_URL =
    "https://us-central1-odml-codelabs.cloudfunctions.net/productSearch"
const val VISION_API_KEY = ""
const val VISION_API_PROJECT_ID = "odml-codelabs"
const val VISION_API_LOCATION_ID = "us-east1"
const val VISION_API_PRODUCT_SET_ID = "product_set0"
  • VISION_API_URL היא נקודת הקצה של ה-API של Cloud Vision API. תוך כדי המשך הקצה העורפי של ההדגמה, מגדירים את הערך הזה לנקודת הקצה של שרת ה-proxy. עם זאת, אם תפרסו את הקצה העורפי שלכם, תצטרכו לשנות אותו לנקודת הקצה של Cloud Vision API. https://vision.googleapis.com/v1.
  • VISION_API_KEY הוא מפתח ה-API של הפרויקט ב-Cloud. מאחר ששרת ה-proxy כבר מטפל באימות, אפשר להשאיר אותו ריק.
  • VISION_API_PROJECT_ID הוא מזהה הפרויקט ב-Cloud. odml-codelabs הוא פרויקט הענן שבו מתבצעת הקצה העורפי של ההדגמה.
  • VISION_API_LOCATION_ID הוא המיקום של הענן שבו מתבצעת הקצה העורפי לחיפוש מוצרים. us-east1 הוא המקום שבו פרסנו את הקצה העורפי של ההדגמה.
  • VISION_API_PRODUCT_SET_ID הוא המזהה של קטלוג המוצרים (נקרא גם - "product set" במונח Vision API), שבו אתם רוצים לחפש מוצרים דומים מבחינה חזותית. אפשר ליצור כמה קטלוגים בפרויקט אחד ב-Cloud. product_set0 הוא קטלוג המוצרים המוגדר מראש של הקצה העורפי של ההדגמה.

7. קריאה ל-API של חיפוש מוצרים

עיון בבקשה ל-API ובפורמט התגובה

כדי למצוא מוצרים דומים לתמונה נתונה, צריך להעביר את ה-URI של התמונה ב-Google Cloud Storage, את כתובת ה-URL של האתר או את המחרוזת המקודדת של base64 אל חיפוש המוצרים ב-Vision API. במעבדת קוד זו תוכלו להשתמש באפשרות המחרוזת מקודדת base64, כי תמונת השאילתה שלנו קיימת רק במכשיר של המשתמש.

יש לשלוח בקשת POST לנקודת הקצה projects.locations.images.annotate עם גוף ה-JSON עם הבקשה:

{
  "requests": [
    {
      "image": {
        "content": {base64-encoded-image}
      },
      "features": [
        {
          "type": "PRODUCT_SEARCH",
          "maxResults": 5
        }
      ],
      "imageContext": {
        "productSearchParams": {
          "productSet": "projects/{project-id}/locations/{location-id}/productSets/{product-set-id}",
          "productCategories": [
               "apparel-v2"
          ],
        }
      }
    }
  ]
}

יש כמה פרמטרים שצריך לציין:

  • base64-encoded-image: הייצוג base64 (מחרוזת ASCII) של נתוני השאילתה הבינארית של&#39.
  • project-id: מזהה הפרויקט שלכם ב-GCP.
  • location-id: מזהה מיקום חוקי.
  • product-set-id: המזהה של קבוצת המוצרים שבה רוצים להריץ את הפעולה.

כשקטלוג המוצרים מכיל רק תמונות של נעליים ושמלות, יש לציין את productcategory [קטגוריות_מוצרים] כ-apparel-v2. v2 כאן אנחנו משתמשים בגרסה 2 של מודל הלמידה החישובית למוצרי חיפוש למוצרי לבוש.

אם הבקשה מצליחה, השרת מחזיר קוד סטטוס HTTP 200 ואת התגובה בפורמט JSON. JSON של תגובה כולל את שני סוגי התוצאות הבאים:

  • productSearchResults – מכיל רשימה של מוצרים תואמים לתמונה כולה.
  • productGroupedResults – מכיל קואורדינטות תוחמות של פריטים ופריטים תואמים לכל מוצר המזוהה בתמונה.

המוצר כבר נחתך מהתמונה המקורית, כדי לנתח את התוצאות ברשימה productSearchResults.

יש כמה שדות חשובים באובייקט התוצאה של חיפוש המוצר:

  • product.name: המזהה הייחודי של מוצר בפורמט projects/{project-id}/locations/{location-id}/products/{product_id}
  • product.score: ערך המציין עד כמה תוצאת החיפוש דומה לתמונה של השאילתה. ערכים גבוהים יותר מאפשרים דמיון נוסף.
  • product.image: המזהה הייחודי של תמונת ההפניה של מוצר בפורמט projects/{project-id}/locations/{location-id}/products/{product_id}/referenceImages/{image_id}. יהיה עליכם לשלוח בקשת API נוספת אל projects.locations.products.referenceImage.get כדי לקבל את כתובת ה-URL של תמונת ההפניה הזו, כך שתוצג במסך.
  • product.labels: רשימה של תגים מוגדרים מראש של המוצר. פעולה זו שימושית אם רוצים לסנן את תוצאות החיפוש כך שיוצגו רק קטגוריה אחת של ביגוד, כמו שמלות.

המרת תמונת השאילתה ל-base64

יש להמיר את תמונת השאילתה לייצוג מחרוזת base64 ולצרף את המחרוזת לאובייקט JSON בגוף הבקשה.

יש לעבור לקורס ProductSearchAPIClient, למצוא את השיטה convertBitmapToBase64 ריקה ולהחליף אותה בהטמעה הזו:

private fun convertBitmapToBase64(bitmap: Bitmap): String {
    val byteArrayOutputStream = ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
    val byteArray: ByteArray = byteArrayOutputStream.toByteArray()
    return Base64.encodeToString(byteArray, Base64.DEFAULT)
}

הטמעה של קריאת ה-API

בשלב הבא, יוצרים בקשת API לחיפוש מוצר ושולחים אותו לקצה העורפי. אתם יכולים להשתמש ב-Volly כדי לבצע את בקשת ה-API, ולהחזיר את התוצאה באמצעות ה-Task API.

חזרה לקורס ProductSearchAPIClient, חיפוש השיטה annotateImage הריקה והחלפתה ביישום הזה:

fun annotateImage(image: Bitmap): Task<List<ProductSearchResult>> {
    // Initialization to use the Task API
    val apiSource = TaskCompletionSource<List<ProductSearchResult>>()
    val apiTask = apiSource.task

    // Convert the query image to its Base64 representation to call the Product Search API.
    val base64: String = convertBitmapToBase64(image)

    // Craft the request body JSON.
    val requestJson = """
        {
          "requests": [
            {
              "image": {
                "content": """".trimIndent() + base64 + """"
              },
              "features": [
                {
                  "type": "PRODUCT_SEARCH",
                  "maxResults": $VISION_API_PRODUCT_MAX_RESULT
                }
              ],
              "imageContext": {
                "productSearchParams": {
                  "productSet": "projects/${VISION_API_PROJECT_ID}/locations/${VISION_API_LOCATION_ID}/productSets/${VISION_API_PRODUCT_SET_ID}",
                  "productCategories": [
                       "apparel-v2"
                     ]
                }
              }
            }
          ]
        }
    """.trimIndent()

    // Add a new request to the queue
    requestQueue.add(object :
        JsonObjectRequest(
            Method.POST,
            "$VISION_API_URL/images:annotate?key=$VISION_API_KEY",
            JSONObject(requestJson),
            { response ->
                // Parse the API JSON response to a list of ProductSearchResult object/
                val productList = apiResponseToObject(response)

                // Return the list.
                apiSource.setResult(productList)
            },
            // Return the error
            { error -> apiSource.setException(error) }
        ) {
        override fun getBodyContentType() = "application/json"
    }.apply {
        setShouldCache(false)
    })

    return apiTask
}

הצגת תוצאת החיפוש בממשק המשתמש

עכשיו קוד ה-API ב-ProductSearchAPIClient מוכן. יש לחזור לפעילות ProductSearchActivity כדי להטמיע את קוד ממשק המשתמש.

לפעילות כבר יש קוד המבוך שמפעיל את השיטה searchByImage(queryImage: Bitmap). צריך להוסיף את הקוד כדי להפעיל את הקצה העורפי ולהציג תוצאות בממשק המשתמש בשיטה הזו שכרגע ריקה.

apiClient.annotateImage(queryImage)
    .addOnSuccessListener { showSearchResult(it) }
    .addOnFailureListener { error ->
        Log.e(TAG, "Error calling Vision API Product Search.", error)
        showErrorResponse(error.localizedMessage)
    }

השיטה showSearchResult מכילה קוד אישור סטנדרטי שמנתח את תגובת ה-API ומציג אותם במסך.

להפעלה

עכשיו לוחצים על הפעלה (exe.png) בסרגל הכלים של Android Studio. אחרי שהאפליקציה נטענת, מקישים על תמונות שהוגדרו מראש, בוחרים אובייקט שזוהה, מקישים על הלחצן חיפוש ורואים את תוצאות החיפוש שהוחזרו בקצה העורפי. תראו משהו כזה:

bb5e7c27c283a2fe.png

צילום מסך של תוצאת חיפוש של מוצר

הקצה העורפי כבר מחזיר רשימה של מוצרים הדומים מבחינה חזותית מקטלוג המוצרים המוגדר מראש. עם זאת, אפשר לראות שהתמונה של המוצר עדיין ריקה. הסיבה לכך היא שנקודת הקצה projects.locations.images.annotate מחזירה רק מזהי תמונות של מוצר, כמו projects/odml-codelabs/locations/us-east1/products/product_id77/referenceImages/image77. יהיה עליך לבצע קריאה נוספת ל-API אל נקודת הקצה projects.locations.products.referenceImage.get ולקבל את כתובת ה-URL של תמונת ההפניה הזו כדי להציג אותה על המסך.

8. תמונות של הפניות למוצרים

עיון בבקשה ל-API ובפורמט התגובה

יש לשלוח בקשת HTTP מסוג GET עם גוף בקשה ריק לנקודת הקצה projects.locations.products.referenceImage.get כדי לקבל את ה-URI של תמונות המוצרים שהוחזרו על ידי נקודת הקצה של חיפוש המוצרים.

בקשת ה-HTTP נראית כך:

GET $VISION_API_URL/projects/odml-codelabs/locations/us-east1/products/product_id77/referenceImages/image77?key=$VISION_API_KEY

אם הבקשה מצליחה, השרת מחזיר קוד סטטוס HTTP 200 ואת התגובה בפורמט JSON באופן הבא:

{
  "name":"projects/odml-codelabs/locations/us-east1/products/product_id77/referenceImages/image77",
  "uri":"gs://cloud-ai-vision-data/product-search-tutorial/images/46991e7370ba11e8a1bbd20059124800.jpg"
}
  • name [שם]: המזהה של תמונת ההפניה
  • uri: URI של התמונה ב-Google Cloud Storage (GCS).

תמונות העזר של הקצה העורפי של חיפוש המוצרים בהדגמה הוגדרו כהרשאות קריאה לציבור. לכן, אפשר להמיר בקלות את ה-URI של GCS לכתובת URL מסוג HTTP ולהציג אותו בממשק המשתמש של האפליקציה. צריך להחליף את הקידומת gs:// רק ב-https://storage.googleapis.com/.

הטמעה של קריאת ה-API

בשלב הבא, יוצרים בקשת API לחיפוש מוצר ושולחים אותו לקצה העורפי. אתם תשתמשו ב-Volly וב-Task API בדומה לקריאה ל-API לחיפוש מוצרים.

חזרה לקורס ProductSearchAPIClient, חיפוש השיטה fetchReferenceImage הריקה והחלפתה ביישום הזה:

private fun fetchReferenceImage(searchResult: ProductSearchResult): Task<ProductSearchResult> {
    // Initialization to use the Task API
    val apiSource = TaskCompletionSource<ProductSearchResult>()
    val apiTask = apiSource.task

    // Craft the API request to get details about the reference image of the product
    val stringRequest = object : StringRequest(
        Method.GET,
        "$VISION_API_URL/${searchResult.imageId}?key=$VISION_API_KEY",
        { response ->
            val responseJson = JSONObject(response)
            val gcsUri = responseJson.getString("uri")

            // Convert the GCS URL to its HTTPS representation
            val httpUri = gcsUri.replace("gs://", "https://storage.googleapis.com/")

            // Save the HTTPS URL to the search result object
            searchResult.imageUri = httpUri

            // Invoke the listener to continue with processing the API response (eg. show on UI)
            apiSource.setResult(searchResult)
        },
        { error -> apiSource.setException(error) }
    ) {

        override fun getBodyContentType(): String {
            return "application/json; charset=utf-8"
        }
    }
    Log.d(ProductSearchActivity.TAG, "Sending API request.")

    // Add the request to the RequestQueue.
    requestQueue.add(stringRequest)

    return apiTask
}

השיטה הזו משתמשת באובייקט searchResult: ProductSearchResult שמוחזר מנקודת הקצה של חיפוש מוצרים, ולאחר מכן:

  1. קריאה לנקודת הקצה של תמונת ההפניה כדי לקבל את ה-URI של GCS של תמונת ההפניה.
  2. המרת ה-URI של GCS לכתובת URL מסוג HTTP.
  3. מתבצע עדכון של המאפיין httpUri של האובייקט searchResult בכתובת ה-URL הזו של HTTP.

קישור שתי הבקשות ל-API

יש לחזור אל annotateImage ולשנות את ההגדרות כדי לקבל את כל תמונות ההפניה' כתובות URL מסוג HTTP לפני החזרת הרשימה ProductSearchResult למתקשר שלה.

מחפשים את השורה הזו:

// Return the list.
apiSource.setResult(productList)

לאחר מכן החליפו אותו בהטמעה הזו:

// Loop through the product list and create tasks to load reference images.
// We will call the projects.locations.products.referenceImages.get endpoint
// for each product.
val fetchReferenceImageTasks = productList.map { fetchReferenceImage(it) }

// When all reference image fetches have completed,
// return the ProductSearchResult list
Tasks.whenAllComplete(fetchReferenceImageTasks)
    // Return the list of ProductSearchResult with product images' HTTP URLs.
    .addOnSuccessListener { apiSource.setResult(productList) }
    // An error occurred so returns it to the caller.
    .addOnFailureListener { apiSource.setException(it) }

הקוד של תבנית ה-OLC כדי להציג את תמונות העזר במסך כבר הוטמע בכיתה ProductSearchAdapter, כך שאפשר להמשיך ולהפעיל את האפליקציה.

להפעלה

עכשיו לוחצים על הפעלה (exe.png) בסרגל הכלים של Android Studio. אחרי שהאפליקציה נטענת, מקישים על תמונות שהוגדרו מראש, בוחרים אובייקט שזוהה, מקישים על הלחצן חיפוש כדי להציג את תוצאות החיפוש הפעם, ביחד עם תמונות המוצר.

האם לדעתך תוצאות החיפוש של מוצרים נשמעות לך הגיוניות?

25939f5a13eeb3c3.png

9. מעולה!

למדת איך להפעיל קצה עורפי לחיפוש מוצרים ב-Vision API כדי להוסיף יכולת חיפוש של תמונות מוצרים לאפליקציה ל-Android. זה כל מה שצריך לעשות כדי להתחיל לעבוד!

בהמשך תוכלו ליצור קצה עורפי באמצעות קטלוג המוצרים שלכם. כדי ללמוד איך לבנות קצה עורפי ולהגדיר את המפתח של ה-API מאפליקציה לנייד, יש לעיין בשיעור ה-Lab הבא במסלול הלימוד לחיפוש תמונות של מוצרים.

באילו נושאים מדובר?

  • איך להפעיל את הקצה העורפי של חיפוש המוצרים של ממשק ה-API באמצעות אפליקציה ל-Android

השלבים הבאים

למידע נוסף