Серверная часть Call Vision API Product Search на Android

1. Прежде чем начать

bd8c01b2f8013c6d.png

Вы видели демонстрацию Google Lens, где вы можете навести камеру телефона на объект и найти, где его можно купить в Интернете? Если вы хотите узнать, как добавить ту же функцию в свое приложение, эта лабораторная работа для вас. Это часть пути обучения, который научит вас встраивать функцию поиска изображений продукта в мобильное приложение.

В этой лабораторной работе вы узнаете, как вызывать серверную часть, созданную с помощью Vision API Product Search , из мобильного приложения. Этот бэкэнд может принимать изображение запроса и искать визуально похожие продукты из каталога продуктов.

Вы можете узнать об оставшихся этапах создания функции визуального поиска продуктов, в том числе о том, как использовать обнаружение и отслеживание объектов ML Kit для обнаружения объектов в изображении запроса и предоставления пользователям возможности выбирать, какой продукт они хотят искать, в пути обучения .

Что вы будете строить

  • В этой кодовой лаборатории вы начинаете с приложения для Android, которое может обнаруживать объекты на входном изображении. Вы напишете код, который берет объект, выбранный пользователем, отправляет его в серверную часть поиска продукта и отображает результат поиска на экране.
  • В итоге вы должны увидеть что-то похожее на изображение справа.

Что вы узнаете

  • Как вызвать и проанализировать ответ Vision API Product Search API из приложения для Android

Что вам понадобится

  • Последняя версия Android Studio (v4.1.2+)
  • Эмулятор Android Studio или физическое устройство Android
  • Пример кода
  • Базовые знания Android-разработки на Kotlin

Эта лаборатория кода посвящена поиску продуктов Vision API. Нерелевантные концепции и блоки кода не исследуются и предоставляются для простого копирования и вставки.

2. О поиске продуктов Vision API

Vision API Product Search — это функция в Google Cloud, которая позволяет пользователям искать визуально похожие продукты в каталоге продуктов. Розничные продавцы могут создавать продукты, каждый из которых содержит эталонные изображения, которые визуально описывают продукт с определенного набора точек зрения. Затем вы можете добавить эти продукты в наборы продуктов (например, в каталог продуктов). В настоящее время Vision API Product Search поддерживает следующие категории продуктов: товары для дома, одежда, игрушки, упакованные товары и общие товары.

Когда пользователи запрашивают набор продуктов со своими собственными изображениями, Vision API Product Search применяет машинное обучение для сравнения продукта в изображении запроса пользователя с изображениями в наборе продуктов розничного продавца, а затем возвращает ранжированный список визуально и семантически похожих результатов.

3. Загрузите и запустите стартовое приложение.

Скачать код

Щелкните следующую ссылку, чтобы загрузить весь код для этой лаборатории кода:

Распакуйте загруженный zip-файл. Это распакует корневую папку ( odml-pathways-main ) со всеми необходимыми ресурсами. Для этой лаборатории кода вам понадобятся только исходники в подкаталоге product-search/codelab2/android .

codelab2 в репозитории odml-pathways содержит два каталога:

  • android_studio_folder.png starter — начальный код, на основе которого вы строите эту лабораторию кода.
  • android_studio_folder.png final — Завершенный код для готового примера приложения.

Стартовое приложение здесь — это то, которое вы встроили в Обнаружение объектов в изображениях для создания визуального поиска продукта: Android codelab. Он использует обнаружение и отслеживание объектов ML Kit для обнаружения объектов на изображении и отображения их на экране.

Импортируйте приложение в Android Studio

Начните с импорта начального приложения в Android Studio.

Перейдите в Android Studio, выберите «Импортировать проект» (Gradle, Eclipse ADT и т. д.) и выберите starter папку из загруженного ранее исходного кода.

7c0f27882a2698ac.png

Запустите стартовое приложение

Теперь, когда вы импортировали проект в Android Studio, вы готовы запустить приложение в первый раз. Подключите устройство Android через USB к хосту или запустите эмулятор Android Studio и нажмите « Выполнить» ( исполнять.png ) на панели инструментов Android Studio.

(Если эта кнопка отключена, убедитесь, что вы импортируете только start/app/build.gradle, а не весь репозиторий.)

