Skip to content

Commit d667d1b

Browse files
committed
refactor: 품목 items DB에서 가져오도록 수정
1 parent ccd806f commit d667d1b

File tree

3 files changed

+42
-24
lines changed

3 files changed

+42
-24
lines changed

src/main/java/com/trashheroesbe/feature/trash/infrastructure/TrashItemRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.trashheroesbe.feature.trash.infrastructure;
22

3+
import com.trashheroesbe.feature.trash.domain.Type;
34
import com.trashheroesbe.feature.trash.domain.entity.TrashItem;
45
import com.trashheroesbe.feature.trash.domain.entity.TrashType;
56
import java.util.List;
@@ -15,4 +16,7 @@ public interface TrashItemRepository extends JpaRepository<TrashItem, Long> {
1516
List<TrashItem> findByTrashTypeId(Long trashTypeId);
1617

1718
Optional<TrashItem> findByTrashTypeAndName(TrashType trashType, String name);
19+
20+
@EntityGraph(attributePaths = {"trashType"})
21+
List<TrashItem> findByTrashType_Type(Type type);
1822
}

src/main/java/com/trashheroesbe/feature/trash/infrastructure/TrashTypeRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ public interface TrashTypeRepository extends JpaRepository<TrashType, Long> {
1717
Optional<TrashType> findByType(Type type);
1818

1919
List<TrashType> findAllByOrderByIdAsc();
20+
21+
@Query("select t.type from TrashType t")
22+
java.util.List<Type> findAllTypes();
2023
}

src/main/java/com/trashheroesbe/infrastructure/adapter/out/gpt/OpenAIChatAdapter.java

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,37 @@
1111
import com.trashheroesbe.feature.trash.dto.response.TrashAnalysisResponseDto;
1212
import com.trashheroesbe.feature.trash.domain.Type;
1313
import com.trashheroesbe.feature.trash.domain.entity.TrashType;
14+
import com.trashheroesbe.feature.trash.infrastructure.TrashItemRepository;
15+
import com.trashheroesbe.feature.trash.infrastructure.TrashTypeRepository;
1416
import com.trashheroesbe.global.exception.BusinessException;
1517
import com.trashheroesbe.infrastructure.port.gpt.ChatAIClientPort;
16-
import java.util.EnumMap;
1718
import java.util.List;
1819
import java.util.Map;
19-
import java.util.Optional;
20+
import java.util.concurrent.ConcurrentHashMap;
2021
import java.util.stream.Collectors;
2122
import lombok.extern.slf4j.Slf4j;
2223
import org.springframework.ai.chat.client.ChatClient;
2324
import org.springframework.core.io.ByteArrayResource;
2425
import org.springframework.stereotype.Service;
2526
import org.springframework.util.MimeType;
2627
import org.springframework.util.MimeTypeUtils;
28+
import com.trashheroesbe.feature.trash.domain.entity.TrashItem;
2729

