Partilhar via


Tutorial: Carregar imagens para a API de Pesquisa Visual do Bing

Aviso

Em 30 de outubro de 2020, as APIs de Pesquisa do Bing foram movidas dos serviços de IA do Azure para os Serviços de Pesquisa do Bing. Esta documentação é fornecida apenas para referência. Para obter documentação atualizada, consulte a documentação da API de pesquisa do Bing. Para obter instruções sobre como criar novos recursos do Azure para a pesquisa do Bing, consulte Criar um recurso de Pesquisa do Bing através do Azure Marketplace.

A API de Pesquisa Visual do Bing permite-lhe pesquisar na Web imagens semelhantes às que carrega. Use este tutorial para criar um aplicativo Web que possa enviar uma imagem para a API e exibir as informações que ela retorna dentro da página da Web. Observe que este aplicativo não adere a todos os Requisitos de Uso e Exibição do Bing para usar a API.

Você pode encontrar o código-fonte completo para este exemplo com manipulação de erros e anotações adicionais no GitHub.

A aplicação de tutorial ilustra como:

  • Carregar uma imagem para a API de Pesquisa Visual do Bing
  • Exibir resultados de pesquisa de imagens em um aplicativo Web
  • Explore os diferentes insights fornecidos pela API

Pré-requisitos

Criar um recurso do Azure

Comece a usar a API de Pesquisa Visual do Bing criando um dos seguintes recursos do Azure:

Recurso Pesquisa do Bing v7

  • Disponível através do portal do Azure até eliminar o recurso.
  • Selecione o nível de S9 preço.

Recurso multisserviço

  • Disponível através do portal do Azure até eliminar o recurso.
  • Use a mesma chave e ponto de extremidade para seus aplicativos, em vários serviços de IA do Azure.

Criar e estruturar a página Web

Crie uma página HTML que envie uma imagem para a API de Pesquisa Visual do Bing, receba informações e as exiba. No seu editor ou IDE favorito, crie um arquivo chamado "uploaddemo.html". Adicione a seguinte estrutura HTML básica ao arquivo:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Visual Search Upload Demo</title>
    </head>

    <body>
    </body>
</html>

Divida a página em uma seção de solicitação, onde o usuário fornece todas as informações necessárias para a solicitação, e uma seção de resposta, onde os insights são exibidos. Adicione as seguintes <div> tags ao <body>arquivo . A <hr> tag separa visualmente a seção de solicitação da seção de resposta:

<div id="requestSection"></div>
<hr />
<div id="responseSection"></div>

Adicione uma <script> tag à <head> tag para conter o JavaScript do aplicativo:

<script>
<\script>

Obter o ficheiro de carregamento

Para permitir que o usuário selecione uma imagem para carregar, o aplicativo usa a <input> tag com o atributo type definido como file. A interface do usuário precisa deixar claro que o aplicativo usa o Bing para obter os resultados da pesquisa.

Adicione o seguinte <div> ao requestSection <div>arquivo . A entrada de ficheiro aceita um ficheiro individual de qualquer tipo de imagem (por exemplo, .jpg, .gif, .png). O evento onchange especifica o processador que é chamado quando um utilizador seleciona um ficheiro.

A <output> tag é usada para exibir uma miniatura da imagem selecionada:

<div>
    <p>Select image to get insights from Bing:
        <input type="file" accept="image/*" id="uploadImage" name="files[]" size=40 onchange="handleFileSelect('uploadImage')" />
    </p>

    <output id="thumbnail"></output>
</div>

Criar um manipulador de arquivos

Crie uma função de manipulador que possa ler na imagem que você deseja carregar. Ao iterar pelos arquivos no objeto, o FileList manipulador deve certificar-se de que o arquivo selecionado é um arquivo de imagem e que seu tamanho é de 1 MB ou menos. Se a imagem for maior, você deve reduzir seu tamanho antes de carregá-la. Por fim, o manipulador exibe uma miniatura da imagem:

