이 글에서는 Tencent cloud의 serverless 서비스인 SCF와 API Explorer에서 제공하는
OCR API를 이용해서 아주 간단한 OCR 로직을 구현하는 방법을 소개한다.
준비물
1) Tencent cloud SCF (AWS lambda와 같은 서버리스 서비스)
2) Tencent cloud OCR API
3) Tencent cloud COS _(AWS S3의 역할을 할 오브젝트 스토리지 서비스)
아키텍처
구현할 로직의 간단한 아키텍처를 그려보면 위와 같다.
1) 유저가 COS 버킷에 텍스트 추출이 필요한 이미지 파일을 업로드 하면,
2) COS Bucket 업로드 이벤트를 트리거로 하여 SCF 함수가 실행되고
3) SCF 함수에서는 OCR API를 호출하고 결과값을 JSON으로 리턴받아 다른 COS 버킷에 txt 파일로 업로드한다.
이렇게 되면 유저는 COS 버킷에 이미지를 업로드 하고 곧바로 다른 버킷에서 OCR 추출결과를 확인하게 된다.
SCF에서는 COS GET/POST/PUT 이벤트 외에도 LB, API Gateway, Kafka 등 다양한 방식의 트리거 방식을 지원하지만 COS를 선택한 이유는 서버 기반 애플리케이션 구축을 하지 않기 위함이기도 하고 COS Browser라는 훌륭한 GUI 툴을 통해 일반 사용자들에게 간단히 결과물을 체험가능하게 하기 때문이다.
물론 마지막 단계에서 전달받은 JSON 결과 값을 DB에 저장해서 활용해도된다.
재료탐색
OCR테스트에 일반적으로 사용되는 영수증, 신분증 등의 물건을 시료로 활용하면 가장 좋지만 텍스트의 위치만 고정되어 있다면 어떤 것도 상관 없으니 준비하도록 한다. 이 글에서는 특정 브랜드의 캐릭터 스티커를 사용한다.
API Explorer
Tencent cloud API Explorer에 있는 API 사용에 앞서 먼저 Tencent cloud 콘솔에서 해당 Tencent cloud 계정의
API KEY (SecretID, SecretKey) 를 발급 받는다.
API KEY 발급이 완료되면, API Explorer 에서 Optical Character Recognition -> GeneralBasicOCR 을 클릭하면 예시코드가 나오는데 편한 언어를 선택하면된다. (이 글은 nodejs 기준으로 한다.) 코드를 살펴보면 tencentcloud-sdk-nodejs-intl-en이라는 npm 모듈을 설치해야함을 알 수 있다.
뒤에 나오겠지만 COS 관련 모듈인 cos-nodejs-sdk-v5도 설치가 필요하므로 런타임 대상 디렉토리에 해당 패키지들을 설치한다.
COS 버킷 생성
Tencent cloud COS 콘솔에서 새 Bucket을 생성한다.
이때 시료의 이미지를 업로드 받을 Bucket 1개, OCR 분석 후 텍스트 값이 리턴될 Bucket 1개, 이렇게 총 2개의 Bucket을 생성한다. (Access Permission의 경우 Public Read/Write로 설정하였으나 필요에 따라 ACL 설정을 하도록 한다.)
SCF
다음은 콘솔의 Serverless Cloud Function 항목으로 이동하여 SCF 함수를 생성 한다.
Function type은 Event-triggered function으로 한다.
코드 Submitting method의 경우 로컬에서 작성 후 압축해서 올려도 되고 온라인에디터에서 직접 작성해도 되지만
일단 어떤 경우든 초기 함수 생성 시 에는 Online editing 을 선택하는 것이 편리하다.
SCF 생성 후 생성된 SCF를 클릭하여 Trigger management 를 보면 트리거를 생성할 수 있다. 이때 Trigger method : COS trigger , 트리거 대상이 될 버킷은 방금 생성한 버킷 중 이미지가 업로드 될 버킷을 선택하면 된다.
코드작성
SCF 코드는
1) OCR API와 COS 모듈을 호출하고
2) 업로드된 이미지 메타데이터에서 imageUrl파라미터를 추출하여 OCR API 엔드포인트로 전송
3) 리턴 값을 두 번째 버킷으로 전달하는 3단계로 작성한다.
이때, OCR 결과 값 중 "DetectedText" 값만 전달하도록 한다.
작성한 전체 소스코드는 아래와 같다.
//텐센트 클라우드 모듈 호출
const tencentcloud = require("tencentcloud-sdk-nodejs-intl-en");
const COS = require("cos-nodejs-sdk-v5");
//API Explorer의 예시코드 참고 (텐클 console)
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
const OcrClient = tencentcloud.ocr.v20181119.Client;
const models = tencentcloud.ocr.v20181119.Models;
// 발급받은 API KEY 정보를 입력
const cosClient = new COS({
SecretId: "IKIDAEA0mU6hEi3LXZRBpMnHhBTp4XXXXXX", // COS Secret ID
SecretKey: "c8hHuYBtjsgMAnR9xrjyAKc3dXXXXXXX" // COS Secret Key
});
// SCF
exports.main_handler = async (event, context) => {
const secretId = "IKIDAEA0mU6hEi3LXZRBpMnHhBTp4XXXXXX";
const secretKey = "c8hHuYBtjsgMAnR9xrjyAKc3dXXXXXXX";
let cred = new Credential(secretId, secretKey);
let httpProfile = new HttpProfile();
httpProfile.endpoint = "ocr.tencentcloudapi.com";
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new OcrClient(cred, "ap-seoul", clientProfile);
// 메타데이터에서 이미지 파일명 추출
const record = event["Records"][0];
const imageUrl = decodeURIComponent(record["cos"]["cosObject"]["url"]);
// OCR 요청객체생성
let req = new models.GeneralBasicOCRRequest();
let params = `{"ImageUrl": "${imageUrl}"}`;
req.from_json_string(params);
// OCR 요청실행
return new Promise((resolve, reject) => {
client.GeneralBasicOCR(req, function(err, response) {
if (err) {
console.error("에러 :", err);
reject(err);
return;
}
console.log("결과 값:", response.to_json_string());
const ocrResult = JSON.parse(response.to_json_string());
const detectedTexts = ocrResult.TextDetections.map(detection => detection.DetectedText).join('\n');
// 결과값 중복 방지를 위한 처리, 띠부띠부씰을 여러 장을 연속으로 찍을 때 결과 값이 한 장만 나오는 것을 방지
const timestamp = new Date().getTime();
const fileName = `his-name-is-${timestamp}.txt`;
const fileContent = Buffer.from(detectedTexts);
// OCR 결과를 COS 버킷에 업로드
cosClient.putObject({
Bucket: 'pocketmon-name-1316520384',
Region: 'ap-seoul',
Key: fileName,
Body: fileContent,
}, function(err, data) {
if (err) {
console.error("에러2:", err);
reject(err);
} else {
console.log("성공:", data);
resolve(data);
}
});
});
});
};
작성한 소스코드를 포함한 아티팩트를 압축하여 SCF에 업로드하고 배포한다.
테스트 (COS Browser)
다양한 COS 업로드 방식이 있지만 서문에 말했듯이 이번에는 COS의 GUI툴인 COS Browser를 이용해 본다.
COS Browser을 다운로드 하고 API KEY를 입력하여 로그인 후 이미지 업로드 버킷에 스티커 이미지를 업로드 한 뒤
두 번째 버킷에 추출된 OCR 결과 값이 텍스트 파일 형태(.txt) 로 전달되는지 확인한다. 로직에 문제가 있는 경우 콘솔의 SCF 메뉴에서 로그를 확인하도록 한다.
대표적인 오류로 아래와 같은 타임아웃 오류가 있는데,
START RequestId: 25c20b87-4237-45f6-9904-4912a7fb2ddbInit
Report RequestId: 25c20b87-4237-45f6-9904-4912a7fb2ddb
Coldstart: 762ms (PullCode: 0ms InitRuntime: 138ms InitFunction: 624ms)
Memory: 128MB MemUsage: 117.24MBERROR
RequestId: 25c20b87-4237-45f6-9904-4912a7fb2ddb
Result: Invoking task timed out after 3 secondsEND
RequestId: 25c20b87-4237-45f6-9904-4912a7fb2ddbReport
RequestId: 25c20b87-4237-45f6-9904-4912a7fb2ddb Duration: 3000ms
Memory: 128MB MemUsage: 119.32MB
이는 SCF 기본 타임아웃 설정이 OCR 판독 시간보다 짧게 설정되어서 발생되는 오류로,
Function management의 Execution timeout period의 값을 10초 정도로 설정해주면 된다.
이제 테스트 대상 이미지를
COS Browser에 업로드하고
두 번째 버킷을 확인한다.
파일이 성공적으로 전송된 것을 확인하고 파일을 열어보면
캐릭터의 이미지와 꽤 어울리는 이름을 확인할 수 있다.
마치며
기존 AWS의 S3와 Lambda를 사용해 본 유저라면 EventTrigger를 활용한 서버리스 구현이 매우 간편하고 경제적인 솔루션이란 걸 잘 알고 있을 것이다. 이처럼 Tencent cloud에서도 S3와 Lambda와 같은 퍼포먼스를 내는 COS와 SCF가 있으니 서버리스 아키텍쳐 구현에 활용해도 좋을 것 같다. 하지만, COS에서 이미지 업로드 시 OCR을 추출하는 기능을 이미 제공하고 있으므로😂.. 이 글은 SCF와 COS를 한 번 경험해본 것에 의미를 두는게 좋다.