AWS Lambda с API Google Vision выдает PEM_read_bio: нет строки запуска или ошибка ::ENAMETOOLONG

#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();
    });
}