function handleFileSelect(selector) {

    var files = document.getElementById(selector).files; // A FileList object

    for (var i = 0, f; f = files[i]; i++) {

        // Ensure the file is an image file.
        if (!f.type.match('image.*')) {
            alert("Selected file must be an image file.");
            document.getElementById("uploadImage").value = null;
            continue;
        }

        // Image must be <= 1 MB and should be about 1500px.
        if (f.size > 1000000) {
            alert("Image must be less than 1 MB.");
            document.getElementById("uploadImage").value = null;
            continue;
        }

        var reader = new FileReader();

        // Capture the file information.
        reader.onload = (function(theFile) {
            return function(e) {
                var fileOutput = document.getElementById('thumbnail');

                if (fileOutput.childElementCount > 0) {
                    fileOutput.removeChild(fileOutput.lastChild);  // Remove the current pic, if it exists
                }

                // Render thumbnail.
                var span = document.createElement('span');
                span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                    '" title="', escape(theFile.name), '"/>'].join('');
                fileOutput.insertBefore(span, null);
            };
        })(f);

        // Read in the image file as a data URL.
        reader.readAsDataURL(f);
    }
}

Adicionar e armazenar uma chave de subscrição

O aplicativo requer uma chave de assinatura para fazer chamadas para a API de Pesquisa Visual do Bing. Para este tutorial, você o fornecerá na interface do usuário. Adicione a seguinte <input> tag (com o atributo type definido como text) logo <body> abaixo da tag do <output> arquivo:

    <div>
        <p>Subscription key: 
            <input type="text" id="key" name="subscription" size=40 maxlength="32" />
        </p>
    </div>

Com a imagem e a chave de assinatura, você pode fazer a chamada para a Pesquisa Visual do Bing para obter informações sobre a imagem. Neste tutorial, a chamada usa o mercado padrão (en-us) e o valor de pesquisa segura (moderate).

Esta aplicação tem uma opção para alterar estes valores. Adicione o seguinte <div> abaixo da chave <div>de subscrição . O aplicativo usa uma <select> tag para fornecer uma lista suspensa para valores de mercado e pesquisa segura. Ambas as listas exibem o valor padrão.

<div>
    <p><a href="#" onclick="expandCollapse(options.id)">Query options</a></p>

    <div id="options" style="display:none">
        <p style="margin-left: 20px">Market: 
            <select id="mkt">
                <option value="es-AR">Argentina (Spanish)</option>
                <option value="en-AU">Australia (English)</option>
                <option value="de-AT">Austria (German)</option>
                <option value="nl-BE">Belgium (Dutch)</option>
                <option value="fr-BE">Belgium (French)</option>
                <option value="pt-BR">Brazil (Portuguese)</option>
                <option value="en-CA">Canada (English)</option>
                <option value="fr-CA">Canada (French)</option>
                <option value="es-CL">Chile (Spanish)</option>
                <option value="da-DK">Denmark (Danish)</option>
                <option value="fi-FI">Finland (Finnish)</option>
                <option value="fr-FR">France (French)</option>
                <option value="de-DE">Germany (German)</option>
                <option value="zh-HK">Hong Kong SAR(Traditional Chinese)</option>
                <option value="en-IN">India (English)</option>
                <option value="en-ID">Indonesia (English)</option>
                <option value="it-IT">Italy (Italian)</option>
                <option value="ja-JP">Japan (Japanese)</option>
                <option value="ko-KR">Korea (Korean)</option>
                <option value="en-MY">Malaysia (English)</option>
                <option value="es-MX">Mexico (Spanish)</option>
                <option value="nl-NL">Netherlands (Dutch)</option>
                <option value="en-NZ">New Zealand (English)</option>
                <option value="no-NO">Norway (Norwegian)</option>
                <option value="zh-CN">People's Republic of China (Chinese)</option>
                <option value="pl-PL">Poland (Polish)</option>
                <option value="pt-PT">Portugal (Portuguese)</option>
                <option value="en-PH">Philippines (English)</option>
                <option value="ru-RU">Russia (Russian)</option>
                <option value="ar-SA">Saudi Arabia (Arabic)</option>
                <option value="en-ZA">South Africa (English)</option>
                <option value="es-ES">Spain (Spanish)</option>
                <option value="sv-SE">Sweden (Swedish)</option>
                <option value="fr-CH">Switzerland (French)</option>
                <option value="de-CH">Switzerland (German)</option>
                <option value="zh-TW">Taiwan (Traditional Chinese)</option>
                <option value="tr-TR">Türkiye (Turkish)</option>
                <option value="en-GB">United Kingdom (English)</option>
                <option value="en-US" selected>United States (English)</option>
                <option value="es-US">United States (Spanish)</option>
            </select>
        </p>
        <p style="margin-left: 20px">Safe search: 
            <select id="safesearch">
                <option value="moderate" selected>Moderate</option>
                <option value="strict">Strict</option>
                <option value="off">off</option>
            </select>
        </p>
    </div>
