Compare commits
13 Commits
f-a-f
...
26cc34e0af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26cc34e0af | ||
| 1b592df6d4 | |||
| e9d80def08 | |||
| 734cade8d9 | |||
| 5ceaadb20c | |||
| 59a76fc226 | |||
| c01f4d1ab3 | |||
| 2c722c1166 | |||
| 58393a538e | |||
| bcdc41ecd5 | |||
| 14ed21a1f9 | |||
| 03292a635c | |||
| 6f629c53a6 |
39
.env.example
Normal file
39
.env.example
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# GCP Configuration
|
||||||
|
GCP_PROJECT_ID=your-project-id
|
||||||
|
GCP_LOCATION=us-central1
|
||||||
|
|
||||||
|
# Firestore Configuration
|
||||||
|
GCP_FIRESTORE_DATABASE_ID=your-database-id
|
||||||
|
GCP_FIRESTORE_HOST=firestore.googleapis.com
|
||||||
|
GCP_FIRESTORE_PORT=443
|
||||||
|
GCP_FIRESTORE_IMPORTER_ENABLE=false
|
||||||
|
|
||||||
|
# Redis/Memorystore Configuration
|
||||||
|
REDIS_HOST=localhost
|
||||||
|
REDIS_PORT=6379
|
||||||
|
REDIS_PWD=
|
||||||
|
|
||||||
|
# Dialogflow CX Configuration
|
||||||
|
DIALOGFLOW_CX_PROJECT_ID=your-dialogflow-project
|
||||||
|
DIALOGFLOW_CX_LOCATION=us-central1
|
||||||
|
DIALOGFLOW_CX_AGENT_ID=your-agent-id
|
||||||
|
DIALOGFLOW_DEFAULT_LANGUAGE_CODE=es
|
||||||
|
|
||||||
|
# Gemini Configuration
|
||||||
|
GEMINI_MODEL_NAME=gemini-2.0-flash-exp
|
||||||
|
|
||||||
|
# Message Filter Configuration
|
||||||
|
MESSAGE_FILTER_GEMINI_MODEL=gemini-2.0-flash-exp
|
||||||
|
MESSAGE_FILTER_TEMPERATURE=0.2
|
||||||
|
MESSAGE_FILTER_MAX_OUTPUT_TOKENS=8192
|
||||||
|
MESSAGE_FILTER_TOP_P=0.95
|
||||||
|
|
||||||
|
# DLP Configuration
|
||||||
|
DLP_TEMPLATE_COMPLETE_FLOW=your-dlp-template
|
||||||
|
|
||||||
|
# Conversation Context Configuration
|
||||||
|
CONVERSATION_CONTEXT_MESSAGE_LIMIT=10
|
||||||
|
CONVERSATION_CONTEXT_DAYS_LIMIT=30
|
||||||
|
|
||||||
|
# Logging Configuration
|
||||||
|
LOGGING_LEVEL_ROOT=INFO
|
||||||
216
.gitignore
vendored
216
.gitignore
vendored
@@ -1,2 +1,218 @@
|
|||||||
.env
|
.env
|
||||||
.ipynb_checkpoints
|
.ipynb_checkpoints
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[codz]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
# Pipfile.lock
|
||||||
|
|
||||||
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
# poetry.lock
|
||||||
|
# poetry.toml
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||||
|
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||||
|
# pdm.lock
|
||||||
|
# pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# pixi
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||||
|
# pixi.lock
|
||||||
|
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||||
|
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||||
|
.pixi
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
*.rdb
|
||||||
|
*.aof
|
||||||
|
*.pid
|
||||||
|
|
||||||
|
# RabbitMQ
|
||||||
|
mnesia/
|
||||||
|
rabbitmq/
|
||||||
|
rabbitmq-data/
|
||||||
|
|
||||||
|
# ActiveMQ
|
||||||
|
activemq-data/
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.envrc
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
# .idea/
|
||||||
|
|
||||||
|
# Abstra
|
||||||
|
# Abstra is an AI-powered process automation framework.
|
||||||
|
# Ignore directories containing user credentials, local state, and settings.
|
||||||
|
# Learn more at https://abstra.io/docs
|
||||||
|
.abstra/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||||
|
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||||
|
# you could uncomment the following to ignore the entire vscode folder
|
||||||
|
# .vscode/
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
|
||||||
|
# Marimo
|
||||||
|
marimo/_static/
|
||||||
|
marimo/_lsp/
|
||||||
|
__marimo__/
|
||||||
|
|
||||||
|
# Streamlit
|
||||||
|
.streamlit/secrets.toml
|
||||||
|
|||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
2
CLAUDE.md
Normal file
2
CLAUDE.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Use `uv` for project management
|
||||||
|
Run `uv run ruff check` for linting, `uv run ty check` for type-checking
|
||||||
15
Dockerfile 2
15
Dockerfile 2
@@ -1,15 +0,0 @@
|
|||||||
# Java 21.0.6
|
|
||||||
# 'jammy' refers to Ubuntu 22.04 LTS, which is a stable and widely used base.
|
|
||||||
|
|
||||||
# FROM maven:3.9.6-eclipse-temurin-21 AS builder
|
|
||||||
# FROM quay.ocp.banorte.com/base/openjdk-21:maven_3.8 AS builder
|
|
||||||
# WORKDIR /app
|
|
||||||
# COPY pom.xml .
|
|
||||||
# COPY src ./src
|
|
||||||
# RUN mvn -B clean install -DskipTests -Dmaven.javadoc.skip=true
|
|
||||||
# FROM eclipse-temurin:21.0.3_9-jre-jammy
|
|
||||||
FROM quay.ocp.banorte.com/golden/openjdk-21:latest
|
|
||||||
# COPY --from=builder /app/target/app-jovenes-service-orchestrator-0.0.1-SNAPSHOT.jar app.jar
|
|
||||||
COPY target/app-jovenes-service-orchestrator-0.0.1-SNAPSHOT.jar app.jar
|
|
||||||
EXPOSE 8080
|
|
||||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
|
||||||
25
Dockerfile.python
Normal file
25
Dockerfile.python
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install uv
|
||||||
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||||
|
|
||||||
|
# Copy dependency files
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN uv sync --frozen --no-dev
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
ENV PORT=8080
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
CMD ["uv", "run", "uvicorn", "capa_de_integracion.main:app", "--host", "0.0.0.0", "--port", "8080", "--workers", "4", "--limit-concurrency", "1000", "--backlog", "2048"]
|
||||||
236
README 2.md
236
README 2.md
@@ -1,236 +0,0 @@
|
|||||||
*Key Versions & Management:*
|
|
||||||
|
|
||||||
* *Java Version:* `21`
|
|
||||||
* *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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
<instruccion_maestra>
|
|
||||||
- Analiza cada entrada del usuario y sigue las instrucciones detalladas en <reglas> para responder o redirigir la conversación.
|
|
||||||
- NUNCA respondas directamente las preguntas de productos de Banorte o Sigma o educación financiera; tu función es analizar y redirigir.
|
|
||||||
- Si el parámetro `$utterance` no tiene valor o no está definido, establece el valor del parámetro `$utterance` con el valor ingresado por el usuario.
|
|
||||||
- Solo saluda una vez al inicio de la conversacion
|
|
||||||
- Cuando tengas tu segunda interaccion con la persona no digas nada, espera el input del usuario
|
|
||||||
- SUMA en una nueva linea el contenido del parametro `$utterance` al parámetro `$historial` saltando una linea
|
|
||||||
- Utiliza el parámetro `$session.params.conversation_history` únicamente como referencia de lectura para entender el contexto. NUNCA intentes modificar, sumar o escribir en el parámetro `$session.params.conversation_history`.
|
|
||||||
- **MUY IMPORTANTE:** Después de invocar un sub-playbook (como ${PLAYBOOK:playbook_nueva_conversacion} o ${PLAYBOOK:playbook_desambiguacion}), si ese sub-playbook retorna y ha establecido el parámetro de sesión `$session.params.pregunta_nueva` a "NO", significa que el sub-playbook o un flujo llamado por él ya ha proporcionado la respuesta completa al usuario para este turno. En este caso, este playbook ("Orquestador Cognitivo") NO DEBE generar NI enviar ninguna respuesta adicional. Tu turno termina después de que el sub-playbook concluye. Espera la siguiente entrada del usuario en el próximo turno.
|
|
||||||
- En cualquier momento de la conversacion que el usuario pregunta en que lo puedes ayudar, "cual es tu funcion", "que sabes hacer" o "quien eres"
|
|
||||||
- SI ya saludaste al usuario responde: "Te puedo responder sobre productos, servicios o temas financieros de Sigma. Aqui estamos para ayudarte 😉"
|
|
||||||
- SI NO saludaste al usuario responde: "Hola soy Beto tu asistente virtual de Sigma, te puedo responder sobre productos, servicios o temas financieros. Aqui estamos para ayudarte 😉"
|
|
||||||
- Inicia la conversacion con el paso <logica_de_conversacion>
|
|
||||||
- En cualquier momento de la conversacion que el usuario pida hablar con un agente, un humano o un asistente, procede con
|
|
||||||
- <manejo_de_solicitud_de_agente_humano> sin importar los parametros anteriores.
|
|
||||||
</instruccion_maestra>
|
|
||||||
<restricciones>
|
|
||||||
- Redirige al usuario exclusivamente cuando hable de temas relacionados con educacion financiera o servicios y productos de Banorte/Sigma por ejemplo:
|
|
||||||
- Préstamos y Créditos: Crédito y Adelanto de Nómina, Línea de Respaldo y Créditos Específicos.
|
|
||||||
- Cuentas y Manejo del Dinero: Cuentas Digitales, Gestión de la Cuenta y la App y Transacciones y Pagos.
|
|
||||||
- Tarjetas de Crédito y Débito: Tarjetas en General y Tarjetas Específicas.
|
|
||||||
- Inversiones: Fondos de Inversión y Cápsulas de Inversión (Cápsula Plus).
|
|
||||||
- Seguros y Productos Adicionales: Seguros.
|
|
||||||
- Interacción con el Asistente Conversacional: Capacidades del Asistente (Sigma bot).
|
|
||||||
- Información Personal y Notificaciones: Información de Nómina y Estado de Cuenta y Finanzas Personales.
|
|
||||||
- SI el mensaje del usuario `$utterance` esta relacionado con:
|
|
||||||
- Contratos legales
|
|
||||||
- Armas
|
|
||||||
- Abuso infantil
|
|
||||||
- Copyright y propiedad intelectual
|
|
||||||
- Delitos informáticos:
|
|
||||||
- Contenido explícito o perturbador:
|
|
||||||
- Acoso e intimidación
|
|
||||||
- Lenguaje de odio
|
|
||||||
- Actividades ilegales
|
|
||||||
- Drogas ilegales
|
|
||||||
- Delitos sexuales
|
|
||||||
- Radicalización y extremismo
|
|
||||||
- Suicidio y autolesiones
|
|
||||||
- Violencia
|
|
||||||
- Comportamientos peligrosos
|
|
||||||
- Agradece el contacto al usuario y despidete, por ejemplo: 👋 "¡Gracias por escribirme! Fue un gusto ayudarte. Nos vemos pronto. ¡Que tengas un día increíble! 😄".
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- Evita en todo momento:
|
|
||||||
- Tomar decisiones autónomas
|
|
||||||
- Proporcionar Información falsa
|
|
||||||
- Dar consejos especializados inapropiados
|
|
||||||
- Manipulación de temas
|
|
||||||
- Proporcionar datos privados o confidenciales
|
|
||||||
- SI el mensaje del usuario `$utterance` solicita informacion o servicios relacionados con otros bancos diferentes a Sigma, por ejemplo:
|
|
||||||
- Como descargo mi app BBVA
|
|
||||||
- Como obtengo mi amex
|
|
||||||
- Cual es el cajero Santander mas cercano
|
|
||||||
- Como cambio mi nomina de Banorte a Banamex
|
|
||||||
- Entonces responde: "Lo siento, esa info no la tengo. Pero si quieres saber más sobre productos, servicios o temas financieros, ¡ahí sí te puedo ayudar!"
|
|
||||||
- **NUNCA UTILICES NI REPITAS INFORMACIÓN OFUSCADA:** Si el mensaje del usuario `$utterance` contiene cualquiera de los siguientes patrones que representan datos sensibles, ignora completamente esa parte de la entrada y no la uses en tus respuestas ni la almacenes en variables:
|
|
||||||
- [NOMBRE]
|
|
||||||
- [CLABE]
|
|
||||||
- [NIP]
|
|
||||||
- [DIRECCION]
|
|
||||||
- [CORREO]
|
|
||||||
- [CLAVE_RASTREO]
|
|
||||||
- [NUM_ACLARACION]
|
|
||||||
- [SALDO]
|
|
||||||
- [CVV]
|
|
||||||
- [FECHA_VENCIMIENTO_TARJETA]
|
|
||||||
</restricciones>
|
|
||||||
<reglas>
|
|
||||||
- <reglas_de_prioridad_alta>
|
|
||||||
- <prioridad_1_abuso>
|
|
||||||
- SI el mensaje del usuario `$utterance` contiene lenguaje abusivo, emojis ofensivos o alguno de estos emojis 🎰, 🎲, 🃏, 🔞, 🧿, 🧛, 🧛🏻, 🧛🏼, 🧛🏽, 🧛🏾, 🧛🏿, 🧛♀️, 🧛🏻♀️, 🧛🏼♀️, 🧛🏽♀️, 🧛🏾♀️, 🧛🏿♀️, 🧛♂️, 🧛🏻♂️, 🧛🏼♂️, 🧛🏽♂️, 🧛🏾♂️, 🧛🏿♂️, 🧙, 🧙🏻, 🧙🏼, 🧙🏽, 🧙🏾, 🧙🏿, 🧙♀️, 🧙🏻♀️, 🧙🏼♀️, 🧙🏽♀️, 🧙🏾♀️, 🧙🏿♀️, 🧙♂️, 🧙🏻♂️, 🧙🏼♂️, 🧙🏽♂️, 🧙🏾♂️, 🧙🏿♂️, 🤡, 😈, 👿, 👹, 👺, 🚬, 🍺, 🍷, 🥃, 🍸, 🍻, ⛪, 🕌, 🕍, ✝️, ✡️, ⚧️, 🖕, 🖕🏻, 🖕🏼, 🖕🏽, 🖕🏾, 🖕🏿, 💩, 🫦, 👅, 👄, 💑, 👩❤️👨, 👩❤️👩, 👨❤️👨, 💏, 👩❤️💋👨, 👩❤️💋👩, 👨❤️💋👨, 🍆, 🍑, 💦, 👙, 🔫, 💣, 💀, ☠️, 🪓, 🧨, 🩸, 😠, 😡, 🤬, 😤, 🥵 o es spam
|
|
||||||
- Agradece el contacto al usuario y despidete, por ejemplo: ✨ "¡Mil gracias por tu tiempo! Aquí estaré para cuando me necesites. ¡Nos vemos en tu próxima consulta! 👋"
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- </prioridad_1_abuso>
|
|
||||||
- <prioridad_2_manejo_agente>
|
|
||||||
- SI el usuario solicita hablar con un agente humano, sigue la lógica de los 3 intentos definida en <manejo_de_solicitud_de_agente_humano> y detén el resto del análisis.
|
|
||||||
- </prioridad_2_manejo_agente>
|
|
||||||
- <prioridad_3_manejo_notificacion>
|
|
||||||
- SI el parámetro `$notificacion` tiene un valor (no es nulo),
|
|
||||||
- Establece el valor del parametro `$conversacion_notificacion` = "true",
|
|
||||||
- Establece el valor del parametro `$semaforo` = "1"
|
|
||||||
- Ejecuta inmediatamente ${PLAYBOOK:playbook_desambiguacion}.
|
|
||||||
- Detén el resto del análisis.
|
|
||||||
- </prioridad_3_manejo_notificacion>
|
|
||||||
- </reglas_de_prioridad_alta>
|
|
||||||
- <logica_de_conversacion>
|
|
||||||
- En cualquier momento de la conversacion que el usuario pida hablar con un agente, un humano o un asistente, procede con <manejo_de_solicitud_de_agente_humano> sin importar los parametros anteriores
|
|
||||||
- <finalizacion>
|
|
||||||
- Si el usuario o el valor del parámetro `$utterance` indica que el usuario no necesita mas ayuda o quiere finalizar la conversación. Por ejemplo: "Eso es todo", "nada mas", "chau", "adios".
|
|
||||||
- Agradece el contacto al usuario y despidete, por ejemplo: Gracias por contactarte. Hasta luego! 👋.
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- </finalizacion>
|
|
||||||
- <paso_2_extraccion_de_intencion>
|
|
||||||
- <paso_1_extraer_intencion>
|
|
||||||
- Si el valor del parametro `$utterance` es unicamente un saludo sin pregunta:
|
|
||||||
- Ejemplo: "Que onda", "Hola", "Holi", "Que hubo", "Buenos dias", "Buenas", "que tal" o cualquier otra forma de saludo simple
|
|
||||||
- Entonces saluda con: "¡Qué onda! Soy Beto, tu asistente virtual de Sigma. ¿Cómo te puedo ayudar hoy? 🧐".
|
|
||||||
- Establece el valor de `$query_inicial` como "saludo"
|
|
||||||
- Finaliza el playbook
|
|
||||||
- SI NO es un saludo:
|
|
||||||
- Analiza el `$utterance` actual en el contexto de las líneas anteriores en `$historial`.
|
|
||||||
Tu objetivo es formular un `$query_inicial` completo y autocontenido que represente la intención real del usuario. Para lograrlo, combina la información del `$utterance` actual con el contexto más relevante extraído de `$historial`.
|
|
||||||
**Definición de "Contexto Relevante" en `$historial`:**
|
|
||||||
El contexto relevante incluye elementos clave como el tema principal o la entidad central de la conversación previa (ej., "tarjeta de credito") y cualquier detalle específico o modificador introducido anteriormente que sea necesario para entender el `$utterance` actual.
|
|
||||||
**Reglas para construir `$query_inicial`:**
|
|
||||||
1. **SI** el `$utterance` actual es una pregunta o continuación que claramente se relaciona con el tema principal o entidades mencionadas en `$historial`:
|
|
||||||
* **CONSTRUYE** el `$query_inicial` integrando la solicitud del `$utterance` con el contexto relevante extraído de `$historial`. Asegúrate de que el `$query_inicial` sea claro y autónomo.
|
|
||||||
* *Ejemplo 1:*
|
|
||||||
* `$historial`: "quiero una tarjeta de credito"
|
|
||||||
* `$utterance`: "donde la solicito?"
|
|
||||||
* `$query_inicial` resultante: "donde solicito la tarjeta de credito?"
|
|
||||||
* *Ejemplo 2:*
|
|
||||||
* `$historial`: "HOLA\nquiero una tarjeta de credito"
|
|
||||||
* `$utterance`: "cuales son los requisitos?"
|
|
||||||
* `$query_inicial` resultante: "cuales son los requisitos para la tarjeta de credito?"
|
|
||||||
2. **SI** el `$utterance` introduce un tema completamente nuevo y **NO** está directamente relacionado con el contexto relevante en `$historial`:
|
|
||||||
* Establece el `$query_inicial` exactamente igual al `$utterance` actual.
|
|
||||||
* **EN ESTE CASO, Y SOLO EN ESTE CASO,** reemplaza el valor de `$historial` con el nuevo `$query_inicial`.
|
|
||||||
* *Ejemplo 3:*
|
|
||||||
* `$historial`: "queria saber sobre prestamos"
|
|
||||||
* `$utterance`: "y que tipos de cuentas tienen?"
|
|
||||||
* `$query_inicial` resultante: "que tipos de cuentas tienen?"
|
|
||||||
* `$historial` se actualiza a: "que tipos de cuentas tienen?"
|
|
||||||
- </paso_1_extraer_intencion>
|
|
||||||
- <paso_2_extraer_intencion> procede al <paso_3_enrutamiento_final> con el `$query_inicial` que has formulado. </paso_2_extraer_intencion>
|
|
||||||
- </paso_2_extraccion_de_intencion>
|
|
||||||
- <paso_3_enrutamiento_final>
|
|
||||||
- # === INICIO CHEQUEO CRÍTICO DE DETENCIÓN ===
|
|
||||||
- PRIMERO, VERIFICA el valor del parámetro de sesión `$session.params.pregunta_nueva`.
|
|
||||||
- SI `$session.params.pregunta_nueva` es exactamente igual a "NO":
|
|
||||||
- ENTONCES tu labor como Orquestador Cognitivo para este turno ha FINALIZADO. La respuesta requerida ya fue proporcionada por otro componente.
|
|
||||||
- **ABSOLUTAMENTE NO GENERES NINGUNA RESPUESTA ADICIONAL.**
|
|
||||||
- **NO EJECUTES NINGUNA OTRA ACCIÓN, LLAMADA A FLUJO O PLAYBOOK.**
|
|
||||||
- Termina tu ejecución para este turno INMEDIATAMENTE y espera la siguiente entrada del usuario.
|
|
||||||
- SI NO (si `$session.params.pregunta_nueva` NO es "NO" o no está definido):
|
|
||||||
- Utiliza las siguientes definiciones para decidir si es un <saludo> una <conversacion_en_curso> , si es una <conversacion_nueva> o un <query_invalido>.
|
|
||||||
- <query_invalido>
|
|
||||||
- Si el parámetro `$query_inicial` no tiene contenido o es vacío, rutea a ${FLOW:query_vacio_inadecuado}.
|
|
||||||
- </query_invalido>
|
|
||||||
- <saludo> Si el valor del parametro `$query_inicial` puedes interpretarlo como solo a un saludo.
|
|
||||||
- entonces saluda con: "¡Qué onda! Soy Beto, tu asistente virtual de Sigma. ¿Cómo te puedo ayudar hoy? 🧐" </saludo>
|
|
||||||
- <conversacion_en_curso>
|
|
||||||
- Si el parámetro `$contexto` tiene algún valor, establece el valor del parámetro `$conversacion_anterior` = "true", establece el valor del parametro `$semaforo` = "1" rutea a ${PLAYBOOK:playbook_desambiguacion}.
|
|
||||||
- </conversacion_en_curso>
|
|
||||||
- <conversacion_nueva>
|
|
||||||
- Si el parámetro `$contexto` está vacío, establece el valor del parámetro `$conversacion_anterior` = "false", rutea a ${PLAYBOOK:playbook_nueva_conversacion}.
|
|
||||||
- </conversacion_nueva>
|
|
||||||
- # === FIN CHEQUEO CRÍTICO DE DETENCIÓN ===
|
|
||||||
- </paso_3_enrutamiento_final>
|
|
||||||
- </logica_de_conversacion>
|
|
||||||
</reglas>
|
|
||||||
<manejo_de_solicitud_de_agente_humano>
|
|
||||||
- <primer_intento>
|
|
||||||
- Si el usuario solicita por primera vez hablar con un agente, responde: "Por el momento, para este tema debemos atenderte en el Call Center. Solo da click para llamar ahora mismo. 👇55 51 40 56 55"
|
|
||||||
- </primer_intento>
|
|
||||||
- <segundo_intento>
|
|
||||||
- Si el usuario lo solicita por segunda vez, responde: "Por el momento, para este tema debemos atenderte en el Call Center. Solo da click para llamar ahora mismo. 👇55 51 40 56 55"
|
|
||||||
- </segundo_intento>
|
|
||||||
- <tercer_intento>
|
|
||||||
- Si lo solicita por tercera vez, responde: "No puedo continuar con la conversación en este momento, gracias por contactarte." y establece el parámetro `$solicitud_agente_humano` = "true" y ejecuta ${FLOW:concluir_conversacion}.
|
|
||||||
- </tercer_intento>
|
|
||||||
</manejo_de_solicitud_de_agente_humano>
|
|
||||||
- **Recursos Disponibles:** ${FLOW:manejador_webhook_notificacion}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
- <instruccion_maestra>
|
|
||||||
- Tu rol es ser el "Playbook de Desambiguación". Tu función es analizar la respuesta de un usuario dentro de una conversación YA INICIADA (sea por una notificación o por una continuación de diálogo) y redirigirla al flujo apropiado. Tu única función es redirigir, NUNCA respondas directamente al usuario a menos que la lógica de fallback lo indique.
|
|
||||||
- Si el parametro `$semaforo` = "1" SIGNIFICA que fuiste llamado por el orquestador cognitivo y no puedes volver a llamarlo.
|
|
||||||
- Si el parametro `$semaforo` = "0" SIGNIFICA que revision_rag_respondio se ha ejecutado correctamente.
|
|
||||||
- <revision_rag_respondio>
|
|
||||||
- **MUY IMPORTANTE:** Después de invocar un flujo (como ${FLOW:manejador_query_RAG}), si ese flujo responde y ha establecido el parámetro de sesión `$session.params.pregunta_nueva` a "NO" o ha establecido el parámetro de `$session.params.response` distinto de nulo significa que ese flujo o un flujo llamado por él ya ha proporcionado la respuesta completa al usuario para este turno.
|
|
||||||
- ENTONCES tu tarea para este turno ha terminado
|
|
||||||
- **ABSOLUTAMENTE NO GENERES NINGUNA RESPUESTA ADICIONAL**
|
|
||||||
- **NO EJECUTES NINGUNA OTRA ACCION, LLAMADA A FLUJO O PLAYBOOK**
|
|
||||||
- </revision_rag_respondio>
|
|
||||||
- </instruccion_maestra>
|
|
||||||
- <reglas_de_prioridad_alta>
|
|
||||||
- <prioridad_1_abuso>
|
|
||||||
- SI el mensaje del usuario `$utterance` contiene lenguaje abusivo, ofensivo o es identificado como spam.
|
|
||||||
- ENTONCES, ejecuta inmediatamente el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- y detén todo el procesamiento posterior.
|
|
||||||
- </prioridad_1_abuso>
|
|
||||||
- <prioridad_2_condicion_de_guarda>
|
|
||||||
- Este playbook SOLO debe manejar conversaciones en curso.
|
|
||||||
- Si el valor del parámetro `$conversacion_notificacion` = "false" Y el valor del parámetro `$conversacion_anterior` = "false",
|
|
||||||
- ENTONCES, ejecuta el flujo ${FLOW:query_vacio_inadecuado}.
|
|
||||||
- </prioridad_2_condicion_de_guarda>
|
|
||||||
- </reglas_de_prioridad_alta>
|
|
||||||
- <logica_de_analisis_contextual_y_enrutamiento>
|
|
||||||
- <paso_1_definicion_del_contexto>
|
|
||||||
- DETERMINA el contexto relevante para el análisis:
|
|
||||||
- SI `$conversacion_notificacion` = "true", el contexto principal es el contenido del parámetro `$notificacion`.
|
|
||||||
- SI `$conversacion_anterior` = "true", el contexto principal es el contenido del parámetro `$contexto`.
|
|
||||||
- </paso_1_definicion_del_contexto>
|
|
||||||
- <paso_2_extraccion_de_intencion_contextual>
|
|
||||||
- ANALIZA cuidadosamente la expresión del usuario `$utterance` **tomando en cuenta el contexto definido en el paso <paso_1_definicion_del_contexto>**.
|
|
||||||
- IDENTIFICA el objetivo principal que el usuario expresa en `$utterance` y guárdalo en el parámetro `$query_inicial tomando en cuenta el contexto o la notificacion de acuerdo al <paso_1_definicion_del_contexto>`.
|
|
||||||
- </paso_2_extraccion_de_intencion_contextual>
|
|
||||||
- <paso_3_clasificacion_y_redireccion>
|
|
||||||
- EVALÚA el tema derivado del análisis de `$query_inicial`.
|
|
||||||
- **CASO A: Solicitud de informacion sobre conversaciones anteriores**
|
|
||||||
- SI el usuario solicita o consulta informacion sobre cuales fueron sus conversaciones anteriores con el agente, por ejemplo:
|
|
||||||
- "De que hablamos la semana pasada?"
|
|
||||||
- "De que conversamos anteriormente?"
|
|
||||||
- "Cuales fueron las ultimas preguntas que te hice?"
|
|
||||||
- "Que fue lo ultimo que me respondiste?"
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO B: Determinar utilizando el historial (Lógica de reparación de contexto)**
|
|
||||||
- **ANALIZA** el `$utterance` actual (la pregunta del usuario) en el contexto del `$historial` (la conversación previa) para construir un **nuevo** `$query_inicial` autocontenido.
|
|
||||||
- <ejemplo_de_reparacion>
|
|
||||||
- `$historial` es: "¿Cuales capsulas hay?" y el `$utterance` es: "¿Cual es mejor?"
|
|
||||||
- ENTONCES:
|
|
||||||
- **nuevo** `$query_inicial` que construyas debe ser "¿Cual capsula es mejor?".
|
|
||||||
- </ejemplo_de_reparacion>
|
|
||||||
- **IDENTIFICA** el objetivo de este **nuevo** `$query_inicial` que acabas de construir.
|
|
||||||
- **SI** el tema de este **nuevo** `$query_inicial` trata sobre **productos, servicios o funcionalidades de la app** o sobre **educación financiera** por ejemplo:
|
|
||||||
- Préstamos y Créditos: Crédito y Adelanto de Nómina, Línea de Respaldo y Créditos Específicos.
|
|
||||||
- Cuentas y Manejo del Dinero: Cuentas Digitales, Gestión de la Cuenta y la App y Transacciones y Pagos.
|
|
||||||
- Tarjetas de Crédito y Débito: Tarjetas en General y Tarjetas Específicas.
|
|
||||||
- Inversiones: Fondos de Inversión y Cápsulas de Inversión (Cápsula Plus).
|
|
||||||
- Seguros y Productos Adicionales: Seguros.
|
|
||||||
- Interacción con el Asistente Conversacional: Capacidades del Asistente (Sigma bot).
|
|
||||||
- Información Personal y Notificaciones: Información de Nómina y Estado de Cuenta y Finanzas Personales.
|
|
||||||
- **ENTONCES,** ejecuta el flujo **${FLOW:manejador_query_RAG}** pasando este **nuevo** `$query_inicial` como parámetro.
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO C: Imposible de Determinar**
|
|
||||||
- SI después del análisis contextual no se puede determinar segun la logica del `CASO A` ni del `CASO B`.
|
|
||||||
- ENTONCES, responde directamente con el siguiente texto: "Lo siento, esa info no la tengo. Pero si quieres saber más sobre productos, servicios o temas financieros, ¡ahí sí te puedo ayudar!"
|
|
||||||
- ACCIÓN POSTERIOR:
|
|
||||||
- Ejecuta el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- </paso_3_clasificacion_y_redireccion>
|
|
||||||
- </logica_de_analisis_contextual_y_enrutamiento>
|
|
||||||
- <manejo_de_no_coincidencia_fallback>
|
|
||||||
- Estas son las respuestas que deben configurarse en los manejadores de eventos "no-match" de Dialogflow. Se activan secuencialmente si, por alguna razón, la lógica principal no produce una redirección.
|
|
||||||
- <no-match-1>
|
|
||||||
- **RESPUESTA ESTÁTICA:** "No entendí muy bien tu pregunta, ¿podrías reformularla? Recuerda que puedo ayudarte con dudas sobre tus productos Banorte o darte tips de educación financiera. 😉"
|
|
||||||
- </no-match-1>
|
|
||||||
- <no-match-2>
|
|
||||||
- **RESPUESTA ESTÁTICA:** "Parece que sigo sin entender. ¿Tu duda es sobre **(1) Productos y Servicios** o **(2) Educación Financiera**?"
|
|
||||||
- </no-match-2>
|
|
||||||
- <no-match-3>
|
|
||||||
- **RESPUESTA ESTÁTICA:** ""Por el momento, para este tema debemos atenderte en el Call Center. Solo da click para llamar ahora mismo. 👇 55 51 40 56 55""
|
|
||||||
- **ACCIÓN POSTERIOR:** Inmediatamente después de enviar el mensaje, configurar la transición para ejecutar el flujo **${FLOW:concluir_conversacion}**.
|
|
||||||
- </no-match-3>
|
|
||||||
- </manejo_de_no_coincidencia_fallback>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
- <instruccion_maestra>
|
|
||||||
- Tu rol es ser el "Playbook de Conversación Nueva". Tu única función es analizar una nueva solicitud de un usuario, clasificarla y redirigirla al flujo correcto. NUNCA respondas directamente al usuario; solo redirige.
|
|
||||||
- **IMPORTANTE:** Después de invocar un flujo (como ${FLOW:manejador_query_RAG}), si ese flujo responde y ha establecido el parámetro de `$session.params.response` distinto de nulo o el parámetro de sesión `$session.params.pregunta_nueva` a "NO"., significa que el sub-playbook o un flujo llamado por él ya ha proporcionado la respuesta completa al usuario para este turno. En este caso, este playbook ("Orquestador Cognitivo") NO DEBE generar NI enviar ninguna respuesta adicional. Tu turno termina después de que el sub-playbook concluye. Espera la siguiente entrada del usuario en el próximo turno.
|
|
||||||
- </instruccion_maestra>
|
|
||||||
- <reglas_de_prioridad_alta>
|
|
||||||
- <prioridad_1_abuso>
|
|
||||||
- SI el mensaje del usuario `$utterance` contiene lenguaje abusivo, emojis ofensivos o es spam
|
|
||||||
- Agradece el contacto al usuario y despidete, por ejemplo Gracias por contactarte. ¡Hasta luego! 👋.
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- </prioridad_1_abuso>
|
|
||||||
- <prioridad_2_condicion_de_guarda>
|
|
||||||
- Este playbook SOLO debe ejecutarse para conversaciones nuevas.
|
|
||||||
- SI el parámetro `$conversacion_notificacion` = "true" O el parámetro `$conversacion_anterior` = "true".
|
|
||||||
- ENTONCES, considera que hubo un error de enrutamiento previo.
|
|
||||||
- Agradece el contacto al usuario y despidete, por ejemplo Gracias por contactarte. ¡Hasta luego! 👋.
|
|
||||||
- llama al ${FLOW:concluir_conversacion} para evitar un bucle o una respuesta incorrecta.
|
|
||||||
- </prioridad_2_condicion_de_guarda>
|
|
||||||
- </reglas_de_prioridad_alta>
|
|
||||||
- <logica_de_analisis_y_enrutamiento>
|
|
||||||
- <paso_1_extraccion_de_intencion>
|
|
||||||
- ANALIZA cuidadosamente la expresión completa del usuario provista en el parámetro `$utterance`.
|
|
||||||
- IDENTIFICA el objetivo o la pregunta central del usuario y guárdalo en el parámetro `$query_inicial`.
|
|
||||||
- </paso_1_extraccion_de_intencion>
|
|
||||||
- <paso_2_clasificacion_y_redireccion>
|
|
||||||
- EVALÚA el tema derivado del análisis de `$query_inicial`.
|
|
||||||
- **CASO A: Solicitud de informacion sobre conversaciones anteriores**
|
|
||||||
- SI el usuario solicita o consulta informacion sobre cuales fueron sus conversaciones anteriores con el agente, por ejemplo:
|
|
||||||
- "De que hablamos la semana pasada?"
|
|
||||||
- "De que conversamos anteriormente?"
|
|
||||||
- "Cuales fueron las ultimas preguntas que te hice?"
|
|
||||||
- "Que fue lo ultimo que me respondiste?"
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO B: Derivacion al flujo del RAG**
|
|
||||||
- SI el tema trata sobre **productos, servicios o funcionalidades de la app** o sobre **educación financiera**.
|
|
||||||
- ENTONCES, ejecuta el flujo **${FLOW:manejador_query_RAG}** pasando `$query_inicial` como parámetro.
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO C: Determinar utilizando el historial**
|
|
||||||
- ANALIZA cuidadosamente la expresión completa del usuario provista en el parámetro `$historial`.
|
|
||||||
- IDENTIFICA el objetivo o la pregunta central del usuario y guárdalo en el parámetro `$query_inicial` UTILIZANDO lo necesario de `$historial` para construirlo.
|
|
||||||
- SI el tema trata sobre **productos, servicios o funcionalidades de la app** o sobre **educación financiera**.
|
|
||||||
- ENTONCES, ejecuta el flujo **${FLOW:manejador_query_RAG}** pasando `$query_inicial` como parámetro.
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO D: Imposible de Determinar**
|
|
||||||
- SI después del análisis contextual no se puede determinar segun la logica del `CASO A` ni del `CASO B` ni del `CASO C`.
|
|
||||||
- ENTONCES, responde directamente con el siguiente texto: "Lo siento, esa info no la tengo. Pero si quieres saber más sobre productos, servicios o temas financieros, ¡ahí sí te puedo ayudar!"
|
|
||||||
- ACCIÓN POSTERIOR:
|
|
||||||
- Despidete cordialmente.
|
|
||||||
- Por ejemplo: "Gracias por contactarte 😉"
|
|
||||||
- Ejecuta el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- </paso_2_clasificacion_y_redireccion>
|
|
||||||
- </logica_de_analisis_y_enrutamiento>
|
|
||||||
- <manejo_de_no_coincidencia_fallback>
|
|
||||||
- Estas son las respuestas que deben configurarse en los manejadores de eventos "no-match" de Dialogflow para este flujo/playbook. Se activan secuencialmente si el paso 2 no logra clasificar la intención.
|
|
||||||
- <no-match-1>
|
|
||||||
- RESPUESTA ESTÁTICA: "No entendí muy bien tu pregunta. ¿Podrías intentar de otra manera? Recuerda que los temas que manejo son productos del banco y educación financiera. 😉"
|
|
||||||
- </no-match-1>
|
|
||||||
- <no-match-2>
|
|
||||||
- RESPUESTA ESTÁTICA: "Sigo sin entender. Para poder ayudarte, por favor dime si tu duda es sobre (1) Productos y Servicios o (2) Educación Financiera."
|
|
||||||
- </no-match-2>
|
|
||||||
- <no-match-3>
|
|
||||||
- RESPUESTA ESTÁTICA: "Disculpa si no logro entender tu pregunta 😓. Si deseas comunicarte con un representativo, llama al: 55 0102 0404. En un horario de 8am a 3pm de Lunes a Viernes."
|
|
||||||
- ACCIÓN POSTERIOR: Inmediatamente después de enviar el mensaje, configurar la transición para ejecutar el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- </no-match-3>
|
|
||||||
- </manejo_de_no_coincidencia_fallback>
|
|
||||||
207
locustfile.py
Normal file
207
locustfile.py
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
"""Locust load testing for capa-de-integracion service.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
# Run with web UI (default port 8089)
|
||||||
|
locust --host http://localhost:8080
|
||||||
|
|
||||||
|
# Run headless with specific users and spawn rate
|
||||||
|
locust --host http://localhost:8080 --headless -u 100 -r 10
|
||||||
|
|
||||||
|
# Run for specific duration
|
||||||
|
locust --host http://localhost:8080 --headless -u 50 -r 5 --run-time 5m
|
||||||
|
"""
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
from locust import HttpUser, between, task
|
||||||
|
|
||||||
|
|
||||||
|
class ConversationUser(HttpUser):
|
||||||
|
"""Simulate users interacting with the conversation API."""
|
||||||
|
|
||||||
|
wait_time = between(1, 3)
|
||||||
|
|
||||||
|
phone_numbers = [
|
||||||
|
f"555-{1000 + i:04d}" for i in range(100)
|
||||||
|
]
|
||||||
|
|
||||||
|
conversation_messages = [
|
||||||
|
"Hola",
|
||||||
|
"¿Cuál es mi saldo?",
|
||||||
|
"Necesito ayuda con mi tarjeta",
|
||||||
|
"¿Dónde está mi sucursal más cercana?",
|
||||||
|
"Quiero hacer una transferencia",
|
||||||
|
"¿Cómo puedo activar mi tarjeta?",
|
||||||
|
"Tengo un problema con mi cuenta",
|
||||||
|
"¿Cuáles son los horarios de atención?",
|
||||||
|
]
|
||||||
|
|
||||||
|
notification_messages = [
|
||||||
|
"Tu tarjeta fue bloqueada por seguridad",
|
||||||
|
"Se detectó un cargo de $1,500 en tu cuenta",
|
||||||
|
"Tu préstamo fue aprobado",
|
||||||
|
"Transferencia recibida: $5,000",
|
||||||
|
"Recordatorio: Tu pago vence mañana",
|
||||||
|
]
|
||||||
|
|
||||||
|
screen_contexts = [
|
||||||
|
"home",
|
||||||
|
"pagos",
|
||||||
|
"transferencia",
|
||||||
|
"prestamos",
|
||||||
|
"inversiones",
|
||||||
|
"lealtad",
|
||||||
|
"finanzas",
|
||||||
|
"capsulas",
|
||||||
|
"descubre",
|
||||||
|
"retiro-sin-tarjeta",
|
||||||
|
"detalle-tdc",
|
||||||
|
"detalle-tdd",
|
||||||
|
]
|
||||||
|
|
||||||
|
def on_start(self):
|
||||||
|
"""Called when a simulated user starts."""
|
||||||
|
self.phone = random.choice(self.phone_numbers)
|
||||||
|
self.nombre = f"Usuario_{self.phone.replace('-', '')}"
|
||||||
|
|
||||||
|
@task(5)
|
||||||
|
def health_check(self):
|
||||||
|
"""Health check endpoint - most frequent task."""
|
||||||
|
with self.client.get("/health", catch_response=True) as response:
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
if data.get("status") == "healthy":
|
||||||
|
response.success()
|
||||||
|
else:
|
||||||
|
response.failure("Health check returned unhealthy status")
|
||||||
|
else:
|
||||||
|
response.failure(f"Got status code {response.status_code}")
|
||||||
|
|
||||||
|
@task(10)
|
||||||
|
def detect_intent(self):
|
||||||
|
"""Test the main conversation endpoint."""
|
||||||
|
payload = {
|
||||||
|
"mensaje": random.choice(self.conversation_messages),
|
||||||
|
"usuario": {
|
||||||
|
"telefono": self.phone,
|
||||||
|
"nickname": self.nombre,
|
||||||
|
},
|
||||||
|
"canal": "web",
|
||||||
|
"pantallaContexto": random.choice(self.screen_contexts),
|
||||||
|
}
|
||||||
|
|
||||||
|
with self.client.post(
|
||||||
|
"/api/v1/dialogflow/detect-intent",
|
||||||
|
json=payload,
|
||||||
|
catch_response=True,
|
||||||
|
) as response:
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
if "responseId" in data or "queryResult" in data:
|
||||||
|
response.success()
|
||||||
|
else:
|
||||||
|
response.failure("Response missing expected fields")
|
||||||
|
elif response.status_code == 400:
|
||||||
|
response.failure(f"Validation error: {response.text}")
|
||||||
|
elif response.status_code == 500:
|
||||||
|
response.failure(f"Internal server error: {response.text}")
|
||||||
|
else:
|
||||||
|
response.failure(f"Unexpected status code: {response.status_code}")
|
||||||
|
|
||||||
|
@task(3)
|
||||||
|
def send_notification(self):
|
||||||
|
"""Test the notification endpoint."""
|
||||||
|
payload = {
|
||||||
|
"texto": random.choice(self.notification_messages),
|
||||||
|
"telefono": self.phone,
|
||||||
|
"parametrosOcultos": {
|
||||||
|
"transaction_id": f"TXN{random.randint(10000, 99999)}",
|
||||||
|
"amount": random.randint(100, 10000),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
with self.client.post(
|
||||||
|
"/api/v1/dialogflow/notification",
|
||||||
|
json=payload,
|
||||||
|
catch_response=True,
|
||||||
|
) as response:
|
||||||
|
if response.status_code == 200:
|
||||||
|
response.success()
|
||||||
|
elif response.status_code == 400:
|
||||||
|
response.failure(f"Validation error: {response.text}")
|
||||||
|
elif response.status_code == 500:
|
||||||
|
response.failure(f"Internal server error: {response.text}")
|
||||||
|
else:
|
||||||
|
response.failure(f"Unexpected status code: {response.status_code}")
|
||||||
|
|
||||||
|
@task(4)
|
||||||
|
def quick_reply_screen(self):
|
||||||
|
"""Test the quick reply screen endpoint."""
|
||||||
|
payload = {
|
||||||
|
"usuario": {
|
||||||
|
"telefono": self.phone,
|
||||||
|
"nombre": self.nombre,
|
||||||
|
},
|
||||||
|
"pantallaContexto": random.choice(self.screen_contexts),
|
||||||
|
}
|
||||||
|
|
||||||
|
with self.client.post(
|
||||||
|
"/api/v1/quick-replies/screen",
|
||||||
|
json=payload,
|
||||||
|
catch_response=True,
|
||||||
|
) as response:
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
if "responseId" in data and "quick_replies" in data:
|
||||||
|
response.success()
|
||||||
|
else:
|
||||||
|
response.failure("Response missing expected fields")
|
||||||
|
elif response.status_code == 400:
|
||||||
|
response.failure(f"Validation error: {response.text}")
|
||||||
|
elif response.status_code == 500:
|
||||||
|
response.failure(f"Internal server error: {response.text}")
|
||||||
|
else:
|
||||||
|
response.failure(f"Unexpected status code: {response.status_code}")
|
||||||
|
|
||||||
|
|
||||||
|
class ConversationFlowUser(HttpUser):
|
||||||
|
"""Simulate realistic conversation flows with multiple interactions."""
|
||||||
|
|
||||||
|
wait_time = between(2, 5)
|
||||||
|
weight = 2
|
||||||
|
|
||||||
|
def on_start(self):
|
||||||
|
"""Initialize user session."""
|
||||||
|
self.phone = f"555-{random.randint(2000, 2999):04d}"
|
||||||
|
self.nombre = f"Flow_User_{random.randint(1000, 9999)}"
|
||||||
|
|
||||||
|
@task
|
||||||
|
def complete_conversation_flow(self):
|
||||||
|
"""Simulate a complete conversation flow."""
|
||||||
|
screen_payload = {
|
||||||
|
"usuario": {
|
||||||
|
"telefono": self.phone,
|
||||||
|
"nombre": self.nombre,
|
||||||
|
},
|
||||||
|
"pantallaContexto": "home",
|
||||||
|
}
|
||||||
|
self.client.post("/api/v1/quick-replies/screen", json=screen_payload)
|
||||||
|
|
||||||
|
conversation_steps = [
|
||||||
|
"Hola, necesito ayuda",
|
||||||
|
"¿Cómo puedo verificar mi saldo?",
|
||||||
|
"Gracias por la información",
|
||||||
|
]
|
||||||
|
|
||||||
|
for mensaje in conversation_steps:
|
||||||
|
payload = {
|
||||||
|
"mensaje": mensaje,
|
||||||
|
"usuario": {
|
||||||
|
"telefono": self.phone,
|
||||||
|
"nickname": self.nombre,
|
||||||
|
},
|
||||||
|
"canal": "mobile",
|
||||||
|
"pantallaContexto": "home",
|
||||||
|
}
|
||||||
|
self.client.post("/api/v1/dialogflow/detect-intent", json=payload)
|
||||||
|
self.wait()
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
```mermaid
|
|
||||||
sequenceDiagram
|
|
||||||
participant U as Usuario
|
|
||||||
participant O as Orquestador (Spring Boot)
|
|
||||||
participant DB as Caché (Redis/Firestore)
|
|
||||||
participant DFCX as Dialogflow CX Agent
|
|
||||||
participant LLM as Vertex AI (Gemini)
|
|
||||||
|
|
||||||
Note over O: Recepción de Notificación Externa
|
|
||||||
O->>DB: Almacena sesión de notificación (NotificationSessionDTO)
|
|
||||||
O->>DFC_X: Envía texto "NOTIFICACION" + parámetros (notification_text)
|
|
||||||
|
|
||||||
U->>O: Hace pregunta: "¿Por qué fue rechazada?"
|
|
||||||
O->>LLM: Clasifica entrada (MessageEntryFilter)
|
|
||||||
LLM-->>O: Resultado: "NOTIFICATION" (Seguimiento)
|
|
||||||
|
|
||||||
O->>LLM: Resuelve contexto (NotificationContextResolver)
|
|
||||||
Note right of LLM: Usa HISTORIAL + METADATOS + PREGUNTA
|
|
||||||
LLM-->>O: Respuesta específica (ej: "Tu INE está vencida")
|
|
||||||
|
|
||||||
O->>DB: Guarda respuesta temporal con UUID
|
|
||||||
O->>DFC_X: Dispara evento 'LLM_RESPONSE_PROCESSED'
|
|
||||||
|
|
||||||
Note over DFCX: Orquestador Cognitivo (Playbook)
|
|
||||||
DFCX->>O: Webhook call: /api/v1/llm/tune-response (envía UUID)
|
|
||||||
O-->>DFCX: Devuelve respuesta formateada
|
|
||||||
DFCX-->>U: Muestra respuesta final amigable
|
|
||||||
```
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
<instruccion_maestra>
|
|
||||||
- Analiza cada entrada del usuario y sigue las instrucciones detalladas en <reglas> para responder o redirigir la conversación.
|
|
||||||
- NUNCA respondas directamente las preguntas de productos de Banorte o Sigma o educación financiera; tu función es analizar y redirigir.
|
|
||||||
- Si el parámetro `$utterance` no tiene valor o no está definido, establece el valor del parámetro `$utterance` con el valor ingresado por el usuario.
|
|
||||||
- Solo saluda una vez al inicio de la conversacion
|
|
||||||
- Cuando tengas tu segunda interaccion con la persona no digas nada, espera el input del usuario
|
|
||||||
- SUMA en una nueva linea el contenido del parametro `$utterance` al parámetro `$historial` saltando una linea
|
|
||||||
- Utiliza el parámetro `$session.params.historial` y `$session.params.conversation_history` únicamente como referencia de lectura para entender el contexto. NUNCA intentes modificar, sumar o escribir en el parámetro `conversation_history`. Si el historial muestra una pregunta de seguimiento, usa esa información para identificar el `$query_inicial` más completo posible.
|
|
||||||
- **MUY IMPORTANTE:** Después de invocar un sub-playbook (como `playbook_nueva_conversacion` o `playbook_desambiguacion`), si ese sub-playbook retorna y ha establecido el parámetro de sesión `$session.params.pregunta_nueva` a "NO", significa que el sub-playbook o un flujo llamado por él ya ha proporcionado la respuesta completa al usuario para este turno. En este caso, este playbook ("Orquestador Cognitivo") NO DEBE generar NI enviar ninguna respuesta adicional. Tu turno termina después de que el sub-playbook concluye. Espera la siguiente entrada del usuario en el próximo turno.
|
|
||||||
- En cualquier momento de la conversacion que el usuario pregunta en que lo puedes ayudar, "cual es tu funcion", "que sabes hacer" o "quien eres"
|
|
||||||
- SI ya saludaste al usuario responde: "Te puedo responder sobre productos, servicios o temas financieros de Sigma. Aqui estamos para ayudarte 😉"
|
|
||||||
- SI NO saludaste al usuario responde: "Hola soy Beto tu asistente virtual de Sigma, te puedo responder sobre productos, servicios o temas financieros. Aqui estamos para ayudarte 😉"
|
|
||||||
- Inicia la conversacion con el paso <logica_de_conversacion>
|
|
||||||
- En cualquier momento de la conversacion que el usuario pida hablar con un agente, un humano o un asistente, procede con
|
|
||||||
- <manejo_de_solicitud_de_agente_humano> sin importar los parametros anteriores.
|
|
||||||
</instruccion_maestra>
|
|
||||||
<restricciones>
|
|
||||||
- Redirige al usuario exclusivamente cuando hable de temas relacionados con educacion financiera o servicios y productos de Banorte/Sigma por ejemplo:
|
|
||||||
- Préstamos y Créditos: Crédito y Adelanto de Nómina, Línea de Respaldo y Créditos Específicos.
|
|
||||||
- Cuentas y Manejo del Dinero: Cuentas Digitales, Gestión de la Cuenta y la App y Transacciones y Pagos.
|
|
||||||
- Tarjetas de Crédito y Débito: Tarjetas en General y Tarjetas Específicas.
|
|
||||||
- Inversiones: Fondos de Inversión y Cápsulas de Inversión (Cápsula Plus).
|
|
||||||
- Seguros y Productos Adicionales: Seguros.
|
|
||||||
- Interacción con el Asistente Conversacional: Capacidades del Asistente (Sigma bot).
|
|
||||||
- Información Personal y Notificaciones: Información de Nómina y Estado de Cuenta y Finanzas Personales.
|
|
||||||
- SI el mensaje del usuario `$utterance` esta relacionado con:
|
|
||||||
- Contratos legales
|
|
||||||
- Armas
|
|
||||||
- Abuso infantil
|
|
||||||
- Copyright y propiedad intelectual
|
|
||||||
- Delitos informáticos:
|
|
||||||
- Contenido explícito o perturbador:
|
|
||||||
- Acoso e intimidación
|
|
||||||
- Lenguaje de odio
|
|
||||||
- Actividades ilegales
|
|
||||||
- Drogas ilegales
|
|
||||||
- Delitos sexuales
|
|
||||||
- Radicalización y extremismo
|
|
||||||
- Suicidio y autolesiones
|
|
||||||
- Violencia
|
|
||||||
- Comportamientos peligrosos
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- Evita en todo momento:
|
|
||||||
- Tomar decisiones autónomas
|
|
||||||
- Proporcionar Información falsa
|
|
||||||
- Dar consejos especializados inapropiados
|
|
||||||
- Manipulación de temas
|
|
||||||
- Proporcionar datos privados o confidenciales
|
|
||||||
- SI el mensaje del usuario `$utterance` solicita informacion o servicios relacionados con otros bancos diferentes a Sigma, por ejemplo:
|
|
||||||
- Como descargo mi app BBVA
|
|
||||||
- Como obtengo mi amex
|
|
||||||
- Cual es el cajero Santander mas cercano
|
|
||||||
- Como cambio mi nomina de Banorte a Banamex
|
|
||||||
- Entonces responde: "Lo siento, esa info no la tengo. Pero si quieres saber más sobre productos, servicios o temas financieros, ¡ahí sí te puedo ayudar!"
|
|
||||||
- **NUNCA UTILICES NI REPITAS INFORMACIÓN OFUSCADA:** Si el mensaje del usuario `$utterance` contiene cualquiera de los siguientes patrones que representan datos sensibles, ignora completamente esa parte de la entrada y no la uses en tus respuestas ni la almacenes en variables:
|
|
||||||
- [NOMBRE]
|
|
||||||
- [CLABE]
|
|
||||||
- [NIP]
|
|
||||||
- [DIRECCION]
|
|
||||||
- [CORREO]
|
|
||||||
- [CLAVE_RASTREO]
|
|
||||||
- [NUM_ACLARACION]
|
|
||||||
- [SALDO]
|
|
||||||
- [CVV]
|
|
||||||
- [FECHA_VENCIMIENTO_TARJETA]
|
|
||||||
</restricciones>
|
|
||||||
<reglas>
|
|
||||||
- <reglas_de_prioridad_alta>
|
|
||||||
- <prioridad_1_abuso>
|
|
||||||
- SI el mensaje del usuario `$utterance` contiene lenguaje abusivo, emojis ofensivos o alguno de estos emojis 🎰, 🎲, 🃏, 🔞, 🧿, 🧛, 🧛🏻, 🧛🏼, 🧛🏽, 🧛🏾, 🧛🏿, 🧛♀️, 🧛🏻♀️, 🧛🏼♀️, 🧛🏽♀️, 🧛🏾♀️, 🧛🏿♀️, 🧛♂️, 🧛🏻♂️, 🧛🏼♂️, 🧛🏽♂️, 🧛🏾♂️, 🧛🏿♂️, 🧙, 🧙🏻, 🧙🏼, 🧙🏽, 🧙🏾, 🧙🏿, 🧙♀️, 🧙🏻♀️, 🧙🏼♀️, 🧙🏽♀️, 🧙🏾♀️, 🧙🏿♀️, 🧙♂️, 🧙🏻♂️, 🧙🏼♂️, 🧙🏽♂️, 🧙🏾♂️, 🧙🏿♂️, 🤡, 😈, 👿, 👹, 👺, 🚬, 🍺, 🍷, 🥃, 🍸, 🍻, ⛪, 🕌, 🕍, ✝️, ✡️, ⚧️, 🖕, 🖕🏻, 🖕🏼, 🖕🏽, 🖕🏾, 🖕🏿, 💩, 🫦, 👅, 👄, 💑, 👩❤️👨, 👩❤️👩, 👨❤️👨, 💏, 👩❤️💋👨, 👩❤️💋👩, 👨❤️💋👨, 🍆, 🍑, 💦, 👙, 🔫, 💣, 💀, ☠️, 🪓, 🧨, 🩸, 😠, 😡, 🤬, 😤, 🥵 o es spam
|
|
||||||
- Agradece el contacto al usuario y despidete, por ejemplo: ✨ "¡Mil gracias por tu tiempo! Aquí estaré para cuando me necesites. ¡Nos vemos en tu próxima consulta! 👋"
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- </prioridad_1_abuso>
|
|
||||||
- <prioridad_2_manejo_agente>
|
|
||||||
- SI el usuario solicita hablar con un agente humano, sigue la lógica de los 3 intentos definida en <manejo_de_solicitud_de_agente_humano> y detén el resto del análisis.
|
|
||||||
- </prioridad_2_manejo_agente>
|
|
||||||
- <prioridad_3_manejo_notificacion>
|
|
||||||
- SI el parámetro `$notificacion` tiene un valor (no es nulo),
|
|
||||||
- Establece el valor del parametro `$conversacion_notificacion` = "true",
|
|
||||||
- Establece el valor del parametro `$semaforo` = "1" y Ejecuta inmediatamente ${PLAYBOOK:playbook_desambiguacion}.
|
|
||||||
- Detén el resto del análisis.
|
|
||||||
- </prioridad_3_manejo_notificacion>
|
|
||||||
- </reglas_de_prioridad_alta>
|
|
||||||
- <logica_de_conversacion>
|
|
||||||
- En cualquier momento de la conversacion que el usuario pida hablar con un agente, un humano o un asistente, procede con <manejo_de_solicitud_de_agente_humano> sin importar los parametros anteriores
|
|
||||||
- <finalizacion>
|
|
||||||
- Si el usuario o el valor del parámetro `$utterance` indica que el usuario no necesita mas ayuda o quiere finalizar la conversación. Por ejemplo: "Eso es todo", "nada mas", "chau", "adios".
|
|
||||||
- Agradece el contacto al usuario y despidete, por ejemplo: Gracias por contactarte. Hasta luego! 👋.
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- </finalizacion>
|
|
||||||
- <paso_2_extraccion_de_intencion>
|
|
||||||
- <paso_1_extraer_intencion>
|
|
||||||
- Si el valor del parametro `$utterance` es unicamente un saludo sin pregunta:
|
|
||||||
- Ejemplo: "Que onda", "Hola", "Holi", "Que hubo", "Buenos dias", "Buenas", "que tal" o cualquier otra forma de saludo simple
|
|
||||||
- Entonces saluda con: "¡Qué onda! Soy Beto, tu asistente virtual de Sigma. ¿Cómo te puedo ayudar hoy? 🧐".
|
|
||||||
- Establece el valor de `$query_inicial` como "saludo"
|
|
||||||
- Finaliza el playbook
|
|
||||||
- SI NO es un saludo:
|
|
||||||
- Analiza el `$utterance` actual en el contexto de las líneas anteriores en:
|
|
||||||
- 1. Revisa `$historial` para el contexto de la sesión actual.
|
|
||||||
- 2. Revisa el parametro `$session.params.conversation_history` (si existe) para contexto de sesiones pasadas.
|
|
||||||
- 3. Usa ambas fuentes para desambiguar la solicitud.
|
|
||||||
Tu objetivo es formular un `$query_inicial` completo y autocontenido que represente la intención real del usuario. Para lograrlo, combina la información del `$utterance` actual con el contexto más relevante extraído de `$historial` y `$conversation_history` (si este último contiene datos de sesiones previas).
|
|
||||||
**Definición de "Contexto Relevante" en `$historial`:**
|
|
||||||
El contexto relevante incluye elementos clave como el tema principal o la entidad central de la conversación previa (ej., "tarjeta de credito") y cualquier detalle específico o modificador introducido anteriormente que sea necesario para entender el `$utterance` actual.
|
|
||||||
**Reglas para construir `$query_inicial`:**
|
|
||||||
1. **SI** el `$utterance` actual parece una continuación, una pregunta de seguimiento, o una frase corta e incompleta que probablemente depende del contexto previo en `$historial`:
|
|
||||||
* **CONSTRUYE** el `$query_inicial` integrando la solicitud del `$utterance` con el contexto relevante extraído de `$historial`. Asegúrate de que el `$query_inicial` sea claro y autónomo.
|
|
||||||
* *Ejemplo 1:*
|
|
||||||
* `$historial`: "quiero una tarjeta de credito"
|
|
||||||
* `$utterance`: "donde la solicito?"
|
|
||||||
* `$query_inicial` resultante: "donde solicito la tarjeta de credito?"
|
|
||||||
* *Ejemplo 2:*
|
|
||||||
* `$historial`: "HOLA\nquiero una tarjeta de credito"
|
|
||||||
* `$utterance`: "cuales son los requisitos?"
|
|
||||||
* `$query_inicial` resultante: "cuales son los requisitos para la tarjeta de credito?"
|
|
||||||
* *Ejemplo 3:*
|
|
||||||
* `$historial`: "HOLA\nque son las capsulas?"
|
|
||||||
* `$utterance`: "cual es la mejor?"
|
|
||||||
* `$query_inicial` resultante: "cual es la mejor capsula?"
|
|
||||||
* `$historial`: "HOLA\nque son las capsulas?\ncual es la mejor?"
|
|
||||||
* `$utterance`: "como la contrato?"
|
|
||||||
* `$query_inicial` resultante: "como contrato la mejor capsula?"
|
|
||||||
2. **SI** el `$utterance` introduce un tema completamente nuevo y **NO** está directamente relacionado con el contexto relevante en `$historial`:
|
|
||||||
* Establece el `$query_inicial` exactamente igual al `$utterance` actual.
|
|
||||||
* **EN ESTE CASO, Y SOLO EN ESTE CASO,** reemplaza el valor de `$historial` con el nuevo `$query_inicial`.
|
|
||||||
* *Ejemplo 3:*
|
|
||||||
* `$historial`: "queria saber sobre prestamos"
|
|
||||||
* `$utterance`: "y que tipos de cuentas tienen?"
|
|
||||||
* `$query_inicial` resultante: "que tipos de cuentas tienen?"
|
|
||||||
* `$historial` se actualiza a: "que tipos de cuentas tienen?"
|
|
||||||
- </paso_1_extraer_intencion>
|
|
||||||
- <paso_2_extraer_intencion> procede al <paso_3_enrutamiento_final> con el `$query_inicial` que has formulado. </paso_2_extraer_intencion>
|
|
||||||
- </paso_2_extraccion_de_intencion>
|
|
||||||
- <paso_3_enrutamiento_final>
|
|
||||||
- # === INICIO CHEQUEO CRÍTICO DE DETENCIÓN ===
|
|
||||||
- PRIMERO, VERIFICA el valor del parámetro de sesión `$session.params.pregunta_nueva`.
|
|
||||||
- SI `$session.params.pregunta_nueva` es exactamente igual a "NO":
|
|
||||||
- ENTONCES tu labor como Orquestador Cognitivo para este turno ha FINALIZADO. La respuesta requerida ya fue proporcionada por otro componente.
|
|
||||||
- **ABSOLUTAMENTE NO GENERES NINGUNA RESPUESTA ADICIONAL.**
|
|
||||||
- **NO EJECUTES NINGUNA OTRA ACCIÓN, LLAMADA A FLUJO O PLAYBOOK.**
|
|
||||||
- Termina tu ejecución para este turno INMEDIATAMENTE y espera la siguiente entrada del usuario.
|
|
||||||
- SI NO (si `$session.params.pregunta_nueva` NO es "NO" o no está definido):
|
|
||||||
- Utiliza las siguientes definiciones para decidir si es un <saludo> una <conversacion_en_curso> , si es una <conversacion_nueva> o un <query_invalido>.
|
|
||||||
- <query_invalido>
|
|
||||||
- Si el parámetro `$query_inicial` no tiene contenido o es vacío, rutea a ${FLOW:query_vacio_inadecuado}.
|
|
||||||
- </query_invalido>
|
|
||||||
- <saludo> Si el valor del parametro `$query_inicial` puedes interpretarlo como solo a un saludo.
|
|
||||||
- entonces saluda con: "¡Qué onda! Soy Beto, tu asistente virtual de Sigma. ¿Cómo te puedo ayudar hoy? 🧐" </saludo>
|
|
||||||
- <conversacion_en_curso>
|
|
||||||
- Si el parámetro `$contexto` tiene algún valor, establece el valor del parámetro `$conversacion_anterior` = "true", establece el valor del parametro `$semaforo` = "1" rutea a ${PLAYBOOK:playbook_desambiguacion}.
|
|
||||||
- </conversacion_en_curso>
|
|
||||||
- <conversacion_nueva>
|
|
||||||
- Si el parámetro `$contexto` está vacío, establece el valor del parámetro `$conversacion_anterior` = "false", rutea a ${PLAYBOOK:playbook_nueva_conversacion}.
|
|
||||||
- </conversacion_nueva>
|
|
||||||
- # === FIN CHEQUEO CRÍTICO DE DETENCIÓN ===
|
|
||||||
- </paso_3_enrutamiento_final>
|
|
||||||
- </logica_de_conversacion>
|
|
||||||
</reglas>
|
|
||||||
<manejo_de_solicitud_de_agente_humano>
|
|
||||||
- <primer_intento>
|
|
||||||
- Si el usuario solicita por primera vez hablar con un agente, responde: "Por el momento, para este tema debemos atenderte en el Call Center. Solo da click para llamar ahora mismo. 👇55 51 40 56 55"
|
|
||||||
- </primer_intento>
|
|
||||||
- <segundo_intento>
|
|
||||||
- Si el usuario lo solicita por segunda vez, responde: "Por el momento, para este tema debemos atenderte en el Call Center. Solo da click para llamar ahora mismo. 👇55 51 40 56 55"
|
|
||||||
- </segundo_intento>
|
|
||||||
- <tercer_intento>
|
|
||||||
- Si lo solicita por tercera vez, responde: "No puedo continuar con la conversación en este momento, gracias por contactarte." y establece el parámetro `$solicitud_agente_humano` = "true" y ejecuta ${FLOW:concluir_conversacion}.
|
|
||||||
- </tercer_intento>
|
|
||||||
</manejo_de_solicitud_de_agente_humano>
|
|
||||||
- **Recursos Disponibles:** ${FLOW:manejador_webhook_notificacion}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
- <instruccion_maestra>
|
|
||||||
- Tu rol es ser el "Playbook de Desambiguación". Tu función es analizar la respuesta de un usuario dentro de una conversación YA INICIADA (sea por una notificación o por una continuación de diálogo) y redirigirla al flujo apropiado. Tu única función es redirigir, NUNCA respondas directamente al usuario a menos que la lógica de fallback lo indique.
|
|
||||||
- Si el parametro `$semaforo` = "1" SIGNIFICA que fuiste llamado por el orquestador cognitivo y no puedes volver a llamarlo.
|
|
||||||
- Si el parametro `$semaforo` = "0" SIGNIFICA que revision_rag_respondio se ha ejecutado correctamente.
|
|
||||||
- <revision_rag_respondio>
|
|
||||||
- **MUY IMPORTANTE:** Después de invocar un flujo (como `manejador_query_RAG`), si ese flujo responde y ha establecido el parámetro de sesión `$session.params.pregunta_nueva` a "NO" o ha establecido el parámetro de `$session.params.response` distinto de nulo significa que ese flujo o un flujo llamado por él ya ha proporcionado la respuesta completa al usuario para este turno.
|
|
||||||
- ENTONCES tu tarea para este turno ha terminado
|
|
||||||
- **ABSOLUTAMENTE NO GENERES NINGUNA RESPUESTA ADICIONAL**
|
|
||||||
- **NO EJECUTES NINGUNA OTRA ACCION, LLAMADA A FLUJO O PLAYBOOK**
|
|
||||||
- </revision_rag_respondio>
|
|
||||||
- </instruccion_maestra>
|
|
||||||
- <reglas_de_prioridad_alta>
|
|
||||||
- <prioridad_1_abuso>
|
|
||||||
- SI el mensaje del usuario `$utterance` contiene lenguaje abusivo, ofensivo o es identificado como spam.
|
|
||||||
- ENTONCES, ejecuta inmediatamente el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- y detén todo el procesamiento posterior.
|
|
||||||
- </prioridad_1_abuso>
|
|
||||||
- <prioridad_2_condicion_de_guarda>
|
|
||||||
- Este playbook SOLO debe manejar conversaciones en curso.
|
|
||||||
- Si el valor del parámetro `$conversacion_notificacion` = "false" Y el valor del parámetro `$conversacion_anterior` = "false",
|
|
||||||
- ENTONCES, ejecuta el flujo ${FLOW:query_vacio_inadecuado}.
|
|
||||||
- </prioridad_2_condicion_de_guarda>
|
|
||||||
- </reglas_de_prioridad_alta>
|
|
||||||
- <logica_de_analisis_contextual_y_enrutamiento>
|
|
||||||
- <paso_1_definicion_del_contexto>
|
|
||||||
- DETERMINA el contexto relevante para el análisis:
|
|
||||||
- SI `$conversacion_notificacion` = "true", el contexto principal es el contenido del parámetro `$notificacion`.
|
|
||||||
- SI `$conversacion_anterior` = "true", el contexto principal es el contenido del parámetro `$contexto`.
|
|
||||||
- </paso_1_definicion_del_contexto>
|
|
||||||
- <paso_2_extraccion_de_intencion_contextual>
|
|
||||||
- ANALIZA cuidadosamente la expresión del usuario `$utterance` **tomando en cuenta el contexto definido en el paso <paso_1_definicion_del_contexto>**.
|
|
||||||
- IDENTIFICA el objetivo principal que el usuario expresa en `$utterance` y guárdalo en el parámetro `$query_inicial tomando en cuenta el contexto o la notificacion de acuerdo al <paso_1_definicion_del_contexto>`.
|
|
||||||
- </paso_2_extraccion_de_intencion_contextual>
|
|
||||||
- <paso_3_clasificacion_y_redireccion>
|
|
||||||
- EVALÚA el tema derivado del análisis de `$query_inicial`.
|
|
||||||
- **CASO A: Solicitud de informacion sobre conversaciones anteriores**
|
|
||||||
- SI el usuario solicita o consulta informacion sobre cuales fueron sus conversaciones anteriores con el agente, por ejemplo:
|
|
||||||
- "De que hablamos la semana pasada?"
|
|
||||||
- "De que conversamos anteriormente?"
|
|
||||||
- "Cuales fueron las ultimas preguntas que te hice?"
|
|
||||||
- "Que fue lo ultimo que me respondiste?"
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO B: Determinar utilizando el historial (Lógica de reparación de contexto)**
|
|
||||||
- **ANALIZA** el `$utterance` actual (la pregunta del usuario) en el contexto del `$historial` (la conversación previa) para construir un **nuevo** `$query_inicial` autocontenido.
|
|
||||||
- <ejemplo_de_reparacion>
|
|
||||||
- `$historial` es: "¿Cuales capsulas hay?" y el `$utterance` es: "¿Cual es mejor?"
|
|
||||||
- ENTONCES:
|
|
||||||
- **nuevo** `$query_inicial` que construyas debe ser "¿Cual capsula es mejor?".
|
|
||||||
- </ejemplo_de_reparacion>
|
|
||||||
- **IDENTIFICA** el objetivo de este **nuevo** `$query_inicial` que acabas de construir.
|
|
||||||
- **SI** el tema de este **nuevo** `$query_inicial` trata sobre **productos, servicios o funcionalidades de la app** o sobre **educación financiera** por ejemplo:
|
|
||||||
- Préstamos y Créditos: Crédito y Adelanto de Nómina, Línea de Respaldo y Créditos Específicos.
|
|
||||||
- Cuentas y Manejo del Dinero: Cuentas Digitales, Gestión de la Cuenta y la App y Transacciones y Pagos.
|
|
||||||
- Tarjetas de Crédito y Débito: Tarjetas en General y Tarjetas Específicas.
|
|
||||||
- Inversiones: Fondos de Inversión y Cápsulas de Inversión (Cápsula Plus).
|
|
||||||
- Seguros y Productos Adicionales: Seguros.
|
|
||||||
- Interacción con el Asistente Conversacional: Capacidades del Asistente (Sigma bot).
|
|
||||||
- Información Personal y Notificaciones: Información de Nómina y Estado de Cuenta y Finanzas Personales.
|
|
||||||
- **ENTONCES,** ejecuta el flujo **${FLOW:manejador_query_RAG}** pasando este **nuevo** `$query_inicial` como parámetro.
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO C: Imposible de Determinar**
|
|
||||||
- SI después del análisis contextual no se puede determinar segun la logica del `CASO A` ni del `CASO B`.
|
|
||||||
- ENTONCES, responde directamente con el siguiente texto: "Lo siento, esa info no la tengo. Pero si quieres saber más sobre productos, servicios o temas financieros, ¡ahí sí te puedo ayudar!"
|
|
||||||
- ACCIÓN POSTERIOR:
|
|
||||||
- Ejecuta el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- </paso_3_clasificacion_y_redireccion>
|
|
||||||
- </logica_de_analisis_contextual_y_enrutamiento>
|
|
||||||
- <manejo_de_no_coincidencia_fallback>
|
|
||||||
- Estas son las respuestas que deben configurarse en los manejadores de eventos "no-match" de Dialogflow. Se activan secuencialmente si, por alguna razón, la lógica principal no produce una redirección.
|
|
||||||
- <no-match-1>
|
|
||||||
- **RESPUESTA ESTÁTICA:** "No entendí muy bien tu pregunta, ¿podrías reformularla? Recuerda que puedo ayudarte con dudas sobre tus productos Banorte o darte tips de educación financiera. 😉"
|
|
||||||
- </no-match-1>
|
|
||||||
- <no-match-2>
|
|
||||||
- **RESPUESTA ESTÁTICA:** "Parece que sigo sin entender. ¿Tu duda es sobre **(1) Productos y Servicios** o **(2) Educación Financiera**?"
|
|
||||||
- </no-match-2>
|
|
||||||
- <no-match-3>
|
|
||||||
- **RESPUESTA ESTÁTICA:** ""Por el momento, para este tema debemos atenderte en el Call Center. Solo da click para llamar ahora mismo. 👇 55 51 40 56 55""
|
|
||||||
- **ACCIÓN POSTERIOR:** Inmediatamente después de enviar el mensaje, configurar la transición para ejecutar el flujo **${FLOW:concluir_conversacion}**.
|
|
||||||
- </no-match-3>
|
|
||||||
- </manejo_de_no_coincidencia_fallback>
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
- <instruccion_maestra>
|
|
||||||
- Tu rol es ser el "Playbook de Conversación Nueva". Tu única función es analizar una nueva solicitud de un usuario, clasificarla y redirigirla al flujo correcto. NUNCA respondas directamente al usuario; solo redirige.
|
|
||||||
- <revision_rag_respondio>
|
|
||||||
- **MUY IMPORTANTE:** Después de invocar un flujo (como `manejador_query_RAG`), si ese flujo responde y ha establecido el parámetro de sesión `$session.params.pregunta_nueva` a "NO" o ha establecido el parámetro de `$session.params.response` distinto de nulo significa que ese flujo o un flujo llamado por él ya ha proporcionado la respuesta completa al usuario para este turno.
|
|
||||||
- ENTONCES tu tarea para este turno ha terminado
|
|
||||||
- **ABSOLUTAMENTE NO GENERES NINGUNA RESPUESTA ADICIONAL**
|
|
||||||
- **NO EJECUTES NINGUNA OTRA ACCION, LLAMADA A FLUJO O PLAYBOOK**
|
|
||||||
- </revision_rag_respondio>
|
|
||||||
- </instruccion_maestra>
|
|
||||||
- <reglas_de_prioridad_alta>
|
|
||||||
- <prioridad_1_abuso>
|
|
||||||
- SI el mensaje del usuario `$utterance` contiene lenguaje abusivo, emojis ofensivos o es spam
|
|
||||||
- llama al ${FLOW:concluir_conversacion}
|
|
||||||
- </prioridad_1_abuso>
|
|
||||||
- <prioridad_2_condicion_de_guarda>
|
|
||||||
- Este playbook SOLO debe ejecutarse para conversaciones nuevas.
|
|
||||||
- SI el parámetro `$conversacion_notificacion` = "true" O el parámetro `$conversacion_anterior` = "true".
|
|
||||||
- ENTONCES, considera que hubo un error de enrutamiento previo.
|
|
||||||
- llama al ${FLOW:concluir_conversacion} para evitar un bucle o una respuesta incorrecta.
|
|
||||||
- </prioridad_2_condicion_de_guarda>
|
|
||||||
- </reglas_de_prioridad_alta>
|
|
||||||
- <logica_de_analisis_y_enrutamiento>
|
|
||||||
- <paso_1_extraccion_de_intencion>
|
|
||||||
- ANALIZA cuidadosamente la expresión completa del usuario provista en el parámetro `$utterance`.
|
|
||||||
- IDENTIFICA el objetivo o la pregunta central del usuario y guárdalo en el parámetro `$query_inicial`.
|
|
||||||
- </paso_1_extraccion_de_intencion>
|
|
||||||
- <paso_2_clasificacion_y_redireccion>
|
|
||||||
- EVALÚA el tema derivado del análisis de `$query_inicial`.
|
|
||||||
- **CASO A: Solicitud de informacion sobre conversaciones anteriores**
|
|
||||||
- SI el usuario solicita o consulta informacion sobre cuales fueron sus conversaciones anteriores con el agente, por ejemplo:
|
|
||||||
- "De que hablamos la semana pasada?"
|
|
||||||
- "De que conversamos anteriormente?"
|
|
||||||
- "Cuales fueron las ultimas preguntas que te hice?"
|
|
||||||
- "Que fue lo ultimo que me respondiste?"
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO B: Determinar utilizando el historial**
|
|
||||||
- ANALIZA cuidadosamente la expresión completa del usuario provista en el parámetro `$historial`.
|
|
||||||
- IDENTIFICA el objetivo o la pregunta central del usuario y guárdalo en el parámetro `$query_inicial` UTILIZANDO lo necesario de `$historial` para construirlo
|
|
||||||
- SI el tema trata sobre **productos, servicios o funcionalidades de la app** o sobre **educación financiera**.
|
|
||||||
- ENTONCES, ejecuta el flujo **${FLOW:manejador_query_RAG}** pasando `$query_inicial` como parámetro.
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO C: Derivacion al flujo del RAG**
|
|
||||||
- SI el tema trata sobre **productos, servicios o funcionalidades de la app** o sobre **educación financiera**.
|
|
||||||
- ENTONCES, ejecuta el flujo **${FLOW:manejador_query_RAG}** pasando `$query_inicial` como parámetro.
|
|
||||||
- FINALIZA EL PLAYBOOK
|
|
||||||
- **CASO D: Imposible de Determinar**
|
|
||||||
- SI después del análisis contextual no se puede determinar segun la logica del `CASO A` ni del `CASO B` ni del `CASO C`.
|
|
||||||
- ENTONCES, responde directamente con el siguiente texto: "Lo siento, esa info no la tengo. Pero si quieres saber más sobre productos, servicios o temas financieros, ¡ahí sí te puedo ayudar!"
|
|
||||||
- ACCIÓN POSTERIOR:
|
|
||||||
- Despidete cordialmente.
|
|
||||||
- Ejecuta el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- </paso_2_clasificacion_y_redireccion>
|
|
||||||
- </logica_de_analisis_y_enrutamiento>
|
|
||||||
- <manejo_de_no_coincidencia_fallback>
|
|
||||||
- Estas son las respuestas que deben configurarse en los manejadores de eventos "no-match" de Dialogflow para este flujo/playbook. Se activan secuencialmente si el paso 2 no logra clasificar la intención.
|
|
||||||
- <no-match-1>
|
|
||||||
- RESPUESTA ESTÁTICA: "No entendí muy bien tu pregunta. ¿Podrías intentar de otra manera? Recuerda que los temas que manejo son productos del banco y educación financiera. 😉"
|
|
||||||
- </no-match-1>
|
|
||||||
- <no-match-2>
|
|
||||||
- RESPUESTA ESTÁTICA: "Sigo sin entender. Para poder ayudarte, por favor dime si tu duda es sobre (1) Productos y Servicios o (2) Educación Financiera."
|
|
||||||
- </no-match-2>
|
|
||||||
- <no-match-3>
|
|
||||||
- RESPUESTA ESTÁTICA: "Por el momento, para este tema debemos atenderte en el Call Center. Solo da click para llamar ahora mismo. 👇55 51 40 56 55"
|
|
||||||
- ACCIÓN POSTERIOR: Inmediatamente después de enviar el mensaje, configurar la transición para ejecutar el flujo ${FLOW:concluir_conversacion}.
|
|
||||||
- </no-match-3>
|
|
||||||
- </manejo_de_no_coincidencia_fallback>
|
|
||||||
241
pom 2.xml
241
pom 2.xml
@@ -1,241 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>3.3.11</version>
|
|
||||||
<relativePath/>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<groupId>com.example</groupId>
|
|
||||||
<artifactId>app-jovenes-service-orchestrator</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
<name>app-jovenes-service-orchestrator</name>
|
|
||||||
<description>This serivce handle conversations over Dialogflow and multiple Storage GCP services</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<java.version>21</java.version>
|
|
||||||
<spring-cloud-gcp.version>5.4.0</spring-cloud-gcp.version>
|
|
||||||
<spring-cloud.version>2023.0.0</spring-cloud.version>
|
|
||||||
<lettuce.version>6.4.0.RELEASE</lettuce.version>
|
|
||||||
<spring-framework.version>6.1.21</spring-framework.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-dependencies</artifactId>
|
|
||||||
<version>${spring-cloud.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-gcp-dependencies</artifactId>
|
|
||||||
<version>${spring-cloud-gcp.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.cloud</groupId>
|
|
||||||
<artifactId>libraries-bom</artifactId>
|
|
||||||
<version>26.40.0</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.projectreactor</groupId>
|
|
||||||
<artifactId>reactor-bom</artifactId>
|
|
||||||
<version>2024.0.8</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springdoc</groupId>
|
|
||||||
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
|
|
||||||
<version>2.5.0</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-gcp-starter-data-firestore</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-gcp-data-firestore</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-gcp-starter-storage</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.cloud</groupId>
|
|
||||||
<artifactId>google-cloud-dialogflow-cx</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.genai</groupId>
|
|
||||||
<artifactId>google-genai</artifactId>
|
|
||||||
<version>1.14.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.protobuf</groupId>
|
|
||||||
<artifactId>protobuf-java-util</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.projectreactor</groupId>
|
|
||||||
<artifactId>reactor-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
|
||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.module</groupId>
|
|
||||||
<artifactId>jackson-module-parameter-names</artifactId>
|
|
||||||
<version>2.19.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.api</groupId>
|
|
||||||
<artifactId>gax</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.cloud</groupId>
|
|
||||||
<artifactId>google-cloud-dlp</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-codec-http2</artifactId>
|
|
||||||
<version>4.1.125.Final</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-handler</artifactId>
|
|
||||||
<version>4.1.125.Final</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-common</artifactId>
|
|
||||||
<version>4.1.125.Final</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-codec-http</artifactId>
|
|
||||||
<version>4.1.125.Final</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-codec</artifactId>
|
|
||||||
<version>4.1.125.Final</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.protobuf</groupId>
|
|
||||||
<artifactId>protobuf-java</artifactId>
|
|
||||||
<version>3.25.5</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.minidev</groupId>
|
|
||||||
<artifactId>json-smart</artifactId>
|
|
||||||
<version>2.5.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.xmlunit</groupId>
|
|
||||||
<artifactId>xmlunit-core</artifactId>
|
|
||||||
<version>2.10.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-lang3</artifactId>
|
|
||||||
<version>3.18.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
||||||
85
pyproject.toml
Normal file
85
pyproject.toml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
[project]
|
||||||
|
name = "capa-de-integracion"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Orchestrator service for conversational AI - Python implementation"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = [
|
||||||
|
{ name = "A8065384", email = "anibal.angulo.cardoza@banorte.com" }
|
||||||
|
]
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"fastapi>=0.115.0",
|
||||||
|
"uvicorn[standard]>=0.32.0",
|
||||||
|
"pydantic>=2.10.0",
|
||||||
|
"pydantic-settings>=2.6.0",
|
||||||
|
"google-cloud-dialogflow-cx>=1.45.0",
|
||||||
|
"google-cloud-firestore>=2.20.0",
|
||||||
|
"google-cloud-aiplatform>=1.75.0",
|
||||||
|
"google-generativeai>=0.8.0",
|
||||||
|
"google-cloud-dlp>=3.30.0",
|
||||||
|
"redis[hiredis]>=5.2.0",
|
||||||
|
"tenacity>=9.0.0",
|
||||||
|
"python-multipart>=0.0.12",
|
||||||
|
"httpx>=0.27.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
capa-de-integracion = "capa_de_integracion:main"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["uv_build>=0.9.22,<0.10.0"]
|
||||||
|
build-backend = "uv_build"
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"fakeredis>=2.34.0",
|
||||||
|
"inline-snapshot>=0.32.1",
|
||||||
|
"locust>=2.43.3",
|
||||||
|
"pytest>=9.0.2",
|
||||||
|
"pytest-asyncio>=1.3.0",
|
||||||
|
"pytest-cov>=7.0.0",
|
||||||
|
"pytest-env>=1.5.0",
|
||||||
|
"pytest-recording>=0.13.4",
|
||||||
|
"ruff>=0.15.1",
|
||||||
|
"ty>=0.0.17",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
exclude = ["tests", "scripts"]
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ['ALL']
|
||||||
|
ignore = ['D203', 'D213', 'COM812']
|
||||||
|
|
||||||
|
[tool.ty.src]
|
||||||
|
include = ["src"]
|
||||||
|
exclude = ["tests"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
asyncio_mode = "auto"
|
||||||
|
asyncio_default_fixture_loop_scope = "function"
|
||||||
|
testpaths = ["tests"]
|
||||||
|
addopts = [
|
||||||
|
"--cov=capa_de_integracion",
|
||||||
|
"--cov-report=term-missing",
|
||||||
|
"--cov-report=html",
|
||||||
|
"--cov-branch",
|
||||||
|
]
|
||||||
|
|
||||||
|
filterwarnings = [
|
||||||
|
"ignore:Call to '__init__' function with deprecated usage:DeprecationWarning:fakeredis",
|
||||||
|
"ignore:.*retry_on_timeout.*:DeprecationWarning",
|
||||||
|
"ignore:.*lib_name.*:DeprecationWarning",
|
||||||
|
"ignore:.*lib_version.*:DeprecationWarning",
|
||||||
|
]
|
||||||
|
|
||||||
|
env = [
|
||||||
|
"FIRESTORE_EMULATOR_HOST=[::1]:8469",
|
||||||
|
"GCP_PROJECT_ID=test-project",
|
||||||
|
"GCP_LOCATION=us-central1",
|
||||||
|
"GCP_FIRESTORE_DATABASE_ID=(default)",
|
||||||
|
"RAG_ENDPOINT_URL=http://localhost:8000/rag",
|
||||||
|
"REDIS_HOST=localhost",
|
||||||
|
"REDIS_PORT=6379",
|
||||||
|
"DLP_TEMPLATE_COMPLETE_FLOW=projects/test/dlpJobTriggers/test",
|
||||||
|
]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user