Skip to content

Commit 42b71ad

Browse files
committed
feat[chat]: 채팅 조회 응답 형식 변경
1 parent be55f8e commit 42b71ad

File tree

8 files changed

+189
-22
lines changed

8 files changed

+189
-22
lines changed

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

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.ai.lawyer.domain.chatbot.dto;
22

33
import com.ai.lawyer.domain.chatbot.entity.Chat;
4+
import com.ai.lawyer.domain.chatbot.entity.ChatLaw;
5+
import com.ai.lawyer.domain.chatbot.entity.ChatPrecedent;
46
import io.swagger.v3.oas.annotations.media.Schema;
57
import lombok.*;
68
import org.springframework.ai.document.Document;
79

810
import java.time.LocalDateTime;
11+
import java.util.ArrayList;
912
import java.util.List;
1013

1114
@Schema(description = "채팅 관련 DTO")
@@ -18,10 +21,8 @@ public class ChatDto {
1821
@AllArgsConstructor
1922
@Schema(description = "채팅 요청 DTO")
2023
public static class ChatRequest {
21-
2224
@Schema(description = "사용자가 입력한 메시지", example = "보험 회사에서 손해배상 청구를 거절당했어요. 어떻게 해야 하나요?")
2325
private String message;
24-
2526
}
2627

2728
@Getter
@@ -48,6 +49,52 @@ public static class ChatResponse {
4849
private List<Document> similarLaws;
4950
}
5051

52+
@Getter
53+
@Setter
54+
@Builder
55+
@NoArgsConstructor
56+
@AllArgsConstructor
57+
@Schema(description = "판례 내용 DTO")
58+
public static class ChatPrecedentDto {
59+
60+
@Schema(description = "판례 내용", example = "이 사건은 손해배상 청구에 관한 판례입니다...")
61+
private String precedentContent;
62+
63+
@Schema(description = "케이스 넘버", example = "[2020다12345]")
64+
private String caseNumber;
65+
66+
@Schema(description = "사건명", example = "손해배상 청구 사건")
67+
private String caseName;
68+
69+
public static ChatPrecedentDto from(ChatPrecedent cp) {
70+
return ChatPrecedentDto.builder()
71+
.precedentContent(cp.getPrecedentContent())
72+
.caseNumber(cp.getCaseNumber())
73+
.caseName(cp.getCaseName())
74+
.build();
75+
}
76+
}
77+
78+
@Data
79+
@Builder
80+
@AllArgsConstructor
81+
@NoArgsConstructor
82+
public static class ChatLawDto {
83+
84+
@Schema(description = "법령 내용", example = "제123조(손해배상) ① 누구든지 타인에게 손해를 가한 때에는 그 손해를 배상할 책임이 있다...")
85+
private String content;
86+
87+
@Schema(description = "법령명", example = "민법")
88+
private String lawName;
89+
90+
public static ChatLawDto from(ChatLaw cl) {
91+
return ChatLawDto.builder()
92+
.content(cl.getContent())
93+
.lawName(cl.getLawName())
94+
.build();
95+
}
96+
}
97+
5198
@Getter
5299
@Setter
53100
@Builder
@@ -62,16 +109,32 @@ public static class ChatHistoryDto {
62109
@Schema(description = "메시지 내용", example = "안녕하세요~~")
63110
private String message;
64111

112+
private List<ChatPrecedentDto> precedents;
113+
114+
private List<ChatLawDto> laws;
115+
65116
@Schema(description = "생성 시간")
66117
private LocalDateTime createdAt;
67118

68119
public static ChatHistoryDto from(Chat chat) {
120+
121+
List<ChatPrecedentDto> precedentDtos = new ArrayList<>();
122+
for (ChatPrecedent cp : chat.getChatPrecedents()) {
123+
precedentDtos.add(ChatPrecedentDto.from(cp));
124+
}
125+
126+
List<ChatLawDto> lawDtos = new ArrayList<>();
127+
for (ChatLaw cl : chat.getChatLaws()) {
128+
lawDtos.add(ChatLawDto.from(cl));
129+
}
130+
69131
return ChatHistoryDto.builder()
70132
.type(chat.getType().toString())
71133
.message(chat.getMessage())
72134
.createdAt(chat.getCreatedAt())
135+
.precedents(precedentDtos)
136+
.laws(lawDtos)
73137
.build();
74138
}
75139
}
76-
77140
}

backend/src/main/java/com/ai/lawyer/domain/chatbot/entity/Chat.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.springframework.ai.chat.messages.MessageType;
1010

1111
import java.time.LocalDateTime;
12+
import java.util.List;
1213

