Skip to content

Commit a1f457c

Browse files
authored
Merge pull request #245 from prgrms-web-devcourse-final-project/release/1.0.0
운영배포
2 parents 6c260d7 + b9aa6c0 commit a1f457c

40 files changed

+2574
-841
lines changed

.github/workflows/CI-CD_Pipeline.yml

Lines changed: 312 additions & 72 deletions
Large diffs are not rendered by default.

backend/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ dependencies {
8585
// Testing (테스트)
8686
testImplementation 'org.springframework.boot:spring-boot-starter-test'
8787
testImplementation 'org.springframework.security:spring-security-test'
88+
testImplementation 'org.mockito:mockito-inline:5.2.0'
8889
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
8990
implementation("it.ozimov:embedded-redis:0.7.3") {
9091
exclude group: "org.slf4j", module: "slf4j-simple"

backend/src/main/java/com/ai/lawyer/domain/auth/dto/OAuth2LoginResponse.java

Lines changed: 0 additions & 11 deletions
This file was deleted.

backend/src/main/java/com/ai/lawyer/domain/chatbot/dto/ChatDto.java

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import org.springframework.ai.document.Document;
99

1010
import java.time.LocalDateTime;
11-
import java.util.ArrayList;
12-
import java.util.List;
1311

1412
@Schema(description = "채팅 관련 DTO")
1513
public class ChatDto {
@@ -42,11 +40,10 @@ public static class ChatResponse {
4240
@Schema(description = "AI 챗봇의 응답 메시지", example = "네, 관련 법령과 판례를 바탕으로 답변해 드리겠습니다.")
4341
private String message;
4442

45-
@Schema(description = "응답 생성에 참고한 유사 판례 정보 목록")
46-
private List<Document> similarCases;
43+
private ChatPrecedentDto precedent;
44+
45+
private ChatLawDto law;
4746

48-
@Schema(description = "응답 생성에 참고한 유사 법령 정보 목록")
49-
private List<Document> similarLaws;
5047
}
5148

5249
@Getter
@@ -73,6 +70,14 @@ public static ChatPrecedentDto from(ChatPrecedent cp) {
7370
.caseName(cp.getCaseName())
7471
.build();
7572
}
73+
74+
public static ChatPrecedentDto from(Document doc) {
75+
return ChatPrecedentDto.builder()
76+
.precedentContent(doc.getText())
77+
.caseNumber(doc.getMetadata().get("caseNumber").toString())
78+
.caseName(doc.getMetadata().get("caseName").toString())
79+
.build();
80+
}
7681
}
7782

7883
@Data
@@ -93,6 +98,13 @@ public static ChatLawDto from(ChatLaw cl) {
9398
.lawName(cl.getLawName())
9499
.build();
95100
}
101+
102+
public static ChatLawDto from(Document doc) {
103+
return ChatLawDto.builder()
104+
.content(doc.getText())
105+
.lawName(doc.getMetadata().get("lawName").toString())
106+
.build();
107+
}
96108
}
97109

98110
@Getter
@@ -109,31 +121,31 @@ public static class ChatHistoryDto {
109121
@Schema(description = "메시지 내용", example = "안녕하세요~~")
110122
private String message;
111123

112-
private List<ChatPrecedentDto> precedents;
124+
private ChatPrecedentDto precedent;
113125

114-
private List<ChatLawDto> laws;
126+
private ChatLawDto law;
115127

116128
@Schema(description = "생성 시간")
117129
private LocalDateTime createdAt;
118130

119131
public static ChatHistoryDto from(Chat chat) {
120132

121-
List<ChatPrecedentDto> precedentDtos = new ArrayList<>();
122-
for (ChatPrecedent cp : chat.getChatPrecedents()) {
123-
precedentDtos.add(ChatPrecedentDto.from(cp));
133+
ChatPrecedentDto precedentDto = null;
134+
if (chat.getChatPrecedents() != null && !chat.getChatPrecedents().isEmpty()) {
135+
precedentDto = ChatPrecedentDto.from(chat.getChatPrecedents().get(0));
124136
}
125137

126-
List<ChatLawDto> lawDtos = new ArrayList<>();
127-
for (ChatLaw cl : chat.getChatLaws()) {
128-
lawDtos.add(ChatLawDto.from(cl));
138+
ChatLawDto lawDto = null;
139+
if (chat.getChatLaws() != null && !chat.getChatLaws().isEmpty()) {
140+
lawDto = ChatLawDto.from(chat.getChatLaws().get(0));
129141
}
130142

131143
return ChatHistoryDto.builder()
132144
.type(chat.getType().toString())
133145
.message(chat.getMessage())
134146
.createdAt(chat.getCreatedAt())
135-
.precedents(precedentDtos)
136-
.laws(lawDtos)
147+
.precedent(precedentDto)
148+
.law(lawDto)
137149
.build();
138150
}
139151
}

backend/src/main/java/com/ai/lawyer/domain/chatbot/service/ChatBotService.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.ai.lawyer.domain.chatbot.service;
22

3+
import com.ai.lawyer.domain.chatbot.dto.ChatDto.ChatLawDto;
4+
import com.ai.lawyer.domain.chatbot.dto.ChatDto.ChatPrecedentDto;
35
import com.ai.lawyer.domain.chatbot.dto.ChatDto.ChatRequest;
46
import com.ai.lawyer.domain.chatbot.dto.ChatDto.ChatResponse;
57
import com.ai.lawyer.domain.chatbot.dto.ExtractionDto.KeywordExtractionDto;
@@ -37,6 +39,7 @@ public class ChatBotService {
3739

3840
private final QdrantService qdrantService;
3941
private final HistoryService historyService;
42+
private final KeywordService keywordService;
4043

4144
private final ChatRepository chatRepository;
4245
private final HistoryRepository historyRepository;
@@ -91,21 +94,26 @@ public Flux<ChatResponse> sendMessage(Long memberId, ChatRequest chatChatRequest
9194
.onErrorResume(throwable -> Flux.just(handleError(history))); // 에러 발생 시 에러 핸들링 -> 재전송 유도
9295
}
9396

94-
// 키워드 추출 메서드
95-
public <T> T keywordExtract(String content, String promptTemplate, Class<T> classType) {
96-
String prompt = promptTemplate + content;
97-
return chatClient.prompt(new Prompt(new UserMessage(prompt)))
98-
.call()
99-
.entity(classType);
100-
}
101-
10297
private ChatResponse ChatResponse(History history, String fullResponse, List<Document> cases, List<Document> laws) {
98+
99+
ChatPrecedentDto precedentDto = null;
100+
if (cases != null && !cases.isEmpty()) {
101+
Document firstCase = cases.get(0);
102+
precedentDto = ChatPrecedentDto.from(firstCase);
103+
}
104+
105+
ChatLawDto lawDto = null;
106+
if (laws != null && !laws.isEmpty()) {
107+
Document firstLaw = laws.get(0);
108+
lawDto = ChatLawDto.from(firstLaw);
109+
}
110+
103111
return ChatResponse.builder()
104112
.roomId(history.getHistoryId())
105113
.title(history.getTitle())
106114
.message(fullResponse)
107-
.similarCases(cases)
108-
.similarLaws(laws)
115+
.precedent(precedentDto)
116+
.law(lawDto)
109117
.build();
110118
}
111119

@@ -161,7 +169,7 @@ private void handlerTasks(ChatRequest chatDto, History history, String fullRespo
161169
}
162170

163171
private void extractAndUpdateKeywordRanks(String message) {
164-
KeywordExtractionDto keywordResponse = keywordExtract(message, keywordExtraction, KeywordExtractionDto.class);
172+
KeywordExtractionDto keywordResponse = keywordService.keywordExtract(message, keywordExtraction, KeywordExtractionDto.class);
165173

166174
KeywordRank keywordRank = keywordRankRepository.findByKeyword(keywordResponse.getKeyword());
167175

@@ -180,7 +188,7 @@ private void extractAndUpdateKeywordRanks(String message) {
180188

181189
private void setHistoryTitle(ChatRequest chatDto, History history, String fullResponse) {
182190
String targetText = fullResponse.contains("해당 질문은 법률") ? chatDto.getMessage() : fullResponse;
183-
TitleExtractionDto titleDto = keywordExtract(targetText, titleExtraction, TitleExtractionDto.class);
191+
TitleExtractionDto titleDto = keywordService.keywordExtract(targetText, titleExtraction, TitleExtractionDto.class);
184192
history.setTitle(titleDto.getTitle());
185193
historyRepository.save(history);
186194
}

backend/src/main/java/com/ai/lawyer/domain/chatbot/service/KeywordService.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import com.ai.lawyer.domain.chatbot.entity.KeywordRank;
44
import com.ai.lawyer.domain.chatbot.repository.KeywordRankRepository;
55
import lombok.RequiredArgsConstructor;
6+
import org.springframework.ai.chat.client.ChatClient;
7+
import org.springframework.ai.chat.messages.UserMessage;
8+
import org.springframework.ai.chat.prompt.Prompt;
69
import org.springframework.stereotype.Service;
710

811
import java.util.List;
@@ -11,10 +14,20 @@
1114
@RequiredArgsConstructor
1215
public class KeywordService {
1316

17+
private final ChatClient chatClient;
18+
1419
private final KeywordRankRepository keywordRepository;
1520

1621
public List<KeywordRank> getTop5KeywordRanks() {
1722
return keywordRepository.findTop5ByOrderByScoreDesc();
1823
}
1924

25+
// 키워드 추출 메서드
26+
public <T> T keywordExtract(String content, String promptTemplate, Class<T> classType) {
27+
String prompt = promptTemplate + content;
28+
return chatClient.prompt(new Prompt(new UserMessage(prompt)))
29+
.call()
30+
.entity(classType);
31+
}
32+
2033
}

backend/src/main/java/com/ai/lawyer/domain/law/service/LawService.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.springframework.transaction.annotation.Transactional;
1616
import org.springframework.util.StringUtils;
1717
import org.springframework.web.client.RestTemplate;
18+
import org.springframework.web.reactive.function.client.WebClient;
1819
import org.springframework.web.util.UriComponentsBuilder;
1920

2021
import java.io.IOException;
@@ -36,8 +37,8 @@ public class LawService {
3637
private final JoRepository joRepository;
3738
private final HangRepository hangRepository;
3839
private final HoRepository hoRepository;
39-
private final RestTemplate restTemplate = new RestTemplate();
4040
private final ObjectMapper objectMapper = new ObjectMapper();
41+
private final WebClient webClient = WebClient.builder().build();
4142

4243
// 상수 정의
4344
private static final String BASE_URL = "http://www.law.go.kr/DRF";
@@ -149,7 +150,11 @@ private String getLawSearchResponse(String query) {
149150
.build()
150151
.toUriString();
151152

152-
return restTemplate.getForObject(url, String.class);
153+
return webClient.get()
154+
.uri(url)
155+
.retrieve()
156+
.bodyToMono(String.class)
157+
.block();
153158
}
154159

155160
/**
@@ -167,7 +172,11 @@ private String getLawDetailResponse(String lawId) {
167172
.build()
168173
.toUriString();
169174

170-
return restTemplate.getForObject(url, String.class);
175+
return webClient.get()
176+
.uri(url)
177+
.retrieve()
178+
.bodyToMono(String.class)
179+
.block();
171180
}
172181

173182
/**

backend/src/main/java/com/ai/lawyer/domain/lawWord/controller/LawWordController.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,25 @@ public class LawWordController {
1919

2020
private final LawWordService lawWordService;
2121

22-
@GetMapping("/{word}")
23-
@Operation(summary = "법령 용어 검색", description = "법령 용어에 대한 정의를 반환합니다. \n" +
24-
"예시: /api/law-word/선박")
25-
public ResponseEntity<?> getPrecedent(@PathVariable String word) {
22+
@GetMapping("/v1/{word}")
23+
@Operation(summary = "법령 용어 검색 version 1", description = "법령 용어에 대한 정의를 반환합니다. \n" +
24+
"예시: /api/law-word/승소")
25+
public ResponseEntity<?> getPrecedentV1(@PathVariable String word) {
2626
try {
2727
return ResponseEntity.ok(lawWordService.findDefinition(word));
2828
}catch (Exception e){
2929
return ResponseEntity.badRequest().body(e.getMessage());
3030
}
31+
}
3132

33+
@GetMapping("/v2/{word}")
34+
@Operation(summary = "법령 용어 검색 version 2", description = "법령 용어에 대한 정의를 반환합니다. \n" +
35+
"예시: /api/law-word/승소")
36+
public ResponseEntity<?> getPrecedentV2(@PathVariable String word) {
37+
try {
38+
return ResponseEntity.ok(lawWordService.findDefinitionV2(word));
39+
}catch (Exception e){
40+
return ResponseEntity.badRequest().body(e.getMessage());
41+
}
3242
}
3343
}

0 commit comments

Comments
 (0)