【云原生】在 React Native 中使用 AWS Textract 实现文本提取

Amazon Textract 是 Amazon 推出的一项机器学习服务,可将扫描文档、PDF 和图像中的文本、手写文字提取到文本文档中,然后可以将其存储在任何类型的存储服务中,例如 DynamoDB、s3 等。

今天我将介绍从 React Native 移动应用程序中捕获或选择图像并将这些图像上传到 S3 的过程,然后一旦我们使用 API Gateway 触发 lambda 函数,就会从这些图像中提取数据,然后在处理完数据后我们 会将这些数据作为 DynamoDB 记录插入。大致的过程如下图所示:

在这里插入图片描述

在开始实战前,我假设你对AWS 的 lambda 函数 和 API Gateway 已经了解了。同时,请准备好如下实战环境:

  • npm or yarn
  • react-native > 0.59
  • aws-amplify
  • nodejs
  • aws-sdk

我会将内容分为 2 部分来讲解:

  1. 前端
  2. 后端

前端

在本节中,我们将处理我们在移动应用程序中捕获的图像,并将图像上传到 S3 中,以便我们的后端从这些图像中提取数据。首先,我们将从安装开始:

  • 安装 aws-amplify,它会用在 React Native 中。 在命令行中执行如下命令: npm install aws-amplify 或使用 npm install @aws-amplify/api @aws-amplify/core @aws-amplify/storage 因为我们不需要所有的 aws-amplify 库。
  • 安装 react-native-image-picker : 它能从设备库或相机中选择照片。 执行如下命令: npm install react-native-image-picker

接下来,我们将从实现两个函数开始,一个是用户从库中选择图像,一个是从相机中选择图像

代码语言:javascript
复制
import {launchCamera, launchImageLibrary} from 'react-native-image-picker';

const options = {
mediaType: 'photo',
quality: 0.5,
includeBase64: true,
};
// 从库中选择图像
const libraryPickerHandler = () => {
launchImageLibrary(options, async (response) => {
if (response.didCancel) {
console.log('用户取消了图像选择');
} else if (response.errorMessage) {
console.log('ImagePicker Error: ', response.errorMessage);
} else {
await onImageSelect(response?.assets[0].uri);
}
});
};
// 从相机中提取图像
const cameraPickerHandler = async () => {
launchCamera(options, async (response) => {
if (response.didCancel) {
console.log('用户取消了图像选择');
} else if (response.errorMessage) {
console.log('ImagePicker Error: ', response.errorMessage);
} else {
await onImageSelect(response?.assets[0].uri);
}
});
};

onImageSelect 函数将处理图像上传到 S3,并将 S3 密钥发送到我们将在后端部分开发的 API 端点 /textract-scan

代码语言:javascript
复制
import Storage from '@aws-amplify/storage';
import API from '@aws-amplify/api';
// or
import { Storage, API } from 'aws-amplify';

const onImageSelect = async (uri: string) => {
let imageResponse = await fetch(uri);
const blob = await imageResponse.blob();

// timestamp for random image names
let naming = {new Date().getTime()}.jpeg;

const s3Response = await Storage.put(naming, blob, {
contentType: 'image/jpeg',
level: 'protected',
});

await API.post('your-endpoint-name', '/main/textract-scan', {
body: {
imageKey: s3Response.key,
},
});
};

目前,前端部分就完成了。接下来,看后端部分。

后端

在本节中,我们将处理从将用 nodejs 编写的图像中提取数据。首先安装如下依赖:

  • aws-sdk,它使你能够轻松地使用 Amazon Web Services。执行如下命令:
    npm install aws-sdk or yarn add aws-sdk

我们将创建一个名为 textract.ts 的文件,其中将包含名为 textractScanlambda 函数。textractScan 将是我们的主要函数,它将被前端通过指定的 api 调用。该函数将是一个 post 方法,它将在 body 中获取一个 imageKey 属性。 此 imageKey 表示指定 Bucket 中的 S3 对象键。

你需要将其添加到功能块内的 serverless.yml 文件中:

代码语言:javascript
复制
TextractScanLambda:
handler: path-to-your-file/textract.textractScan
events:
- http:
method: post
path: main/textract-scan
authorizer: aws_iam

现在在 textract.ts 文件中,我们开始实现 lambda 函数。让我们首先编写 Textract 函数来分析我们将在 lambda 函数中使用的 Text:

代码语言:javascript
复制
import { Textract } from 'aws-sdk';

const analyzeText = async(key: string) => {
const payload = {
Document: {
S3Object: {
//the bucket where you uploaded your images
Bucket: 'BUCKET_NAME',
Name: key,
},
},
};

return new Textract().detectDocumentText(payload);

}

现在我们开始编写我们的 lambda 函数 textractScan:

代码语言:javascript
复制
const textractScan = async (event: AWSLambda.APIGatewayProxyEvent) => {
try {
console.log(event);
const body = JSON.parse(event.body);

const { imageKey } = body;

const analyzeTextResult = await analyzeText(imageKey);

} catch (e) {
console.log(e);
return {
statusCode: 500,
body: JSON.stringify({ message: 'ERROR_ANALYZING_DOCUMENT' }),
};
}
};

现在我们完成了该功能,我们可以使用它从图像中提取文本。 analyzeTextResult 中的结果将包含一个对象数组,其中包含在文档中检测到的文本,但是从该对象中提取我们需要的实际数据将非常耗时。

这就是创建 aws-textract-json-parser 的原因,该库将来自 AWS Textract 的 json 响应解析为更可用的格式,然后你可以将其插入 DynamoDB:

代码语言:javascript
复制
import { DynamoDB } from 'aws-sdk';

const textractScan = async (event: AWSLambda.APIGatewayProxyEvent) => {
try {
console.log(event);
const body = JSON.parse(event.body);

const { imageKey } = body;

const analyzeTextResult = await analyzeText(imageKey);
const parsedData = await AWSJsonParser(analyzeTextResult);
console.info(parsedData);
const rawData = parsedData.getRawData();
console.info(data);
  if (data.length === 0) {
    console.error('no text detected');

return {
statusCode: 400,
body: JSON.stringify({ message: 'INVALID_DOCUMENT' }),
};
}
const payload = {
...someData,
textractData: rawData
}
new DynamoDB.DocumentClient(payload).put;

....

} catch (e) {
console.log(e);
return {
statusCode: 500,
body: JSON.stringify({ message: 'ERROR_ANALYZING_DOCUMENT' }),
};
}
};

现在,你可以实现许多需要用户拍照的场景,并通过简单的步骤提取数据并将其与他的个人资料相关联。