Vamos construir una aplicación de reconocimiento de objetos en imágenes. No olvides que puedes encontrar el código fuente de la aplicación en github.com/juandc/serverless-rekognition.
Si quieres aprender todo sobre los servicios de Amazon Web Services puedes tomar el Curso de Fundamentos de AWS Cloud.
Los servidores no son más que computadoras que atienden las peticiones de un usuario y le devuelven una respuesta por internet.
Muchas empresas nos ofrecen un alquiler de sus servidores, pero no siempre es lo más conveniente: Tenemos que ocuparnos del sistema operativo, las actualizaciones, instalar los lenguajes de programación, aumentar o disminuir el número de servidores que necesitamos (porque debemos pagar aunque nadie esté usando nuestra aplicación), entre muchas otras complicaciones.
Serverless resuelve todos estos problemas: En vez de pagar por una cantidad de servidores durante un tiempo, le pediremos a nuestros proveedores (Amazon, Google, Microsoft) que nos cobren únicamente por las veces que nuestros usuarios entren a nuestra aplicación. Ahora no debemos preocuparnos por la administración de nuestros servidores, solo por programar.
Serverless Framework es una herramienta open source para construir e implementar aplicaciones serverless. Tiene soporte para las tecnologías más populares como AWS Lambda, Microsoft Azure, Google Cloud Platform e IBM OpenWhisk. Nos va a ser muy útil para desarrollar nuestra aplicación super rápido y simple.
AWS Recognition es un servicio basado en Deep Learning (inteligencia artificial). Su trabajo es detectar objetos, personas, celebridades o actividades especiales en el contenido de fotografías y videos. Nuestra aplicación va a utilizar esta herramienta para etiquetar el contenido de nuestras imágenes.
Para instalar la herramienta podemos ejecutar el siguiente comando: npm install serverless --global
.
Recuerda pasar las credenciales de IAM a la configuración de Serverless Framework:
sls config credentials -p aws --key TOKEN -s PASSWORD
Para usar esta herramienta solo necesitamos crear el archivo serverless.yml
con los siguientes campos:
service
: El nombre de nuestra aplicación.plugins
: Podemos darle aún más super poderes a nuestra aplicación usando los plugins de serverless. En este caso usaremos serverless-webpack y serverless-offline, pero puedes ver la lista de plugins disponibles en github.com/serverless/plugins.functions
: En esta sección describimos los archivos y eventos que necesita nuestra aplicación para funcionar. Puedes separar tu aplicación en muchas funciones.El objetivo de nuestra aplicación es construir una API a la que podamos pasar la URL de una imagen y nos devuelve información sobre su contenido.
Necesitaremos los siguientes paquetes:
express
para manejar nuestras rutas (/, /api, /api?img=…)serverless-http
para traducir la información de Expressjs a Serverless Frameworkaws-sdk
nos proporciona los métodos necesarios para conectarnos con AWS Rekognitionrequest
para convertir la URL de nuestras imágenes en información que AWS Rekognition pueda entenderserverless-webpack
para traducir nuestro código JavaScript a Serverless Frameworkwebpack
webpack-node-externals
serverless-offline
para probar nuestro código en etapa de desarrollo (por defecto no podemos 😅)Puedes instalar estos paquetes usando los siguientes comandos:
npm i express serverless-http aws-sdk request -S
npm i webpack webpack-node-externals serverless-webpack serverless-offline -D
Ahora vamos a crear los archivos serverless.yml
y webpack.config.js
:
# severless.ymlservice: EL_NOMBRE_DE_TU_APLICACIÓN
provider: name: aws
runtime: nodejs8.10 stage: test
environment: ACCESS_KEY_ID: TU_ACCESS_KEY_ID_DE_IAM
SECRET_ACCESS_KEY: TU_SECRET_ACCESS_KEY_DE_IAM
plugins: - serverless-webpack
- serverless-offline
functions: rekognition: handler: api.default
events: - http: ANY /
- http:'ANY {proxi+}'
// webpack.config.jsconst path = require('path');
const slsw = require('serverless-webpack');
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: slsw.lib.entries,
output: {
libraryTarget: 'commonjs2',
path: path.join(__dirname, '.webpack'),
filename: '[name].js',
},
target: 'node',
externals: [nodeExternals()],
mode: slsw.lib.webpack.isLocal ? 'development' : 'production'
};
El código de nuestra aplicación la vamos a escribir en el archivo api.js, se divide en 5 secciones:
1. Importamos las dependencias:
import serverless from'serverless-http';
import express from'express';
import AWS from'aws-sdk';
import request from'request';
2. Configuración de express
, request
y AWS Rekognition:
const app = express();
const requests = request.defaults({ encoding: null });
const rek = new AWS.Rekognition({
region: 'us-west-2',
accessKeyId: process.env.ACCESS_KEY_ID,
secretAccessKey: process.env.SECRET_ACCESS_KEY,
});
3. Creamos la función GetImageLabels
que nos devuelve la información de nuestras imágenes:
functionGetImageLabels(params, func) {
params = {
img: params.img || params.image || null,
maxLabels: params.maxLabels || params.MaxLabels || 10,
minConfidence: params.minConfidence || params.MinConfidence || 80,
};
if (!params.img) return func(newError('The image param cannot be null.'));
if (params.img.length <= 8) return func(newError('The image param length can not be <= 8.'));
requests.get(params.img, (reqErr, _, body) => {
if (reqErr) return func(newError('Error in request: ' + reqErr));
const rekParams = {
Image: { Bytes: body },
MaxLabels: params.maxLabels,
MinConfidence: params.minConfidence,
};
rek.detectLabels(rekParams, (rekErr, data) => {
if (rekErr) return func(newError('Error in rek: ' + rekErr));
return func(null, data);
});
});
}
4. Definimos las rutas de nuestra API usando la función GetImageLabels
:
app.get('/', (req, res) => {
GetImageLabels(req.query, (err, data) => {
if (err) return res.json({ message: err.message, error: true });
res.json({
image: req.query.img || req.query.image,
message: 'Success!',
data,
});
});
});
5. Y por último, exportamos las rutas de expressjs con ayuda de serverless-http
:
exportdefault serverless(app);
Nuestro archivo completo quedaría así:
// api.jsimport serverless from'serverless-http';
import express from'express';
import AWS from'aws-sdk';
import request from'request';
const app = express();
const requests = request.defaults({ encoding: null });
const rek = new AWS.Rekognition({
region: 'us-west-2',
accessKeyId: process.env.ACCESS_KEY_ID,
secretAccessKey: process.env.SECRET_ACCESS_KEY,
});
app.get('/', (req, res) => {
GetImageLabels(req.query, (err, data) => {
if (err) return res.json({ message: err.message, error: true });
res.json({
image: req.query.img || req.query.image,
message: 'Success!',
data,
});
});
});
functionGetImageLabels(params, func) {
params = {
img: params.img || params.image || null,
maxLabels: params.maxLabels || params.MaxLabels || 10,
minConfidence: params.minConfidence || params.MinConfidence || 80,
};
if (!params.img) return func(newError('The image param cannot be null.'));
if (params.img.length <= 8) return func(newError('The image param length can not be <= 8.'));
requests.get(params.img, (reqErr, _, body) => {
if (reqErr) return func(newError('Error in request: ' + reqErr));
const rekParams = {
Image: { Bytes: body },
MaxLabels: params.maxLabels,
MinConfidence: params.minConfidence,
};
rek.detectLabels(rekParams, (rekErr, data) => {
if (rekErr) return func(newError('Error in rek: ' + rekErr));
return func(null, data);
});
});
}
exportdefault serverless(app);
Para probar que nuestra aplicación esté funcionando podemos correr el siguiente comando:
sls offline start
Ahora si navegamos a http://localhost:3000/?img=http://www.grupocanton.com/all/imagenes/1/2018/07/16/447131_grande_EPFBUm8C.jpg (con una imagen de ejemplo, por supuesto) obtenemos un resultado en tipo JSON con los objetos que Rekognition detecto en nuestra imagen:
{
"image": "http://www.grupocanton.com/all/imagenes/1/2018/07/16/447131_grande_EPFBUm8C.jpg",
"message": "Success!",
"data": {
"Labels": [
{
"Name": "Human",
"Confidence": 99.18035125732422
},
{
"Name": "People",
"Confidence": 99.18035125732422
},
{
"Name": "Person",
"Confidence": 99.18035125732422
},
{
"Name": "Clothing",
"Confidence": 91.23234558105469
},
{
"Name": "Coat",
"Confidence": 91.23234558105469
},
{
"Name": "Overcoat",
"Confidence": 91.23234558105469
},
{
"Name": "Suit",
"Confidence": 91.23234558105469
}
],
"OrientationCorrection": "ROTATE_0"
}
}
Serverless Framework también se puede encargar de configurar nuestro entorno en AWS para hacer deploy, solo tenemos que ejecutar el siguiente comando dentro de la carpeta de nuestro proyecto:
sls deploy
¡Felicidades! Nuestra aplicación funciona correctamente y devuelve las etiquetas de nuestras imágenes. Ahora es tu turno: ¿Cómo podrías mejorar esta aplicación? Puedes dejar el link a tu proyecto en los comentarios. 😏😌
Existen muchos otros servicios de AWS que puedes utilizar con Lambda y Serverless Framework. Recuerda tomar el Curso de Fundamentos de AWS Cloud y toda la Carrera de Amazon Web Services para aprender a integrar los servicios de AWS y construir tu mejor aplicación.
#NuncaParesDeAprender 🤓💚
Se ganó su estrella en github 🙌
En este post también se puede ver un patrón de trabajo que puede aplicar para otros servicios basados en serverless. Como BaaS (Firebase, Supabase) o otras nubes como Azure Functions