From 9ad1a756130a3f8298fe1df387c2a182beedaa82 Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 11 Jul 2024 01:44:58 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[FEAT/#55]=20OCR=20=EB=AA=85=ED=95=A8=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20DTO=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/external/naver/dto/OcrBusinessResponse.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/org/sopt/seonyakServer/global/common/external/naver/dto/OcrBusinessResponse.java diff --git a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/dto/OcrBusinessResponse.java b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/dto/OcrBusinessResponse.java new file mode 100644 index 0000000..813a684 --- /dev/null +++ b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/dto/OcrBusinessResponse.java @@ -0,0 +1,10 @@ +package org.sopt.seonyakServer.global.common.external.naver.dto; + +public record OcrBusinessResponse( + String company, + String phoneNumber +) { + public static OcrBusinessResponse of(String company, String phoneNumber) { + return new OcrBusinessResponse(company, phoneNumber); + } +} From fb495a8211a55d0009ec87ba049b65bfbd0ca794 Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 11 Jul 2024 01:45:56 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[CHORE/#55]=20=EB=8C=80=ED=95=99=EB=AA=85,?= =?UTF-8?q?=20=EB=AA=85=ED=95=A8=20OCR=20=EC=84=A4=EC=A0=95=EA=B0=92=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/auth/security/SecurityConfig.java | 1 + .../global/common/external/naver/OcrConfig.java | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/sopt/seonyakServer/global/auth/security/SecurityConfig.java b/src/main/java/org/sopt/seonyakServer/global/auth/security/SecurityConfig.java index b1de9aa..acff0ae 100644 --- a/src/main/java/org/sopt/seonyakServer/global/auth/security/SecurityConfig.java +++ b/src/main/java/org/sopt/seonyakServer/global/auth/security/SecurityConfig.java @@ -25,6 +25,7 @@ public class SecurityConfig { private static final String[] AUTH_WHITE_LIST = { "/api/v1/**", + "/api/v1/ocr/**", "/api/v1/auth/**", "/actuator/health", "/v3/api-docs/**", diff --git a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrConfig.java b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrConfig.java index 79aabf9..d894584 100644 --- a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrConfig.java +++ b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrConfig.java @@ -8,10 +8,16 @@ @Getter public class OcrConfig { - @Value("${naver.ocr.api.url}") - private String apiUrl; + @Value("${naver.ocr.api.univ-url}") + private String univUrl; + + @Value("${naver.ocr.api.univ-key}") + private String univUrlKey; + + @Value("${naver.ocr.api.business-url}") + private String businessUrl; + + @Value("${naver.ocr.api.business-key}") + private String businessKey; - @Value("${naver.ocr.api.key}") - private String apiKey; - } From fca79d0fb22d0b1859a178b9d60ef689f394fd4c Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 11 Jul 2024 01:48:04 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[FEAT/#55]=20=EB=AA=85=ED=95=A8=20OCR=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/external/naver/OcrController.java | 12 ++- .../common/external/naver/OcrService.java | 88 ++++++++++++++++++- 2 files changed, 95 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrController.java b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrController.java index 68b38e6..b596512 100644 --- a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrController.java +++ b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrController.java @@ -2,6 +2,7 @@ import java.io.IOException; import lombok.RequiredArgsConstructor; +import org.sopt.seonyakServer.global.common.external.naver.dto.OcrBusinessResponse; import org.sopt.seonyakServer.global.common.external.naver.dto.OcrUnivResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -18,7 +19,14 @@ public class OcrController { private final OcrService ocrService; @PostMapping("/univ") - public ResponseEntity ocrText(@RequestParam("imageFile") MultipartFile file) throws IOException { - return ResponseEntity.ok(ocrService.ocrText(file)); + public ResponseEntity ocrUniv(@RequestParam("imageFile") MultipartFile file) + throws IOException { + return ResponseEntity.ok(ocrService.ocrUniv(file)); + } + + @PostMapping("/business-card") + public ResponseEntity ocrBusiness(@RequestParam("imageFile") MultipartFile file) + throws IOException { + return ResponseEntity.ok(ocrService.ocrBusiness(file)); } } diff --git a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java index 6a5a953..c68f57b 100644 --- a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java +++ b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java @@ -16,6 +16,7 @@ import lombok.RequiredArgsConstructor; import org.json.JSONArray; import org.json.JSONObject; +import org.sopt.seonyakServer.global.common.external.naver.dto.OcrBusinessResponse; import org.sopt.seonyakServer.global.common.external.naver.dto.OcrUnivResponse; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -25,10 +26,10 @@ public class OcrService { private final OcrConfig ocrConfig; - public OcrUnivResponse ocrText(MultipartFile file) throws IOException { + public OcrUnivResponse ocrUniv(MultipartFile file) throws IOException { // OCR 설정파일로부터 URL, Secret Key 가져옴 - String apiUrl = ocrConfig.getApiUrl(); - String apiKey = ocrConfig.getApiKey(); + String apiUrl = ocrConfig.getUnivUrl(); + String apiKey = ocrConfig.getUnivUrlKey(); // 네이버 OCR API 요청 헤더 설정 URL url = new URL(apiUrl); @@ -79,6 +80,66 @@ public OcrUnivResponse ocrText(MultipartFile file) throws IOException { return OcrUnivResponse.of(extractUnivText(response.toString())); } + public OcrBusinessResponse ocrBusiness(MultipartFile file) throws IOException { + // OCR 설정파일로부터 URL, Secret Key 가져옴 + String apiUrl = ocrConfig.getBusinessUrl(); + String apiKey = ocrConfig.getBusinessKey(); + + //회사명, 휴대전화번호 JSON 응답에서 파싱 + String company = extractTextByKey(requestNaverOcr(apiUrl, apiKey, file), "company"); + String phoneNumber = extractTextByKey(requestNaverOcr(apiUrl, apiKey, file), "mobile"); + return OcrBusinessResponse.of(company, phoneNumber); + } + + // 네이버 OCR API 요청 구성 + public static String requestNaverOcr(String apiUrl, String apiKey, MultipartFile file) + throws IOException { + String boundary = "----" + UUID.randomUUID().toString().replaceAll("-", ""); + URL url = new URL(apiUrl); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setUseCaches(false); + con.setDoInput(true); + con.setDoOutput(true); + con.setReadTimeout(30000); + con.setRequestMethod("POST"); + con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + con.setRequestProperty("X-OCR-SECRET", apiKey); + + // 네이버 OCR API 요청 바디 설정 + JSONObject json = new JSONObject(); + json.put("version", "V2"); + json.put("requestId", UUID.randomUUID().toString()); + json.put("timestamp", System.currentTimeMillis()); + JSONObject image = new JSONObject(); + image.put("format", "jpg"); + image.put("name", "demo"); + JSONArray images = new JSONArray(); + images.put(image); + json.put("images", images); + String postParams = json.toString(); + + // 네이버 OCR API 요청 날림 + con.connect(); + try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) { + writeMultiPart(wr, postParams, file, boundary); + wr.flush(); + } + + int responseCode = con.getResponseCode(); + BufferedReader br; + if (responseCode == 200) { + br = new BufferedReader(new InputStreamReader(con.getInputStream())); + } else { + br = new BufferedReader(new InputStreamReader(con.getErrorStream())); + } + String inputLine; + StringBuilder response = new StringBuilder(); + while ((inputLine = br.readLine()) != null) { + response.append(inputLine); + } + br.close(); + return response.toString(); + } // 네이버 공식문서 대로 OCR 요청 보내는 함수 private static void writeMultiPart(OutputStream out, String jsonMessage, MultipartFile file, String boundary) @@ -140,4 +201,25 @@ private String extractUnivText(String jsonResponse) { }) .collect(Collectors.joining(",")); } + + // 명함 OCR 응답에서 keyword에 해당하는 필드값을 추출하는 함수 + private String extractTextByKey(String jsonResponse, String key) { + JSONObject jsonObject = new JSONObject(jsonResponse); + JSONArray imagesArray = jsonObject.getJSONArray("images"); + + return IntStream.range(0, imagesArray.length()) + .mapToObj(imagesArray::getJSONObject) + .filter(imageObject -> imageObject.has("nameCard")) + .map(imageObject -> imageObject.getJSONObject("nameCard")) + .filter(nameCard -> nameCard.has("result")) + .map(nameCard -> nameCard.getJSONObject("result")) + .filter(result -> result.has(key)) + .flatMap(result -> { + JSONArray textArray = result.getJSONArray(key); + return IntStream.range(0, textArray.length()) + .mapToObj(textArray::getJSONObject); + }) + .map(textObject -> textObject.getString("text")) + .collect(Collectors.joining(", ")); + } } \ No newline at end of file From 05b01a11c8146c1772c993c8afeeb5e235477463 Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 11 Jul 2024 02:09:37 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[REFACTOR/#55]=20=EB=8C=80=ED=95=99?= =?UTF-8?q?=EB=AA=85=20OCR=20=EC=9A=94=EC=B2=AD=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/external/naver/OcrService.java | 54 +++---------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java index c68f57b..d779cd3 100644 --- a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java +++ b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java @@ -26,60 +26,18 @@ public class OcrService { private final OcrConfig ocrConfig; + // 대학명 OCR public OcrUnivResponse ocrUniv(MultipartFile file) throws IOException { // OCR 설정파일로부터 URL, Secret Key 가져옴 String apiUrl = ocrConfig.getUnivUrl(); String apiKey = ocrConfig.getUnivUrlKey(); - // 네이버 OCR API 요청 헤더 설정 - URL url = new URL(apiUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setUseCaches(false); - con.setDoInput(true); - con.setDoOutput(true); - con.setReadTimeout(30000); - con.setRequestMethod("POST"); - String boundary = "----" + UUID.randomUUID().toString().replaceAll("-", ""); - con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); - con.setRequestProperty("X-OCR-SECRET", apiKey); - - // 네이버 OCR API 요청 바디 설정 - JSONObject json = new JSONObject(); - json.put("version", "V2"); - json.put("requestId", UUID.randomUUID().toString()); - json.put("timestamp", System.currentTimeMillis()); - JSONObject image = new JSONObject(); - image.put("format", "jpg"); - image.put("name", "demo"); - JSONArray images = new JSONArray(); - images.put(image); - json.put("images", images); - String postParams = json.toString(); - - // 네이버 OCR API 요청 날림 - con.connect(); - try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) { - writeMultiPart(wr, postParams, file, boundary); - wr.flush(); - } - - int responseCode = con.getResponseCode(); - BufferedReader br; - if (responseCode == 200) { - br = new BufferedReader(new InputStreamReader(con.getInputStream())); - } else { - br = new BufferedReader(new InputStreamReader(con.getErrorStream())); - } - String inputLine; - StringBuilder response = new StringBuilder(); - while ((inputLine = br.readLine()) != null) { - response.append(inputLine); - } - br.close(); - - return OcrUnivResponse.of(extractUnivText(response.toString())); + // 대학교 OCR 응답 문자열로 받아옴 + String response = requestNaverOcr(apiUrl, apiKey, file); + return OcrUnivResponse.of(extractUnivText(response)); } + // 명함 OCR public OcrBusinessResponse ocrBusiness(MultipartFile file) throws IOException { // OCR 설정파일로부터 URL, Secret Key 가져옴 String apiUrl = ocrConfig.getBusinessUrl(); @@ -88,7 +46,7 @@ public OcrBusinessResponse ocrBusiness(MultipartFile file) throws IOException { //회사명, 휴대전화번호 JSON 응답에서 파싱 String company = extractTextByKey(requestNaverOcr(apiUrl, apiKey, file), "company"); String phoneNumber = extractTextByKey(requestNaverOcr(apiUrl, apiKey, file), "mobile"); - return OcrBusinessResponse.of(company, phoneNumber); + return OcrBusinessResponse.of(company, "010" + lastEightNumber); } // 네이버 OCR API 요청 구성 From 1ad23eb907f78834a68c5ca7c54256ed32374e86 Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 11 Jul 2024 02:10:26 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[FEAT/#55]=20=EC=A0=84=ED=99=94=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=A0=95=EA=B7=9C=EC=8B=9D=EC=9C=BC=EB=A1=9C=2011?= =?UTF-8?q?=EC=9E=90=EB=A6=AC=EB=A7=8C=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seonyakServer/global/common/external/naver/OcrService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java index d779cd3..8b9f160 100644 --- a/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java +++ b/src/main/java/org/sopt/seonyakServer/global/common/external/naver/OcrService.java @@ -46,6 +46,9 @@ public OcrBusinessResponse ocrBusiness(MultipartFile file) throws IOException { //회사명, 휴대전화번호 JSON 응답에서 파싱 String company = extractTextByKey(requestNaverOcr(apiUrl, apiKey, file), "company"); String phoneNumber = extractTextByKey(requestNaverOcr(apiUrl, apiKey, file), "mobile"); + String cleanedNumber = phoneNumber.replaceAll("[^\\d]", ""); + String lastEightNumber = + cleanedNumber.length() > 8 ? cleanedNumber.substring(cleanedNumber.length() - 8) : cleanedNumber; return OcrBusinessResponse.of(company, "010" + lastEightNumber); }