</div>

Adicionar opções de pesquisa à página Web

O aplicativo oculta as listas em um dobrável <div> que é controlado pelo link Opções de consulta. Quando você clica no link Opções de consulta, o <div> expande para que você possa ver e modificar as opções de consulta. Se você clicar no link Opções de consulta novamente, o recolhimento <div> e ficará oculto. O trecho a seguir mostra o manipulador do link Opções de onclick consulta. O manipulador controla se o <div> é expandido ou recolhido. Adicione este manipulador à <script> seção . O manipulador é usado por todas as seções dobráveis <div> na demonstração.

// Contains the toggle state of divs.
var divToggleMap = {};  // divToggleMap['foo'] = 0;  // 1 = show, 0 = hide


// Toggles between showing and hiding the specified div.
function expandCollapse(divToToggle) {
    var div = document.getElementById(divToToggle);

    if (divToggleMap[divToToggle] == 1) {   // if div is expanded
        div.style.display = "none";
        divToggleMap[divToToggle] = 0;
    }
    else {                                  // if div is collapsed
        div.style.display = "inline-block";
        divToggleMap[divToToggle] = 1;
    }
}

Chame o onclick manipulador

Adicione o seguinte "Get insights" botão abaixo das opções <div> no corpo. O botão permite-lhe iniciar a chamada. Quando o botão é clicado, o cursor é alterado para o cursor de espera giratório e o onclick manipulador é chamado.

<p><input type="button" id="query" value="Get insights" onclick="document.body.style.cursor='wait'; handleQuery()" /></p>

Adicione o manipulador handleQuery() do onclick botão à <script> tag .

Manipular a consulta

O manipulador handleQuery() garante que a chave de assinatura esteja presente e tenha 32 caracteres, e que uma imagem seja selecionada. Também limpa todas as informações relativas a uma consulta anterior. Depois, chama a sendRequest() função para fazer a chamada.

function handleQuery() {
    var subscriptionKey = document.getElementById('key').value;

    // Make sure user provided a subscription key and image.
    // For this demo, the user provides the key but typically you'd
    // get it from secured storage.
    if (subscriptionKey.length !== 32) {
        alert("Subscription key length is not valid. Enter a valid key.");
        document.getElementById('key').focus();
        return;
    }

    var imagePath = document.getElementById('uploadImage').value;

    if (imagePath.length === 0)
    {
        alert("Please select an image to upload.");
        document.getElementById('uploadImage').focus();
        return;
    }

    var responseDiv = document.getElementById('responseSection');

    // Clear out the response from the last query.
    while (responseDiv.childElementCount > 0) {
        responseDiv.removeChild(responseDiv.lastChild);
    }

    // Send the request to Bing to get insights about the image.
    var f = document.getElementById('uploadImage').files[0];
    sendRequest(f, subscriptionKey);
}

Enviar o pedido de pesquisa

A sendRequest() função formata a URL do ponto de extremidade, define o Ocp-Apim-Subscription-Key cabeçalho para a chave de assinatura, acrescenta o binário da imagem a ser carregada, especifica o manipulador de resposta e faz a chamada:

function sendRequest(file, key) {
    var market = document.getElementById('mkt').value;
    var safeSearch = document.getElementById('safesearch').value;
    var baseUri = `https://api.cognitive.microsoft.com/bing/v7.0/images/visualsearch?mkt=${market}&safesearch=${safeSearch}`;

    var form = new FormData();
    form.append("image", file);

    var request = new XMLHttpRequest();

    request.open("POST", baseUri);
    request.setRequestHeader('Ocp-Apim-Subscription-Key', key);
    request.addEventListener('load', handleResponse);
    request.send(form);
}

