Google Assistant. Desarrollo de aplicaciones IoT para Arduino y ESP8266

Tekst
Loe katkendit
Märgi loetuks
Kuidas lugeda raamatut pärast ostmist
Šrift:Väiksem АаSuurem Aa

6.2.1 Práctica de uso de contextos

A continuación, completará su primer asistente para que, una vez conocido el nombre del usuario, le pregunte si quiere jugar. Este podrá aceptar o rechazar el ofrecimiento, para lo que utilizará dos intenciones de seguimiento predefinidas por Dialogflow. En una de ellas (la que se activaría si contestara afirmativamente), le agradecerá personalmente su predisposición a jugar, aunque todavía no pueda hacerlo (tendrá que esperar hasta que haya completado el apartado «Cumplimiento (fulfillment)» de este capítulo. En la otra, únicamente se despediría del usuario.

Para conseguir este nuevo comportamiento, vaya a la consola Dialogflow y acceda a la intención en la que se recoge el nombre del usuario («obtener nombre»). Borre todas las respuestas agregadas anteriormente y añada únicamente la siguiente: «$nombre. ¿Quiere jugar conmigo?». Luego, desmarque la opción «Set this intent as end of conversation», que provoca que la intención finalice la conversación, ya que esta deberá permanecer activa (el usuario debe responder si quiere jugar). Para acabar, pulse el botón «SAVE».


A continuación, seleccione la opción «Intents» del menú lateral izquierdo, para ver la lista de intenciones que actualmente tiene su primer asistente. Luego, sitúe el ratón sobre «obtener nombre». Podrá observar que, a la derecha, aparecen tres opciones representadas por el enlace «Add follow-up intent» y dos iconos.



La opción que hay a continuación de «Add follow-up intent» sirve para descargar un archivo en formato JSON (JavaScript Object Notation), con toda la información de configuración de la intención. Este importante formato de datos lo estudiará más adelante. Por último, la opción con el icono de una papelera se utilizará para borrarla.

Pulse sobre dicho enlace y, del menú desplegable que aparece, seleccione la intención predefinida «yes».


Se habrá creado la intención «obtener nombre → yes», tal como puede apreciar en la imagen inferior. Además, a la izquierda de su nombre, verá un símbolo que indica que dicha intención solo se activará si lo hace previamente «obtener nombre», de la que depende.


Si recuerda, cuando se crea una intención de seguimiento, esta lo hace con un contexto de entrada que también se incluye como contexto de salida en la intención de la que depende. Compruébelo seleccionando, en primer lugar, la intención «obtener nombre». Como puede apreciar en la imagen inferior, en la sección «Contexts», se ha añadido el contexto «obtenernombre-followup», con una vida útil de dos turnos de palabra.



Para modificar la vida útil de un contexto, solo tiene que pulsar en el número y editarlo. El nombre del contexto no se puede modificar, por lo que, si quiere cambiarlo, deberá borrarlo (pulsando sobre el símbolo del aspa situado en el extremo derecho) y añadir otro nuevo.


Una intención podrá tener más de un contexto de entrada o de salida. Solo es necesario posicionar el cursor a continuación del último, empezar a escribir el nombre del contexto deseado y seleccionarlo del menú contextual, que mostraría los existentes cuyo nombre coincide con el que ha empezado a escribir.

Compruebe, a continuación, que ese mismo contexto se ha añadido automáticamente como entrada a la intención de seguimiento.



Al pulsar de nuevo sobre la opción «Intents» del menú lateral izquierdo para acceder a la intención de seguimiento que acaba de crear, habrá observado que esta ha desaparecido. En realidad, queda oculta debajo de la intención de la que depende. Para verla de nuevo, solo tiene que pulsar en el icono con forma de punta de flecha que aparece a la derecha de su nombre.


Aunque el nombre de la intención de seguimiento de confirmación esté en inglés, observará que las frases de entrenamiento que tiene por defecto emplean el lenguaje de su asistente (español). Puede borrar las que no le interesen o crear otras nuevas. Aproveche también para cambiar el nombre de la intención que le ha dado Dialogflow de forma predeterminada, poniendo «jugar». Es una forma más significativa de expresar que el usuario quiere jugar.


A continuación, vaya a la sección «Responses» e introduzca un texto de respuesta para agradecer personalmente al usuario que haya querido jugar diciendo, por ejemplo, «Gracias $nombre, pero todavía no me han enseñado a jugar a nada». Como el nombre de la persona no es un parámetro de la propia intención, sino de la que depende («obtener nombre»), deberá obtenerlo de su contexto de salida que, como sabe, es el mismo que el de entrada de esta intención. La sintaxis para acceder al valor del parámetro contenido en un contexto es:

#nombre del contexto.nombre del parámetro

En el caso que nos ocupa sería:

#obtenernombre-followup.nombre

Por lo tanto, el texto de respuesta que deberá introducir en la sección «Responses» es: «Gracias, #obtenernombre-followup.nombre, pero todavía no me han enseñado a jugar a nada». Marque también la opción que indica que esta intención finaliza la conversación («Set this intent as end of conversation»). Por último, pulse sobre el botón «SAVE» para guardar los cambios realizados.


Repita los mismos pasos para crear la intención de seguimiento que atienda una respuesta negativa del usuario. Dele el nombre «no jugar» y añada el texto de respuesta: «¡Qué pena! Hasta luego, #obtenernombre-followup. nombre». Finalmente, marque la casilla de verificación que finaliza la conversación con esta intención. Después de pulsar sobre el botón «SAVE», las intenciones de las que se compone ahora su primer asistente son las que aparecen en la imagen inferior.


Para probar que el asistente se comporta de la manera esperada, acceda a la consola de Actions on Google y seleccione la pestaña «Test». Una vez allí, invoque la acción principal de su proyecto, diga su nombre y, cuando le pregunte si quiere jugar, responda «sí» o «no». Verifique que el asistente responde, en cada caso, de forma adecuada, diciendo su nombre.

Si hubiera contestado que «sí», le diría que todavía no le han enseñado a jugar a nada.


Si hubiera contestado negativamente, simplemente, se despediría.


6.3 ENTIDADES (ENTITIES)

Los valores de los parámetros que se extraen de las expresiones del usuario pertenecen a un tipo determinado, denominado «entidad». Dialogflow proporciona entidades de sistema predefinidas que representan muchos tipos comunes de datos (por ejemplo, fecha, hora, monedas, ciudades, colores, etc.), aunque usted también podrá crear sus propias entidades.

Una entidad se compone de:

• Nombre: identifica el tipo de información que se extrae de las expresiones del usuario. Ya ha utilizado la entidad del sistema «@sys.person» para manejar nombres de personas. En la siguiente práctica, creará la entidad «juego», cuyas entradas serán los juegos a los que su primer asistente podrá jugar con el usuario.

• Entradas: son cada uno de los valores que agrupa la entidad. Siguiendo con el ejemplo de la entidad «juego», dichos valores serán «adivina el número» y «sigue la secuencia», los dos juegos a los que enseñará a jugar a su primer asistente.

 

• Valor de referencia y sinónimos: algunas entradas de la entidad tienen valores que se consideran equivalentes. Por ejemplo, para encender o apagar la luz, un usuario puede utilizar los términos «bombilla» o «lámpara». En ese caso, luz sería el valor de referencia y bombilla o lámpara, los sinónimos.

Para crear una entidad, debe pulsar sobre el signo «+», que está a la derecha del elemento «Entities» del menú lateral izquierdo.


En el panel principal, verá todas las opciones de configuración de la entidad. Así, en la parte superior, hay un campo de texto («Entity name») donde podrá asignarle un nombre. En la parte inferior, están aquellos en los que añadirá cada una de las entradas que la componen («Click here to edit entry»).


Entremedias, hay una serie de casillas de verificación que determinan la forma de identificar las entradas en las expresiones del usuario:

• «Define synonims»: cuando está seleccionada (por defecto), le permite definir sinónimos para cada uno de los elementos de referencia de la entidad. De esta forma, al pulsar sobre el retorno de carro para confirmar el valor de cada entrada, le dará la posibilidad de añadir términos alternativos a su derecha que representen los sinónimos. El primer valor de una entrada es el de referencia. Por ejemplo, si una de las entradas de referencia de la entidad «propiedad» fuera «casa», podría añadir como sinónimos «vivienda» y «hogar».

• «Regexp entity»: si marcara esta casilla, sería posible declarar las entradas mediante patrones, en vez de tener que emplear términos específicos. Eso le permitirá el uso de expresiones regulares que encajen con un determinado conjunto de cadenas de caracteres. Por ejemplo, si las entradas de una entidad fueran los prefijos telefónicos formados por dos dígitos, tiene dos alternativas: añadir 99 entradas, una por cada prefijo; o seleccionar esta casilla y añadir como única entrada la expresión regular «\d{2}». Para saber cómo construir expresiones regulares, visite https://github.com/google/re2/wiki/Syntax.

• «Allow automated expansion»: la expansión automática de entidades permite que un agente reconozca entradas que no se han añadido explícitamente en la entidad. Para ello, utiliza las frases de entrenamiento de la propia intención. Por ese motivo, cuanto más parecidas sean las expresiones del usuario a dichas frases de entrenamiento, mejores serán los resultados obtenidos por esta creación automática de entradas. Sin embargo, hay que ser muy cuidadoso con su empleo, ya que puede causar conflictos y resultados inesperados.

• «Fuzzy matching»: de forma predeterminada, la identificación de una entidad en la expresión de un usuario requiere que esta contenga una de sus entradas. Esta coincidencia deberá ser exacta, por lo que una palabra mal pronunciada, aunque muy parecida a la que se pretendía decir, no será identificada como una entrada de la entidad en cuestión. Para evitar dicho problema, marque esta casilla que, además, en el caso de entidades cuyas entradas estén formadas por varias palabras, no afectará tampoco el orden en el que se digan.

6.3.1 Práctica de uso de entidades personalizadas

En esta sección, seguirá mejorando su primer asistente para que, una vez que le haya confirmado que quiere jugar con él, le permita elegir entre los siguientes juegos:

• Adivina el número: el asistente «pensará» en un número del 1 al 10 y el usuario tendrá que adivinarlo. Cuando este diga uno cualquiera, si no hubiera acertado, le daría como pista si es mayor o menor que el que tiene que descubrir. Tendrá tres intentos para averiguarlo.

• Sigue la secuencia: en este juego, el asistente generará inicialmente una secuencia de cinco dígitos que le pedirá que repita. Si lo hace correctamente, irá añadiendo nuevos números a la secuencia, que tendrá que seguir repitiendo. El juego finalizará cuando su memoria no llegue a más, informándole del número de dígitos que ha conseguido repetir correctamente.

En primer lugar, procederá a crear la entidad «juego», cuyas entradas serán los dos juegos que conoce: «adivina el número» y «sigue la secuencia». Para ello, pulse en el símbolo «+» de la opción «Entities» del menú lateral izquierdo. Rellene los campos de la nueva entidad, tal como aparece a continuación, y pulse sobre el botón «SAVE».


Para comprobar que la nueva entidad se ha creado correctamente, pulse en la opción «Entities» (no en el símbolo «+») del menú lateral izquierdo. En el panel principal, verá dos pestañas: una para las entidades del sistema que haya utilizado («SYSTEM») y otra para las personalizadas que vaya creando («CUSTOM»). En la primera pestaña, estará la entidad del sistema @sys.person empleada por la intención «obtener nombre». En la segunda pestaña, encontrará la entidad «juego» que acaba de crear.


Ahora modifique el texto de respuesta de la intención «jugar», para que pregunte al usuario a qué desea jugar. Ponga, por ejemplo, «¿A qué quieres jugar, #obtenernombre-followup.nombre?». Además, desmarque la casilla de verificación que indicaba que dicha intención finalizaba la conversación.

Luego, pulse en la opción «Intents», para ver todas las intenciones (desplegando las de seguimiento que hay debajo de «obtener nombre»). Puesto que solo se jugará cuando el usuario haya contestado que desea hacerlo, la intención desde la que se obtenga el nombre del juego que haya elegido deberá depender de «jugar», que es la intención que se activa cuando el usuario confirma que quiere jugar, y en la que también se pregunta a qué quiere jugar. Por lo tanto, sitúe el cursor sobre la intención de seguimiento «jugar» y pulse en su enlace «Add follow-up intent». En este caso, no va a utilizar ninguna intención de seguimiento predefinida, por lo que, de las opciones mostradas, elegirá «custom».


Una vez creada la nueva intención de seguimiento (llamada por defecto «jugar — custom»), acceda a ella para editar su nombre y darle otro más apropiado: «obtener juego». Comprobará que se ha creado de forma automática el contexto de entrada «jugar—followup», que coincide con el de salida de su intención padre («jugar»).



Si en la intención que acaba de crear le aparece el mismo contexto en el campo de los contextos de salida, bórrelo pulsando en la marca «x» que tiene a su derecha.

A continuación, establezca las respuestas que podría dar el usuario cuando se le pregunte a qué quiere jugar, que serán las frases de entrenamiento de esta nueva intención de seguimiento. Añada, por ejemplo: «Quiero jugar a adivinar el número», «A adivina el número» o, simplemente, «Adivina el número». Al pulsar sobre el retorno de carro, el nombre del juego «adivina el número» se tendrá que haber identificado automáticamente como parámetros de la entidad «@juego», lo que significa que, aunque solo se haya hecho referencia a dicho juego, estas frases de entrenamiento servirán también para «sigue la secuencia» o cualquier otro que añada posteriormente a dicha entidad.

Si este parámetro no se hubiera reconocido automáticamente, seleccione el texto «adivina el número» de cada frase de entrenamiento y, del menú que se despliega, seleccione la entidad «@juego».


Puesto que, para empezar a jugar es imprescindible que el usuario diga el nombre de uno de los dos juegos, en la sección «Actions and parameters», seleccionará la casilla de verificación «REQUIRED» del parámetro «@juego».


Una vez conocido el juego elegido por el usuario, se debería empezar a jugar, pero, como todavía no ha desarrollado el código JavaScript que lo permite, de momento le va a responder diciendo que ya queda poco para empezar a divertirse. Por ejemplo, si yo hubiera elegido el juego «adivina el número», me debería responder: «Gracias, Tomás, ya falta poco para que puedas jugar conmigo a adivina el número». Puesto que la frase debe ser general para cualquier usuario y juego, deberá utilizar los parámetros correspondientes.

El nombre del juego lo obtiene del parámetro «juego» de la propia intención, pero el nombre del usuario lo tiene que recoger del parámetro «nombre» de la intención a la que pertenece que, si recuerda, era «obtener nombre», cuyo contexto de salida (del que se puede extraer dicho parámetro) es «obtenernombre-followup». Por ese motivo, la frase que introduzca en la sección «Responses» será: «Gracias, #obtenernombre-followup.nombre, ya falta poco para que puedas jugar conmigo a $juego».



Seleccione también la opción «Set this intent as end of conversation», para que esta intención finalice la conversación.

Sin embargo, para acceder a los datos del contexto «obtenernombrefollowup», previamente es necesario añadirlo como contexto de entrada de esta nueva intención de seguimiento. Por lo tanto, inclúyalo manualmente en los contextos de entrada de su nueva intención.



Al haber añadido como contexto de entrada «obtenernombre-followup», la intención solo podrá cumplirse cuando, además de haberse activado dicho contexto, lo haya hecho también «jugar-followup». Dicho de otra forma, cuando previamente se hayan cumplido las intenciones «obtener nombre» y «jugar», es decir, cuando el usuario haya dicho su nombre y haya mostrado su intención de jugar.


Recuerde que, para añadir nuevos contextos, solo tiene que pulsar a continuación del último existente. En cuanto empiece a escribir, surgirá un menú con los nombres de los que contengan las primeras letras que haya empezado a introducir. Solo tendrá que seleccionarlo para añadirlo a su intención.

Además, modifique ese mismo contexto («obtenernombre-followup») en la intención «obtener nombre» (donde aparece como contexto de salida), para que tenga un tiempo de vida de tres turnos de palabra, es decir, para que todavía siga activo cuando se diga el nombre de un juego.


Ya solo queda probarlo, por lo que vaya a la pestaña «Test», de la consola de Actions on Google. Allí, compruebe que únicamente le solicita que elija un juego cuando haya confirmado previamente que desea jugar y que solo le deja seguir si introduce uno de los juegos de la entidad «juego». Finalmente, verifique que la respuesta con la que se cierra la conversación hace referencia a su nombre y el del juego elegido en cada caso.

 

6.4 CUMPLIMIENTO (FULFILLMENT)

Hasta ahora, todas las respuestas que ha dado su primer asistente han sido estáticas; es decir, ya estaban escritas por usted en la sección «Responses». Para generar respuestas dinámicas, Dialogflow utiliza el concepto de cumplimiento o entrega (fulfillment), que es un programa cuya lógica realizaría las tareas específicas a la intención que se hubiera activado, generando una respuesta dinámica como resultado de su ejecución. Una respuesta estática sería útil, por ejemplo, para indicar el horario de consulta de un médico (siempre es la misma), mientras que las respuestas dinámicas serían necesarias para dar cita a un paciente un día y una hora a la que el médico pudiera atenderlo (cambiaría según el momento en que se solicitara).

El cumplimiento se utiliza, además, para la integración con otros servicios, a los que se enviaría, o de los que se recogería, la información necesaria para realizar la tarea solicitada por el usuario y darle la respuesta correspondiente. Por ejemplo, si deseara conocer la temperatura que hace en su casa, debería tener un cumplimiento que se integrara con un dispositivo ESP8266 que tuviera conectado un sensor DHT11 del que obtendría dicha temperatura.

Para que una intención ejecute el código de un cumplimiento cuando se active, previamente deberá haberlo habilitado ya que, de lo contrario, devolvería la respuesta estática que hubiera establecido en la sección «Responses». Para ello, tendrá que ir a la sección «Fulfillment» de la intención y establecer la opción «Enable webhook call for this intent», tal como se muestra en la imagen inferior.



La siguiente opción («Enable webhook call for slot filling») se utiliza para solicitar al usuario los valores de los parámetros declarados como obligatorios desde el cumplimiento (en vez de hacerlo de forma estática con las frases introducidas en el campo «PROMPTS»).


La tecnología webhook permite la invocación de funciones en la nube mediante HTTP (en este caso, mediante solicitudes HTTP enviadas por Dialogflow cuando se activan las intenciones que tienen habilitada la opción «Enable webhook call for this intent»). Tanto la información de la solicitud HTTP realizada por Dialogflow como la de la respuesta devuelta tras la ejecución del cumplimiento viajan en formato JSON. Más adelante, tendrá ocasión de conocer con detalle qué es la tecnología webhook y el formato de datos JSON.

El código del cumplimiento (fulflillment) se puede desarrollar de dos formas diferentes:

• Utilizando un webhook que se invoque mediante una petición HTTP

• Mediante el editor Inline de Dialogflow

En ambos casos, el código JavaScript del cumplimiento no se ejecuta en Dialogflow, sino en Firebase Cloud Service. Dicho servicio (que podrá ser otro de naturaleza similar) proporcionará tanto la infraestructura HW (CPU, memoria, etc.) como el entorno Node.js de ejecución del código JavaScript.


De forma muy simplificada, Node.js es un entorno de ejecución de código JavaScript de lado de servidor (a diferencia del utilizado en los navegadores web, en el lado cliente).


Puesto que, en este libro, siempre se va a utilizar el servicio Firebase Cloud Functions para la ejecución de código JavaScript, la diferencia entre estas dos formas de desarrollar un cumplimiento es que, con el editor Inline, se oculta el manejo de dicho servicio, del que se ocupa el propio Dialogflow.

Para configurar el cumplimiento de su primer asistente, seleccione la opción «Fulfillment» del menú lateral izquierdo. Si en el panel principal habilitara la opción «Webhook», debería haberlo desarrollado previamente en Firebase Cloud Functions. Si activara la opción «Inline Editor», podría empezar a escribir directamente el código del cumplimiento en dicho editor.


Aunque más adelante aprenderá a desarrollar y desplegar el código JavaScript del cumplimiento como un webhook, el editor en línea es la forma más fácil de implementarlo. Habilite dicha opción.

Le aparecerá una ventana indicándole que debe proporcionar información de facturación. Eso no significa que le vayan a cobrar, ya que el límite de recursos que se pueden usar de forma gratuita es lo suficientemente amplio como para cubrir las necesidades del uso privado de una aplicación. Sin embargo, para beneficiarse de este límite gratuito, deberá crear una cuenta de facturación.

Por lo tanto, para continuar trabajando con Dialogflow, deberá pulsar el botón «OPEN CLOUD CONSOLE».



Tal como se indica en la propia ventana, puede acceder a https://cloud.google.com/functions/pricing para conocer en detalle los límites de uso gratuitos y, en caso de superarlos, los costes en los que incurriría. En dicha página, se puede leer que estos se determinan según el tiempo que tardan las funciones en ejecutarse (en este caso, el cumplimiento de sus asistentes), el número de veces que se invocan (provocadas por la activación de intenciones con la opción «Enable webhook call for this intent») y la cantidad de recursos que se aprovisionen para ellas (CPU, memoria y tráfico de red). Por poner un ejemplo, en el momento de escribir este libro, dispone de dos millones de invocaciones mensuales gratuitas, además de 400 000 GB por segundo (1 GB por segundo equivale a un segundo de tiempo real aprovisionado con 1 GB de memoria), un tiempo de procesamiento de 200 000 GHz por segundo (1 GHz por segundo equivale a un segundo de tiempo real aprovisionado con una CPU de 1 GHz) y 5 GB de tráfico de salida de Internet al mes.

Surgirá una ventana en la que tendrá que indicar que acepta las condiciones del servicio. Luego, pulse sobre el botón «ACEPTAR Y CONTINUAR».



Google Cloud Platform (GCP) proporciona como servicios los recursos requeridos para la ejecución de aplicaciones en la nube (CPU, memoria, almacenamiento en disco, etc.). Dichos recursos están ubicados físicamente en centros de datos que Google tiene repartidos por todo el mundo (regiones). Allí es donde se almacena la configuración y se ejecuta el código de sus proyectos (en su caso, de Actions on Google, Dialogflow y Firebase).

Verá una nueva ventana en la que se le informa de que no gestiona ninguna cuenta de facturación y que, por lo tanto, tendrá que crear una. Para ello, pulse sobre el botón «CREAR CUENTA DE FACTURACIÓN».


Aparecerá un formulario en el que se le indica que podrá disfrutar de los servicios Firebase de forma gratuita durante un año. Además, le aseguran que solo piden los datos de su tarjeta de crédito para comprobar que no sea un robot. No le cobrará nada, a menos que actualice la cuenta de forma manual a una versión de pago.

En consecuencia, marque la casilla que indica que acepta las condiciones del servicio y, luego, pulse sobre el botón «CONTINUAR».


Una vez cumplimentados todos sus datos, habrá finalizado el proceso de creación de la cuenta de facturación. Pulse «ENTENDIDO».


Para consultar los costes en los que podría estar incurriendo, vaya a https://console.cloud.google.com/billing/. Allí verá sus cuentas de facturación (en estos momentos, la que acaba de crear).


Pulsando sobre ella, conocería el detalle de sus consumos. En el lateral derecho se muestra el dinero que le queda por consumir, los días del periodo de prueba restantes y, muy importante, el botón «ACTUALIZAR», que deberá pulsar pasado el periodo de prueba para seguir usando los proyectos que hubiera desarrollado y/o crear otros nuevos. Recuerde que el límite de recursos gratuito lo seguirá teniendo; solo que, a partir del final del periodo de prueba, ya se facturaría en caso de superarlos. Viendo los consumos realizados en este primer año, sabrá si podría llegar a dicho límite en un futuro. En cualquier caso, también se pueden configurar alertas de presupuesto que le avisen de dichos costes. En https://cloud.google.com/billing/docs/how-to/budgets, tiene toda la información para hacerlo.


Ahora vuelva a la ventana donde estaba Dialogflow y pulse de nuevo la opción «Inline Editor». Comprobará cómo esta vez sí le deja activarlo.



Cada vez que active el editor Inline en un nuevo agente, podrá crear una nueva cuenta de facturación (repitiendo de nuevo todo el proceso descrito), o asociarlo a la que acaba de crear (opción recomendada). Dicha cuenta de facturación también podrá utilizarla en los proyectos Firebase que cree en un futuro con el modelo Blaze de pago por uso.

El editor Inline se compone de dos pestañas:

• «idex.js»: es el archivo que contiene el código JavaScript del cumplimiento.

• «package.json»: fichero con formato JSON en el que se guarda información de configuración del código JavaScript del cumplimiento; en especial, las dependencias de los diferentes módulos o librerías que requiere para su funcionamiento.

En la parte superior del editor hay un enlace desde el que podrá descargar el código en su propio ordenador (previamente guardado y desplegado). En la parte inferior se encuentra el botón «DEPLOY», utilizado para desplegar el código desarrollado antes de que pueda ejecutarse.