Skip to content

Commit

Permalink
vision: support image URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenplusplus committed Apr 18, 2016
1 parent 5199cad commit c0f5573
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 92 deletions.
93 changes: 4 additions & 89 deletions lib/common/grpc-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,95 +33,10 @@ var path = require('path');
var Service = require('./service.js');

/**
* @const {object} - A map of protobuf codes to HTTP status codes.
* @type {module:common/util}
* @private
*/
var HTTP_ERROR_CODE_MAP = {
0: {
code: 200,
message: 'OK'
},

1: {
code: 499,
message: 'Client Closed Request'
},

2: {
code: 500,
message: 'Internal Server Error'
},

3: {
code: 400,
message: 'Bad Request'
},

4: {
code: 504,
message: 'Gateway Timeout'
},

5: {
code: 404,
message: 'Not Found'
},

6: {
code: 409,
message: 'Conflict'
},

7: {
code: 403,
message: 'Forbidden'
},

8: {
code: 429,
message: 'Too Many Requests'
},

9: {
code: 412,
message: 'Precondition Failed'
},

10: {
code: 409,
message: 'Conflict'
},

11: {
code: 400,
message: 'Bad Request'
},

12: {
code: 501,
message: 'Not Implemented'
},

13: {
code: 500,
message: 'Internal Server Error'
},

14: {
code: 503,
message: 'Service Unavailable'
},

15: {
code: 500,
message: 'Internal Server Error'
},

16: {
code: 401,
message: 'Unauthorized'
}
};
var util = require('./util.js');

/**
* Service is a base class, meant to be inherited from by a "service," like
Expand Down Expand Up @@ -243,8 +158,8 @@ GrpcService.prototype.request = function(protoOpts, reqOpts, callback) {

service[protoOpts.method](reqOpts, function(err, resp) {
if (err) {
if (HTTP_ERROR_CODE_MAP[err.code]) {
var httpError = HTTP_ERROR_CODE_MAP[err.code];
if (util.HTTP_ERROR_CODE_MAP[err.code]) {
var httpError = util.HTTP_ERROR_CODE_MAP[err.code];
err.code = httpError.code;
}

Expand Down
93 changes: 93 additions & 0 deletions lib/common/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,3 +545,96 @@ function normalizeArguments(globalContext, localConfig, options) {
}

util.normalizeArguments = normalizeArguments;

/**
* @const {object} - A map of protobuf codes to HTTP status codes.
* @private
*/
var HTTP_ERROR_CODE_MAP = {
0: {
code: 200,
message: 'OK'
},

1: {
code: 499,
message: 'Client Closed Request'
},

2: {
code: 500,
message: 'Internal Server Error'
},

3: {
code: 400,
message: 'Bad Request'
},

4: {
code: 504,
message: 'Gateway Timeout'
},

5: {
code: 404,
message: 'Not Found'
},

6: {
code: 409,
message: 'Conflict'
},

7: {
code: 403,
message: 'Forbidden'
},

8: {
code: 429,
message: 'Too Many Requests'
},

9: {
code: 412,
message: 'Precondition Failed'
},

10: {
code: 409,
message: 'Conflict'
},

11: {
code: 400,
message: 'Bad Request'
},

12: {
code: 501,
message: 'Not Implemented'
},

13: {
code: 500,
message: 'Internal Server Error'
},

14: {
code: 503,
message: 'Service Unavailable'
},

15: {
code: 500,
message: 'Internal Server Error'
},

16: {
code: 401,
message: 'Unauthorized'
}
};

util.HTTP_ERROR_CODE_MAP = HTTP_ERROR_CODE_MAP;
55 changes: 52 additions & 3 deletions lib/vision/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var fs = require('fs');
var is = require('is');
var nodeutil = require('util');
var prop = require('propprop');
var request = require('request');

/**
* @type {module:storage/file}
Expand Down Expand Up @@ -315,12 +316,20 @@ Vision.prototype.detect = function(images, options, callback) {
return;
}

var originalResp = extend(true, {}, resp);
var errors = [];

function mergeArrayOfObjects(arr) {
return extend.apply(null, arr);
}

function formatAnnotationBuilder(type) {
return function(annotation) {
if (type === 'error') {
errors.push(Vision.formatError_(annotation));
return [];
}

var formatMethodMap = {
faceAnnotations: Vision.formatFaceAnnotation_,
imagePropertiesAnnotation: Vision.formatImagePropertiesAnnotation_,
Expand All @@ -335,8 +344,6 @@ Vision.prototype.detect = function(images, options, callback) {
};
}

var originalResp = extend(true, {}, resp);

var detections = images
.map(function() {
// Group detections by image...
Expand Down Expand Up @@ -412,8 +419,21 @@ Vision.prototype.detect = function(images, options, callback) {
return annotations;
});

var respErrors = null;
if (errors.length > 0) {
respErrors = errors;
}

// If only a single image was given, expose it from the array.
callback(null, isSingleImage ? detections[0] : detections, originalResp);
if (isSingleImage) {
if (respErrors) {
respErrors = respErrors[0];
}

detections = detections[0];
}

callback(respErrors, detections, originalResp);
});
});
};
Expand Down Expand Up @@ -1178,6 +1198,24 @@ Vision.findImages_ = function(images, callback) {
return;
}

// File is a URL.
if (image.indexOf('http') === 0) {
request({
method: 'GET',
uri: image,
encoding: 'base64'
}, function(err, resp, body) {
if (err) {
callback(err);
return;
}

callback(null, { content: body });
});

return;
}

// File exists on disk.
fs.readFile(image, { encoding: 'base64' }, function(err, contents) {
if (err) {
Expand Down Expand Up @@ -1234,6 +1272,17 @@ Vision.formatEntityAnnotation_ = function(entityAnnotation, options) {
return formattedEntityAnnotation;
};

/**
* Format an error from the API.
*
* @private
*/
Vision.formatError_ = function(error) {
var statusError = new Error(error.message);
statusError.code = util.HTTP_ERROR_CODE_MAP[error.code].code;
return statusError;
};

/**
* Format a raw face annotation response from the API.
*
Expand Down
25 changes: 25 additions & 0 deletions system-test/vision.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
'use strict';

var assert = require('assert');
var fs = require('fs');
var http = require('http');
var is = require('is');
var multiline = require('multiline');
var path = require('path');
Expand All @@ -36,6 +38,29 @@ describe('Vision', function() {
vision = new Vision(env);
});

it('should detect from a URL', function(done) {
var server = http.createServer(function(req, res) {
fs.readFile(IMAGES.logo, function(err, resp) {
assert.ifError(err);
res.end(resp);
});
});

server.listen(8800, function(err) {
assert.ifError(err);

var url = 'http://localhost:8800/logo.png';

vision.detectLogos(url, function(err, logos) {
assert.ifError(err);

assert.deepEqual(logos, ['Google']);

done();
});
});
});

it('should perform multiple detections', function(done) {
var detectionTypes = ['faces', 'labels', 'safeSearch'];

Expand Down

0 comments on commit c0f5573

Please sign in to comment.