Obter e lidar com a resposta da API

A handleResponse() função lida com a resposta da chamada para a Pesquisa Visual do Bing. Se a chamada for bem-sucedida, a função analisa a resposta JSON nas tags individuais, as quais contêm as informações. Em seguida, adiciona os resultados da pesquisa à página. Em seguida, o aplicativo cria um recolhível <div> para cada tag para gerenciar a quantidade de dados exibidos. Adicione o manipulador à <script> seção.

function handleResponse() {
    if(this.status !== 200){
        alert("Error calling Bing Visual Search. See console log for details.");
        console.log(this.responseText);
        return;
    }

    var tags = parseResponse(JSON.parse(this.responseText));
    var h4 = document.createElement('h4');
    h4.textContent = 'Bing internet search results';
    document.getElementById('responseSection').appendChild(h4);
    buildTagSections(tags);

    document.body.style.cursor = 'default'; // reset the wait cursor set by query insights button
}

Analisar a resposta

A parseResponse função converte a resposta JSON em um objeto de dicionário iterando através json.tagsdo .

function parseResponse(json) {
    var dict = {};

    for (var i =0; i < json.tags.length; i++) {
        var tag = json.tags[i];

        if (tag.displayName === '') {
            dict['Default'] = JSON.stringify(tag);
        }
        else {
            dict[tag.displayName] = JSON.stringify(tag);
        }
    }

    return(dict);
}

Criar uma seção de tags

A buildTagSections() função itera através das tags JSON analisadas e chama a buildDiv() função para criar um <div> para cada tag. Cada tag é exibida como um link. Quando o link é clicado, a tag se expande, mostrando as informações associadas à tag. Clicar no link novamente faz com que a seção seja recolhida.

function buildTagSections(tags) {
    for (var tag in tags) {
        if (tags.hasOwnProperty(tag)) {
            var tagSection = buildDiv(tags, tag);
            document.getElementById('responseSection').appendChild(tagSection);
        }
    }  
}

function buildDiv(tags, tag) {
    var tagSection = document.createElement('div');
    tagSection.setAttribute('class', 'subSection');

    var link = document.createElement('a');
    link.setAttribute('href', '#');
    link.setAttribute('style', 'float: left;')
    link.text = tag;
    tagSection.appendChild(link);

    var contentDiv = document.createElement('div');
    contentDiv.setAttribute('id', tag);
    contentDiv.setAttribute('style', 'clear: left;')
    contentDiv.setAttribute('class', 'section');
    tagSection.appendChild(contentDiv);

    link.setAttribute('onclick', `expandCollapse("${tag}")`);
    divToggleMap[tag] = 0;  // 1 = show, 0 = hide

    addDivContent(contentDiv, tag, tags[tag]);

    return tagSection;
}

Exibir os resultados da pesquisa na página da Web

A buildDiv() função chama a addDivContent função para construir o conteúdo dobrável <div>de cada tag.

Os conteúdos das tags incluem o JSON das resposta das mesmas. Inicialmente, apenas os primeiros 100 caracteres do JSON são mostrados, mas você pode clicar na cadeia de caracteres JSON para mostrar todos os JSON. Se clicar outra vez, a cadeia JSON retrai-se novamente para os cem carateres.

Em seguida, adicione os tipos de ações que estão na tag. Para cada tipo de ação, chame as funções apropriadas para adicionar seus insights:

