diff --git a/src/main/java/com/going/server/domain/graph/controller/graphController.java b/src/main/java/com/going/server/domain/graph/controller/graphController.java index 8706f36..4f4f5d5 100644 --- a/src/main/java/com/going/server/domain/graph/controller/graphController.java +++ b/src/main/java/com/going/server/domain/graph/controller/graphController.java @@ -12,6 +12,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; @@ -90,4 +92,28 @@ public SuccessResponse getNode(@PathVariable("graphId") Long grap return SuccessResponse.of(result); } + @PostMapping("/{graphId}") + @Operation(summary = "노드 추가", description = "지식 그래프에서 노드를 추가합니다.") + @ApiResponses({ + @ApiResponse( + responseCode = "200", + description = "노드가 성공적으로 추가되었습니다.", + content = @Content( + mediaType = "application/json", + schema = @Schema(example = "{\"message\":\"\"}") + ) + ) + }) + + public SuccessResponse addNode( + @PathVariable("graphId") + Long graphId, + @RequestBody @Valid @NotNull(message = "추가할 그룹을 입력해주세요.") + String group, + @RequestBody @Valid @NotNull(message = "추가할 라벨을 입력해주세요.") + String label) { + knowledgeGraphDto result = graphService.addNode(graphId,group,label); + return SuccessResponse.of(result); + } + } diff --git a/src/main/java/com/going/server/domain/graph/entity/Edge.java b/src/main/java/com/going/server/domain/graph/entity/Edge.java new file mode 100644 index 0000000..f899657 --- /dev/null +++ b/src/main/java/com/going/server/domain/graph/entity/Edge.java @@ -0,0 +1,21 @@ +package com.going.server.domain.graph.entity; + + +import lombok.*; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +@Node("Edge") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Edge { + @Id @GeneratedValue + private Long id; + private String source; + private String target; + private String label; +} diff --git a/src/main/java/com/going/server/domain/graph/repository/EdgeRepository.java b/src/main/java/com/going/server/domain/graph/repository/EdgeRepository.java new file mode 100644 index 0000000..7c5d606 --- /dev/null +++ b/src/main/java/com/going/server/domain/graph/repository/EdgeRepository.java @@ -0,0 +1,7 @@ +package com.going.server.domain.graph.repository; + +import com.going.server.domain.graph.entity.Edge; +import org.springframework.data.neo4j.repository.Neo4jRepository; + +public interface EdgeRepository extends Neo4jRepository { +} diff --git a/src/main/java/com/going/server/domain/graph/service/graphService.java b/src/main/java/com/going/server/domain/graph/service/graphService.java index db63ec5..111af20 100644 --- a/src/main/java/com/going/server/domain/graph/service/graphService.java +++ b/src/main/java/com/going/server/domain/graph/service/graphService.java @@ -12,4 +12,6 @@ public interface graphService { knowledgeGraphDto getGraph(Long graphId); nodeDetailDto getNode(Long graphId, Long nodeId); + + knowledgeGraphDto addNode(Long graphId, String group,String label); } diff --git a/src/main/java/com/going/server/domain/graph/service/graphServiceImpl.java b/src/main/java/com/going/server/domain/graph/service/graphServiceImpl.java index ab2dc39..ce23c8d 100644 --- a/src/main/java/com/going/server/domain/graph/service/graphServiceImpl.java +++ b/src/main/java/com/going/server/domain/graph/service/graphServiceImpl.java @@ -40,4 +40,19 @@ public nodeDetailDto getNode(Long graphId, Long nodeId) { //TODO : nodeId로 노드 찾기 return nodeDetailDto.from(null,null,null,null,null); } + + @Override + public knowledgeGraphDto addNode(Long graphId,String group,String label) { + //TODO : graphId로 그래프 찾기 + //TODO : group 추가하는 코드 작성 + //TODO : label 추가하는 코드 작성 + + //TODO : nodeDto에 값 매핑하는 코드 작성 + List nodeDto = new ArrayList<>(); + + //TODO : edgeDto에 값 매핑하는 코드 작성 + List edgeDto = new ArrayList<>(); + + return knowledgeGraphDto.of(nodeDto,edgeDto); + } } diff --git a/src/main/java/com/going/server/domain/upload/service/UploadServiceImpl.java b/src/main/java/com/going/server/domain/upload/service/UploadServiceImpl.java index 2c92160..d8bbe3b 100644 --- a/src/main/java/com/going/server/domain/upload/service/UploadServiceImpl.java +++ b/src/main/java/com/going/server/domain/upload/service/UploadServiceImpl.java @@ -1,5 +1,12 @@ package com.going.server.domain.upload.service; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.going.server.domain.graph.dto.edgeDto; +import com.going.server.domain.graph.dto.nodeDto; +import com.going.server.domain.graph.entity.Edge; +import com.going.server.domain.graph.repository.EdgeRepository; import com.going.server.domain.ocr.OcrService; import com.going.server.domain.ocr.PdfOcrService; import com.going.server.domain.upload.dto.UploadRequestDto; @@ -11,6 +18,9 @@ import org.springframework.web.server.ResponseStatusException; import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import java.util.Map; @Service @@ -18,6 +28,7 @@ public class UploadServiceImpl implements UploadService { private final OcrService ocrService; private final PdfOcrService pdfOcrService; + private final EdgeRepository edgeRepository; @Value("${ocr.api.url}") private String apiUrl; @Value("${ocr.api.secret-key}") @@ -26,17 +37,40 @@ public class UploadServiceImpl implements UploadService { @Override public UploadResponseDto uploadFile(UploadRequestDto dto) { try { - String jsonResponse = ocrService.processOcr(dto.getFile(),apiUrl,secretKey); - //System.out.println("jsonResponse: "+jsonResponse); + String jsonResponse = ocrService.processOcr(dto.getFile(), apiUrl, secretKey); Map paresData = pdfOcrService.parse(jsonResponse); - //System.out.println("paresData: "+paresData); - String text = paresData.get("6학년 읽기자료 내용"); - System.out.println("추출된 텍스트: "+text); + System.out.println("추출된 텍스트: " + text); - //TODO : 그래프 생성을 위한 FastApi 호출 코드 작성 + ObjectMapper mapper = new ObjectMapper(); + InputStream is = getClass().getClassLoader().getResourceAsStream("data.json"); + JsonNode root = mapper.readTree(is); + JsonNode dataNode = root.get("data"); + JsonNode edgesNode = dataNode.get("edges"); - //TODO : 데이터 받아와서 DB에 저장 + List edgeList = new ArrayList<>(); + + for (JsonNode edgeNode : edgesNode) { + if (!edgeNode.has("source") || !edgeNode.has("target") || !edgeNode.has("label")) { + System.out.println("필드 누락: " + edgeNode.toPrettyString()); + continue; + } + + String source = edgeNode.get("source").asText(); + String target = edgeNode.get("target").asText(); + String label = edgeNode.get("label").asText(); + + Edge edge = Edge.builder() + .source(source) + .target(target) + .label(label) + .build(); + + edgeList.add(edge); + } + + edgeRepository.saveAll(edgeList); + System.out.println("총 " + edgeList.size() + "개의 edge가 저장되었습니다."); return UploadResponseDto.from( null, @@ -46,9 +80,9 @@ public UploadResponseDto uploadFile(UploadRequestDto dto) { null, null ); - } catch (IllegalArgumentException e){ + } catch (IllegalArgumentException e) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage()); - } catch (IOException e){ + } catch (IOException e) { throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } } diff --git a/src/main/resources/data.json b/src/main/resources/data.json new file mode 100644 index 0000000..477c59f --- /dev/null +++ b/src/main/resources/data.json @@ -0,0 +1,67 @@ +{ + "isSuccess": true, + "code": "201", + "message": "지식그래프 생성에 성공하였습니다.", + "data" : { + "nodes": [ + { + "id": "1", + "label": "동물", + "group": 1, + "level": 0, + "description": "기린은 세계에서 가장 키가 큰 동물로, 길게 뻗은 목을 이용해 높은 나무의 잎을 먹습니다. 초식동물이며 아프리카 사바나에서 주로 서식하고, 길고 튼튼한 다리로 천천히 이동하며, 천적을 피할 때는 매우 빠른 속도로 달릴 수 있습니다." + }, + { + "id": "2", + "label": "고양이", + "group": 2, + "level": 1, + "description": "기린은 세계에서 가장 키가 큰 동물로, 길게 뻗은 목을 이용해 높은 나무의 잎을 먹습니다. 초식동물이며 아프리카 사바나에서 주로 서식하고, 길고 튼튼한 다리로 천천히 이동하며, 천적을 피할 때는 매우 빠른 속도로 달릴 수 있습니다." + }, + { + "id": "3", + "label": "토끼", + "group": 2, + "level": 1, + "description": "기린은 세계에서 가장 키가 큰 동물로, 길게 뻗은 목을 이용해 높은 나무의 잎을 먹습니다. 초식동물이며 아프리카 사바나에서 주로 서식하고, 길고 튼튼한 다리로 천천히 이동하며, 천적을 피할 때는 매우 빠른 속도로 달릴 수 있습니다." + + }, + { + "id": "4", + "label": "기린", + "group": 2, + "level": 1, + "description": "기린은 세계에서 가장 키가 큰 동물로, 길게 뻗은 목을 이용해 높은 나무의 잎을 먹습니다. 초식동물이며 아프리카 사바나에서 주로 서식하고, 길고 튼튼한 다리로 천천히 이동하며, 천적을 피할 때는 매우 빠른 속도로 달릴 수 있습니다." + }, + { + "id": "5", + "label": "원숭이", + "group": 2, + "level": 1, + "description": "원숭이는 사람과 유전적으로 가까운 영장류에 속하며, 높은 지능과 손을 이용한 다양한 도구 사용 능력을 갖추고 있습니다. 나무를 잘 타며 무리를 지어 생활하고, 감정 표현이 풍부하며 사회적 행동이 발달해 있습니다." + }, + { + "id": "6", + "label": "추론", + "group": 2, + "level": 2, + "description": "추론은 관찰하거나 알고 있는 사실을 바탕으로 새로운 사실이나 결론을 이끌어내는 사고 과정입니다. 예를 들어, 고양이가 생선을 먹는다는 사실을 안다면, 생선을 보고 고양이가 있을 가능성을 추론할 수 있습니다. 과학적 탐구나 문제 해결에서 매우 중요한 능력입니다." + }, + { + "id": "7", + "label": "생선", + "group": 2, + "level": 2, + "description": "생선은 물속에 사는 척추동물로, 지느러미와 비늘을 가지고 있으며 아가미로 숨을 쉽니다. 다양한 종류가 있으며, 많은 동물과 사람에게 중요한 단백질 공급원입니다. 고양이는 생선을 매우 좋아하는 동물로 자주 묘사됩니다." + } + ], + "edges": [ + { "source": "1", "target": "2", "label": "포유류" }, + { "source": "1", "target": "3", "label": "초식동물" }, + { "source": "1", "target": "4", "label": "육상동물" }, + { "source": "1", "target": "5", "label": "영장류" }, + { "source": "2", "target": "6", "label": "결과" }, + { "source": "2", "target": "7", "label": "먹이" } + ] + } +} \ No newline at end of file