3

I am trying to use the Bing Search Image API to search through an array of items that I have called names. I have used the documentation on https://learn.microsoft.com/en-us/azure/cognitive-services/bing-image-search/quickstarts/nodejs for getting started on sending a request for JSON parsing. I am able to receive the image URLs back when calling the names individually, however, when I run the bing_image_search function through a for loop, the console prints that it couldn't find image results and if it does find some of them, they are not returned in order that the bing_image_search function calls each name in. Below is the code to show what I have going now. Any help is appreciated.

  var imagesArr = [];
  let num_results = 1;
  var names = []; // assume already filled with names

  let response_handler = function (response) {
    let body = '';
    response.on('data', function (d) {
        body += d;
    });
    response.on('end', function () {
        let imageResults = JSON.parse(body);
          if (imageResults.value) {
            let imageLink = imageResults.value[0].thumbnailUrl;
            //console.log(`Image result count: ${imageResults.value.length}`);
            //imagesArr.push(imageLink);
            //console.log(imageLink);
            return imageLink;
          }
          else {
            console.log("Couldn't find image results!");
          }
        
          });
    response.on('error', function (e) {
        console.log('Error: ' + e.message);
    });
  
  };

  let bing_image_search = function (search) {
    console.log('Searching images for: ' + search);
    let request_params = {
          method : 'GET',
          hostname : host,
          path : path + '?q=' + encodeURIComponent(search) + '&count=' + num_results,
          headers : {
              'Ocp-Apim-Subscription-Key' : subscriptionKey,
          }
      };
  
      let req = https.request(request_params, response_handler);
      req.end();
    }

  for(index in names) {
    bing_image_search(names[index]);
  }
Rajat Khare
  • 522
  • 8
  • 26

1 Answers1

1

You might want to consider wrapping the bing_image_search logic in a promise to make it easier to control the flow... See if something like the below helps you:

const { RateLimiter } = require("limiter");
const limiter = new RateLimiter({ tokensPerInterval: 3, interval: "second" });

var imagesArr = [];
let num_results = 1;
var names = []; // assume already filled with names

function bing_image_search(search) {
    return new Promise(async (resolve,reject)=>{
        const remainingMessages = await limiter.removeTokens(1);
        console.log('Searching images for: ' + search);
        let request_params = {
            method : 'GET',
            hostname : host,
            path : path + '?q=' + encodeURIComponent(search) + '&count=' + num_results,
            headers : {
              'Ocp-Apim-Subscription-Key' : subscriptionKey,
            }
        };
  
        let req = https.request(request_params, (response)=>{
            let body = '';
            response.on('data', function (d) {
                body += d;
            });
            response.on('end', function () {
                let imageResults = JSON.parse(body);
                if (imageResults.value) {
                    let imageLink = imageResults.value[0].thumbnailUrl;
                    //console.log(`Image result count: ${imageResults.value.length}`);
                    //imagesArr.push(imageLink);
                    //console.log(imageLink);
                    resolve(imageLink);
                }
                else {
                    resolve("Couldn't find image results!");
                }
            });
            response.on('error', function (e) {
                reject(e);
            });       
        });
      
        req.on('error', (e) => {
            reject(e);
        });
      
        req.end();
    })
}

(async()=>{
    let imgUrls = []
    for (const name of names){
        let imgurl = await bing_image_search(name)
        imgUrls.push(imgurl)
    }   
})()
Sully
  • 395
  • 3
  • 7
  • Hi Sully, thanks for your comment. I got the following syntax error when trying your code? Any advice on this? "let results = await Promise.all(names.map(bing_image_search)); SyntaxError: await is only valid in async function" – Rajat Khare Jun 24 '21 at 20:50
  • Sorry - you could've added a .then handler, or wrapped it in an IIFE (I updated the sample to show the IIFE) – Sully Jun 24 '21 at 21:11
  • Hi Sully, so your solution partially works. Every time I run it in pairs of 3 names at a time it works, however if I do more names than that, it doesn't find the images some of the times. I have around 200 names to go through so if you have any advice I would appreciate it. – Rajat Khare Jun 24 '21 at 21:49
  • If you're sure each of the 200 or so names should get a response, you might be hitting a rate limit on the API. Check the documentation to see if they limit requests to a certain number within a time frame... you'd then need to add something like p-limit or something like this: https://www.npmjs.com/package/limiter – Sully Jun 24 '21 at 21:55
  • Looks like they have a 3 transactions per second limit on the free one, which is probably what you're hitting... https://azure.microsoft.com/en-us/pricing/details/cognitive-services/search-api/ try incorporating limiter to get around that – Sully Jun 24 '21 at 21:59
  • Hey Sully, I'm trying to do the limiter, but am running in to this problem : import {RateLimiter} from "limiter"; ^^^^^^ SyntaxError: Cannot use import statement outside a module. Any thoughts? – Rajat Khare Jun 25 '21 at 09:51
  • I've updated the sample code with a suggestion on how to incorporate limiter. It'll need some cleaning up, but that should work for you – Sully Jun 25 '21 at 14:24
  • Hey Sully, I tried your updated solution, but am still running into the issue where it "Couldn't find the image results." I tried moving around the remainingMessages line, but that doesn't seem to work – Rajat Khare Jun 25 '21 at 23:56
  • Can you put some logging in the response handler to see what's coming back? let req = https.request(request_params, (response)=>{ console.log(response) let body = ''; response.on('data', function (d) { console.log(d) body += d; }); – Sully Jun 28 '21 at 14:49