Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue#21 OCR 기능(임시) #31

Merged
merged 3 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ jobs:
docker stop nullnull-server || true
docker rm nullnull-server || true
docker pull ${{ secrets.DOCKERHUB_USERNAME }}/nullnull-server:latest
docker run -d --name nullnull-server -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/nullnull-server:latest \
docker run -d --name nullnull-server -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/nullnull-server:latest
-e REDIRECT_URL=${{ secrets.REDIRECT_URL }}



2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5")

implementation 'org.json:json:20210307'
}

tasks.named('test') {
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/hackathon/nullnullteam/ocr/OcrController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.hackathon.nullnullteam.ocr;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/ocr")
public class OcrController {

private final OcrService ocrService;

@PostMapping("/extract-text")
public List<String> extractText(@RequestParam("file") MultipartFile file) {
List<String> extractedText = ocrService.extractTextFromImage(file);
return extractedText;
}
}
113 changes: 113 additions & 0 deletions src/main/java/com/hackathon/nullnullteam/ocr/OcrService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.hackathon.nullnullteam.ocr;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
@Service
public class OcrService {

private String secretKey = "aXlVdkxtbHlHd2ppZ3pDaE9EVHVYTmlsaFhFemhSQUY=";
private String ocrUrl = "https://ahkbcepidb.apigw.ntruss.com/custom/v1/35950/126a9919713e051ba28c70a4e4dc6d2d4df3a2d21801b5ffa7ab91cc5aa3886c/general\n";
private final RestTemplate restTemplate = new RestTemplate();

public List<String> extractTextFromImage(MultipartFile file) {
// 헤더 설정: X-OCR-SECRET 및 Content-Type 설정
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.set("X-OCR-SECRET", secretKey);

// 메시지 데이터 구성
Map<String, Object> message = new HashMap<>();
message.put("version", "V2"); // 권장값
message.put("requestId", UUID.randomUUID().toString()); // UUID 생성
message.put("timestamp", System.currentTimeMillis() / 1000); // 초 단위 타임스탬프
message.put("lang", "ko"); // 요청 언어
//message.put("enableTableDetection", true); // 테이블 인식 활성화

// images 데이터 구성
Map<String, Object> imageInfo = new HashMap<>();
imageInfo.put("format", "jpg"); // 이미지 형식
imageInfo.put("name", file.getOriginalFilename()); // 이미지 이름
imageInfo.put("data", encodeFileToBase64(file)); // Base64 인코딩된 이미지 데이터

List<Map<String, Object>> images = new ArrayList<>();
images.add(imageInfo);
message.put("images", images); // message에 images 정보 추가

// 메시지 전체 데이터
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("message", message);

// 파일을 multipart/form-data 형식으로 추가 (MultipartFile을 그대로 추가)
map.add("file", file.getResource());

// HttpEntity로 요청 메시지 구성
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);


// RestTemplate 설정
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new org.springframework.http.converter.FormHttpMessageConverter());

ResponseEntity<String> response = restTemplate.exchange(ocrUrl, HttpMethod.POST, requestEntity, String.class);
JSONObject object = new JSONObject(response.getBody());
List<String> text = extractInferText(object);
return text;
}

private String encodeFileToBase64(MultipartFile file) {
try {
byte[] fileBytes = file.getBytes(); // 파일 내용을 바이트 배열로 읽기
return Base64.getEncoder().encodeToString(fileBytes); // Base64 인코딩
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("파일을 Base64로 변환하는 중 오류 발생: " + e.getMessage());
}
}

public static List<String> extractInferText(JSONObject response) {
List<String> inferTexts = new ArrayList<>();

// 'images' 배열을 가져옴
JSONArray images = response.getJSONArray("images");

for (int i = 0; i < images.length(); i++) {
JSONObject image = images.getJSONObject(i);

// 각 이미지에서 'fields' 배열을 가져옴
JSONArray fields = image.getJSONArray("fields");

for (int j = 0; j < fields.length(); j++) {
JSONObject field = fields.getJSONObject(j);

// 각 'field'에서 inferText 추출
String inferText = field.getString("inferText");

// 추출한 inferText를 리스트에 추가
inferTexts.add(inferText);
}
}

return inferTexts;
}
}
8 changes: 6 additions & 2 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ spring.datasource.hikari.connection-test-query=SELECT 1
apikey.secretkey=TZCmq9MFSSj3tDUk7qL5Ds8k6PBc3tyGmjD0vUqUmcFDRWh8xpChWEWB8is%2BLsp1Fh47q9PHDVxn%2FUyZwRvJiQ%3D%3D
apikey.vitamin-info-url=https://apis.data.go.kr/1471000/HtfsInfoService03/getHtfsItem01

kakao.redirect-uri=http://3.37.196.200:8080/api/member/callback
kakao.redirect-uri=${REDIRECT_URL}
kakao.client-id=27053b55aed58a9387699a86941543cd
kakao.auth-url=https://kauth.kakao.com/oauth/authorize
kakao.token-url=https://kauth.kakao.com/oauth/token
kakao.user-info-url=https://kapi.kakao.com/v2/user/me
kakao.user-info-url=https://kapi.kakao.com/v2/user/me

spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB