#javascript #amazon-ec2 #lambda #google-cloud-vision
# #javascript #amazon-ec2 #лямбда #google-cloud-vision
Вопрос:
Цель: пользователь загружает на S3, Lambda запускается для получения файла и отправки в Google Vision API для анализа, возвращая результаты.
В соответствии с этим google-cloud
требуются собственные библиотеки, и они должны быть скомпилированы для ОС, на которой работает lambda. Использование lambda-packager
выдало ошибку, но некоторые поисковые запросы в Интернете показали, что вместо этого используется EC2 с Node и NPM для запуска установки. В духе взлома этого, это то, что я сделал, чтобы заставить его в основном работать *. По крайней мере, lambda перестала выдавать мне ошибки заголовка ELF.
Моя текущая проблема заключается в том, что есть 2 способа вызвать API Vision, ни один из них не работает, и оба возвращают разные ошибки (в основном).
Общий код: этот код всегда один и тот же, он находится в верхней части функции, и я разделяю его, чтобы последующие блоки кода были сосредоточены на проблеме.
'use strict';
const AWS = require('aws-sdk');
const S3 = new AWS.S3();
const Bucket = 'my-awesome-bucket';
const gCloudConfig = {
projectId: 'myCoolApp',
credentials: {
client_email: 'your.serviceapi@project.email.com',
private_key: 'yourServiceApiPrivateKey'
}
}
const gCloud = require('google-cloud')(gCloudConfig);
const gVision = gCloud.vision();
Использование detect()
: Этот код всегда возвращает ошибку Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
. Теоретически это должно работать, потому что URL является общедоступным. Из поиска по ошибке я подумал, что это может быть HTTPS, поэтому я даже попробовал вариант этого, где я заменил HTTPS на HTTP, но получил ту же ошибку.
exports.handler = (event, context, callback) => {
const params = {
Bucket,
Key: event.Records[0].s3.object.key
}
const img = S3.getSignedUrl('getObject', params);
gVision.detect(img, ['labels','text'], function(err, image){
if(err){
console.log('vision error', err);
}
console.log('vision result:', JSON.stringify(image, true, 2));
});
}
Использование detectLabels()
: этот код всегда возвращается Error: ENAMETOOLONG: name too long, open ....[the image in base64]...
. По предложению считалось, что методу не следует передавать изображение base64, а вместо этого общедоступный путь; что объясняет, почему он говорит, что имя слишком длинное (изображение base64 — это вполне URL). К сожалению, это приводит к ошибке PEM сверху. Я также пытался не использовать кодировку base64 и передавать объектный буфер напрямую из aws, но это также привело к ошибке PEM.
exports.handler = (event, context, callback) => {
const params = {
Bucket,
Key: event.Records[0].s3.object.key
}
S3.getObject(params, function(err, data){
const img = data.Body.toString('base64');
gVision.detectLabels(img, function(err, labels){
if(err){
console.log('vision error', err);
}
console.log('vision result:', labels);
});
});
}
Согласно рекомендациям, изображение должно быть закодировано на base64.
Из документов и примеров API и чего-либо еще кажется, что я использую их правильно. Я чувствую, что прочитал все эти документы миллион раз.
Я не уверен, что делать с ошибкой NAMETOOLONG, если она ожидает base64. Эти изображения не превышают 1 МБ.
* Ошибка PEM, похоже, связана с учетными данными, и поскольку я понимаю, как работают все эти учетные данные и как модули компилируются на EC2 (в котором нет каких-либо файлов PEM), это может быть моей проблемой. Может быть, мне нужно настроить некоторые учетные данные перед запуском npm install
, примерно в том же духе, что и при установке на Linux box? Это начинает выходить за рамки моего понимания, поэтому я надеюсь, что кто-то здесь знает.
В идеале использование detect
было бы лучше, потому что я могу указать, что я хочу обнаружить, но просто получить любой действительный ответ от Google было бы здорово. Любые подсказки, которые вы все можете предоставить, были бы очень признательны.
Комментарии:
1. Кроме того, прежде чем кто-либо предложит использовать больше Google Cloud для всего этого, на данный момент это не вариант. Если у AWS есть что-то похожее на Vision API, о котором я не знаю, пожалуйста, дайте мне знать.
Ответ №1:
Итак, разговор с другим коллегой указал мне на то, чтобы рассмотреть возможность отказа от полной загрузки API и использования google-cloud
модуля. Вместо этого я должен рассмотреть возможность использования Cloud REST API через curl
и посмотреть, может ли он работать таким образом.
Короче говоря, выполнение HTTP-запроса и использование REST API для Google Cloud — вот как я решил эту проблему.
Вот рабочая лямбда-функция, которая у меня есть сейчас. Вероятно, все еще нуждается в доработках, но это работает.
'use strict';
const AWS = require('aws-sdk');
const S3 = new AWS.S3();
const Bucket = 'yourBucket';
const fs = require('fs');
const https = require('https');
const APIKey = 'AIza...your.api.key...kIVc';
const options = {
method: 'POST',
host: `vision.googleapis.com`,
path: `/v1/images:annotate?key=${APIKey}`,
headers: {
'Content-Type': 'application/json'
}
}
exports.handler = (event, context, callback) => {
const req = https.request(options, res => {
const body = [];
res.setEncoding('utf8');
res.on('data', chunk => {
body.push(chunk);
});
res.on('end', () => {
console.log('results', body.join(''));
callback(null, body.join(''));
});
});
req.on('error', err => {
console.log('problem with request:', err.message);
});
const params = {
Bucket,
Key: event.Records[0].s3.object.key
}
S3.getObject(params, function(err, data){
const payload = {
"requests": [{
"image": {
"content": data.Body.toString('base64')
},
"features": [{
"type": "LABEL_DETECTION",
"maxResults": 10
},{
"type": "TEXT_DETECTION",
"maxResults": 10
}]
}]
};
req.write(JSON.stringify(payload));
req.end();
});
}