Creando un Bot (Android) para una tienda de Postres (Dialogflow V2 + Kotlin 1.3.72) – Parte 3

Demo

En este Post continuaremos con la parte anterior de este tutorial llamada Creando un Bot (Android) para una tienda de Postres (Dialogflow V2 + Kotlin 1.3.72) – Parte 2 en donde creamos el Layout Principal para la actividad principal de la aplicación, con sus elementos, colores, botones y demás elementos correspondientes, en esta parte 3 vamos a escribir el código Kotlin para nuestra aplicación.

Partes

Antes de continuar te invito a leer los siguientes artículos:

Asimismo te invito a escuchar el Podcast: “Donde buscar ayuda sobre Programación”:

Spotify SoundCloud

Bien ahora continuemos con el Post: Creando un Bot (Android) para una tienda de Postres (Dialogflow V2 + Kotlin 1.3.72) – Parte 3. 

En esta Parte 3 comenzaremos trabajando con el archivo MainActivity.kt, este archivo fue generado por Android Studio automáticamente, cuando creamos el nuevo proyecto para esta aplicación.

Actividad Principal

En el directorio principal del proyecto se encuentra el archivo en formato Kotlin llamado MainActivity.kt

/app
├── /manifests
├── /java
    ├── /com.example.tiendapostresbot 
        ├── MainActivity.kt // Abre este Archivo 
    ├── /com.example.tiendapostresbot (androidTest) 
    ├── /com.example.tiendapostresbot (test) 
├── /java (generated)
├── /res
/Gradle Scripts

Abro el archivo MainActivity.kt  y antes de la clase MainActivity voy a importar los siguientes elementos, asimismo creo 3 variables llamadas, USUARIO, BOT y ENTRADA_DE_VOZ.

package com.example.tiendapostresbot

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.speech.RecognizerIntent
import android.util.Log
import android.view.KeyEvent
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
import android.view.LayoutInflater
import com.google.api.gax.core.FixedCredentialsProvider
import com.google.auth.oauth2.ServiceAccountCredentials
import com.google.auth.oauth2.GoogleCredentials
import com.google.cloud.dialogflow.v2.*
import java.util.*
import android.widget.*
import android.widget.Toast
import android.content.ActivityNotFoundException
import android.content.Intent
import android.speech.RecognizerResultsIntent
import android.speech.tts.TextToSpeech
import android.text.Editable


const val USUARIO = 0
const val BOT = 1
const val ENTRADA_DE_VOZ = 2


class MainActivity : AppCompatActivity() {
    
    // Acá va el código 

}

Dentro de la clase MainActivity y antes del ciclo de vida o método onCreate crearé las variables uuid para generar un string aleatorio, cliente, session y la variable asistente_voz.

class MainActivity : AppCompatActivity() {

    // Variables 
    private val uuid = UUID.randomUUID().toString()
    private var cliente: SessionsClient? = null
    private var sesion: SessionName? = null
    private var asistente_voz: TextToSpeech?=null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

Dentro del método onCreate voy a crear una variable llamada scrollview en ella llamo al ScrollView que definí en la Parte 2 de este tutorial, en el archivo activity_main.xml

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // Llamo al ScrollView 
    val scrollview = findViewById<ScrollView>(R.id.scroll_chat)
    scrollview.post {
        scrollview.fullScroll(ScrollView.FOCUS_DOWN)
    }

}

El ScrollView va  ser el contenedor en donde se desplazarán los mensajes entre el usuario y el bot, dentro de la aplicación.

Luego creo una variable con el nombre cajaMensajes y en ella llamo al EditTex que es la caja en donde el usuario escribirá el mensaje para enviarlo al chat, este EditText, le dimos el id cajadetexto en la Parte 2 de este tutorial, en el archivo activity_main.xml