function addDivContent(div, tag, json) {

    // Adds the first 100 characters of the json that contains
    // the tag's data. The user can click the text to show the
    // full json. They can click it again to collapse the json.
    var para = document.createElement('p');
    para.textContent = String(json).substr(0, 100) + '...';
    para.setAttribute('title', 'click to expand');
    para.setAttribute('style', 'cursor: pointer;')
    para.setAttribute('data-json', json);
    para.addEventListener('click', function(e) {
        var json = e.target.getAttribute('data-json');

        if (e.target.textContent.length <= 103) {  // 100 + '...'
            e.target.textContent = json;
            para.setAttribute('title', 'click to collapse');
        }
        else {
            para.textContent = String(json).substr(0, 100) + '...';
            para.setAttribute('title', 'click to expand');
        }
    });
    div.appendChild(para); 

    var parsedJson = JSON.parse(json);

    // Loop through all the actions in the tag and display them.
    for (var j = 0; j < parsedJson.actions.length; j++) {
        var action = parsedJson.actions[j];

        var subSectionDiv = document.createElement('div');
        subSectionDiv.setAttribute('class', 'subSection');
        div.appendChild(subSectionDiv);

        var h4 = document.createElement('h4');
        h4.innerHTML = action.actionType;
        subSectionDiv.appendChild(h4);

        if (action.actionType === 'ImageResults') {
            addImageWithWebSearchUrl(subSectionDiv, parsedJson.image, action);
        }
        else if (action.actionType === 'DocumentLevelSuggestions') {
            addRelatedSearches(subSectionDiv, action.data.value);
        }
        else if (action.actionType === 'RelatedSearches') {
            addRelatedSearches(subSectionDiv, action.data.value);
        }
        else if (action.actionType === 'PagesIncluding') {
            addPagesIncluding(subSectionDiv, action.data.value);
        }
        else if (action.actionType === 'VisualSearch') {
            addRelatedImages(subSectionDiv, action.data.value);
        }
        else if (action.actionType === 'Recipes') {
            addRecipes(subSectionDiv, action.data.value);
        }
        else if (action.actionType === 'ShoppingSources') {
            addShopping(subSectionDiv, action.data.offers);
        }
        else if (action.actionType === 'ProductVisualSearch') {
            addProducts(subSectionDiv, action.data.value);
        }
        else if (action.actionType === 'TextResults') {
            addTextResult(subSectionDiv, action);
        }
        else if (action.actionType === 'Entity') {
            addEntity(subSectionDiv, action);
        }
    }
}

Exibir insights para diferentes ações

As funções a seguir exibem insights para diferentes ações. As funções fornecem uma imagem clicável ou um link clicável que envia você para uma página da Web com mais informações sobre a imagem. Esta página é hospedada pela Bing.com ou pelo site original da imagem. Nem todos os dados dos insights são exibidos neste aplicativo. Para ver todos os campos disponíveis para uma perceção, consulte a referência Imagens - Pesquisa Visual.

Nota

Há uma quantidade mínima de informações de insight que você deve exibir na página. Consulte os requisitos de uso e exibição da API de Pesquisa do Bing para saber mais.

Insights do RelatedImages

A addRelatedImages() função cria um título para cada um dos sites que hospedam a imagem relacionada, iterando através da lista de RelatedImages ações e anexando uma tag para o exterior <div> para cada um<img>:

    function addRelatedImages(div, images) {
        var length = (images.length > 10) ? 10 : images.length;

        // Set the title to the website that hosts the image. The title displays
        // when the user hovers over the image.

        // Make the image clickable. If the user clicks the image, they're taken
        // to the image in Bing.com.

        for (var j = 0; j < length; j++) {
            var img = document.createElement('img');
            img.setAttribute('src', images[j].thumbnailUrl + '&w=120&h=120');
            img.setAttribute('style', 'margin: 20px 20px 0 0; cursor: pointer;');
            img.setAttribute('title', images[j].hostPageDisplayUrl);
            img.setAttribute('data-webSearchUrl', images[j].webSearchUrl)

            img.addEventListener('click', function(e) {
                var url = e.target.getAttribute('data-webSearchUrl');
                window.open(url, 'foo');
            })

            div.appendChild(img);
        }
    }

PáginasIncluindo informações