1314
@Entity
1415
@Data
@@ -32,6 +33,12 @@ public class Chat {
3233
@Lob
3334
private String message;
3435

36+
@OneToMany(mappedBy = "chatId")
37+
private List<ChatPrecedent> chatPrecedents;
38+
39+
@OneToMany(mappedBy = "chatId")
40+
private List<ChatLaw> chatLaws;
41+
3542
@CreationTimestamp
3643
@Column(updatable = false)
3744
private LocalDateTime createdAt;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.ai.lawyer.domain.chatbot.entity;
2+
3+
import jakarta.persistence.*;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
@Entity
10+
@Data
11+
@Builder
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Table(name = "chat_law")
15+
public class ChatLaw {
16+
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
private Long chatLawId;
20+
21+
@ManyToOne
22+
@JoinColumn(name = "chat_id")
23+
private Chat chatId;
24+
25+
@Lob
26+
String content;
27+
28+
String lawName;
29+
30+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.ai.lawyer.domain.chatbot.entity;
2+
3+
import jakarta.persistence.*;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
@Entity
10+
@Data
11+
@Builder
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Table(name = "chat_precedent")
15+
public class ChatPrecedent {
16+
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
private Long chatPrecedentId;
20+
21+
@ManyToOne
22+
@JoinColumn(name = "chat_id")
23+
private Chat chatId;
24+
25+
@Lob
26+
private String precedentContent;
27+
28+
private String caseNumber;
29+
30+
private String caseName;
31+
32+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.ai.lawyer.domain.chatbot.repository;
2+
3+
import com.ai.lawyer.domain.chatbot.entity.ChatLaw;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface ChatLawRepository extends JpaRepository<ChatLaw, Long> {
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.ai.lawyer.domain.chatbot.repository;
2+
3+
import com.ai.lawyer.domain.chatbot.entity.ChatPrecedent;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface ChatPrecedentRepository extends JpaRepository<ChatPrecedent, Long> {
7+
}

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

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44
import com.ai.lawyer.domain.chatbot.dto.ChatDto.ChatResponse;
55
import com.ai.lawyer.domain.chatbot.dto.ExtractionDto.KeywordExtractionDto;
66
import com.ai.lawyer.domain.chatbot.dto.ExtractionDto.TitleExtractionDto;
7-
import com.ai.lawyer.domain.chatbot.entity.Chat;
8-
import com.ai.lawyer.domain.chatbot.entity.History;
9-
import com.ai.lawyer.domain.chatbot.entity.KeywordRank;
10-
import com.ai.lawyer.domain.chatbot.repository.ChatRepository;
11-
import com.ai.lawyer.domain.chatbot.repository.HistoryRepository;
12-
import com.ai.lawyer.domain.chatbot.repository.KeywordRankRepository;
7+
import com.ai.lawyer.domain.chatbot.entity.*;
8+
import com.ai.lawyer.domain.chatbot.repository.*;
139
import com.ai.lawyer.domain.member.entity.Member;
1410
import com.ai.lawyer.domain.member.repositories.MemberRepository;
1511
import com.ai.lawyer.global.qdrant.service.QdrantService;
@@ -40,14 +36,15 @@ public class ChatBotService {
4036
private final ChatClient chatClient;
4137

4238
private final QdrantService qdrantService;
39+
private final HistoryService historyService;
4340

4441
private final ChatRepository chatRepository;
4542
private final HistoryRepository historyRepository;
4643
private final KeywordRankRepository keywordRankRepository;
4744
private final ChatMemoryRepository chatMemoryRepository;
48-
private final HistoryService historyService;
49-
5045
private final MemberRepository memberRepository;
46+
private final ChatPrecedentRepository chatPrecedentRepository;
47+
private final ChatLawRepository chatLawRepository;
5148

5249
@Value("${custom.ai.system-message}")
5350
private String systemMessageTemplate;
@@ -64,9 +61,9 @@ public Flux<ChatResponse> sendMessage(Long memberId, ChatRequest chatChatRequest
6461
() -> new IllegalArgumentException("존재하지 않는 회원입니다.")
6562
);
6663

67-
// 벡터 검색 (판례 3개, 법령 2개)
68-
List<Document> similarCaseDocuments = qdrantService.searchDocument(chatChatRequestDto.getMessage(), "type", "판례", 3);
69-
List<Document> similarLawDocuments = qdrantService.searchDocument(chatChatRequestDto.getMessage(), "type", "법령", 2);
64+
// 벡터 검색 (판례, 법령)
65+
List<Document> similarCaseDocuments = qdrantService.searchDocument(chatChatRequestDto.getMessage(), "type", "판례");
66+
List<Document> similarLawDocuments = qdrantService.searchDocument(chatChatRequestDto.getMessage(), "type", "법령");
7067

7168
// 판례와 법령 정보를 구분 있게 포맷팅
7269
String caseContext = formatting(similarCaseDocuments);
@@ -88,7 +85,7 @@ public Flux<ChatResponse> sendMessage(Long memberId, ChatRequest chatChatRequest
8885
.content()
8986
.collectList()
9087
.map(fullResponseList -> String.join("", fullResponseList))
91-
.doOnNext(fullResponse -> handlerTasks(chatChatRequestDto, history, fullResponse, chatMemory)) // 응답이 완성되면 후처리 실행 (대화 저장, 키워드/제목 추출 등)
88+
.doOnNext(fullResponse -> handlerTasks(chatChatRequestDto, history, fullResponse, chatMemory, similarCaseDocuments, similarLawDocuments)) // 응답이 완성되면 후처리 실행 (대화 저장, 키워드/제목 추출 등)
9289
.map(fullResponse -> ChatResponse(history, fullResponse, similarCaseDocuments, similarLawDocuments) // 최종적으로 ChatResponse DTO 생성
9390
).flux()
9491
.onErrorResume(throwable -> Flux.just(handleError(history))); // 에러 발생 시 에러 핸들링 -> 재전송 유도
@@ -143,7 +140,7 @@ private ChatResponse handleError(History history) {
143140
.build();
144141
}
145142

146-
private void handlerTasks(ChatRequest chatDto, History history, String fullResponse, ChatMemory chatMemory) {
143+
private void handlerTasks(ChatRequest chatDto, History history, String fullResponse, ChatMemory chatMemory, List<Document> similarCaseDocuments, List<Document> similarLawDocuments) {
147144

148145
// 메시지 기억 저장
149146
chatMemory.add(String.valueOf(history.getHistoryId()), new AssistantMessage(fullResponse));
@@ -153,8 +150,8 @@ private void handlerTasks(ChatRequest chatDto, History history, String fullRespo
153150
setHistoryTitle(chatDto, history, fullResponse);
154151

155152
// 채팅 기록 저장
156-
saveChat(history, MessageType.USER, chatDto.getMessage());
157-
saveChat(history, MessageType.ASSISTANT, fullResponse);
153+
saveChat(history, MessageType.USER, chatDto.getMessage(), similarCaseDocuments, similarLawDocuments);
154+
saveChat(history, MessageType.ASSISTANT, fullResponse, similarCaseDocuments, similarLawDocuments);
158155

159156
// 키워드 추출 및 키워드 랭킹 저장 (법과 관련 없는 질문은 제외)
160157
if (!fullResponse.contains("해당 질문은 법과 관련된")) {
@@ -187,12 +184,35 @@ private void setHistoryTitle(ChatRequest chatDto, History history, String fullRe
187184
historyRepository.save(history);
188185
}
189186

190-
private void saveChat(History history, MessageType type, String message) {
191-
chatRepository.save(Chat.builder()
187+
private void saveChat(History history, MessageType type, String message, List<Document> similarCaseDocuments, List<Document> similarLawDocuments) {
188+
Chat chat = chatRepository.save(Chat.builder()
192189
.historyId(history)
193190
.type(type)
194191
.message(message)
195192
.build());
193+
194+
if (type == MessageType.USER && similarCaseDocuments != null) {
195+
List<ChatPrecedent> chatPrecedents = similarCaseDocuments.stream()
196+
.map(doc -> ChatPrecedent.builder()
197+
.chatId(chat)
198+
.precedentContent(doc.getText())
199+
.caseNumber(doc.getMetadata().get("caseNumber").toString())
200+
.caseName(doc.getMetadata().get("caseName").toString())
201+
.build())
202+
.toList();
203+
chatPrecedentRepository.saveAll(chatPrecedents);
204+
205+
List<ChatLaw> chatLaws = similarLawDocuments.stream()
206+
.map(doc -> ChatLaw.builder()
207+
.chatId(chat)
208+
.content(doc.getText())
209+
.lawName(doc.getMetadata().get("lawName").toString())
210+
.build())
211+
.toList();
212+
213+
chatLawRepository.saveAll(chatLaws);
214+
}
215+
196216
}
197217

198218
private History getOrCreateRoom(Member member, Long roomId) {

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public String deleteHistory(Long memberId, Long roomId) {
4444

4545
History room = historyRepository.findByHistoryIdAndMemberId(roomId, member);
4646

47-
4847
historyRepository.delete(room);
4948
return "채팅방이 삭제되었습니다.";
5049

@@ -56,4 +55,4 @@ public History getHistory(Long roomId) {
5655
);
5756
}
5857

59-
}
58+
}

0 commit comments

Comments
 (0)