El usuario se coloca en el EditText, escribe un mensaje y presiona la tecla Enter para enviarlo, este evento lo manejamos con KeyEvent.ACTION_DOWN de Android y posteriormente con KeyEvent.KEYCODE_DPAD_CENTER en donde llamamos al método enviarMensaje(enviar) el cual crearemos más adelante y le estamos pasando el botón o ImageView que creamos también en la Parte 2 de este tutorial, en el archivo activity_main.xml

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val scrollview = findViewById<ScrollView>(R.id.scroll_chat)
    scrollview.post {
        scrollview.fullScroll(ScrollView.FOCUS_DOWN)
    }

    // Caja para escribir los mensajes en el chat
    val cajaMensajes = findViewById<EditText>(R.id.cajadetexto)
    cajaMensajes.setOnKeyListener { view, keyCode, event ->
        if (event.action === KeyEvent.ACTION_DOWN) {
            when (keyCode) {
                KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_ENTER -> {
                    
                    // Llamamos al método enviarMensaje() el cual crearemos más adelante
                    enviarMensaje(enviar)

                    true
                }
                else -> {
                }
            }
        }
        false
    }

}

Para terminar con el código del método o ciclo de vida onCreate(), pasamos setOnClickListener() al botón para enviar los mensajes de texto y también al botón del micrófono que sirve para enviar mensajes de audio en el chat, este botón llama la función enviarMensajeMicrofono() la cual creamos más adelante y por último llamamos a las funciones iniciarAsistente() y iniciarAsistenteVoz(), las cuales crearemos más adelante.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val scrollview = findViewById<ScrollView>(R.id.scroll_chat)
    scrollview.post {
        scrollview.fullScroll(ScrollView.FOCUS_DOWN)
    }

    val cajaMensajes = findViewById<EditText>(R.id.cajadetexto)
    cajaMensajes.setOnKeyListener { view, keyCode, event ->
        if (event.action === KeyEvent.ACTION_DOWN) {
            when (keyCode) {
                KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_ENTER -> {                    
                            enviarMensaje(enviar)
                    true
                }
                else -> {
                }
            }
        }
        false
    }

    // Pasamos un setOnClickListener al botón para enviar mensajes llamando al
    // método enviarMensaje() el cual crearemos más adelante
    enviar.setOnClickListener(this::enviarMensaje)

    // Al botón del microfono también le pasamos un setOnClickListener, este envia mensajes de audio con el
    // método enviarMensajeMicrofono() el cual crearemos más adelante
    microfono.setOnClickListener(this::enviarMensajeMicrofono)

    // Llamamos al método iniciarAsistente() el cual crearemos más adelante
    iniciarAsistente()

    // Llamamos al método iniciarAsistenteVoz() el cual crearemos más adelante
    iniciarAsistenteVoz()

}

Ahora creare la función iniciarAsistente() la cual llamamos en la parte final del método onCreate(), en la función iniciarAsistente() exactamente haré uso de las credenciales del proyecto que crearé más adelante en Dialogflow (Google Cloud Platform) y no quiero salirme del tema, estamos trabajando en el código de la actividad principal (MainActivity.kt).

Puedes ver en el código he colocado comentarios para explicar que hace cada línea del código.

// Función inicarAsistente
private fun iniciarAsistente() {
    try {
        // Archivo JSON de configuración de la cuenta de Dialogflow (Google Cloud Platform)
        val config = resources.openRawResource(R.raw.credenciales)

        // Leemos las credenciales de la cuenta de Dialogflow (Google Cloud Platform)
        val credenciales = GoogleCredentials.fromStream(config)

        // Leemos el 'projectId' el cual se encuentra en el archivo 'credenciales.json'
        val projectId = (credenciales as ServiceAccountCredentials).projectId

        // Construimos una configuración para acceder al servicio de Dialogflow (Google Cloud Platform)
        val generarConfiguracion = SessionsSettings.newBuilder()

        // Configuramos las sesiones que usaremos en la aplicación
        val configurarSesiones =
            generarConfiguracion.setCredentialsProvider(FixedCredentialsProvider.create(credenciales)).build()
        cliente = SessionsClient.create(configurarSesiones)
        sesion = SessionName.of(projectId, uuid)

    } catch (e: Exception) {
        e.printStackTrace()
    }

}

En el código anterior de la función iniciarAsistente() puedes ver que menciono sobre el archivo de credenciales credenciales.json, este archivo lo crearemos mas adelante, primero terminemos con el código de la actividad principal (MainActivity.kt).

