From 379dd769adcc50450040ba8849e11481e0c60126 Mon Sep 17 00:00:00 2001 From: PAVEL PALMA Date: Tue, 16 Dec 2025 12:28:41 -0600 Subject: [PATCH] Revert "UPGRADE 10-12-2025" This reverts commit 84bb14c12617bc947c6098ee3d3d023320097264 --- README.md | 230 ------------------ pom.xml | 4 + .../controller/QuickRepliesController.java | 4 +- .../ConversationContextMapper.java | 21 +- .../ConversationContextMapperTest.java | 27 -- 5 files changed, 10 insertions(+), 276 deletions(-) diff --git a/README.md b/README.md index c38b0a3..9392ea1 100644 --- a/README.md +++ b/README.md @@ -4,233 +4,3 @@ * *Spring Boot Version:* `3.2.5` (defined in the parent POM) * *Spring Cloud GCP Version:* `5.3.0` (managed via `spring-cloud-gcp-dependencies`) * *Spring Cloud Version:* `2023.0.0` (managed via `spring-cloud-dependencies`) - - -This project is a **Spring Boot Service Orchestrator** running on **Java 21**. - -Here is step-by-step guide to getting this deployed locally in your IDE. - ------ - -### Step 1: Ensure Prerequisites - -Before we touch the code, we need to make sure your local machine matches the project requirements found in the `pom.xml` and `Dockerfile`. - -1. **Install Java 21 JDK:** The project explicitly requires Java 21. - * *Check:* Run `java -version` in your terminal. If it doesn't say "21", you need to install it. -2. **Install Maven:** This is used to build the project dependencies. -3. **Install the "Extension Pack for Java" in VS Code:** This includes tools for Maven, debugging, and IntelliSense. -4. **Install Docker (Desktop or Engine):** We will need this to run a local Redis instance. - ------ - -### Step 2: The "Redis Gotcha" (Local Infrastructure) - -If you look at `src/main/resources/application-dev.properties`, you will see this line: -`spring.data.redis.host=localhost`. - - -1. **Start Redis in Docker:** - Open your terminal and run: - ```bash - docker run --name local-redis -p 6379:6379 -d redis - ``` -2. **Verify it's running:** - Run `docker ps`. You should see redis running on port `6379`. - ------ - -### Step 3: Google Cloud Authentication - -This application connects to **Firestore**, **Dialogflow CX**, and **Vertex AI (Gemini)**. It uses the "Application Default Credentials" strategy. - -1. **Install the Google Cloud CLI (`gcloud`)** if you haven't already. -2. **Login:** - In your terminal, run: - ```bash - gcloud auth application-default login - ``` - *This will open a browser window. Log in with your Google account that has access to the `app-jovenes` project.* - ------ - -### Step 4: Configure Local Properties - -We need to tell the application to look at your *local* Redis instead of the cloud one. - -1. Open `src/main/resources/application.properties`. - -2. Ensure the active profile is set to `dev`: - - ```properties - spring.profiles.active=dev - ``` - ------ - -### Step 5: Build the Project - -Now let's download all the dependencies defined in the `pom.xml`. - -1. Open the Command Palette (Ctrl+Shift+P or Cmd+Shift+P). -2. Type **"Maven: Execute Commands"** -\> select the project -\> **"install"**. - * *Alternative:* Open the built-in terminal and run: - ```bash - mvn clean install -DskipTests - ``` - * *Why skip tests?* The tests might try to connect to real cloud services or check specific configs that might fail on the first local run. Let's just get it compiling first. - ------ - -### Step 6: Run the Application - -1. Navigate to `src/main/java/com/example/Orchestrator.java`. -2. You should see a small "Run | Debug" button appear just above the `public static void main` line. -3. Click **Run**. - -**What to watch for in the Console:** - - * You want to see the Spring Boot logo. - * Look for `Started Orchestrator in X seconds`. - * Look for `Netty started on port 8080` (since this is a WebFlux app). - ------ - -### Step 7: Verify it's working - -Since this is an API, let's test the health or a simple endpoint. - -1. The app runs on port **8080** (defined in Dockerfile). -2. The API has Swagger documentation configured. -3. Open your browser and go to: - `http://localhost:8080/webjars/swagger-ui/index.html` . - * *Note:* If Swagger isn't loading, check the console logs for the exact context path. - -### Summary Checklist for you: - - * [ ] Java 21 Installed? - * [ ] Docker running Redis on localhost:6379? - * [ ] `gcloud auth application-default login` run? - * [ ] `application-dev.properties` updated to use `localhost` for Redis? - -### Examples of endpoint call - -### 1\. The Standard Conversation (Dialogflow) - -This is the most common flow. It simulates a user sending a message like "Hola" to the bot. The orchestrator will route this to Dialogflow CX. - -**Request:** - -```bash -curl -X POST http://localhost:8080/api/v1/dialogflow/detect-intent \ --H "Content-Type: application/json" \ --d '{ - "mensaje": "Hola, ¿quien eres?", - "usuario": { - "telefono": "5550001234", - "nickname": "DiegoLocal" - }, - "canal": "whatsapp", - "tipo": "INICIO" -}' -``` - -**What to expect:** - - * **Status:** `200 OK` - * **Response:** A JSON object containing `responseText` (the answer from Dialogflow) and `responseId`. - * **Logs:** Check your VS Code terminal. You should see logs like `Initiating detectIntent for session...`. - ------ - -### 2\. The "Smart" Notification Flow (Gemini Router) - -This is the cool part. We will first "push" a notification to the user, and then simulate the user asking a question about it. - -**Step A: Push the Notification** -This tells the system: *"Hey, user 5550001234 just received this alert."* - -```bash -curl -X POST http://localhost:8080/api/v1/dialogflow/notification \ --H "Content-Type: application/json" \ --d '{ - "texto": "Tu tarjeta *1234 ha sido bloqueada por seguridad.", - "telefono": "5550001234", - "parametrosOcultos": { - "motivo": "intento_fraude_detectado", - "ubicacion": "CDMX", - "fecha": "Hoy" - } -}' -``` - - * **Check Logs:** You should see `Notification for phone 5550001234 cached`. - -**Step B: User asks a follow-up (The Test)** -Now, ask a question that requires context from that notification. - -```bash -curl -X POST http://localhost:8080/api/v1/dialogflow/detect-intent \ --H "Content-Type: application/json" \ --d '{ - "mensaje": "¿Por qué fue bloqueada?", - "usuario": { - "telefono": "5550001234" - }, - "canal": "whatsapp", - "tipo": "CONVERSACION" -}' -``` - - * **What happens internally:** The `MessageEntryFilter` (Gemini) will see the previous notification in the history and classify this as a `NOTIFICATION` follow-up, routing it to the LLM instead of standard Dialogflow. - ------ - -### 3\. Quick Replies (Static Content) - -This tests the `QuickRepliesManagerService`. It fetches a JSON screen definition from your local files (e.g., `home.json`). - -**Request:** - -```bash -curl -X POST http://localhost:8080/api/v1/quick-replies/screen \ --H "Content-Type: application/json" \ --d '{ - "usuario": { - "telefono": "5550001234" - }, - "canal": "app", - "tipo": "INICIO", - "pantallaContexto": "pagos" -}' -``` - -**What to expect:** - - * **Response:** A JSON object with a `quick_replies` field containing the title "Home" (loaded from `home.json`). - ------ - -### 4\. Reset Everything (Purge) - -If you want to start fresh (clear the cache and history for "Local"), run this: - -```bash -curl -X DELETE http://localhost:8080/api/v1/data-purge/all -``` - - * **Logs:** You'll see `Starting Redis data purge` and `Starting Firestore data purge`. - -### 5\. Optional testing the llm response with uuid - -```bash -/api/v1/llm/tune-response -{ - "sessionInfo": { - "parameters": { - "uuid": "21270589-184e-4a1a-922d-fb48464211e8" - } - } -} -``` - diff --git a/pom.xml b/pom.xml index aecdb7a..83982fd 100644 --- a/pom.xml +++ b/pom.xml @@ -166,6 +166,10 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 + + com.fasterxml.jackson.module + jackson-module-parameter-names + com.fasterxml.jackson.module jackson-module-parameter-names diff --git a/src/main/java/com/example/controller/QuickRepliesController.java b/src/main/java/com/example/controller/QuickRepliesController.java index 497afc4..88a0dbb 100644 --- a/src/main/java/com/example/controller/QuickRepliesController.java +++ b/src/main/java/com/example/controller/QuickRepliesController.java @@ -5,7 +5,6 @@ package com.example.controller; -import com.example.dto.dialogflow.base.DetectIntentResponseDTO; import com.example.dto.quickreplies.QuickReplyScreenRequestDTO; import com.example.service.quickreplies.QuickRepliesManagerService; import jakarta.validation.Valid; @@ -30,8 +29,9 @@ public class QuickRepliesController { } @PostMapping("/screen") - public Mono startSessionAndGetReplies(@Valid @RequestBody QuickReplyScreenRequestDTO request) { + public Mono> startSessionAndGetReplies(@Valid @RequestBody QuickReplyScreenRequestDTO request) { return quickRepliesManagerService.startQuickReplySession(request) + .map(response -> Map.of("responseId", response.responseId())) .doOnSuccess(response -> logger.info("Successfully processed quick reply request")) .doOnError(error -> logger.error("Error processing quick reply request: {}", error.getMessage(), error)); } diff --git a/src/main/java/com/example/mapper/messagefilter/ConversationContextMapper.java b/src/main/java/com/example/mapper/messagefilter/ConversationContextMapper.java index 39448a1..70340cc 100644 --- a/src/main/java/com/example/mapper/messagefilter/ConversationContextMapper.java +++ b/src/main/java/com/example/mapper/messagefilter/ConversationContextMapper.java @@ -23,8 +23,6 @@ public class ConversationContextMapper { private static final int MAX_HISTORY_BYTES = 50 * 1024; // 50 KB - private static final String NOTIFICATION_TEXT_PARAM = "notification_text"; - public String toText(ConversationSessionDTO session, List messages) { if (messages == null || messages.isEmpty()) { return ""; @@ -77,34 +75,23 @@ public class ConversationContextMapper { private String formatEntry(ConversationMessageDTO entry) { String prefix = "User: "; - String content = entry.text(); if (entry.type() != null) { switch (entry.type()) { - case AGENT: + case MessageType.AGENT: prefix = "Agent: "; break; - case SYSTEM: + case MessageType.SYSTEM: prefix = "System: "; - // fix: add notification in the conversation. - if (entry.parameters() != null && entry.parameters().containsKey(NOTIFICATION_TEXT_PARAM)) { - Object paramText = entry.parameters().get(NOTIFICATION_TEXT_PARAM); - if (paramText != null && !paramText.toString().isBlank()) { - content = paramText.toString(); - } - } break; - case LLM: - prefix = "System: "; - break; - case USER: + case MessageType.USER: default: prefix = "User: "; break; } } - String text = prefix + content; + String text = prefix + entry.text(); if (entry.type() == MessageType.AGENT) { text = cleanAgentMessage(text); diff --git a/src/test/java/com/example/mapper/messagefilter/ConversationContextMapperTest.java b/src/test/java/com/example/mapper/messagefilter/ConversationContextMapperTest.java index 4cce3c8..4e90cd7 100644 --- a/src/test/java/com/example/mapper/messagefilter/ConversationContextMapperTest.java +++ b/src/test/java/com/example/mapper/messagefilter/ConversationContextMapperTest.java @@ -7,7 +7,6 @@ import java.lang.reflect.Method; import java.time.Instant; import java.util.ArrayList; import java.util.List; -import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -119,30 +118,4 @@ public class ConversationContextMapperTest { private ConversationMessageDTO createMessage(String text, MessageType type) { return new ConversationMessageDTO(type, Instant.now(), text, null, null); } - - - @Test - public void testToTextFromMessages_SystemNotification_ShouldUseParamText() { - ConversationContextMapper mapper = new ConversationContextMapper(); - - Map params = new java.util.HashMap<>(); - params.put("notification_text", "Tu estado de cuenta está listo"); - - ConversationMessageDTO systemMessage = new ConversationMessageDTO( - MessageType.SYSTEM, - Instant.now(), - "NOTIFICATION", - params, - "whatsapp" - ); - - List messages = new java.util.ArrayList<>(); - messages.add(systemMessage); - - // WHEN - String result = mapper.toTextFromMessages(messages); - System.out.println(result); - // THEN - assertEquals("System: Tu estado de cuenta está listo", result); - } }