A addPagesIncluding() função cria um link para cada um dos sites que hospedam a imagem carregada, iterando através da lista de PagesIncluding ações e anexando uma tag para o exterior <div> para cada um<img>:


    // Display links to the first 5 webpages that include the image.
    // TODO: Add 'more' link in case the user wants to see all of them.
    function addPagesIncluding(div, pages) {
        var length = (pages.length > 5) ? 5 : pages.length;

        for (var j = 0; j < length; j++) {
            var page = document.createElement('a');
            page.text = pages[j].name;
            page.setAttribute('href', pages[j].hostPageUrl);
            page.setAttribute('style', 'margin: 20px 20px 0 0');
            page.setAttribute('target', '_blank')
            div.appendChild(page);

            div.appendChild(document.createElement('br'));
        }
    }

Insights do RelatedSearches

A addRelatedSearches() função cria um link para o site que hospeda a imagem, iterando através da lista de RelatedSearches ações e anexando uma <img> tag para o exterior <div> para cada um:


    // Display the first 10 related searches. Include a link with the image
    // that when clicked, takes the user to Bing.com and displays the 
    // related search results.
    // TODO: Add 'more' link in case the user wants to see all of them.
    function addRelatedSearches(div, relatedSearches) {
        var length = (relatedSearches.length > 10) ? 10 : relatedSearches.length;

        for (var j = 0; j < length; j++) {
            var childDiv = document.createElement('div');
            childDiv.setAttribute('class', 'stackLink');
            div.appendChild(childDiv);

            var img = document.createElement('img');
            img.setAttribute('src', relatedSearches[j].thumbnail.url + '&w=120&h=120');
            img.setAttribute('style', 'margin: 20px 20px 0 0;');
            childDiv.appendChild(img);

            var relatedSearch = document.createElement('a');
            relatedSearch.text = relatedSearches[j].displayText;
            relatedSearch.setAttribute('href', relatedSearches[j].webSearchUrl);
            relatedSearch.setAttribute('target', '_blank');
            childDiv.appendChild(relatedSearch);

        }
    }

Insights de receitas

A addRecipes() função cria um link para cada uma das receitas retornadas iterando pela lista de Recipes ações e anexando uma <img> tag ao exterior <div> para cada uma:

    // Display links to the first 10 recipes. Include the recipe's rating,
    // if available.
    // TODO: Add 'more' link in case the user wants to see all of them.
    function addRecipes(div, recipes) {
        var length = (recipes.length > 10) ? 10 : recipes.length;

        for (var j = 0; j < length; j++) {
            var para = document.createElement('p');

            var recipe = document.createElement('a');
            recipe.text = recipes[j].name;
            recipe.setAttribute('href', recipes[j].url);
            recipe.setAttribute('style', 'margin: 20px 20px 0 0');
            recipe.setAttribute('target', '_blank')
            para.appendChild(recipe);

            if (recipes[j].hasOwnProperty('aggregateRating')) {
                var span = document.createElement('span');
                span.textContent = 'rating: ' + recipes[j].aggregateRating.text;
                para.appendChild(span);
            }

            div.appendChild(para);
        }
    }

Informações sobre compras

A addShopping() função cria um link para todos os resultados de compras retornados iterando através da lista de RelatedImages ações e anexando uma <img> tag para o exterior <div> para cada um:

    // Display links for the first 10 shopping offers.
    // TODO: Add 'more' link in case the user wants to see all of them.
    function addShopping(div, offers) {
        var length = (offers.length > 10) ? 10 : offers.length;

        for (var j = 0; j < length; j++) {
            var para = document.createElement('p');

            var offer = document.createElement('a');
            offer.text = offers[j].name;
            offer.setAttribute('href', offers[j].url);
            offer.setAttribute('style', 'margin: 20px 20px 0 0');
            offer.setAttribute('target', '_blank')
            para.appendChild(offer);

            var span = document.createElement('span');
            span.textContent = 'by ' + offers[j].seller.name + ' | ' + offers[j].price + ' ' + offers[j].priceCurrency;
            para.appendChild(span);

            div.appendChild(para);
        }
    }

Insights sobre os produtos

