From 6120b8d6c24a70092a91c9d193e015efa5d8b103 Mon Sep 17 00:00:00 2001 From: PAVEL PALMA Date: Fri, 12 Sep 2025 16:09:42 -0600 Subject: [PATCH] UPDATE 12-sept --- pom.xml | 50 ++++++- .../ConversationSummaryController.java | 56 -------- .../gemini/ConversationEntrySummaryDTO.java | 53 ------- .../gemini/ConversationSessionSummaryDTO.java | 37 ----- .../gemini/ConversationSummaryRequest.java | 29 ---- .../gemini/ConversationSummaryResponse.java | 13 -- .../ExternalConvRequestMapper.java | 3 +- .../ExternalNotRequestMapper.java | 2 +- .../service/base/MessageEntryFilter.java | 2 +- .../FirestoreConversationService.java | 2 - .../MemoryStoreConversationService.java | 8 +- .../FirestoreNotificationService.java | 7 +- .../MemoryStoreNotificationService.java | 15 +- .../NotificationManagerService.java | 11 +- .../quickreplies/MemoryStoreQRService.java | 10 +- .../QuickRepliesManagerService.java | 34 ++--- .../summary/ConversationSummaryService.java | 132 ------------------ 17 files changed, 89 insertions(+), 375 deletions(-) delete mode 100644 src/main/java/com/example/controller/ConversationSummaryController.java delete mode 100644 src/main/java/com/example/dto/gemini/ConversationEntrySummaryDTO.java delete mode 100644 src/main/java/com/example/dto/gemini/ConversationSessionSummaryDTO.java delete mode 100644 src/main/java/com/example/dto/gemini/ConversationSummaryRequest.java delete mode 100644 src/main/java/com/example/dto/gemini/ConversationSummaryResponse.java delete mode 100644 src/main/java/com/example/service/summary/ConversationSummaryService.java diff --git a/pom.xml b/pom.xml index 9b199f9..dad285d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.0 + 3.3.11 @@ -21,6 +21,7 @@ 5.4.0 2023.0.0 6.4.0.RELEASE + 6.1.20 @@ -46,6 +47,13 @@ pom import + + io.projectreactor + reactor-bom + 2024.0.8 + pom + import + @@ -91,7 +99,7 @@ com.google.genai google-genai - 1.13.0 + 1.14.0 com.google.protobuf @@ -126,13 +134,49 @@ io.netty netty-codec-http2 - 4.1.124.Final + 4.1.125.Final + + + io.netty + netty-handler + 4.1.125.Final + + + io.netty + netty-common + 4.1.125.Final + + + io.netty + netty-codec-http + 4.1.125.Final + + + io.netty + netty-codec + 4.1.125.Final com.google.protobuf protobuf-java 3.25.5 + + net.minidev + json-smart + 2.5.2 + + + org.xmlunit + xmlunit-core + 2.10.0 + test + + + org.apache.commons + commons-lang3 + 3.18.0 + diff --git a/src/main/java/com/example/controller/ConversationSummaryController.java b/src/main/java/com/example/controller/ConversationSummaryController.java deleted file mode 100644 index e73e1b5..0000000 --- a/src/main/java/com/example/controller/ConversationSummaryController.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2025 Google. This software is provided as-is, without warranty or representation for any use or purpose. - * Your use of it is subject to your agreement with Google. - */ - -package com.example.controller; - -import com.example.dto.gemini.ConversationSummaryRequest; -import com.example.dto.gemini.ConversationSummaryResponse; -import com.example.service.summary.ConversationSummaryService; - -import jakarta.validation.Valid; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@RestController -@RequestMapping("/api/v1/summary") -public class ConversationSummaryController { - - private static final Logger logger = LoggerFactory.getLogger(ConversationSummaryController.class); - private final ConversationSummaryService conversationSummaryService; - - public ConversationSummaryController(ConversationSummaryService conversationSummaryService) { - this.conversationSummaryService = conversationSummaryService; - } - - - @PostMapping("/conversation") - public ResponseEntity summarizeConversation( - @Valid @RequestBody ConversationSummaryRequest request) { - - logger.info("Received request to summarize conversation for session ID: {}", - request.sessionId()); - - ConversationSummaryResponse response = conversationSummaryService.summarizeConversation(request); - - if (response.summaryText() != null && - (response.summaryText().contains("Error:") || - response.summaryText().contains("Failed:") || - response.summaryText().contains("not found") || - response.summaryText().contains("No conversation provided"))) { - logger.error("Summarization failed for session ID {}: {}", request.sessionId(), response.summaryText()); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); - } else { - logger.info("Successfully processed summarization request for session ID: {}", request.sessionId()); - return ResponseEntity.ok(response); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/example/dto/gemini/ConversationEntrySummaryDTO.java b/src/main/java/com/example/dto/gemini/ConversationEntrySummaryDTO.java deleted file mode 100644 index a98acec..0000000 --- a/src/main/java/com/example/dto/gemini/ConversationEntrySummaryDTO.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2025 Google. This software is provided as-is, without warranty or representation for any use or purpose. - * Your use of it is subject to your agreement with Google. - */ - -package com.example.dto.gemini; - -import com.example.dto.dialogflow.conversation.ConversationEntryEntity; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.cloud.Timestamp; -import java.util.Map; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public record ConversationEntrySummaryDTO( - @JsonProperty("text") String text, - @JsonProperty("timestamp") Timestamp timestamp, - Optional type, - @JsonProperty("intentDisplayName") String intentDisplayName, - @JsonProperty("parameters") Map parameters, - @JsonProperty("webhookStatus") String webhookStatus, - @JsonProperty("canal") String canal -) { - @JsonCreator - public ConversationEntrySummaryDTO( - @JsonProperty("text") String text, - @JsonProperty("timestamp") Timestamp timestamp, - @JsonProperty("type") String typeString, - @JsonProperty("intentDisplayName") String intentDisplayName, - @JsonProperty("parameters") Map parameters, - @JsonProperty("webhookStatus") String webhookStatus, - @JsonProperty("canal") String canal - ) { - this( - text, - timestamp, - Optional.ofNullable(typeString).map(t -> { - try { - return ConversationEntryEntity.valueOf(t); - } catch (IllegalArgumentException e) { - System.err.println("Warning: Invalid ConversationEntryType string during deserialization: " + t); - return null; - } - }), - intentDisplayName, - parameters, - webhookStatus, - canal - ); - } -} \ No newline at end of file diff --git a/src/main/java/com/example/dto/gemini/ConversationSessionSummaryDTO.java b/src/main/java/com/example/dto/gemini/ConversationSessionSummaryDTO.java deleted file mode 100644 index 5168cba..0000000 --- a/src/main/java/com/example/dto/gemini/ConversationSessionSummaryDTO.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2025 Google. This software is provided as-is, without warranty or representation for any use or purpose. - * Your use of it is subject to your agreement with Google. - */ - -package com.example.dto.gemini; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.cloud.Timestamp; -import java.util.Collections; -import java.util.List; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public record ConversationSessionSummaryDTO( - @JsonProperty("sessionId") String sessionId, - @JsonProperty("userId") String userId, - @JsonProperty("startTime") Timestamp startTime, - @JsonProperty("lastUpdated") Timestamp lastUpdated, - @JsonProperty("entries") List entries -) { - @JsonCreator - public ConversationSessionSummaryDTO( - @JsonProperty("sessionId") String sessionId, - @JsonProperty("userId") String userId, - @JsonProperty("startTime") Timestamp startTime, - @JsonProperty("lastUpdated") Timestamp lastUpdated, - @JsonProperty("entries") List entries - ) { - this.sessionId = sessionId; - this.userId = userId; - this.startTime = startTime; - this.lastUpdated = lastUpdated; - this.entries = entries != null ? entries : Collections.emptyList(); - } -} \ No newline at end of file diff --git a/src/main/java/com/example/dto/gemini/ConversationSummaryRequest.java b/src/main/java/com/example/dto/gemini/ConversationSummaryRequest.java deleted file mode 100644 index 7e71f5f..0000000 --- a/src/main/java/com/example/dto/gemini/ConversationSummaryRequest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2025 Google. This software is provided as-is, without warranty or representation for any use or purpose. - * Your use of it is subject to your agreement with Google. - */ - -package com.example.dto.gemini; - -import jakarta.validation.constraints.DecimalMax; -import jakarta.validation.constraints.DecimalMin; -import jakarta.validation.constraints.NotBlank; - -public record ConversationSummaryRequest( - @NotBlank(message = "Session ID is required.") - String sessionId, - @NotBlank(message = "Prompt for summarization is required.") - String prompt, - @DecimalMin(value = "0.0", message = "Temperature must be between 0.0 and 1.0.") - @DecimalMax(value = "0.1", message = "Temperature must be between 0.0 and 1.0.") - Float temperature, - @DecimalMin(value = "0.1", message = "Max Output Tokens must be at least 1.") - Integer maxOutputTokens, - @NotBlank(message = "model is required.") - String modelName, - @NotBlank(message = "topP is required.") - @DecimalMin(value = "0.0", message = "topP must be between 0.0 and 1.0.") - Float top_P - - -) {} \ No newline at end of file diff --git a/src/main/java/com/example/dto/gemini/ConversationSummaryResponse.java b/src/main/java/com/example/dto/gemini/ConversationSummaryResponse.java deleted file mode 100644 index b7d0a2f..0000000 --- a/src/main/java/com/example/dto/gemini/ConversationSummaryResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2025 Google. This software is provided as-is, without warranty or representation for any use or purpose. - * Your use of it is subject to your agreement with Google. - */ - -package com.example.dto.gemini; - -import jakarta.validation.constraints.NotBlank; - -public record ConversationSummaryResponse( - @NotBlank - String summaryText -) {} \ No newline at end of file diff --git a/src/main/java/com/example/mapper/conversation/ExternalConvRequestMapper.java b/src/main/java/com/example/mapper/conversation/ExternalConvRequestMapper.java index 5cd0876..730e2c1 100644 --- a/src/main/java/com/example/mapper/conversation/ExternalConvRequestMapper.java +++ b/src/main/java/com/example/mapper/conversation/ExternalConvRequestMapper.java @@ -48,12 +48,11 @@ public class ExternalConvRequestMapper { && !externalRequest.user().telefono().isBlank()) { primaryPhoneNumber = externalRequest.user().telefono(); parameters.put("telefono", primaryPhoneNumber); - logger.debug("Mapped 'telefono' from external request: {}", primaryPhoneNumber); } if (primaryPhoneNumber == null || primaryPhoneNumber.isBlank()) { throw new IllegalArgumentException( - "Phone number (telefono) is required in the 'usuario' field for conversation management."); + "Phone number is required in the 'usuario' field for conversation management."); } String resolvedUserId = null; diff --git a/src/main/java/com/example/mapper/notification/ExternalNotRequestMapper.java b/src/main/java/com/example/mapper/notification/ExternalNotRequestMapper.java index 39077b6..1f42f87 100644 --- a/src/main/java/com/example/mapper/notification/ExternalNotRequestMapper.java +++ b/src/main/java/com/example/mapper/notification/ExternalNotRequestMapper.java @@ -39,7 +39,7 @@ public class ExternalNotRequestMapper { Objects.requireNonNull(request, "NotificationRequestDTO cannot be null for mapping."); if (request.phoneNumber() == null || request.phoneNumber().isEmpty()) { - throw new IllegalArgumentException("List of 'telefonos' (phone numbers) is required and cannot be empty in NotificationRequestDTO."); + throw new IllegalArgumentException("Phone numbers is required and cannot be empty in NotificationRequestDTO."); } String phoneNumber = request.phoneNumber(); diff --git a/src/main/java/com/example/service/base/MessageEntryFilter.java b/src/main/java/com/example/service/base/MessageEntryFilter.java index 3fd25ad..d55bc49 100644 --- a/src/main/java/com/example/service/base/MessageEntryFilter.java +++ b/src/main/java/com/example/service/base/MessageEntryFilter.java @@ -104,7 +104,7 @@ public class MessageEntryFilter { String resultCategory = switch (geminiResponse != null ? geminiResponse.trim().toUpperCase() : "") { case CATEGORY_CONVERSATION -> { logger.info("Classified as {}. Input: '{}'", CATEGORY_CONVERSATION); - logger.debug("Classified as {}. Input: '{}'", CATEGORY_CONVERSATION, queryInputText); + logger.debug("Classified as {}. Input: '{}'", CATEGORY_CONVERSATION, queryInputText); yield CATEGORY_CONVERSATION; } case CATEGORY_NOTIFICATION -> { diff --git a/src/main/java/com/example/service/conversation/FirestoreConversationService.java b/src/main/java/com/example/service/conversation/FirestoreConversationService.java index 89c6f03..7c09ebf 100644 --- a/src/main/java/com/example/service/conversation/FirestoreConversationService.java +++ b/src/main/java/com/example/service/conversation/FirestoreConversationService.java @@ -104,7 +104,6 @@ public class FirestoreConversationService { } public Mono getSessionByTelefono(String userPhoneNumber) { - logger.info("Attempting to retrieve conversation session for phone number {}.", userPhoneNumber); return firestoreBaseRepository.getDocumentsByField(getConversationCollectionPath(), "userPhoneNumber", userPhoneNumber) .map(documentSnapshot -> { if (documentSnapshot != null && documentSnapshot.exists()) { @@ -112,7 +111,6 @@ public class FirestoreConversationService { logger.info("Successfully retrieved and mapped conversation session for session {}.", sessionDTO.sessionId()); return sessionDTO; } - logger.info("Conversation session not found for phone number {}.", userPhoneNumber); return null; }); } diff --git a/src/main/java/com/example/service/conversation/MemoryStoreConversationService.java b/src/main/java/com/example/service/conversation/MemoryStoreConversationService.java index 4a989fd..6410f50 100644 --- a/src/main/java/com/example/service/conversation/MemoryStoreConversationService.java +++ b/src/main/java/com/example/service/conversation/MemoryStoreConversationService.java @@ -88,20 +88,18 @@ public class MemoryStoreConversationService { return Mono.empty(); } String phoneToSessionKey = PHONE_TO_SESSION_KEY_PREFIX + telefono; - logger.debug("Attempting to retrieve session ID for phone number {} from Memorystore.", telefono); return stringRedisTemplate.opsForValue().get(phoneToSessionKey) .flatMap(sessionId -> { - logger.debug("Found session ID {} for phone number {}. Retrieving session data.", sessionId, telefono); return redisTemplate.opsForValue().get(SESSION_KEY_PREFIX + sessionId); }) .doOnSuccess(session -> { if (session != null) { - logger.info("Successfully retrieved session {} by phone number {}.", session.sessionId(), telefono); + logger.info("Successfully retrieved session by phone number"); } else { - logger.info("No session found in Redis for phone number {}.", telefono); + logger.info("No session found in Redis for phone number."); } }) - .doOnError(e -> logger.error("Error retrieving session by phone number {}: {}", telefono, e.getMessage(), e)); + .doOnError(e -> logger.error("Error retrieving session by phone number: {}", e)); } public Mono updateSession(ConversationSessionDTO session) { diff --git a/src/main/java/com/example/service/notification/FirestoreNotificationService.java b/src/main/java/com/example/service/notification/FirestoreNotificationService.java index 3d53760..b741521 100644 --- a/src/main/java/com/example/service/notification/FirestoreNotificationService.java +++ b/src/main/java/com/example/service/notification/FirestoreNotificationService.java @@ -95,12 +95,11 @@ public class FirestoreNotificationService { } } catch (ExecutionException e) { logger.error( - "Error saving notification to Firestore for phone {}: {}", - phoneNumber, + "Error saving notification to Firestore for phone: {}", e.getMessage(), e); throw new FirestorePersistenceException( - "Failed to save notification to Firestore for phone " + phoneNumber, e); + "Failed to save notification to Firestore for phone ", e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.error( @@ -109,7 +108,7 @@ public class FirestoreNotificationService { e.getMessage(), e); throw new FirestorePersistenceException( - "Saving notification was interrupted for phone " + phoneNumber, e); + "Saving notification was interrupted for phone ", e); } } }) diff --git a/src/main/java/com/example/service/notification/MemoryStoreNotificationService.java b/src/main/java/com/example/service/notification/MemoryStoreNotificationService.java index 29e6fe1..4475a0f 100644 --- a/src/main/java/com/example/service/notification/MemoryStoreNotificationService.java +++ b/src/main/java/com/example/service/notification/MemoryStoreNotificationService.java @@ -111,12 +111,12 @@ public class MemoryStoreNotificationService { return stringRedisTemplate.opsForValue().get(key) .doOnSuccess(sessionId -> { if (sessionId != null) { - logger.info("Session ID {} found for phone {}.", sessionId, phone); + logger.info("Session ID {} found for phone.", sessionId); } else { - logger.debug("Session ID not found for phone {}.", phone); + logger.debug("Session ID not found for phone."); } }) - .doOnError(e -> logger.error("Error retrieving session ID for phone {} from MemoryStore: {}", phone, + .doOnError(e -> logger.error("Error retrieving session ID for phone from MemoryStore: {}", e.getMessage(), e)); } @@ -144,19 +144,18 @@ public class MemoryStoreNotificationService { return Mono.empty(); } String phoneToSessionKey = PHONE_TO_CONVERSATION_SESSION_KEY_PREFIX + telefono; - logger.debug("Attempting to retrieve session ID for phone number {} from Redis.", telefono); return stringRedisTemplate.opsForValue().get(phoneToSessionKey) .flatMap(sessionId -> { - logger.debug("Found session ID {} for phone number {}. Retrieving session data.", sessionId, telefono); + logger.debug("Found session ID {} for phone number. Retrieving session data.", sessionId); return conversationRedisTemplate.opsForValue().get(CONVERSATION_SESSION_KEY_PREFIX + sessionId); }) .doOnSuccess(session -> { if (session != null) { - logger.info("Successfully retrieved session {} by phone number {}.", session.sessionId(), telefono); + logger.info("Successfully retrieved session {} by phone number.", session.sessionId()); } else { - logger.info("No session found in Redis for phone number {}.", telefono); + logger.info("No session found in Redis for phone number."); } }) - .doOnError(e -> logger.error("Error retrieving session by phone number {}: {}", telefono, e.getMessage(), e)); + .doOnError(e -> logger.error("Error retrieving session by phone number: {}",e.getMessage(), e)); } } \ No newline at end of file diff --git a/src/main/java/com/example/service/notification/NotificationManagerService.java b/src/main/java/com/example/service/notification/NotificationManagerService.java index 80ae260..efe192c 100644 --- a/src/main/java/com/example/service/notification/NotificationManagerService.java +++ b/src/main/java/com/example/service/notification/NotificationManagerService.java @@ -93,11 +93,9 @@ public class NotificationManagerService { firestoreNotificationService.saveOrAppendNotificationEntry(newNotificationEntry) .subscribe( ignored -> logger.debug( - "Background: Notification entry persistence initiated for phone {} in Firestore.", - telefono), + "Background: Notification entry persistence initiated for phone in Firestore."), e -> logger.error( - "Background: Error during notification entry persistence for phone {} in Firestore: {}", - telefono, e.getMessage(), e)); + "Background: Error during notification entry persistence for phone in Firestore: {}", e.getMessage(), e)); }); // 2. Resolve or create a conversation session @@ -117,8 +115,7 @@ public class NotificationManagerService { }) .switchIfEmpty(Mono.defer(() -> { String newSessionId = SessionIdGenerator.generateStandardSessionId(); - logger.info("No existing conversation session found for phone number {}. Creating new session: {}", - telefono, newSessionId); + logger.info("No existing conversation session found for phone number. Creating new session: {}", newSessionId); String userId = "user_by_phone_" + telefono; Map prefixedParameters = new HashMap<>(); if (obfuscatedRequest.hiddenParameters() != null) { @@ -143,7 +140,7 @@ public class NotificationManagerService { return dialogflowClientService.detectIntent(sessionId, detectIntentRequest); }) .doOnSuccess(response -> logger - .info("Finished processing notification. Dialogflow response received for phone {}.", telefono)) + .info("Finished processing notification. Dialogflow response received for phone")) .doOnError(e -> logger.error("Overall error in NotificationManagerService: {}", e.getMessage(), e)); }); } diff --git a/src/main/java/com/example/service/quickreplies/MemoryStoreQRService.java b/src/main/java/com/example/service/quickreplies/MemoryStoreQRService.java index fbb0abb..49836ab 100644 --- a/src/main/java/com/example/service/quickreplies/MemoryStoreQRService.java +++ b/src/main/java/com/example/service/quickreplies/MemoryStoreQRService.java @@ -68,7 +68,6 @@ public class MemoryStoreQRService { return Mono.empty(); } String phoneToSessionKey = PHONE_TO_SESSION_KEY_PREFIX + telefono; - logger.debug("Attempting to retrieve quick reply session ID for phone number {} from Redis.", telefono); return stringRedisTemplate.opsForValue().get(phoneToSessionKey) .flatMap(sessionId -> { logger.debug("Found quick reply session ID {} for phone number {}. Retrieving session data.", @@ -77,13 +76,12 @@ public class MemoryStoreQRService { }) .doOnSuccess(session -> { if (session != null) { - logger.info("Successfully retrieved quick reply session {} by phone number {}.", - session.sessionId(), telefono); + logger.info("Successfully retrieved quick reply session {} by phone number", + session.sessionId()); } else { - logger.info("No quick reply session found in Redis for phone number {}.", telefono); + logger.info("No quick reply session found in Redis for phone number"); } }) - .doOnError(e -> logger.error("Error retrieving quick reply session by phone number {}: {}", telefono, - e.getMessage(), e)); + .doOnError(e -> logger.error("Error retrieving quick reply session by phone numbe: {}",e.getMessage(), e)); } } \ No newline at end of file diff --git a/src/main/java/com/example/service/quickreplies/QuickRepliesManagerService.java b/src/main/java/com/example/service/quickreplies/QuickRepliesManagerService.java index db7b773..890e14c 100644 --- a/src/main/java/com/example/service/quickreplies/QuickRepliesManagerService.java +++ b/src/main/java/com/example/service/quickreplies/QuickRepliesManagerService.java @@ -84,7 +84,7 @@ public class QuickRepliesManagerService { return memoryStoreConversationService.getSessionByTelefono(userPhoneNumber) .switchIfEmpty(Mono.error( - new IllegalStateException("No quick reply session found for phone number: " + userPhoneNumber))) + new IllegalStateException("No quick reply session found for phone number" ))) .flatMap(session -> { String userId = session.userId(); String sessionId = session.sessionId(); @@ -93,13 +93,14 @@ public class QuickRepliesManagerService { List entries = session.entries(); int lastInitIndex = IntStream.range(0, entries.size()) - .map(i -> entries.size() - 1 - i) - .filter(i -> { - ConversationEntryDTO entry = entries.get(i); - return entry.entity() == ConversationEntryEntity.SISTEMA && entry.type() == ConversationEntryType.INICIO; - }) - .findFirst() - .orElse(-1); + .map(i -> entries.size() - 1 - i) + .filter(i -> { + ConversationEntryDTO entry = entries.get(i); + return entry.entity() == ConversationEntryEntity.SISTEMA + && entry.type() == ConversationEntryType.INICIO; + }) + .findFirst() + .orElse(-1); long userMessagesCount; if (lastInitIndex != -1) { @@ -136,19 +137,20 @@ public class QuickRepliesManagerService { // Matched question, return the answer String respuesta = matchedPreguntas.get(0).respuesta(); QueryResultDTO queryResult = new QueryResultDTO(respuesta, null); - DetectIntentResponseDTO response = new DetectIntentResponseDTO(sessionId, queryResult, null); + DetectIntentResponseDTO response = new DetectIntentResponseDTO(sessionId, + queryResult, null); return memoryStoreConversationService - .updateSession(session.withPantallaContexto(null)) - .then(persistConversationTurn(userId, sessionId, - ConversationEntryDTO.forAgentWithMessage(respuesta), - userPhoneNumber, null)) - .thenReturn(response); + .updateSession(session.withPantallaContexto(null)) + .then(persistConversationTurn(userId, sessionId, + ConversationEntryDTO.forAgentWithMessage(respuesta), + userPhoneNumber, null)) + .thenReturn(response); } else { // No match, delegate to Dialogflow return memoryStoreConversationService - .updateSession(session.withPantallaContexto(null)) - .then(conversationManagerService.manageConversation(externalRequest)); + .updateSession(session.withPantallaContexto(null)) + .then(conversationManagerService.manageConversation(externalRequest)); } }); } else { diff --git a/src/main/java/com/example/service/summary/ConversationSummaryService.java b/src/main/java/com/example/service/summary/ConversationSummaryService.java deleted file mode 100644 index ed853c1..0000000 --- a/src/main/java/com/example/service/summary/ConversationSummaryService.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2025 Google. This software is provided as-is, without warranty or representation for any use or purpose. - * Your use of it is subject to your agreement with Google. - */ - -package com.example.service.summary; - -import com.example.dto.gemini.ConversationSummaryRequest; -import com.example.dto.gemini.ConversationSummaryResponse; -import com.example.dto.gemini.ConversationSessionSummaryDTO; -import com.example.dto.gemini.ConversationEntrySummaryDTO; -import com.example.repository.FirestoreBaseRepository; -import com.example.service.base.GeminiClientService; -import com.google.cloud.firestore.DocumentReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.stream.Collectors; - -@Service -public class ConversationSummaryService { - - private static final Logger logger = LoggerFactory.getLogger(ConversationSummaryService.class); - private final GeminiClientService geminiService; - private final FirestoreBaseRepository firestoreBaseRepository; - - private static final String CONVERSATION_COLLECTION_PATH_FORMAT = "artifacts/%s/conversations"; - - private static final String DEFAULT_GEMINI_MODEL_NAME = "gemini-2.0-flash-001"; - private static final Float DEFAULT_TEMPERATURE = 0.7f; - private static final Integer DEFAULT_MAX_OUTPUT_TOKENS = 800; - private static final Float DEFAULT_tOPP = 0.1f; - - - public ConversationSummaryService(GeminiClientService geminiService, FirestoreBaseRepository firestoreBaseRepository) { - this.geminiService = geminiService; - this.firestoreBaseRepository = firestoreBaseRepository; - } - - public ConversationSummaryResponse summarizeConversation(ConversationSummaryRequest request) { - if (request == null) { - logger.warn("Summarization request is null."); - return new ConversationSummaryResponse("Request cannot be null."); - } - if (request.sessionId() == null || request.sessionId().isBlank()) { - logger.warn("Session ID is missing in the summarization request."); - return new ConversationSummaryResponse("Session ID is required."); - } - if (request.prompt() == null || request.prompt().isBlank()) { - logger.warn("Prompt for summarization is missing in the request."); - return new ConversationSummaryResponse("Prompt for summarization is required."); - } - - String sessionId = request.sessionId(); - String summarizationPromptInstruction = request.prompt(); - - String actualModelName = (request.modelName() != null && !request.modelName().isBlank()) - ? request.modelName() : DEFAULT_GEMINI_MODEL_NAME; - Float actualTemperature = (request.temperature() != null) - ? request.temperature() : DEFAULT_TEMPERATURE; - Integer actualMaxOutputTokens = (request.maxOutputTokens() != null) - ? request.maxOutputTokens() : DEFAULT_MAX_OUTPUT_TOKENS; - Float actualTopP = (request.top_P() != null) - ? request.top_P() : DEFAULT_tOPP; - - String collectionPath = String.format(CONVERSATION_COLLECTION_PATH_FORMAT, firestoreBaseRepository.getAppId()); - String documentId = sessionId; - logger.info("Fetching conversation from Firestore: Collection='{}', Document='{}'", collectionPath, documentId); - - ConversationSessionSummaryDTO sessionSummary; - try { - DocumentReference docRef = firestoreBaseRepository.getDocumentReference(collectionPath, documentId); - sessionSummary = firestoreBaseRepository.getDocument(docRef, ConversationSessionSummaryDTO.class); - - logger.debug("Retrieved ConversationSessionSummaryDTO after Firestore fetch: sessionId={}, entries size={}", - sessionSummary != null ? sessionSummary.sessionId() : "null", - sessionSummary != null && sessionSummary.entries() != null ? sessionSummary.entries().size() : "N/A (entries list is null)"); - - if (sessionSummary == null) { - logger.warn("Firestore document not found or could not be mapped: {}/{}", collectionPath, documentId); - return new ConversationSummaryResponse("Conversation document not found for session ID: " + sessionId); - } - - List entries = sessionSummary.entries(); - if (entries == null || entries.isEmpty()) { - logger.warn("No conversation entries found in document {}/{} for session ID: {}", - collectionPath, documentId, sessionId); - return new ConversationSummaryResponse("No conversation messages found in the document for session ID: " + sessionId); - } - - List conversationMessages = entries.stream() - .map(entry -> { - String type = entry.type().map(t -> t.name()).orElse("UNKNOWN_TYPE"); - String timestampString = entry.timestamp() != null ? entry.timestamp().toDate().toInstant().toString() : "UNKNOWN_TIMESTAMP"; - return String.format("[%s - %s] %s", type, timestampString, entry.text()); - }) - .collect(Collectors.toList()); - - String formattedConversation = String.join("\n", conversationMessages); - String fullPromptForGemini = summarizationPromptInstruction + "\n\n" + formattedConversation; - - logger.info("Sending summarization request to Gemini with custom prompt (first 200 chars): \n{}", - fullPromptForGemini.substring(0, Math.min(fullPromptForGemini.length(), 200)) + "..."); - - String summaryText = geminiService.generateContent( - fullPromptForGemini, - actualTemperature, - actualMaxOutputTokens, - actualModelName, - actualTopP - ); - - if (summaryText == null || summaryText.trim().isEmpty()) { - logger.warn("Gemini returned an empty or null summary for the conversation."); - return new ConversationSummaryResponse("Could not generate a summary. The model returned no text."); - } - logger.info("Successfully generated summary for session ID: {}", sessionId); - return new ConversationSummaryResponse(summaryText); - - } catch (InterruptedException | ExecutionException e) { - logger.error("Error accessing Firestore for session ID {}: {}", sessionId, e.getMessage(), e); - Thread.currentThread().interrupt(); - return new ConversationSummaryResponse("Error accessing conversation data: " + e.getMessage()); - } catch (Exception e) { - logger.error("An unexpected error occurred during summarization for session ID {}: {}", sessionId, e.getMessage(), e); - return new ConversationSummaryResponse("An unexpected error occurred during summarization: " + e.getMessage()); - } - } -} \ No newline at end of file