diff --git a/build.gradle b/build.gradle index 222d0dd..5e1c090 100644 --- a/build.gradle +++ b/build.gradle @@ -62,6 +62,10 @@ dependencies { //E-MAIL implementation "org.springframework.boot:spring-boot-starter-mail" + // Add json-simple for JSON processing + implementation 'com.googlecode.json-simple:json-simple:1.1.1' + implementation 'org.json:json:20230618' + } diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/CustomException.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/CustomException.java new file mode 100644 index 0000000..f8f3565 --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/CustomException.java @@ -0,0 +1,7 @@ +package com.mycom.backenddaengplace.ocrtest; + +public class CustomException extends RuntimeException { + public CustomException(String message) { + super(message); + } +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/OcrController.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/OcrController.java new file mode 100644 index 0000000..402eeb6 --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/OcrController.java @@ -0,0 +1,90 @@ +package com.mycom.backenddaengplace.ocrtest.controller; + +import com.mycom.backenddaengplace.ocrtest.service.OcrService; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; + +@Controller +@RequestMapping("/ocr") +public class OcrController { + + private final OcrService ocrService; + + @Autowired + public OcrController(OcrService ocrService) { + this.ocrService = ocrService; + } + + @GetMapping("/upload") + public String showUploadPage() { + return "upload"; + } + + @PostMapping("/upload") + public ResponseEntity uploadImage(@RequestParam("file") MultipartFile file) { + try { + String filePath = ocrService.saveFile(file); + return ResponseEntity.ok(filePath); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error: " + e.getMessage()); + } + } + + @PostMapping("/analyze") + public ResponseEntity> analyzeImage(@RequestParam String filePath) { + try { + String ocrResult = ocrService.performOCR(filePath); // OCR 수행 + List inferTexts = extractInferTexts(ocrResult); // 텍스트만 추출 + return ResponseEntity.ok(inferTexts); // 결과 반환 + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + } + + private List extractInferTexts(String jsonData) { + List inferTexts = new ArrayList<>(); + + try { + JSONParser parser = new JSONParser(); + JSONObject jsonObject = (JSONObject) parser.parse(jsonData); + JSONArray images = (JSONArray) jsonObject.get("images"); + + for (Object imageObj : images) { + JSONObject image = (JSONObject) imageObj; + JSONArray fields = (JSONArray) image.get("fields"); + + for (Object fieldObj : fields) { + JSONObject field = (JSONObject) fieldObj; + String inferText = (String) field.get("inferText"); // 텍스트만 추출 + inferTexts.add(inferText); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + return inferTexts; + } + + @PostMapping("/format") + public ResponseEntity formatInferText(@RequestBody String jsonData) { + try { + String result = ocrService.removeVertices(jsonData); + return ResponseEntity.ok(result); + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error: " + e.getMessage()); + } + } +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/OcrResultProcessor.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/OcrResultProcessor.java new file mode 100644 index 0000000..e57da1f --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/OcrResultProcessor.java @@ -0,0 +1,40 @@ +package com.mycom.backenddaengplace.ocrtest.controller; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +public class OcrResultProcessor { + + public static String extractInferText(String jsonData) { + try { + JSONParser parser = new JSONParser(); + JSONObject jsonObject = (JSONObject) parser.parse(jsonData); + JSONArray images = (JSONArray) jsonObject.get("images"); + JSONArray inferTextArray = new JSONArray(); + + for (Object imageObj : images) { + JSONObject image = (JSONObject) imageObj; + JSONArray fields = (JSONArray) image.get("fields"); + + for (Object fieldObj : fields) { + JSONObject field = (JSONObject) fieldObj; + String inferText = (String) field.get("inferText"); + inferTextArray.add(inferText); + } + } + + // 결과를 JSON 배열로 반환 + return inferTextArray.toJSONString(); + } catch (Exception e) { + e.printStackTrace(); + return "[]"; // 오류 발생 시 빈 배열 반환 + } + } + + public static void main(String[] args) { + String jsonData = "YOUR_JSON_DATA_HERE"; // JSON 데이터 문자열 입력 + String result = extractInferText(jsonData); + System.out.println(result); + } +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/ReceiptOCRController.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/ReceiptOCRController.java new file mode 100644 index 0000000..45c3ff6 --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/controller/ReceiptOCRController.java @@ -0,0 +1,31 @@ +package com.mycom.backenddaengplace.ocrtest.controller; + +import com.mycom.backenddaengplace.ocrtest.service.OcrService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/receipt") +public class ReceiptOCRController { + private final OcrService ocrService; + + @Autowired + public ReceiptOCRController(OcrService ocrService) { + this.ocrService = ocrService; + } + @PostMapping("/process") + public ResponseEntity processInferText(@RequestBody String jsonData) { + try { + String result = ocrService.removeVertices(jsonData); + return ResponseEntity.ok(result); + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error: " + e.getMessage()); + } + } +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/entity/OcrResult.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/entity/OcrResult.java new file mode 100644 index 0000000..7639ef5 --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/entity/OcrResult.java @@ -0,0 +1,21 @@ +package com.mycom.backenddaengplace.ocrtest.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Getter +@Setter +public class OcrResult { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String filePath; + + private String concatenatedText; +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/repository/OcrResultRepository.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/repository/OcrResultRepository.java new file mode 100644 index 0000000..c582ad2 --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/repository/OcrResultRepository.java @@ -0,0 +1,9 @@ +package com.mycom.backenddaengplace.ocrtest.repository; + +import com.mycom.backenddaengplace.ocrtest.entity.OcrResult; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OcrResultRepository extends JpaRepository { +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OCRProcessor.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OCRProcessor.java new file mode 100644 index 0000000..a4033b1 --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OCRProcessor.java @@ -0,0 +1,60 @@ +package com.mycom.backenddaengplace.ocrtest.service; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class OCRProcessor { + public List extractInferTexts(String jsonData) { + List inferTexts = new ArrayList<>(); + + try { + JSONObject jsonObject = new JSONObject(jsonData); + JSONArray images = jsonObject.getJSONArray("images"); + + for (int i = 0; i < images.length(); i++) { + JSONObject image = images.getJSONObject(i); + JSONArray fields = image.getJSONArray("fields"); + + for (int j = 0; j < fields.length(); j++) { + JSONObject field = fields.getJSONObject(j); + + // `vertices`를 무시하고 `inferText`만 추출 + if (field.has("inferText")) { + inferTexts.add(field.getString("inferText")); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + return inferTexts; + } + + public String preprocessJson(String jsonData) { + try { + JSONObject jsonObject = new JSONObject(jsonData); + JSONArray images = jsonObject.getJSONArray("images"); + + for (int i = 0; i < images.length(); i++) { + JSONObject image = images.getJSONObject(i); + JSONArray fields = image.getJSONArray("fields"); + + for (int j = 0; j < fields.length(); j++) { + JSONObject field = fields.getJSONObject(j); + // boundingPoly 필드 제거 + field.remove("boundingPoly"); + } + } + + // 전처리된 JSON 데이터를 문자열로 반환 + return jsonObject.toString(); + } catch (Exception e) { + e.printStackTrace(); + return "{}"; // 실패 시 빈 JSON 반환 + } + } +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OcrService.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OcrService.java new file mode 100644 index 0000000..0d182af --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OcrService.java @@ -0,0 +1,15 @@ +package com.mycom.backenddaengplace.ocrtest.service; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +public interface OcrService { + String saveFile(MultipartFile file) throws IOException; + + String performOCR(String filePath) throws IOException; + + String processJsonData(String jsonData); + + String removeVertices(String jsonData); +} diff --git a/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OcrServiceImpl.java b/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OcrServiceImpl.java new file mode 100644 index 0000000..e6ba869 --- /dev/null +++ b/src/main/java/com/mycom/backenddaengplace/ocrtest/service/OcrServiceImpl.java @@ -0,0 +1,177 @@ +package com.mycom.backenddaengplace.ocrtest.service; + +import com.mycom.backenddaengplace.ocrtest.repository.OcrResultRepository; +import org.apache.tomcat.util.json.JSONParser; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Paths; +import java.util.UUID; + +@Service +public class OcrServiceImpl implements OcrService { + + @Value("${ocr.api.url}") + private String ocrApiUrl; + + @Value("${ocr.api.secret-key}") + private String ocrSecretKey; + + private final OcrResultRepository repository; + + public OcrServiceImpl(OcrResultRepository repository) { + this.repository = repository; + } + + @Override + public String saveFile(MultipartFile file) throws IOException { + String uploadDir = Paths.get(System.getProperty("user.dir"), "uploads").toString(); + File directory = new File(uploadDir); + + if (!directory.exists() && !directory.mkdirs()) { + throw new IOException("Failed to create directory: " + uploadDir); + } + + File targetFile = new File(uploadDir, file.getOriginalFilename()); + file.transferTo(targetFile); + + return targetFile.getAbsolutePath(); + } + + private void writeMultiPart(OutputStream os, String jsonMessage, File file, String boundary) throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append("--").append(boundary).append("\r\n"); + sb.append("Content-Disposition:form-data; name=\"message\"\r\n\r\n"); + sb.append(jsonMessage).append("\r\n"); + os.write(sb.toString().getBytes()); + + if (file != null && file.isFile()) { + sb = new StringBuilder(); + sb.append("--").append(boundary).append("\r\n"); + sb.append("Content-Disposition:form-data; name=\"file\"; filename=\"").append(file.getName()).append("\"\r\n"); + sb.append("Content-Type: application/octet-stream\r\n\r\n"); + os.write(sb.toString().getBytes()); + + try (FileInputStream fis = new FileInputStream(file)) { + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = fis.read(buffer)) != -1) { + os.write(buffer, 0, bytesRead); + } + } + os.write("\r\n".getBytes()); + } + os.write(("--" + boundary + "--\r\n").getBytes()); + } + + @Override + public String performOCR(String filePath) throws IOException { + File file = new File(filePath); + if (!file.exists()) { + throw new FileNotFoundException("File not found: " + filePath); + } + + URL url = new URL(ocrApiUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=OCRBoundary"); + connection.setRequestProperty("X-OCR-SECRET", ocrSecretKey); + + JSONObject json = new JSONObject(); + json.put("version", "V1"); + json.put("requestId", UUID.randomUUID().toString()); + json.put("timestamp", System.currentTimeMillis()); + + JSONObject image = new JSONObject(); + image.put("format", "jpg"); + image.put("name", "test_image"); + + JSONArray images = new JSONArray(); + images.add(image); + json.put("images", images); + + try (OutputStream os = connection.getOutputStream()) { + writeMultiPart(os, json.toString(), file, "OCRBoundary"); + } + + int responseCode = connection.getResponseCode(); + if (responseCode == 200) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + return response.toString(); + } + } else { + throw new IOException("Failed to process OCR: HTTP " + responseCode); + } + } + + @Override + public String processJsonData(String jsonData) { + return extractConcatenatedText(jsonData); + } + + @Override + public String removeVertices(String jsonData) { + try { + JSONParser parser = new JSONParser(jsonData); + JSONObject jsonObject = (JSONObject) parser.parse(); + + JSONArray images = (JSONArray) jsonObject.get("images"); + + for (Object imageObj : images) { + JSONObject image = (JSONObject) imageObj; + JSONArray fields = (JSONArray) image.get("fields"); + + for (Object fieldObj : fields) { + JSONObject field = (JSONObject) fieldObj; + + String[] keysToRemove = {"vertices","boundingPoly", "inferConfidence", "valueType"}; + for (String key : keysToRemove) { + field.remove(key); + } + } + } + return jsonObject.toString(); + } catch (Exception e) { + e.printStackTrace(); + return jsonData; + } + } + + private String extractConcatenatedText(String jsonData) { + try { + JSONParser parser = new JSONParser(jsonData); + JSONObject jsonObject = (JSONObject) parser.parse(); + JSONArray images = (JSONArray) jsonObject.get("images"); + + StringBuilder concatenatedText = new StringBuilder(); + + for (Object imageObj : images) { + JSONObject image = (JSONObject) imageObj; + JSONArray fields = (JSONArray) image.get("fields"); + + for (Object fieldObj : fields) { + JSONObject field = (JSONObject) fieldObj; + concatenatedText.append(((String) field.get("inferText")).trim()); + } + } + return concatenatedText.toString(); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bf1314e..c6139f3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -10,7 +10,26 @@ spring: format_sql: true show_sql: true open-in-view: false - web: resources: - add-mappings: false \ No newline at end of file + add-mappings: false + mvc: + view: + prefix: /WEB-INF/views/ + suffix: .html +# Server Configuration +server: + port: 8080 +# Logging +logging: + level: + root: INFO + com.mycom.ocrtest: DEBUG +# File Upload Directory +file: + upload-dir: src/main/resources/static/img +# OCR API Configuration +ocr: + api: + url: ${OCR_API_URL} + secret-key: ${OCR_SECRET_KEY} \ No newline at end of file