Skip to content

Commit 10588d9

Browse files
authored
[Feat/OPS-327] 자료 등록 llm 연동 (#78)
* refactor/OPS-255 : datasource 테이블 sources 칼럼 추가 * refactor/OPS-319 : 아카이브 로그인 연동 * refactor/OPS-319 : 아카이브 로그인 연동 * refactor/OPS-327 : 자료 등록 LLM 연동
1 parent b8e8c6d commit 10588d9

File tree

5 files changed

+288
-17
lines changed

5 files changed

+288
-17
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
package org.tuna.zoopzoop.backend.domain.datasource.repository;
22

33
import org.springframework.data.jpa.repository.JpaRepository;
4+
import org.springframework.data.jpa.repository.Query;
5+
import org.springframework.data.repository.query.Param;
46
import org.springframework.stereotype.Repository;
57
import org.tuna.zoopzoop.backend.domain.datasource.entity.Tag;
68

9+
import java.util.List;
10+
711
@Repository
812
public interface TagRepository extends JpaRepository<Tag, Integer> {
13+
@Query("""
14+
select distinct t.tagName
15+
from Tag t
16+
where t.dataSource.folder.id = :folderId
17+
""")
18+
List<String> findDistinctTagNamesByFolderId(@Param("folderId") Integer folderId);
919
}

src/main/java/org/tuna/zoopzoop/backend/domain/datasource/service/DataSourceService.java

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88
import org.tuna.zoopzoop.backend.domain.archive.archive.repository.PersonalArchiveRepository;
99
import org.tuna.zoopzoop.backend.domain.archive.folder.entity.Folder;
1010
import org.tuna.zoopzoop.backend.domain.archive.folder.repository.FolderRepository;
11+
import org.tuna.zoopzoop.backend.domain.datasource.dataprocessor.service.DataProcessorService;
12+
import org.tuna.zoopzoop.backend.domain.datasource.dto.DataSourceDto;
1113
import org.tuna.zoopzoop.backend.domain.datasource.entity.Category;
1214
import org.tuna.zoopzoop.backend.domain.datasource.entity.DataSource;
15+
import org.tuna.zoopzoop.backend.domain.datasource.entity.Tag;
1316
import org.tuna.zoopzoop.backend.domain.datasource.repository.DataSourceRepository;
17+
import org.tuna.zoopzoop.backend.domain.datasource.repository.TagRepository;
1418

19+
import java.io.IOException;
1520
import java.time.LocalDate;
1621
import java.util.*;
1722
import java.util.stream.Collectors;
@@ -22,6 +27,8 @@ public class DataSourceService {
2227
private final DataSourceRepository dataSourceRepository;
2328
private final FolderRepository folderRepository;
2429
private final PersonalArchiveRepository personalArchiveRepository;
30+
private final TagRepository tagRepository;
31+
private final DataProcessorService dataProcessorService;
2532

2633
/**
2734
* 지정한 folder 위치에 자료 생성
@@ -35,23 +42,52 @@ public int createDataSource(int currentMemberId, String sourceUrl, Integer folde
3542
folder = folderRepository.findById(folderId)
3643
.orElseThrow(() -> new NoResultException("존재하지 않는 폴더입니다."));
3744

38-
DataSource ds = buildDataSource(sourceUrl, folder);
39-
DataSource saved = dataSourceRepository.save(ds);
45+
// 폴더 하위 자료 태그 수집(중복 X)
46+
List<Tag> contextTags = collectDistinctTagsOfFolder(folder.getId());
4047

48+
DataSource ds = buildDataSource(folder, sourceUrl, contextTags);
49+
50+
// 4) 저장
51+
final DataSource saved = dataSourceRepository.save(ds);
4152
return saved.getId();
4253
}
4354

44-
private DataSource buildDataSource(String sourceUrl, Folder folder) {
55+
// 폴더 하위 태그 중복없이 list 반환
56+
private List<Tag> collectDistinctTagsOfFolder(Integer folderId) {
57+
List<String> names = tagRepository.findDistinctTagNamesByFolderId(folderId);
58+
59+
return names.stream()
60+
.map(Tag::new)
61+
.toList();
62+
}
63+
64+
private DataSource buildDataSource(Folder folder, String sourceUrl, List<Tag> tagList) {
65+
final DataSourceDto dataSourceDto;
66+
try {
67+
dataSourceDto = dataProcessorService.process(sourceUrl, tagList);
68+
} catch (IOException e) {
69+
throw new RuntimeException("자료 처리 중 오류가 발생했습니다.", e);
70+
}
71+
4572
DataSource ds = new DataSource();
4673
ds.setFolder(folder);
47-
ds.setSourceUrl(sourceUrl);
48-
ds.setTitle("자료 제목");
49-
ds.setSource("www.examplesource.com");
50-
ds.setSummary("설명");
51-
ds.setImageUrl("www.example.com/img");
52-
ds.setDataCreatedDate(LocalDate.now());
53-
ds.setCategory(Category.IT);
74+
ds.setSourceUrl(dataSourceDto.sourceUrl());
75+
ds.setTitle(dataSourceDto.title());
76+
ds.setSummary(dataSourceDto.summary());
77+
ds.setDataCreatedDate(dataSourceDto.dataCreatedDate());
78+
ds.setImageUrl(dataSourceDto.imageUrl());
79+
ds.setSource(dataSourceDto.source());
80+
ds.setCategory(dataSourceDto.category());
5481
ds.setActive(true);
82+
83+
if (dataSourceDto.tags() != null) {
84+
for (String tagName : dataSourceDto.tags()) {
85+
Tag tag = new Tag(tagName);
86+
tag.setDataSource(ds);
87+
ds.getTags().add(tag);
88+
}
89+
}
90+
5591
return ds;
5692
}
5793

src/test/java/org/tuna/zoopzoop/backend/domain/archive/folder/service/FolderServiceTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.tuna.zoopzoop.backend.domain.archive.folder.dto.FolderResponse;
1818
import org.tuna.zoopzoop.backend.domain.archive.folder.entity.Folder;
1919
import org.tuna.zoopzoop.backend.domain.archive.folder.repository.FolderRepository;
20+
import org.tuna.zoopzoop.backend.domain.datasource.entity.Category;
2021
import org.tuna.zoopzoop.backend.domain.datasource.dto.FolderFilesDto;
2122
import org.tuna.zoopzoop.backend.domain.datasource.dto.FileSummary;
2223
import org.tuna.zoopzoop.backend.domain.datasource.entity.DataSource;
@@ -272,7 +273,7 @@ void getFilesInFolderForPersonal_success() {
272273
d1.setSourceUrl("http://src/a");
273274
d1.setImageUrl("http://img/a");
274275
d1.setTags(List.of(new Tag("tag1"), new Tag("tag2")));
275-
d1.setCategory(org.tuna.zoopzoop.backend.domain.datasource.entity.Category.IT);
276+
d1.setCategory(Category.IT);
276277

277278
DataSource d2 = new DataSource();
278279
ReflectionTestUtils.setField(d2, "id", 11);
@@ -282,7 +283,7 @@ void getFilesInFolderForPersonal_success() {
282283
d2.setSourceUrl("http://src/b");
283284
d2.setImageUrl("http://img/b");
284285
d2.setTags(List.of());
285-
d2.setCategory(org.tuna.zoopzoop.backend.domain.datasource.entity.Category.SCIENCE);
286+
d2.setCategory(Category.SCIENCE);
286287

287288
when(dataSourceRepository.findAllByFolder(folder)).thenReturn(List.of(d1, d2));
288289

src/test/java/org/tuna/zoopzoop/backend/domain/datasource/controller/DatasourceControllerTest.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import org.junit.jupiter.api.*;
5+
import org.mockito.Mockito;
56
import org.springframework.beans.factory.annotation.Autowired;
67
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
78
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.springframework.boot.test.context.TestConfiguration;
10+
import org.springframework.context.annotation.Bean;
11+
import org.springframework.context.annotation.Primary;
812
import org.springframework.http.MediaType;
913
import org.springframework.security.test.context.support.TestExecutionEvent;
1014
import org.springframework.security.test.context.support.WithUserDetails;
@@ -15,11 +19,13 @@
1519
import org.tuna.zoopzoop.backend.domain.archive.folder.entity.Folder;
1620
import org.tuna.zoopzoop.backend.domain.archive.folder.service.FolderService;
1721
import org.tuna.zoopzoop.backend.domain.archive.folder.repository.FolderRepository;
22+
import org.tuna.zoopzoop.backend.domain.datasource.dataprocessor.service.DataProcessorService;
1823
import org.tuna.zoopzoop.backend.domain.datasource.dto.*;
1924
import org.tuna.zoopzoop.backend.domain.datasource.entity.Category;
2025
import org.tuna.zoopzoop.backend.domain.datasource.entity.DataSource;
2126
import org.tuna.zoopzoop.backend.domain.datasource.entity.Tag;
2227
import org.tuna.zoopzoop.backend.domain.datasource.repository.DataSourceRepository;
28+
import org.tuna.zoopzoop.backend.domain.datasource.repository.TagRepository;
2329
import org.tuna.zoopzoop.backend.domain.member.enums.Provider;
2430
import org.tuna.zoopzoop.backend.domain.member.repository.MemberRepository;
2531
import org.tuna.zoopzoop.backend.domain.member.service.MemberService;
@@ -28,6 +34,8 @@
2834
import java.util.List;
2935

3036
import static org.hamcrest.Matchers.*;
37+
import static org.mockito.ArgumentMatchers.anyInt;
38+
import static org.mockito.Mockito.when;
3139
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
3240
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
3341

@@ -37,7 +45,6 @@
3745
@Transactional
3846
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
3947
class DatasourceControllerTest {
40-
4148
@Autowired private MockMvc mockMvc;
4249
@Autowired private ObjectMapper objectMapper;
4350

@@ -47,13 +54,47 @@ class DatasourceControllerTest {
4754
@Autowired private FolderRepository folderRepository;
4855
@Autowired private DataSourceRepository dataSourceRepository;
4956

50-
private final String TEST_PROVIDER_KEY = "testUser_sc1111"; // WithUserDetails username -> "KAKAO:testUser_sc1111"
57+
private final String TEST_PROVIDER_KEY = "testUser_sc1111";
5158

5259
private Integer testMemberId;
5360
private Integer docsFolderId;
5461
private Integer dataSourceId1;
5562
private Integer dataSourceId2;
5663

64+
@TestConfiguration
65+
static class StubConfig {
66+
@Bean
67+
@Primary
68+
DataProcessorService stubDataProcessorService() throws Exception {
69+
return new DataProcessorService(null, null) {
70+
@Override
71+
public DataSourceDto process(String url, List<Tag> tagList) {
72+
return new DataSourceDto(
73+
"테스트제목",
74+
"테스트요약",
75+
LocalDate.of(2025, 9, 1),
76+
url,
77+
"https://img.example/test.png",
78+
"example.com",
79+
Category.IT,
80+
List.of("ML","Infra")
81+
);
82+
}
83+
};
84+
}
85+
86+
@Bean
87+
@Primary
88+
TagRepository stubTagRepository() {
89+
TagRepository mock = Mockito.mock(TagRepository.class);
90+
91+
when(mock.findDistinctTagNamesByFolderId(anyInt()))
92+
.thenReturn(java.util.List.of("AI", "Spring"));
93+
94+
return mock;
95+
}
96+
}
97+
5798
@BeforeAll
5899
void beforeAll() {
59100
try {
@@ -110,7 +151,6 @@ void beforeAll() {
110151

111152
@AfterAll
112153
void afterAll() {
113-
// 생성한 자료/폴더/멤버 삭제
114154
try {
115155
if (dataSourceId1 != null) dataSourceRepository.findById(dataSourceId1).ifPresent(dataSourceRepository::delete);
116156
} catch (Exception ignored) {}

0 commit comments

Comments
 (0)