UPDATE 01-sep
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -91,7 +91,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.genai</groupId>
|
<groupId>com.google.genai</groupId>
|
||||||
<artifactId>google-genai</artifactId>
|
<artifactId>google-genai</artifactId>
|
||||||
<version>1.8.0</version>
|
<version>1.13.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.protobuf</groupId>
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public record ExternalNotRequestDTO(
|
public record ExternalNotRequestDTO(
|
||||||
@JsonProperty("texto") String text,
|
@JsonProperty("texto") String text,
|
||||||
@JsonProperty("telefono") String phoneNumber) {
|
@JsonProperty("telefono") String phoneNumber,
|
||||||
|
@JsonProperty("parametrosOcultos") java.util.Map<String, String> hiddenParameters
|
||||||
|
) {
|
||||||
public ExternalNotRequestDTO {
|
public ExternalNotRequestDTO {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,5 +3,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
public record QuickReplyDTO(
|
public record QuickReplyDTO(
|
||||||
@JsonProperty("header") String header,
|
@JsonProperty("header") String header,
|
||||||
|
@JsonProperty("body") String body,
|
||||||
|
@JsonProperty("button") String button,
|
||||||
|
@JsonProperty("header_section") String headerSection,
|
||||||
@JsonProperty("preguntas") List<QuestionDTO> preguntas
|
@JsonProperty("preguntas") List<QuestionDTO> preguntas
|
||||||
) {}
|
) {}
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* 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.exception;
|
package com.example.exception;
|
||||||
|
|
||||||
public class DialogflowClientException extends RuntimeException {
|
public class DialogflowClientException extends RuntimeException {
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* 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.exception;
|
package com.example.exception;
|
||||||
|
|
||||||
public class FirestorePersistenceException extends RuntimeException {
|
public class FirestorePersistenceException extends RuntimeException {
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* 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.exception;
|
package com.example.exception;
|
||||||
|
|
||||||
public class GeminiClientException extends Exception {
|
public class GeminiClientException extends Exception {
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ public class ConversationManagerService {
|
|||||||
private final ConversationContextMapper conversationContextMapper;
|
private final ConversationContextMapper conversationContextMapper;
|
||||||
private final DataLossPrevention dataLossPrevention;
|
private final DataLossPrevention dataLossPrevention;
|
||||||
private final String dlpTemplateCompleteFlow;
|
private final String dlpTemplateCompleteFlow;
|
||||||
private final String dlpTemplatePersistFlow;
|
|
||||||
|
|
||||||
public ConversationManagerService(
|
public ConversationManagerService(
|
||||||
DialogflowClientService dialogflowServiceClient,
|
DialogflowClientService dialogflowServiceClient,
|
||||||
@@ -60,8 +59,7 @@ public class ConversationManagerService {
|
|||||||
NotificationContextMapper notificationContextMapper,
|
NotificationContextMapper notificationContextMapper,
|
||||||
ConversationContextMapper conversationContextMapper,
|
ConversationContextMapper conversationContextMapper,
|
||||||
DataLossPrevention dataLossPrevention,
|
DataLossPrevention dataLossPrevention,
|
||||||
@Value("${google.cloud.dlp.dlpTemplateCompleteFlow}") String dlpTemplateCompleteFlow,
|
@Value("${google.cloud.dlp.dlpTemplateCompleteFlow}") String dlpTemplateCompleteFlow) {
|
||||||
@Value("${google.cloud.dlp.dlpTemplatePersistFlow}") String dlpTemplatePersistFlow) {
|
|
||||||
this.dialogflowServiceClient = dialogflowServiceClient;
|
this.dialogflowServiceClient = dialogflowServiceClient;
|
||||||
this.firestoreConversationService = firestoreConversationService;
|
this.firestoreConversationService = firestoreConversationService;
|
||||||
this.memoryStoreConversationService = memoryStoreConversationService;
|
this.memoryStoreConversationService = memoryStoreConversationService;
|
||||||
@@ -73,7 +71,6 @@ public class ConversationManagerService {
|
|||||||
this.conversationContextMapper = conversationContextMapper;
|
this.conversationContextMapper = conversationContextMapper;
|
||||||
this.dataLossPrevention = dataLossPrevention;
|
this.dataLossPrevention = dataLossPrevention;
|
||||||
this.dlpTemplateCompleteFlow = dlpTemplateCompleteFlow;
|
this.dlpTemplateCompleteFlow = dlpTemplateCompleteFlow;
|
||||||
this.dlpTemplatePersistFlow = dlpTemplatePersistFlow;
|
|
||||||
}
|
}
|
||||||
public Mono<DetectIntentResponseDTO> manageConversation(ExternalConvRequestDTO externalrequest) {
|
public Mono<DetectIntentResponseDTO> manageConversation(ExternalConvRequestDTO externalrequest) {
|
||||||
return dataLossPrevention.getObfuscatedString(externalrequest.message(), dlpTemplateCompleteFlow)
|
return dataLossPrevention.getObfuscatedString(externalrequest.message(), dlpTemplateCompleteFlow)
|
||||||
@@ -193,10 +190,7 @@ public class ConversationManagerService {
|
|||||||
private Mono<DetectIntentResponseDTO> processDialogflowRequest(ConversationSessionDTO session, DetectIntentRequestDTO request, String userId, String userMessageText, String userPhoneNumber, boolean newSession) {
|
private Mono<DetectIntentResponseDTO> processDialogflowRequest(ConversationSessionDTO session, DetectIntentRequestDTO request, String userId, String userMessageText, String userPhoneNumber, boolean newSession) {
|
||||||
final String finalSessionId = session.sessionId();
|
final String finalSessionId = session.sessionId();
|
||||||
|
|
||||||
return dataLossPrevention.getObfuscatedString(userMessageText, dlpTemplatePersistFlow)
|
ConversationEntryDTO userEntry = ConversationEntryDTO.forUser(userMessageText);
|
||||||
.flatMap(obfuscatedUserMessageText -> {
|
|
||||||
|
|
||||||
ConversationEntryDTO userEntry = ConversationEntryDTO.forUser(obfuscatedUserMessageText);
|
|
||||||
|
|
||||||
return this.persistConversationTurn(userId, finalSessionId, userEntry, userPhoneNumber)
|
return this.persistConversationTurn(userId, finalSessionId, userEntry, userPhoneNumber)
|
||||||
.doOnSuccess(v -> logger.debug("User entry successfully persisted for session {}. Proceeding to Dialogflow...", finalSessionId))
|
.doOnSuccess(v -> logger.debug("User entry successfully persisted for session {}. Proceeding to Dialogflow...", finalSessionId))
|
||||||
@@ -210,7 +204,6 @@ public class ConversationManagerService {
|
|||||||
})
|
})
|
||||||
.doOnError(error -> logger.error("Overall error during conversation management for session {}: {}", finalSessionId, error.getMessage(), error))
|
.doOnError(error -> logger.error("Overall error during conversation management for session {}: {}", finalSessionId, error.getMessage(), error))
|
||||||
));
|
));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
private Mono<DetectIntentResponseDTO> startNotificationConversation(ConversationContext context, DetectIntentRequestDTO request, NotificationDTO notification) {
|
private Mono<DetectIntentResponseDTO> startNotificationConversation(ConversationContext context, DetectIntentRequestDTO request, NotificationDTO notification) {
|
||||||
final String userId = context.userId();
|
final String userId = context.userId();
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* 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.notification;
|
package com.example.service.notification;
|
||||||
|
|
||||||
import com.example.dto.dialogflow.conversation.ConversationEntryDTO;
|
import com.example.dto.dialogflow.conversation.ConversationEntryDTO;
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* 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.notification;
|
package com.example.service.notification;
|
||||||
|
|
||||||
import com.example.dto.dialogflow.notification.ExternalNotRequestDTO;
|
import com.example.dto.dialogflow.notification.ExternalNotRequestDTO;
|
||||||
@@ -103,6 +108,10 @@ public Mono<DetectIntentResponseDTO> processNotification(ExternalNotRequestDTO e
|
|||||||
parameters.put("telefono", telefono);
|
parameters.put("telefono", telefono);
|
||||||
parameters.put(NOTIFICATION_TEXT_PARAM, newNotificationEntry.texto());
|
parameters.put(NOTIFICATION_TEXT_PARAM, newNotificationEntry.texto());
|
||||||
|
|
||||||
|
if (externalRequest.hiddenParameters() != null && !externalRequest.hiddenParameters().isEmpty()) {
|
||||||
|
parameters.putAll(externalRequest.hiddenParameters());
|
||||||
|
}
|
||||||
|
|
||||||
// Use a TextInputDTO to correctly build the QueryInputDTO
|
// Use a TextInputDTO to correctly build the QueryInputDTO
|
||||||
TextInputDTO textInput = new TextInputDTO(newNotificationEntry.texto());
|
TextInputDTO textInput = new TextInputDTO(newNotificationEntry.texto());
|
||||||
QueryInputDTO queryInput = new QueryInputDTO(textInput, null, defaultLanguageCode);
|
QueryInputDTO queryInput = new QueryInputDTO(textInput, null, defaultLanguageCode);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import com.example.dto.dialogflow.conversation.ConversationEntryEntity;
|
|||||||
import com.example.dto.dialogflow.conversation.ConversationEntryType;
|
import com.example.dto.dialogflow.conversation.ConversationEntryType;
|
||||||
import com.example.dto.dialogflow.conversation.ExternalConvRequestDTO;
|
import com.example.dto.dialogflow.conversation.ExternalConvRequestDTO;
|
||||||
import com.example.dto.quickreplies.QuickReplyScreenRequestDTO;
|
import com.example.dto.quickreplies.QuickReplyScreenRequestDTO;
|
||||||
import com.example.service.conversation.DataLossPrevention;
|
|
||||||
import com.example.dto.quickreplies.QuestionDTO;
|
import com.example.dto.quickreplies.QuestionDTO;
|
||||||
import com.example.dto.quickreplies.QuickReplyDTO;
|
import com.example.dto.quickreplies.QuickReplyDTO;
|
||||||
import com.example.service.conversation.FirestoreConversationService;
|
import com.example.service.conversation.FirestoreConversationService;
|
||||||
@@ -20,10 +19,14 @@ import com.example.util.SessionIdGenerator;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.example.dto.dialogflow.conversation.QueryResultDTO;
|
||||||
|
import com.example.service.conversation.ConversationManagerService;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -32,20 +35,17 @@ public class QuickRepliesManagerService {
|
|||||||
private final MemoryStoreConversationService memoryStoreConversationService;
|
private final MemoryStoreConversationService memoryStoreConversationService;
|
||||||
private final FirestoreConversationService firestoreConversationService;
|
private final FirestoreConversationService firestoreConversationService;
|
||||||
private final QuickReplyContentService quickReplyContentService;
|
private final QuickReplyContentService quickReplyContentService;
|
||||||
private final DataLossPrevention dataLossPrevention;
|
private final ConversationManagerService conversationManagerService;
|
||||||
private final String dlpTemplatePersistFlow;
|
|
||||||
|
|
||||||
public QuickRepliesManagerService(
|
public QuickRepliesManagerService(
|
||||||
|
@Lazy ConversationManagerService conversationManagerService,
|
||||||
MemoryStoreConversationService memoryStoreConversationService,
|
MemoryStoreConversationService memoryStoreConversationService,
|
||||||
FirestoreConversationService firestoreConversationService,
|
FirestoreConversationService firestoreConversationService,
|
||||||
QuickReplyContentService quickReplyContentService,
|
QuickReplyContentService quickReplyContentService) {
|
||||||
DataLossPrevention dataLossPrevention,
|
this.conversationManagerService = conversationManagerService;
|
||||||
@Value("${google.cloud.dlp.dlpTemplatePersistFlow}") String dlpTemplatePersistFlow) {
|
|
||||||
this.memoryStoreConversationService = memoryStoreConversationService;
|
this.memoryStoreConversationService = memoryStoreConversationService;
|
||||||
this.firestoreConversationService = firestoreConversationService;
|
this.firestoreConversationService = firestoreConversationService;
|
||||||
this.quickReplyContentService = quickReplyContentService;
|
this.quickReplyContentService = quickReplyContentService;
|
||||||
this.dataLossPrevention = dataLossPrevention;
|
|
||||||
this.dlpTemplatePersistFlow = dlpTemplatePersistFlow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<DetectIntentResponseDTO> startQuickReplySession(QuickReplyScreenRequestDTO externalRequest) {
|
public Mono<DetectIntentResponseDTO> startQuickReplySession(QuickReplyScreenRequestDTO externalRequest) {
|
||||||
@@ -88,13 +88,27 @@ public class QuickRepliesManagerService {
|
|||||||
.flatMap(session -> {
|
.flatMap(session -> {
|
||||||
String userId = session.userId();
|
String userId = session.userId();
|
||||||
String sessionId = session.sessionId();
|
String sessionId = session.sessionId();
|
||||||
return dataLossPrevention.getObfuscatedString(externalRequest.message(), dlpTemplatePersistFlow)
|
|
||||||
.flatMap(obfuscatedMessage -> {
|
|
||||||
ConversationEntryDTO userEntry = ConversationEntryDTO.forUser(obfuscatedMessage);
|
|
||||||
|
|
||||||
long userMessagesCount = session.entries().stream()
|
ConversationEntryDTO userEntry = ConversationEntryDTO.forUser(externalRequest.message());
|
||||||
|
|
||||||
|
List<ConversationEntryDTO> 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);
|
||||||
|
|
||||||
|
long userMessagesCount;
|
||||||
|
if (lastInitIndex != -1) {
|
||||||
|
userMessagesCount = entries.subList(lastInitIndex + 1, entries.size()).stream()
|
||||||
.filter(e -> e.entity() == ConversationEntryEntity.USUARIO)
|
.filter(e -> e.entity() == ConversationEntryEntity.USUARIO)
|
||||||
.count();
|
.count();
|
||||||
|
} else {
|
||||||
|
userMessagesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (userMessagesCount == 0) { // Is the first user message in the Quick-Replies flow
|
if (userMessagesCount == 0) { // Is the first user message in the Quick-Replies flow
|
||||||
// This is the second message of the flow. Return the full list.
|
// This is the second message of the flow. Return the full list.
|
||||||
@@ -118,33 +132,32 @@ public class QuickRepliesManagerService {
|
|||||||
.filter(p -> p.titulo().equalsIgnoreCase(externalRequest.message().trim()))
|
.filter(p -> p.titulo().equalsIgnoreCase(externalRequest.message().trim()))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
QuickReplyDTO responseQuickReplyDTO;
|
|
||||||
if (!matchedPreguntas.isEmpty()) {
|
if (!matchedPreguntas.isEmpty()) {
|
||||||
responseQuickReplyDTO = new QuickReplyDTO(quickReplyDTO.header(),
|
// Matched question, return the answer
|
||||||
matchedPreguntas);
|
String respuesta = matchedPreguntas.get(0).respuesta();
|
||||||
} else {
|
QueryResultDTO queryResult = new QueryResultDTO(respuesta, null);
|
||||||
responseQuickReplyDTO = new QuickReplyDTO(quickReplyDTO.header(),
|
DetectIntentResponseDTO response = new DetectIntentResponseDTO(sessionId, queryResult, null);
|
||||||
Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
// End the quick reply flow by clearing the pantallaContexto
|
|
||||||
return memoryStoreConversationService
|
return memoryStoreConversationService
|
||||||
.updateSession(session.withPantallaContexto(null))
|
.updateSession(session.withPantallaContexto(null))
|
||||||
.then(persistConversationTurn(userId, sessionId,
|
.then(persistConversationTurn(userId, sessionId,
|
||||||
ConversationEntryDTO.forAgentWithMessage(
|
ConversationEntryDTO.forAgentWithMessage(respuesta),
|
||||||
responseQuickReplyDTO.toString()),
|
|
||||||
userPhoneNumber, null))
|
userPhoneNumber, null))
|
||||||
.thenReturn(new DetectIntentResponseDTO(sessionId, null,
|
.thenReturn(response);
|
||||||
responseQuickReplyDTO));
|
} else {
|
||||||
|
// No match, delegate to Dialogflow
|
||||||
|
return memoryStoreConversationService
|
||||||
|
.updateSession(session.withPantallaContexto(null))
|
||||||
|
.then(conversationManagerService.manageConversation(externalRequest));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Should not happen. End the flow.
|
// Should not happen. End the flow.
|
||||||
return memoryStoreConversationService.updateSession(session.withPantallaContexto(null))
|
return memoryStoreConversationService.updateSession(session.withPantallaContexto(null))
|
||||||
.then(Mono.just(new DetectIntentResponseDTO(session.sessionId(), null,
|
.then(Mono.just(new DetectIntentResponseDTO(session.sessionId(), null,
|
||||||
new QuickReplyDTO("Flow Error", Collections.emptyList()))));
|
new QuickReplyDTO("Flow Error", null, null, null, Collections.emptyList()))));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Void> persistConversationTurn(String userId, String sessionId, ConversationEntryDTO entry,
|
private Mono<Void> persistConversationTurn(String userId, String sessionId, ConversationEntryDTO entry,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class QuickReplyContentService {
|
|||||||
logger.info("Fetching quick replies from Firestore for document: {}", collectionId);
|
logger.info("Fetching quick replies from Firestore for document: {}", collectionId);
|
||||||
if (collectionId == null || collectionId.isBlank()) {
|
if (collectionId == null || collectionId.isBlank()) {
|
||||||
logger.warn("collectionId is null or empty. Returning empty quick replies.");
|
logger.warn("collectionId is null or empty. Returning empty quick replies.");
|
||||||
return Mono.just(new QuickReplyDTO("empty", Collections.emptyList()));
|
return Mono.just(new QuickReplyDTO("empty", null, null, null, Collections.emptyList()));
|
||||||
}
|
}
|
||||||
return Mono.fromCallable(() -> {
|
return Mono.fromCallable(() -> {
|
||||||
try {
|
try {
|
||||||
@@ -45,11 +45,14 @@ public class QuickReplyContentService {
|
|||||||
.filter(DocumentSnapshot::exists)
|
.filter(DocumentSnapshot::exists)
|
||||||
.map(document -> {
|
.map(document -> {
|
||||||
String header = document.getString("header");
|
String header = document.getString("header");
|
||||||
|
String body = document.getString("body");
|
||||||
|
String button = document.getString("button");
|
||||||
|
String headerSection = document.getString("header_section");
|
||||||
List<Map<String, Object>> preguntasData = (List<Map<String, Object>>) document.get("preguntas");
|
List<Map<String, Object>> preguntasData = (List<Map<String, Object>>) document.get("preguntas");
|
||||||
List<QuestionDTO> preguntas = preguntasData.stream()
|
List<QuestionDTO> preguntas = preguntasData.stream()
|
||||||
.map(p -> new QuestionDTO((String) p.get("titulo"), (String) p.get("descripcion"), (String) p.get("respuesta")))
|
.map(p -> new QuestionDTO((String) p.get("titulo"), (String) p.get("descripcion"), (String) p.get("respuesta")))
|
||||||
.toList();
|
.toList();
|
||||||
return new QuickReplyDTO(header, preguntas);
|
return new QuickReplyDTO(header, body, button, headerSection, preguntas);
|
||||||
})
|
})
|
||||||
.doOnSuccess(quickReplyDTO -> {
|
.doOnSuccess(quickReplyDTO -> {
|
||||||
if (quickReplyDTO != null) {
|
if (quickReplyDTO != null) {
|
||||||
|
|||||||
@@ -9,15 +9,18 @@ import com.example.repository.FirestoreBaseRepository;
|
|||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.cloud.firestore.DocumentReference;
|
import com.google.cloud.firestore.DocumentReference;
|
||||||
|
import com.google.cloud.firestore.DocumentSnapshot;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -32,14 +35,19 @@ public class FirestoreDataImporter {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ObjectMapper objectMapper;
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void importDataOnStartup() {
|
public void importDataOnStartup() {
|
||||||
|
if (Boolean.parseBoolean(env.getProperty("firestore.data.importer.enabled"))) {
|
||||||
try {
|
try {
|
||||||
importQuickReplies();
|
importQuickReplies();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Failed to import data to Firestore on startup", e);
|
logger.error("Failed to import data to Firestore on startup", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void importQuickReplies() throws IOException, ExecutionException, InterruptedException {
|
private void importQuickReplies() throws IOException, ExecutionException, InterruptedException {
|
||||||
String collectionPath = String.format(QUICK_REPLIES_COLLECTION_PATH_FORMAT, firestoreBaseRepository.getAppId());
|
String collectionPath = String.format(QUICK_REPLIES_COLLECTION_PATH_FORMAT, firestoreBaseRepository.getAppId());
|
||||||
@@ -67,13 +75,19 @@ public class FirestoreDataImporter {
|
|||||||
logger.warn("Resource not found: {}", resourcePath);
|
logger.warn("Resource not found: {}", resourcePath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Map<String, Object> data = objectMapper.readValue(inputStream, new TypeReference<Map<String, Object>>() {});
|
Map<String, Object> localData = objectMapper.readValue(inputStream, new TypeReference<Map<String, Object>>() {});
|
||||||
DocumentReference docRef = firestoreBaseRepository.getDocumentReference(collectionPath, documentId);
|
DocumentReference docRef = firestoreBaseRepository.getDocumentReference(collectionPath, documentId);
|
||||||
if (!firestoreBaseRepository.documentExists(docRef)) {
|
|
||||||
firestoreBaseRepository.setDocument(docRef, data);
|
if (firestoreBaseRepository.documentExists(docRef)) {
|
||||||
logger.debug("Successfully imported {} to Firestore.", documentId);
|
DocumentSnapshot documentSnapshot = firestoreBaseRepository.getDocumentSnapshot(docRef);
|
||||||
|
Map<String, Object> firestoreData = documentSnapshot.getData();
|
||||||
|
if (!Objects.equals(localData, firestoreData)) {
|
||||||
|
firestoreBaseRepository.setDocument(docRef, localData);
|
||||||
|
logger.info("Successfully updated {} in Firestore.", documentId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.debug("{} already exists in Firestore. Skipping import.", documentId);
|
firestoreBaseRepository.setDocument(docRef, localData);
|
||||||
|
logger.info("Successfully imported {} to Firestore.", documentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,4 +64,7 @@ messagefilter.prompt=prompts/message_filter_prompt.txt
|
|||||||
# (DLP) Configuration
|
# (DLP) Configuration
|
||||||
# =========================================================
|
# =========================================================
|
||||||
google.cloud.dlp.dlpTemplateCompleteFlow=${DLP_TEMPLATE_COMPLETE_FLOW}
|
google.cloud.dlp.dlpTemplateCompleteFlow=${DLP_TEMPLATE_COMPLETE_FLOW}
|
||||||
google.cloud.dlp.dlpTemplatePersistFlow=IMC_INSPECT_NAME
|
# =========================================================
|
||||||
|
# Quick-replies Preset-data
|
||||||
|
# =========================================================
|
||||||
|
firestore.data.importer.enabled=true
|
||||||
@@ -58,3 +58,12 @@ messagefilter.temperature=${MESSAGE_FILTER_TEMPERATURE}
|
|||||||
messagefilter.maxOutputTokens=${MESSAGE_FILTER_MAX_OUTPUT_TOKENS}
|
messagefilter.maxOutputTokens=${MESSAGE_FILTER_MAX_OUTPUT_TOKENS}
|
||||||
messagefilter.topP=${MESSAGE_FILTER_TOP_P}
|
messagefilter.topP=${MESSAGE_FILTER_TOP_P}
|
||||||
messagefilter.prompt=prompts/message_filter_prompt.txt
|
messagefilter.prompt=prompts/message_filter_prompt.txt
|
||||||
|
# =========================================================
|
||||||
|
# (DLP) Configuration
|
||||||
|
# =========================================================
|
||||||
|
google.cloud.dlp.dlpTemplateCompleteFlow=${DLP_TEMPLATE_COMPLETE_FLOW}
|
||||||
|
google.cloud.dlp.dlpTemplatePersistFlow=${DLP_TEMPLATE_PERSIST_FLOW}
|
||||||
|
# =========================================================
|
||||||
|
# Quick-replies Preset-data
|
||||||
|
# =========================================================
|
||||||
|
firestore.data.importer.enabled=true
|
||||||
@@ -58,3 +58,12 @@ messagefilter.temperature=${MESSAGE_FILTER_TEMPERATURE}
|
|||||||
messagefilter.maxOutputTokens=${MESSAGE_FILTER_MAX_OUTPUT_TOKENS}
|
messagefilter.maxOutputTokens=${MESSAGE_FILTER_MAX_OUTPUT_TOKENS}
|
||||||
messagefilter.topP=${MESSAGE_FILTER_TOP_P}
|
messagefilter.topP=${MESSAGE_FILTER_TOP_P}
|
||||||
messagefilter.prompt=prompts/message_filter_prompt.txt
|
messagefilter.prompt=prompts/message_filter_prompt.txt
|
||||||
|
# =========================================================
|
||||||
|
# (DLP) Configuration
|
||||||
|
# =========================================================
|
||||||
|
google.cloud.dlp.dlpTemplateCompleteFlow=${DLP_TEMPLATE_COMPLETE_FLOW}
|
||||||
|
google.cloud.dlp.dlpTemplatePersistFlow=${DLP_TEMPLATE_PERSIST_FLOW}
|
||||||
|
# =========================================================
|
||||||
|
# Quick-replies Preset-data
|
||||||
|
# =========================================================
|
||||||
|
firestore.data.importer.enabled=true
|
||||||
@@ -1 +1 @@
|
|||||||
spring.profiles.active=${SPRING_PROFILE}
|
spring.profiles.active=dev
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"header": "preguntas sobre pagos",
|
"header": "preguntas frecuentes",
|
||||||
|
"body": "Aquí tienes las preguntas frecuentes que suelen hacernos algunos de nuestros clientes",
|
||||||
|
"button": "Ver",
|
||||||
|
"header_section": "preguntas sobre pagos",
|
||||||
"preguntas": [
|
"preguntas": [
|
||||||
{
|
{
|
||||||
"titulo": "Donde veo mi historial de pagos?",
|
"titulo": "Donde veo mi historial de pagos?",
|
||||||
|
|||||||
@@ -54,13 +54,16 @@ public class QuickReplyContentServiceTest {
|
|||||||
// Given
|
// Given
|
||||||
String collectionId = "home";
|
String collectionId = "home";
|
||||||
String header = "home_header";
|
String header = "home_header";
|
||||||
|
String body = "home_body";
|
||||||
|
String button = "home_button";
|
||||||
|
String headerSection = "home_header_section";
|
||||||
List<Map<String, Object>> preguntas = Collections.singletonList(
|
List<Map<String, Object>> preguntas = Collections.singletonList(
|
||||||
Map.of("titulo", "title", "descripcion", "description", "respuesta", "response")
|
Map.of("titulo", "title", "descripcion", "description", "respuesta", "response")
|
||||||
);
|
);
|
||||||
List<QuestionDTO> questionDTOs = Collections.singletonList(
|
List<QuestionDTO> questionDTOs = Collections.singletonList(
|
||||||
new QuestionDTO("title", "description", "response")
|
new QuestionDTO("title", "description", "response")
|
||||||
);
|
);
|
||||||
QuickReplyDTO expected = new QuickReplyDTO(header, questionDTOs);
|
QuickReplyDTO expected = new QuickReplyDTO(header, body, button, headerSection, questionDTOs);
|
||||||
|
|
||||||
when(firestore.collection("artifacts")).thenReturn(collectionReference);
|
when(firestore.collection("artifacts")).thenReturn(collectionReference);
|
||||||
when(collectionReference.document("default-app-id")).thenReturn(documentReference);
|
when(collectionReference.document("default-app-id")).thenReturn(documentReference);
|
||||||
@@ -70,6 +73,9 @@ public class QuickReplyContentServiceTest {
|
|||||||
when(apiFuture.get()).thenReturn(documentSnapshot);
|
when(apiFuture.get()).thenReturn(documentSnapshot);
|
||||||
when(documentSnapshot.exists()).thenReturn(true);
|
when(documentSnapshot.exists()).thenReturn(true);
|
||||||
when(documentSnapshot.getString("header")).thenReturn(header);
|
when(documentSnapshot.getString("header")).thenReturn(header);
|
||||||
|
when(documentSnapshot.getString("body")).thenReturn(body);
|
||||||
|
when(documentSnapshot.getString("button")).thenReturn(button);
|
||||||
|
when(documentSnapshot.getString("header_section")).thenReturn(headerSection);
|
||||||
when(documentSnapshot.get("preguntas")).thenReturn(preguntas);
|
when(documentSnapshot.get("preguntas")).thenReturn(preguntas);
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@@ -112,7 +118,7 @@ public class QuickReplyContentServiceTest {
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
StepVerifier.create(result)
|
StepVerifier.create(result)
|
||||||
.expectNext(new QuickReplyDTO("empty", Collections.emptyList()))
|
.expectNext(new QuickReplyDTO("empty", null, null, null, Collections.emptyList()))
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user