Теперь приложение должно запуститься на вашем Android-устройстве. У него уже есть возможность обнаружения объектов: обнаружение модных вещей на изображении и показ вас, где они находятся. Попробуйте с предустановленными фотографиями, чтобы подтвердить.

c6102a808fdfcb11.png

Снимок экрана начального приложения, которое может обнаруживать объекты на изображении

Затем вы расширите приложение, чтобы отправлять обнаруженные объекты в серверную часть Vision API Product Search и отображать результаты поиска на экране.

4. Управление выбором объекта

Разрешить пользователям нажимать на обнаруженный объект, чтобы выбрать

Теперь вы добавите код, позволяющий пользователям выбирать объект на изображении и запускать поиск продукта. Стартовое приложение уже имеет возможность обнаруживать объекты на изображении. Возможно, на изображении несколько объектов или обнаруженный объект занимает лишь небольшую часть изображения. Поэтому вам нужно, чтобы пользователь коснулся одного из обнаруженных объектов, чтобы указать, какой объект он хочет использовать для поиска продукта.

9cdfcead6d95a87.png

Скриншот модных предметов, обнаруженных на изображении

Чтобы сделать кодовую лабораторию простой и сфокусированной на машинном обучении, в начальном приложении был реализован некоторый шаблонный код Android, который поможет вам определить, на какой объект нажал пользователь. Представление, которое отображает изображение в основном действии ( ObjectDetectorActivity ), на самом деле является настраиваемым представлением ( ImageClickableView ), которое расширяет ImageView по умолчанию в ОС Android. Он реализует несколько удобных служебных методов, в том числе:

  • fun setOnObjectClickListener(listener: ((objectImage: Bitmap) -> Unit)) Это обратный вызов для получения обрезанного изображения, которое содержит только объект, на который нажал пользователь. Вы отправите это обрезанное изображение в серверную часть поиска товаров.

Добавьте код для обработки нажатия пользователем на обнаруженные объекты.

Перейдите к методу 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

Отправьте обрезанное изображение в активность поиска товаров

Теперь вы реализуете логику отправки изображения запроса в серверную часть Vision API Product 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 мог получить его позже для использования в качестве изображения запроса.

Есть несколько вещей, которые следует иметь в виду:

  • Логика обнаружения объектов и запросов к серверной части была разделена на 2 действия только для того, чтобы облегчить понимание кодовой лаборатории. Вам решать, как реализовать их в своем приложении.
  • Вам необходимо записать изображение запроса в файл и передать URI изображения между действиями, поскольку размер изображения запроса может превышать предельный размер 1 МБ для намерения 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))
}

Запустите приложение

Теперь нажмите «Выполнить» ( исполнять.png ) на панели инструментов Android Studio.

После загрузки приложения коснитесь любого предустановленного изображения и выберите один из обнаруженных объектов.

Убедитесь, что ProductSearchActivity отображается с изображением, на которое вы нажали. Кнопка « Поиск » пока ничего не делает, но мы реализуем ее позже.

fed40f81b8b43801.png

Вы должны увидеть аналогичный экран после нажатия на один из обнаруженных объектов.

5. Изучите серверную часть поиска продуктов

Создайте серверную часть поиска изображений продукта

Для этой лаборатории кода требуется серверная часть поиска продуктов, созданная с помощью Vision API Product Search . Для этого есть два варианта:

Вариант 1. Используйте демонстрационную серверную часть, которая была развернута для вас.

Вы можете продолжить работу с этой кодовой лабораторией, используя серверную часть поиска продуктов, которую Google уже развернула для вас. Демонстрационную серверную часть можно воспроизвести, следуя краткому руководству по поиску продуктов Vision API .

Вариант 2. Создайте собственную серверную часть, следуя краткому руководству по поиску продуктов Vision API.

Этот вариант рекомендуется для тех, кто хочет подробно узнать о том, как создать серверную часть поиска продуктов, чтобы позже вы могли создать ее для своего собственного каталога продуктов. Тебе нужно иметь:

  • Аккаунт Google Cloud с включенным выставлением счетов. (Это может быть бесплатная пробная учетная запись.)
  • Некоторые знания о концепциях Google Cloud, включая проекты, учетные записи служб и т. д.

Вы можете узнать, как это сделать позже, в процессе обучения .

Изучите важные понятия