A addProducts() função cria um link para quaisquer resultados de produtos retornados iterando através da lista de Products ações e anexando uma <img> tag ao exterior <div> para cada um:


    // Display the first 10 related products. Display a clickable image of the
    // product that takes the user to Bing.com search results for the product.
    // If there are any offers associated with the product, provide links to the offers.
    // TODO: Add 'more' link in case the user wants to see all of them.
    function addProducts(div, products) {
        var length = (products.length > 10) ? 10 : products.length;

        for (var j = 0; j < length; j++) {
            var childDiv = document.createElement('div');
            childDiv.setAttribute('class', 'stackLink');
            div.appendChild(childDiv);

            var img = document.createElement('img');
            img.setAttribute('src', products[j].thumbnailUrl + '&w=120&h=120');
            img.setAttribute('title', products[j].name);
            img.setAttribute('style', 'margin: 20px 20px 0 0; cursor: pointer;');
            img.setAttribute('data-webSearchUrl', products[j].webSearchUrl)
            img.addEventListener('click', function(e) {
                var url = e.target.getAttribute('data-webSearchUrl');
                window.open(url, 'foo');
            })
            childDiv.appendChild(img);

            if (products[j].insightsMetadata.hasOwnProperty('aggregateOffer')) {
                if (products[j].insightsMetadata.aggregateOffer.offerCount > 0) {
                    var offers = products[j].insightsMetadata.aggregateOffer.offers;

                    // Show all the offers. Not all markets provide links to offers.
                    for (var i = 0; i < offers.length; i++) {  
                        var para = document.createElement('p');

                        var offer = document.createElement('a');
                        offer.text = offers[i].name;
                        offer.setAttribute('href', offers[i].url);
                        offer.setAttribute('style', 'margin: 20px 20px 0 0');
                        offer.setAttribute('target', '_blank')
                        para.appendChild(offer);

                        var span = document.createElement('span');
                        span.textContent = 'by ' + offers[i].seller.name + ' | ' + offers[i].price + ' ' + offers[i].priceCurrency;
                        para.appendChild(span);

                        childDiv.appendChild(para);
                    }
                }
                else {  // Otherwise, just show the lowest price that Bing found.
                    var offer = products[j].insightsMetadata.aggregateOffer;

                    var para = document.createElement('p');
                    para.textContent = `${offer.name} | ${offer.lowPrice} ${offer.priceCurrency}`; 

                    childDiv.appendChild(para);
                }
            }
        }
    }

Insights do TextResult

A addTextResult() função exibe qualquer texto que foi reconhecido na imagem:


    function addTextResult(div, action) {
        var text = document.createElement('p');
        text.textContent = action.displayName;
        div.appendChild(text);
    }

A addEntity() função exibe um link que leva o usuário a Bing.com onde ele pode obter detalhes sobre o tipo de entidade na imagem, se alguma foi detetada:

    // If the image is of a person, the tag might include an entity
    // action type. Display a link that takes the user to Bing.com
    // where they can get details about the entity.
    function addEntity(div, action) {
        var entity = document.createElement('a');
        entity.text = action.displayName;
        entity.setAttribute('href', action.webSearchUrl);
        entity.setAttribute('style', 'margin: 20px 20px 0 0');
        entity.setAttribute('target', '_blank');
        div.appendChild(entity);
    }

A addImageWithWebSearchUrl() função exibe uma imagem clicável para o <div> que leva o usuário aos resultados da pesquisa em Bing.com:

    function addImageWithWebSearchUrl(div, image, action) {
        var img = document.createElement('img');
        img.setAttribute('src', image.thumbnailUrl + '&w=120&h=120');
        img.setAttribute('style', 'margin: 20px 20px 0 0; cursor: pointer;');
        img.setAttribute('data-webSearchUrl', action.webSearchUrl);
        img.addEventListener('click', function(e) {
            var url = e.target.getAttribute('data-webSearchUrl');
            window.open(url, 'foo');
        })
        div.appendChild(img);
    }

Adicionar um estilo CSS

Adicione a seguinte <style> seção à <head> tag para organizar o layout da página da Web:

        <style>

            .thumb {
                height: 75px;
                border: 1px solid #000;
            }

            .stackLink {
                width:180px;
                min-height:210px;
                display:inline-block;
            }
            .stackLink a {
                float:left;
                clear:left;
            }

            .section {
                float:left;
                display:none;
            }

            .subSection {
                clear:left;
                float:left;
            }

        </style>

Próximos passos