package com.example.service; import com.example.dto.dialogflow.DetectIntentRequestDTO; import com.example.dto.dialogflow.DetectIntentResponseDTO; import com.example.mapper.DialogflowRequestMapper; import com.example.mapper.DialogflowResponseMapper; import com.example.exception.DialogflowClientException; import com.google.api.gax.rpc.ApiException; import com.google.cloud.dialogflow.cx.v3.DetectIntentRequest; import com.google.cloud.dialogflow.cx.v3.SessionsClient; import com.google.cloud.dialogflow.cx.v3.SessionName; import com.google.cloud.dialogflow.cx.v3.SessionsSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import javax.annotation.PreDestroy; import java.io.IOException; import java.util.Objects; @Service public class DialogflowClientService { private static final Logger logger = LoggerFactory.getLogger(DialogflowClientService.class); private final String dialogflowCxProjectId; private final String dialogflowCxLocation; private final String dialogflowCxAgentId; private final DialogflowRequestMapper dialogflowRequestMapper; private final DialogflowResponseMapper dialogflowResponseMapper; private SessionsClient sessionsClient; public DialogflowClientService( @org.springframework.beans.factory.annotation.Value("${dialogflow.cx.project-id}") String dialogflowCxProjectId, @org.springframework.beans.factory.annotation.Value("${dialogflow.cx.location}") String dialogflowCxLocation, @org.springframework.beans.factory.annotation.Value("${dialogflow.cx.agent-id}") String dialogflowCxAgentId, DialogflowRequestMapper dialogflowRequestMapper, DialogflowResponseMapper dialogflowResponseMapper) throws IOException { this.dialogflowCxProjectId = dialogflowCxProjectId; this.dialogflowCxLocation = dialogflowCxLocation; this.dialogflowCxAgentId = dialogflowCxAgentId; this.dialogflowRequestMapper = dialogflowRequestMapper; this.dialogflowResponseMapper = dialogflowResponseMapper; try { String regionalEndpoint = String.format("%s-dialogflow.googleapis.com:443", dialogflowCxLocation); SessionsSettings sessionsSettings = SessionsSettings.newBuilder() .setEndpoint(regionalEndpoint) .build(); this.sessionsClient = SessionsClient.create(sessionsSettings); logger.info("Dialogflow CX SessionsClient initialized successfully for endpoint: {}", regionalEndpoint); } catch (IOException e) { logger.error("Failed to create Dialogflow CX SessionsClient: {}", e.getMessage(), e); throw e; } } @PreDestroy public void closeSessionsClient() { if (sessionsClient != null) { sessionsClient.close(); logger.info("Dialogflow CX SessionsClient closed."); } } public Mono detectIntent( String sessionId, DetectIntentRequestDTO request) { Objects.requireNonNull(sessionId, "Dialogflow session ID cannot be null."); Objects.requireNonNull(request, "Dialogflow request DTO cannot be null."); logger.info("Initiating detectIntent for session: {}", sessionId); DetectIntentRequest.Builder detectIntentRequestBuilder; try { detectIntentRequestBuilder = dialogflowRequestMapper.mapToDetectIntentRequestBuilder(request); logger.debug("Obtained partial DetectIntentRequest.Builder from mapper for session: {}", sessionId); } catch (IllegalArgumentException e) { logger.error(" Failed to map DTO to partial Protobuf request for session {}: {}", sessionId, e.getMessage()); return Mono.error(new IllegalArgumentException("Invalid Dialogflow request input: " + e.getMessage())); } SessionName sessionName = SessionName.newBuilder() .setProject(dialogflowCxProjectId) .setLocation(dialogflowCxLocation) .setAgent(dialogflowCxAgentId) .setSession(sessionId) .build(); detectIntentRequestBuilder.setSession(sessionName.toString()); logger.debug("Set session path {} on the request builder for session: {}", sessionName.toString(), sessionId); // Build the final DetectIntentRequest Protobuf object DetectIntentRequest detectIntentRequest = detectIntentRequestBuilder.build(); return Mono.fromCallable(() -> { logger.debug("Calling Dialogflow CX detectIntent for session: {}", sessionId); return sessionsClient.detectIntent(detectIntentRequest); }) .onErrorMap(ApiException.class, e -> { logger.error("Dialogflow CX API error for session {}: status={}, message={}", sessionId, e.getStatusCode().getCode(), e.getMessage(), e); return new DialogflowClientException( "Dialogflow CX API error: " + e.getStatusCode().getCode() + " - " + e.getMessage(), e); }) .onErrorMap(IOException.class, e -> { logger.error("IO error when calling Dialogflow CX for session {}: {}", sessionId, e.getMessage(),e); return new RuntimeException("IO error with Dialogflow CX API: " + e.getMessage(), e); }) .map(dfResponse -> this.dialogflowResponseMapper.mapFromDialogflowResponse(dfResponse, sessionId)); } }