Вы столкнетесь с этими понятиями при взаимодействии с серверной частью поиска продуктов:

  • Набор продуктов : набор продуктов — это простой контейнер для группы продуктов. Каталог товаров может быть представлен в виде набора товаров и его продуктов.
  • Продукт : после того, как вы создали набор продуктов, вы можете создавать продукты и добавлять их в набор продуктов.
  • Эталонные изображения продукта: это изображения, содержащие различные виды ваших продуктов. Эталонные изображения используются для поиска визуально похожих товаров.
  • Поиск продуктов . После того, как вы создали свой набор продуктов и проиндексировали его, вы можете запросить набор продуктов с помощью Cloud Vision API.

Понимание предустановленного каталога продуктов

Демонстрационная серверная часть поиска продуктов, используемая в этой кодовой лаборатории, была создана с использованием Vision API Product Search и каталога продуктов, содержащего около сотни изображений обуви и платьев. Вот несколько изображений из каталога:

4f1a8507b74ab178.png79a5fc6c829eca77.png3528c872f813826e.png

Примеры из предустановленного каталога продукции

Вызов демо-сервера поиска продуктов

Вы можете вызывать Vision API Product Search непосредственно из мобильного приложения, настроив ключ Google Cloud API и ограничив доступ к ключу API только своим приложением.

Чтобы сделать эту лабораторию кода простой, была настроена конечная точка прокси, которая позволяет вам получить доступ к демонстрационному бэкенду, не беспокоясь о ключе API и аутентификации. Он получает HTTP-запрос от мобильного приложения, добавляет ключ API и перенаправляет запрос в серверную часть Vision API Product Search. Затем прокси получает ответ от серверной части и возвращает его в мобильное приложение.

В этой лаборатории кода вы будете использовать два API Vision API Product Search :

  • project.locations.images.annotate : Отправка изображения запроса на сервер и получение списка продуктов из предустановленного каталога продуктов, которые визуально похожи на изображение запроса.
  • Projects.locations.products.referenceImages.get : получение URI изображений продуктов, возвращенных в вызове API выше, для отображения пользователям.

6. Внедрить клиент API

Понимание рабочего процесса поиска продукта

Следуйте этому рабочему процессу, чтобы выполнить поиск продукта с помощью серверной части:

  • Кодировать изображение запроса как строку base64
  • Вызовите конечную точку project.locations.images.annotate с изображением запроса.
  • Получите идентификаторы изображений продуктов из предыдущего вызова API и отправьте их на конечные точки project.locations.products.referenceImages.get , чтобы получить URI изображений продуктов в результатах поиска.

Реализовать клиентский класс API

Теперь вы реализуете код для вызова серверной части поиска продуктов в выделенном классе с именем ProductSearchAPIClient . Некоторый шаблонный код был реализован для вас в стартовом приложении:

  • class ProductSearchAPIClient : этот класс сейчас в основном пуст, но у него есть несколько методов, которые вы реализуете позже в этой лаборатории кода.
  • fun convertBitmapToBase64(bitmap: Bitmap) : преобразование экземпляра Bitmap в его представление base64 для отправки в серверную часть поиска продукта.
  • fun annotateImage(image: Bitmap): Task<List<ProductSearchResult>> : вызовите API проектов.locations.images.annotate и проанализируйте ответ.
  • fun fetchReferenceImage(searchResult: ProductSearchResult): Task<ProductSearchResult> : вызов API-интерфейса project.locations.products.referenceImages.get и анализ ответа.
  • SearchResult.kt : этот файл содержит несколько классов данных для представления типов, возвращаемых серверной частью Vision API Product Search.

Укажите конфигурации 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. Когда вы продолжите работу с демонстрационным бэкэндом, установите конечную точку прокси. Однако, если вы развернете свой собственный сервер, вам нужно будет изменить его на конечную точку Cloud Vision API. https://vision.googleapis.com/v1 .
  • VISION_API_KEY — это ключ API вашего облачного проекта. Поскольку прокси-сервер уже обрабатывает аутентификацию, вы можете оставить это поле пустым.
  • VISION_API_PROJECT_ID — это идентификатор облачного проекта. odml-codelabs — это облачный проект, в котором развернут демонстрационный сервер.
  • VISION_API_LOCATION_ID — это расположение в облаке, в котором развернута серверная часть поиска продуктов. us-east1 — это место, где мы развернули демо-сервер.
  • VISION_API_PRODUCT_SET_ID — это идентификатор каталога продуктов (он же «набор продуктов» в термине Vision API), в котором вы хотите искать визуально похожие продукты. Вы можете иметь несколько каталогов в одном облачном проекте. product_set0 — предустановленный каталог продуктов демо-бэкенда.