Pasaré a crear la función iniciarAsistenteVoz() la cual llamamos también al final del método o ciclo de vida onCreate(). Dentro de la función iniciarAsistenteVoz() básicamente iniciamos el asistente de voz, cuando el usuario envíe un mensaje de audio al Bot.

// Función iniciarAsistenteVoz
private fun iniciarAsistenteVoz() {

    asistente_voz = TextToSpeech(applicationContext,object : TextToSpeech.OnInitListener {
        override fun onInit(status: Int) {
            if (status != TextToSpeech.ERROR){
                asistente_voz?.language=Locale("es")
            }
        }

    })

}

La siguiente función que crearemos será enviarMensaje(), en ella recepcionamos el mensaje del usuario y lo procesamos, en el código he colocado comentarios para explicar que hace cada línea del código.

private fun enviarMensaje(view: View) {

    // Obtenemos el mensaje de la caja de texto y lo pasamos a String
    val mensaje = cajadetexto.text.toString()

    // Si el usuario no ha escrito un mensaje en la caja de texto y presiona el botón enviar, le mostramos
    // un Toast con un mensaje 'Ingresa tu mensaje ...'
    if (mensaje.trim { it <= ' ' }.isEmpty()) {
        Toast.makeText(this@MainActivity, getString(R.string.placeholder), Toast.LENGTH_LONG).show()
    }

    // Si el usuario agrego un mensaje a la caja de texto, llamamos al método agregarTexto()
    else {
        agregarTexto(mensaje, USUARIO)
        cajadetexto.setText("")

        // Enviamos la consulta del usuario al Bot 
        val ingresarConsulta =
            QueryInput.newBuilder().setText(TextInput.newBuilder().setText(mensaje).setLanguageCode("es")).build()
        solicitarTarea(this@MainActivity, sesion!!, cliente!!, ingresarConsulta).execute()
    }
}

Terminado el ciclo de vida o método onCreate(), llamamos a la función enviarMensajeMicrofono() la cual gestiona el mensaje de audio que el usuario envía presionando el botón del micrófono.

private fun enviarMensajeMicrofono(view:View){

    // Llamamos al intento para reconocer voz del usuario y convertirla a texto
    val intento = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)

    // Definimos los modelos de reconocimiento de voz
    intento.putExtra(
        RecognizerIntent.EXTRA_LANGUAGE_MODEL,
        RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
    )

    // Le decimos que haga el reconocimiento de voz en el idioma local 'Locale.getDefault()'
    intento.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())

    // Si el usuario no habla algo, le mostramos el mensaje 'Di algo en el micrófono ...'
    intento.putExtra(
        RecognizerIntent.EXTRA_PROMPT,
        getString(R.string.mensajedevoz)
    )

    // Si todo va bien, enviamos el audio del usuario al Bot
    try {
        startActivityForResult(intento, ENTRADA_DE_VOZ)
    }

    // Si el dispositivo del usuario no es compatible con la función del micrófono
    // Le mostramos el mensaje 'Tu teléfono no es compatible con la función de micrófono ...'
    // en un Toast 
    catch (a: ActivityNotFoundException) {
        Toast.makeText(
            applicationContext,
            getString(R.string.mensajedevoznoadmitido),
            Toast.LENGTH_SHORT
        ).show()
    }

}

Bien hasta aquí terminamos la tercera parte del tutorial en donde creamos el código de los primeros 5 métodos del archivo MainActivity.kt y en la Cuarta Parte terminaremos de crear los demás métodos que faltan.

Ten Paciencia, lo que quiero es que entiendas todo el proceso para Crear este Proyecto y no llenarte el capitulo de mucho contenido porque te puedes marear y no tendrás un óptimo aprendizaje. 

Nota (s)

  • En el siguiente capitulo terminaremos de crear los demás métodos del archivo MainActivity.kt
  • El código expuesto en este capitulo del tutorial pueden cambiar, esto no depende de mi, si no de la empresa que dan soporte a Android Studio, y Kotlin que suelen cambiar sus tecnologías en futuras versiones.
  • No olvides que debemos usar la Tecnología para hacer cosas Buenas por el Mundo. 

Síguenos en nuestras Redes Sociales para que no te pierdas nuestros próximos contenidos.