2830
@Service
2931
@Slf4j
3032
public class OpenAIChatAdapter implements ChatAIClientPort {
3133

3234
private final ObjectMapper om = new ObjectMapper();
3335
private final ChatClient chatClient;
36+
private final TrashItemRepository trashItemRepository;
37+
private final TrashTypeRepository trashTypeRepository;
3438

35-
public OpenAIChatAdapter(ChatClient.Builder builder) {
39+
private final Map<Type, List<String>> itemCache = new ConcurrentHashMap<>();
40+
41+
public OpenAIChatAdapter(ChatClient.Builder builder, final TrashItemRepository trashItemRepository, final TrashTypeRepository trashTypeRepository) {
3642
this.chatClient = builder.build();
43+
this.trashItemRepository = trashItemRepository;
44+
this.trashTypeRepository = trashTypeRepository;
3745
}
3846

3947
@Override
@@ -113,8 +121,9 @@ public Type findSimilarTrashItem(String keyword) {
113121
}
114122

115123
private String buildSimilarTrashTypePrompt(String keyword) {
116-
String availableTypes = ALLOWED_ITEMS.keySet().stream()
117-
.map(Type::name)
124+
var types = trashTypeRepository.findAllTypes();
125+
String availableTypes = types.stream()
126+
.map(Enum::name)
118127
.collect(Collectors.joining(", "));
119128

120129
return String.format("""
@@ -158,32 +167,34 @@ private String buildTypePrompt() {
158167
""".formatted(allowed);
159168
}
160169

161-
private final Map<Type, List<String>> ALLOWED_ITEMS = new EnumMap<>(Type.class) {{
162-
put(Type.PAPER, List.of("일반 종이류"));
163-
put(Type.PAPER_PACK, List.of("종이팩"));
164-
put(Type.PLASTIC, List.of("플라스틱 병", "음식 용기", "과일용기", "샴푸병"));
165-
put(Type.PET, List.of("PET(투명 페트병)", "PET(유색 페트병)"));
166-
put(Type.VINYL_FILM, List.of("비닐봉투", "뽁뽁이", "아이스팩"));
167-
put(Type.STYROFOAM, List.of("완충 포장재", "라면용기", "식품 포장상자", "아이스박스"));
168-
put(Type.GLASS, List.of("투명 유리병", "유색 유리병"));
169-
put(Type.METAL, List.of("알루미늄 캔", "철 캔"));
170-
put(Type.TEXTILES, List.of("의류", "섬유"));
171-
put(Type.E_WASTE, List.of("냉장고", "TV", "핸드폰", "라디오"));
172-
put(Type.HAZARDOUS_SMALL_WASTE, List.of("폐형광등", "폐건전지", "보조배터리"));
173-
put(Type.FOOD_WASTE, List.of("야채,과일 껍질", "남은음식", "뼈(닭 등의 뼈다귀, 생선뼈)", "껍데기(갑각류, 어패류)"));
174-
put(Type.NON_RECYCLABLE, List.of("일반쓰레기", "기름이 묻은 종이", "카드영수증", "부서진 그릇"));
175-
}};
170+
private List<String> loadAllowedItems(Type type) {
171+
return itemCache.computeIfAbsent(type, t ->
172+
trashItemRepository.findByTrashType_Type(t).stream()
173+
.map(TrashItem::getName)
174+
.filter(s -> s != null && !s.isBlank())
175+
.toList()
176+
);
177+
}
176178

177179
private String buildItemPrompt(Type type) {
178-
List<String> items = ALLOWED_ITEMS.getOrDefault(type, List.of());
179-
String list = items.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(", "));
180+
List<String> items = loadAllowedItems(type);
181+
if (items.isEmpty()) {
182+
// 품목 테이블에 데이터가 없는 타입은 목록 제한 없이 간단 규칙만 제공
183+
return """
184+
너는 쓰레기 분류 전문가다. 세부 품목(item)만 판단하여 JSON으로 반환하라.
185+
- JSON(객체)만 반환. 코드블록, 여분 텍스트 금지.
186+
- type=%s 이다. item은 한국어로 간결히 작성:
187+
- 출력 형식: {"item":"PET(투명 페트병)"}
188+
""".formatted(type.name());
189+
}
190+
String list = items.stream().map(s -> "\"" + s + "\"").collect(java.util.stream.Collectors.joining(", "));
180191
return """
181192
너는 쓰레기 분류 전문가다. 세부 품목(item)만 판단하여 JSON으로 반환하라.
182193
- JSON(객체)만 반환. 코드블록, 여분 텍스트 금지.
183194
- type=%s 이며, item은 아래 허용 목록 중 정확히 하나(한국어)만 선택:
184195
[ %s ]
185-
- 출력 형식: {"item":"PET(투명 페트병)"}
186-
""".formatted(type.name(), list);
196+
- 출력 형식: {"item":"%s"}
197+
""".formatted(type.name(), list, items.get(0));
187198
}
188199

189200
private TrashAnalysisResponseDto parseTypeResponse(String content) {

0 commit comments

Comments
 (0)