diff --git a/src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java b/src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java index d00da2e..39d3192 100644 --- a/src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java +++ b/src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java @@ -141,14 +141,8 @@ public Flux streamConversation(Long userId, ConversationReq ChatMessage savedUserMessage = chatMessageRepository.save(userMessage); chatMessageRepository.flush(); // ID 확보 후 MessageAsset 저장 가능 - // 4-1. 메시지-자산 연결 저장 (mentionedAssetIds + canvasImageIds) - List allAssetIds = new ArrayList<>(); - if (request.getMentionedAssetIds() != null) { - allAssetIds.addAll(request.getMentionedAssetIds()); - } - if (request.getCanvasImageIds() != null) { - allAssetIds.addAll(request.getCanvasImageIds()); - } + // 4-1. 메시지-자산 연결 저장 (mentionedAssetIds + canvasImageIds, 중복 제거) + List allAssetIds = mergeDistinctAssetIds(request.getMentionedAssetIds(), request.getCanvasImageIds()); if (!allAssetIds.isEmpty()) { List assets = assetRepository.findAllByIdInAndUserId(allAssetIds, userId); if (assets.size() != allAssetIds.size()) { @@ -179,9 +173,10 @@ public Flux streamConversation(Long userId, ConversationReq .build(); ChatMessage savedAiMessage = chatMessageRepository.save(aiMessage); - // 6. 자산 URL 변환 - List filesUrl = convertAssetIdsToUrls(request.getMentionedAssetIds(), userId); - log.info("[Chat] 자산 URL 변환 완료 - assetIds: {}, filesUrl: {}", request.getMentionedAssetIds(), filesUrl); + // 6. 자산 URL 변환 (mentionedAssetIds + canvasImageIds 모두 포함, 중복 제거) + List filesUrl = convertAssetIdsToUrls(allAssetIds, userId); + log.info("[Chat] 자산 URL 변환 완료 - mentionedAssetIds: {}, canvasImageIds: {}, filesUrl count: {}", + request.getMentionedAssetIds(), request.getCanvasImageIds(), filesUrl.size()); return new StreamInitData(chatSession, note, savedAiMessage, threadIdToUse, filesUrl); }); @@ -211,8 +206,8 @@ public Flux streamConversation(Long userId, ConversationReq .authToken(accessToken) // Spring 인증 토큰 전달 .build(); - log.info("[Chat] Proovy-ai 요청 생성 - threadId: {}, filesUrl: {}, message: {}", - finalThreadIdToUse, filesUrl, request.getText()); + log.info("[Chat] Proovy-ai 요청 생성 - threadId: {}, filesUrl count: {}, message: {}", + finalThreadIdToUse, filesUrl.size(), request.getText()); // 8. SSE 스트리밍 호출 final StringBuilder contentBuilder = new StringBuilder(); @@ -485,12 +480,21 @@ private List convertAssetIdsToUrls(List assetIds, Long userId) { return Collections.emptyList(); } - List assets = assetRepository.findAllByIdInAndUserId(assetIds, userId); - log.info("[Chat] 자산 조회 결과 - 요청: {}, 조회됨: {}, userId: {}", assetIds, assets.size(), userId); + List distinctAssetIds = assetIds.stream() + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + if (distinctAssetIds.size() != assetIds.size()) { + log.debug("[Chat] 자산 ID 중복/NULL 제거 - 원본: {}, 정제 후: {}", assetIds.size(), distinctAssetIds.size()); + } + + List assets = assetRepository.findAllByIdInAndUserId(distinctAssetIds, userId); + log.info("[Chat] 자산 조회 결과 - 요청: {}, 조회됨: {}, userId: {}", distinctAssetIds, assets.size(), userId); - if (assets.size() != assetIds.size()) { + if (assets.size() != distinctAssetIds.size()) { log.warn("[Chat] 일부 자산 조회 실패 - 요청: {}, 조회됨: {}", - assetIds.size(), assets.size()); + distinctAssetIds.size(), assets.size()); } List urls = assets.stream() @@ -498,8 +502,8 @@ private List convertAssetIdsToUrls(List assetIds, Long userId) { // Presigned URL 생성 (15분 유효) String url = s3Service.generatePresignedDownloadUrl( asset.getS3Key(), asset.getFileName(), 15); - log.info("[Chat] Presigned URL 생성 - assetId: {}, s3Key: {}, url: {}", - asset.getId(), asset.getS3Key(), url); + log.debug("[Chat] Presigned URL 생성 - assetId: {}, s3Key: {}", + asset.getId(), asset.getS3Key()); return url; }) .collect(Collectors.toList()); @@ -507,6 +511,18 @@ private List convertAssetIdsToUrls(List assetIds, Long userId) { return urls; } + private List mergeDistinctAssetIds(List mentionedAssetIds, List canvasImageIds) { + LinkedHashSet merged = new LinkedHashSet<>(); + if (mentionedAssetIds != null) { + merged.addAll(mentionedAssetIds); + } + if (canvasImageIds != null) { + merged.addAll(canvasImageIds); + } + merged.remove(null); + return new ArrayList<>(merged); + } + /** * 기능 검증 */