MS의 Azure에서도 OCR 기능을 지원합니다! azure도 사용하기 매우 편리했는데, 리소스를 만들면 알아서 API키와 엔드포인트를 줍니다. REST API를 사용하는 경우에는 엔드포인트에서 추가 URL을 붙인 후에 request header에 API KEY를 넣으면 끝!!
리소스 만드는 과정은 생략 .... azure에서 나온 가이드를 고대로!! 따라하면 문제없이 생성할 수 있다!
기본정보에서 바로 확인 가능! 그럼 바로 사용해보자
구조는 간단하다. 요청을 엔드포인트/vision/v3.2/read/analyze
로 설정하고, 헤더에 Ocp-Apim-Subscription-Key: {시크릿키}
를 추가하는 것이 전부이다. 그리고 요청 body에는 JSON으로 "url": {파싱할 URL}
을 보내주면 된다.
public class AzureOCR {
public static String END_POINT = "{엔드포인트}/vision/v3.2/read/analyze";
public static String SUBSCRIPTION_KEY = {시크릿키};
public static String execute(ImageParsingRequest request) throws IOException, ParseException, ExecutionException, InterruptedException {
StopWatch totalTime = new StopWatch();
totalTime.start();
JSONObject requestBody = new JSONObject();
requestBody.put("url", request.url());
HttpClient requestClient = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create(END_POINT))
.header("Content-Type", "application/json")
.header("Ocp-Apim-Subscription-Key", SUBSCRIPTION_KEY)
.POST(HttpRequest.BodyPublishers.ofString(requestBody.toString()))
.build();
HttpResponse<?> response = requestClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 202) {
return "error";
}
String OPERATION_LOCATION = response.headers().firstValue("Operation-Location").orElseThrow();
StringBuilder result = new StringBuilder();
while (true) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest readRequest = HttpRequest.newBuilder()
.uri(URI.create(OPERATION_LOCATION))
.GET()
.header("Ocp-Apim-Subscription-Key", SUBSCRIPTION_KEY)
.header("Content-Type", "application/json;")
.build();
String responseBody = client.sendAsync(readRequest, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).get();
JSONParser parser = new JSONParser(responseBody);
LinkedHashMap<String, String> hashMap = (LinkedHashMap<String, String>) parser.parse();
JSONObject responseObject = new JSONObject(hashMap);
if (responseObject.get("status").equals("succeeded")) {
JSONObject analyzeResult = (JSONObject) responseObject.get("analyzeResult");
JSONArray readResults = (JSONArray) analyzeResult.get("readResults");
JSONObject resultObject = (JSONObject) readResults.get(0);
JSONArray lines = (JSONArray) resultObject.get("lines");
lines.forEach(line -> {
JSONObject lineObject = (JSONObject) line;
result.append(lineObject.get("text").toString()).append("\n");
});
totalTime.stop();
System.out.println("Total Time : " + totalTime.getTotalTimeMillis() + "ms");
break;
}
else if (responseObject.get("status").equals("notStarted") || responseObject.get("status").equals("failed")) {
return "error";
}
}
return result.toString();
}
}
azure api는 비동기로 작동한다. 요청을 하면 서버에서 받아들이고 계산을 시작하면 202 응답과 함께 헤더에 Operation-Location
를 보내준다. 그럼 저 헤더에 담긴 주소로 다시 GET 요청을 보내서 상태가 바뀌는 것을 체크해야 한다.
난 처음에 이게 엄청 느릴줄 알았는데 반전의 결과가 나왔다.
기존에 진행했던 Clova, GCP보다 훨씬 빨랐다.
이렇게 보다 좋은 성능을 보여주었다. 하지만 단점이라면, 연속적으로 많은 요청을 보낼 수는 없는 것 같았다. 평균적으로 3번은 잘 가는데, 그 다음은 일정 시간이 지나야 다시 이용할 수 있었다. 공식문서에 따르면 1분에 20개의 요청이 가능하다고 하는데, 그럼 사실상 3초에 1건꼴로 신청이 가능한 것 ...
그럼 맞네 ... ㅜㅜ 성능은 좋으나 제한 사항이 좀 그렇다 .. 평균 1.2초가 걸리는 구글에 비하면 압도적이나 제약사항이 너무 크다.
역시 OCR 모델을 만들거나, 만들어진 모델을 이용하는 수 밖에 없다. TODO list가 점점 늘어난다..... OCR도 추가를 하면
1. 자바 병렬처리
2. 파이썬 라이브러리 속도 측정
3. Go 언어 HTML 파싱 라이브러리 탐색
4. 필터링 로직 구현
5. 필터링 전체 시간 테스트
6. 프론트 디자인 구상
7. 엔티티 설계 및 ERD 작성
8. OCR 모델 탐색