├── .gitignore ├── README.md ├── index.js ├── lib ├── clients │ └── v1.js └── models │ ├── Feature.js │ ├── Image.js │ └── Request.js ├── package.json ├── test_annotate.js └── test_annotate_remote.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | tmp/ 3 | .DS_Store 4 | dump.rdb 5 | npm-debug.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node Cloud Vision API 2 | node-cloud-vision-api is a node client wrapper for Cloud Vision API. 3 | 4 | Cloud Vision API Docs 5 | https://cloud.google.com/vision/docs/ 6 | 7 | Note that currently only limited preview for alpha-test users. 8 | 9 | Supported features 10 | 11 | Feature Type | Description 12 | ------------- | ------------- 13 | FACE_DETECTION | Run face detection 14 | LANDMARK_DETECTION | Run models to execute landmark detection 15 | LOGO_DETECTION | Run models to execute product logo detection 16 | LABEL_DETECTION | Run models to execute Image Content Analysis 17 | TEXT_DETECTION | Run models to execute OCR on an image 18 | SAFE_SEARCH_DETECTION | Run models to compute image safe search properties 19 | 20 | 21 | ## Setup 22 | ### Preparation 23 | - Sign up limited preview for Cloud Vision API https://cloud.google.com/vision/ 24 | - Cloud Vision API Key is needed 25 | 26 | ### Install 27 | ` npm install node-cloud-vision-api --save` 28 | 29 | ### Auth 30 | API requests on node-cloud-vision-api is internally managed by [google-api-nodejs-client](https://github.com/google/google-api-nodejs-client/) 31 | 32 | You can setup auth data with the following samples 33 | 34 | * Use Server Key 35 | ```JavaScript 36 | const vision = require('node-cloud-vision-api') 37 | vision.init({auth: 'YOUR_API_KEY'}) 38 | ``` 39 | 40 | * Use OAuth 41 | ```JavaScript 42 | const vision = require('node-cloud-vision-api') 43 | const google = require('googleapis') 44 | const oauth2Client = new google.auth.OAuth2('YOUR_GOOGLE_OAUTH_CLIENT_ID', 'YOUR_GOOGLE_OAUTH_SECRET', 'YOUR_GOOGLE_OAUTH_CALLBACK_URL') 45 | oauth2Client.setCredentials({refresh_token: 'YOUR_GOOGLE_OAUTH_REFRESH_TOKEN'}) 46 | vision.init({auth: oauth2Client}) 47 | ``` 48 | 49 | * For others, see references. 50 | [google-api-nodejs-client](https://github.com/google/google-api-nodejs-client/) 51 | 52 | ## Sample 53 | 54 | ```JavaScript 55 | 'use strict' 56 | const vision = require('node-cloud-vision-api') 57 | 58 | // init with auth 59 | vision.init({auth: 'YOUR_API_KEY'}) 60 | 61 | // construct parameters 62 | const req = new vision.Request({ 63 | image: new vision.Image('/Users/tejitak/temp/test1.jpg'), 64 | features: [ 65 | new vision.Feature('FACE_DETECTION', 4), 66 | new vision.Feature('LABEL_DETECTION', 10), 67 | ] 68 | }) 69 | 70 | // send single request 71 | vision.annotate(req).then((res) => { 72 | // handling response 73 | console.log(JSON.stringify(res.responses)) 74 | }, (e) => { 75 | console.log('Error: ', e) 76 | }) 77 | ``` 78 | See more in [test_annotate.js](https://github.com/tejitak/node-cloud-vision-api/blob/master/test_annotate.js) 79 | 80 | ## Remote image file sample 81 | Image files on web can be specified with 'url' paramters in Image object 82 | 83 | ```JavaScript 84 | const req = new vision.Request({ 85 | image: new vision.Image({ 86 | url: 'https://scontent-nrt1-1.cdninstagram.com/hphotos-xap1/t51.2885-15/e35/12353236_1220803437936662_68557852_n.jpg' 87 | }), 88 | features: [ 89 | new vision.Feature('FACE_DETECTION', 1), 90 | new vision.Feature('LABEL_DETECTION', 10), 91 | ] 92 | }) 93 | ``` 94 | See more in [test_annotate_remote.js](https://github.com/tejitak/node-cloud-vision-api/blob/master/test_annotate_remote.js) 95 | 96 | ## Multiple Requests per API call 97 | 98 | ```JavaScript 99 | // construct parameters 100 | // 1st image of request is load from local 101 | const req1 = new vision.Request({ 102 | image: new vision.Image({ 103 | path: '/Users/tejitak/temp/test1.jpg' 104 | }), 105 | features: [ 106 | new vision.Feature('FACE_DETECTION', 4), 107 | new vision.Feature('LABEL_DETECTION', 10), 108 | ] 109 | }) 110 | 111 | // 2nd image of request is load from Web 112 | const req2 = new vision.Request({ 113 | image: new vision.Image({ 114 | url: 'https://scontent-nrt1-1.cdninstagram.com/hphotos-xap1/t51.2885-15/e35/12353236_1220803437936662_68557852_n.jpg' 115 | }), 116 | features: [ 117 | new vision.Feature('FACE_DETECTION', 1), 118 | new vision.Feature('LABEL_DETECTION', 10), 119 | ] 120 | }) 121 | 122 | // send multi requests by one API call 123 | vision.annotate([req1, req2]).then((res) => { 124 | // handling response for each request 125 | console.log(JSON.stringify(res.responses)) 126 | }, (e) => { 127 | console.log('Error: ', e) 128 | }) 129 | ``` 130 | See more in [test_annotate_remote.js](https://github.com/tejitak/node-cloud-vision-api/blob/master/test_annotate_remote.js) 131 | 132 | ## Supported Node Version 133 | 134 | Recommended node version is above v4.0.0 because this module is implemented with ES6. 135 | 136 | 137 | ## How to create a PR 138 | 139 | Fork the repository and create a PR to 'develop' branch. 140 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const __ = require('underscore') 3 | 4 | module.exports = { 5 | 6 | Request: require('./lib/models/Request'), 7 | 8 | Feature: require('./lib/models/Feature'), 9 | 10 | Image: require('./lib/models/Image'), 11 | 12 | _client: null, 13 | 14 | init(options) { 15 | this._options = __.defaults(options, {version: 'v1'}) 16 | const Endpoint = require('./lib/clients/' + options.version) 17 | var ep = new Endpoint(options) 18 | ep.google = this 19 | this._client = ep 20 | }, 21 | 22 | annotate(requests) { 23 | return new Promise((resolve, reject) => { 24 | if (!requests) { return reject() } 25 | if (!__.isArray(requests)) { requests = [requests] } 26 | this._client.annotate(requests).then(resolve, reject) 27 | }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/clients/v1.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const __ = require('underscore'), 3 | createAPIRequest = require('googleapis/lib/apirequest') 4 | 5 | const API_ANNOTATE = 'https://vision.googleapis.com/v1/images:annotate' 6 | 7 | class Client { 8 | 9 | constructor(options) { 10 | this._options = options || {} 11 | } 12 | 13 | /** 14 | * annotate 15 | * 16 | * @desc Call cloud vision API 17 | * 18 | * @param {array} requests - Parameters for request 19 | */ 20 | annotate(requests) { 21 | return new Promise((resolve, reject) => { 22 | this._buildRequests(requests).then((params) => { 23 | var parameters = { 24 | options: { 25 | url: API_ANNOTATE, 26 | method: 'POST' 27 | }, 28 | params: { 29 | resource: { 30 | requests: params 31 | } 32 | }, 33 | requiredParams: [], 34 | pathParams: [], 35 | context: this 36 | } 37 | createAPIRequest(parameters, (err, response) => { 38 | if (err) { 39 | reject(err) 40 | } else { 41 | resolve(response) 42 | } 43 | }) 44 | }) 45 | }) 46 | } 47 | 48 | _buildRequests(requests) { 49 | return Promise.all(__.map(requests, (req) => req.build())) 50 | } 51 | } 52 | 53 | module.exports = Client 54 | -------------------------------------------------------------------------------- /lib/models/Feature.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const __ = require('underscore') 3 | 4 | class Feature { 5 | 6 | constructor(type, maxResults) { 7 | const options = __.isObject(type) ? type : { 8 | type: type, 9 | maxResults: maxResults 10 | } 11 | this._type = options.type 12 | this._maxResults = options.maxResults || 10 13 | } 14 | 15 | build() { 16 | return { 17 | type: this._type, 18 | maxResults: this._maxResults 19 | } 20 | } 21 | } 22 | 23 | module.exports = Feature -------------------------------------------------------------------------------- /lib/models/Image.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const fs = require('fs'), 3 | request = require('request'), 4 | __ = require('underscore') 5 | 6 | class Image { 7 | 8 | constructor(path) { 9 | const options = __.isObject(path) ? path : { 10 | path: path 11 | } 12 | this._path = options.path 13 | this._url = options.url 14 | this._base64 = options.base64 15 | } 16 | 17 | load() { 18 | return new Promise((resolve, reject) => { 19 | if (this._path) { 20 | resolve(fs.readFileSync(this._path).toString('base64')) 21 | } else if (this._url) { 22 | this._loadRemote().then(resolve) 23 | } else if (this._base64) { 24 | this._base64 = this._base64.substring(this._base64.indexOf(',') + 1); // remove 'data:image/jpeg;base64,' if included 25 | resolve(this._base64) 26 | } else { 27 | console.log('No path or url are specified in image') 28 | reject() 29 | } 30 | }) 31 | } 32 | 33 | _loadRemote() { 34 | return new Promise((resolve, reject) => { 35 | request({ 36 | url: this._url, 37 | encoding: null 38 | }, (err, response, body) => { 39 | if (!err && response.statusCode == 200) { 40 | resolve(new Buffer(body).toString('base64')) 41 | } else { 42 | console.log('Error while loading image. code: ' + response ? response.statusCode : 'none', err) 43 | // reject(err) 44 | resolve('') 45 | // reject(err) 46 | } 47 | }) 48 | }) 49 | } 50 | 51 | build() { 52 | return new Promise((resolve, reject) => { 53 | this.load().then((cotent) => { 54 | resolve({content: content}) 55 | }) 56 | }) 57 | } 58 | } 59 | 60 | module.exports = Image 61 | -------------------------------------------------------------------------------- /lib/models/Request.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const __ = require('underscore') 3 | 4 | class Request { 5 | 6 | constructor(options) { 7 | options = options || {} 8 | this._image = options.image 9 | this._features = options.features || [] 10 | } 11 | 12 | setImage(image) { 13 | this._image = image 14 | return this 15 | } 16 | 17 | addFeature(feature) { 18 | this._features.push(feature) 19 | return this 20 | } 21 | 22 | build() { 23 | return new Promise((resolve, reject) => { 24 | this._image.load().then((content) => { 25 | resolve({ 26 | image: {content: content}, 27 | features: __.map(this._features, (f) => f.build()) 28 | }) 29 | }).catch((e) => { 30 | reject(e) 31 | }) 32 | }) 33 | } 34 | } 35 | 36 | module.exports = Request -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-cloud-vision-api", 3 | "version": "0.2.0", 4 | "description": "Node client for Google Cloud Vision API", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/tejitak/node-cloud-vision-api.git" 12 | }, 13 | "author": "tejitak", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/tejitak/node-cloud-vision-api/issues" 17 | }, 18 | "homepage": "https://github.com/tejitak/node-cloud-vision-api#readme", 19 | "dependencies": { 20 | "googleapis": "^2.1.7", 21 | "request": "^2.67.0", 22 | "underscore": "^1.8.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test_annotate.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const vision = require('./index') 3 | 4 | // init with auth 5 | vision.init({auth: 'YOUR_API_KEY'}) 6 | 7 | // construct parameters 8 | const req = new vision.Request({ 9 | image: new vision.Image('/Users/tejitak/temp/test1.jpg'), 10 | features: [ 11 | new vision.Feature('FACE_DETECTION', 4), 12 | new vision.Feature('LABEL_DETECTION', 10), 13 | ] 14 | }) 15 | 16 | // send single request 17 | vision.annotate(req).then((res) => { 18 | // handling response 19 | console.log(JSON.stringify(res.responses)) 20 | }, (e) => { 21 | console.log('Error: ', e) 22 | }) -------------------------------------------------------------------------------- /test_annotate_remote.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const vision = require('./index') 3 | 4 | // init with auth 5 | vision.init({auth: 'YOUR_API_KEY'}) 6 | 7 | // construct parameters 8 | // 1st image of request is load from local 9 | const req1 = new vision.Request({ 10 | image: new vision.Image({ 11 | path: '/Users/tejitak/temp/test1.jpg' 12 | }), 13 | features: [ 14 | new vision.Feature('FACE_DETECTION', 4), 15 | new vision.Feature('LABEL_DETECTION', 10), 16 | ] 17 | }) 18 | 19 | // 2nd image of request is load from Web 20 | const req2 = new vision.Request({ 21 | image: new vision.Image({ 22 | url: 'https://scontent-nrt1-1.cdninstagram.com/hphotos-xap1/t51.2885-15/e35/12353236_1220803437936662_68557852_n.jpg' 23 | }), 24 | features: [ 25 | new vision.Feature('FACE_DETECTION', 1), 26 | new vision.Feature('LABEL_DETECTION', 10), 27 | ] 28 | }) 29 | 30 | // send multi requests by one API call 31 | vision.annotate([req1, req2]).then((res) => { 32 | // handling response for each request 33 | console.log(JSON.stringify(res.responses)) 34 | }, (e) => { 35 | console.log('Error: ', e) 36 | }) --------------------------------------------------------------------------------