7. Вызов API поиска товаров

Изучите формат запроса и ответа API

Вы можете найти продукты, похожие на данное изображение, передав URI Google Cloud Storage изображения, веб-URL или строку в кодировке base64 в поиск продуктов Vision API. В этой лаборатории кода вы будете использовать параметр строки в кодировке base64, так как наше изображение запроса существует только на устройстве пользователя.

Вам необходимо отправить запрос POST в конечную точку проектов.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) двоичных данных изображения запроса.
  • project-id : идентификатор вашего проекта GCP.
  • location-id : действительный идентификатор местоположения.
  • product-set-id : идентификатор набора продуктов, для которого вы хотите запустить операцию.

Поскольку ваш каталог продуктов содержит только изображения обуви и платьев, укажите для productCategories значение apparel apparel-v2 . v2 здесь означает, что мы используем версию 2 модели машинного обучения поиска продуктов одежды.

Если запрос выполнен успешно, сервер возвращает код состояния HTTP 200 OK и ответ в формате 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 на project.locations.products.referenceImages.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 поиска продуктов и отправьте его серверной части. Вы будете использовать Volley, чтобы сделать запрос 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 и отображает его на экране.

Запустить его

Теперь нажмите «Выполнить» ( исполнять.png ) на панели инструментов Android Studio. После загрузки приложения коснитесь любых предустановленных изображений, выберите обнаруженный объект, коснитесь кнопки « Поиск » и просмотрите результаты поиска, полученные из бэкэнда. Вы увидите что-то вроде этого:

bb5e7c27c283a2fe.png

Скриншот экрана результатов поиска продукта

Бэкэнд уже возвращает список визуально похожих товаров из предустановленного каталога товаров. Однако вы можете видеть, что изображение продукта по-прежнему пусто. Это связано с тем, что конечная точка project.locations.images.annotate возвращает только идентификаторы изображений продуктов, такие как Projects/ odml projects/odml-codelabs/locations/us-east1/products/product_id77/referenceImages/image77 . Вам нужно будет сделать еще один вызов API к конечной точке Projects.locations.products.referenceImages.get и получить URL-адрес этого эталонного изображения, чтобы отобразить его на экране.

8. Получите эталонные изображения продукта

Изучите формат запроса и ответа API

Вы отправите HTTP-запрос GET с пустым телом запроса на конечную точку project.locations.products.referenceImages.get , чтобы получить URI изображений продуктов, возвращенных конечной точкой поиска продуктов.

HTTP-запрос выглядит следующим образом:

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

Если запрос выполнен успешно, сервер возвращает код состояния HTTP 200 OK и ответ в формате 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 поиска продуктов и отправьте его серверной части. Вы будете использовать Volley и 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. Вызывает конечную точку эталонного изображения, чтобы получить GCS URI эталонного изображения.
  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) }

Стандартный код для отображения эталонных изображений на экране уже реализован в классе ProductSearchAdapter , поэтому вы можете перезапустить приложение.

Запустить его

Теперь нажмите «Выполнить» ( исполнять.png ) на панели инструментов Android Studio. После загрузки приложения коснитесь любых предустановленных изображений, выберите обнаруженный объект, коснитесь кнопки « Поиск », чтобы просмотреть результаты поиска, на этот раз с изображениями продуктов.

Понятны ли вам результаты поиска продуктов?

25939f5a13eeb3c3.png

9. Поздравляем!

Вы узнали, как вызвать серверную часть поиска продуктов Vision API, чтобы добавить возможность поиска изображений продуктов в ваше приложение для Android. Это все, что вам нужно, чтобы запустить его!

По мере продвижения вы, возможно, захотите создать свой собственный бэкэнд, используя свой каталог продуктов. Ознакомьтесь со следующей лабораторией кода в пути обучения Product Image Search , чтобы узнать, как создать собственную серверную часть и настроить ключ API для вызова ее из мобильного приложения.

Что мы рассмотрели

  • Как вызвать серверную часть Vision API Product Search из приложения для Android

Следующие шаги

Учить больше