Cómo integrar un asistente de voz en cualquier aplicación móvil. Desmontamos usando el ejemplo de Habitica

¿No crees que muchas aplicaciones móviles serían mucho más convenientes si tuvieran control por voz? No, no se trata de tener conversaciones con el asistente del banco en el chat de soporte técnico. Básicamente, la navegación por voz a través de la aplicación o el llenado de formularios en modo diálogo sería suficiente.



Usando el ejemplo de Habitica (una aplicación de código abierto para corregir hábitos y lograr objetivos, escrita en Kotlin), Vitalya Gorbachev, un arquitecto de soluciones en Just AI, muestra cómo integrar rápida y sin problemas una interfaz de voz en la funcionalidad de cualquier aplicación.





Pero primero, analicemos por qué es conveniente el control por voz de una aplicación móvil. Empecemos por lo obvio.



  • A menudo necesitamos usar la aplicación cuando nuestras manos están ocupadas: cocinando, conduciendo, cargando maletas, durante el trabajo mecánico, etc.
  • La voz es una herramienta fundamental para las personas con discapacidad visual.


Los casos ya son transparentes, pero en realidad todo es aún más simple: en algunos casos, ¡la marcación por voz es más rápida ! Imagínese: pedir un billete de avión con una frase "Cómprame un billete para mañana para dos a Samara" en lugar de un formulario largo. Al mismo tiempo, con la posibilidad de hacer preguntas aclaratorias al usuario: ¿por la tarde o por la tarde? con o sin equipaje?

La voz es útil cuando pasamos por el escenario de "llenado de formularios" y es conveniente para completar casi cualquier formulario largo que requiera una cierta cantidad de información del usuario. Y estas formas están presentes en la mayoría de las aplicaciones móviles.






De izquierda a derecha: aplicación Prigorod Russian Railways, diario de alimentos FatSecret (los usuarios deben completar un formulario varias veces al día, eligiendo entre cientos de productos), aplicación de panadería Korzhov.



Debido al hecho de que hoy en día los asistentes de voz a menudo se introducen en el chat de soporte y se desarrollan a partir de ahí, la mayoría de las empresas están tratando de llevar la funcionalidad de la aplicación al chat. Recargue el saldo, averigüe algo sobre un producto o servicio ... Esto no siempre se implementa convenientemente y, en el caso de la entrada de voz, es completamente contraproducente, aunque solo sea porque el reconocimiento de voz a menudo no funciona perfectamente.

El enfoque correcto es integrar el asistente sin problemas en la funcionalidad existente de la aplicación, en la interfaz de la cual se completará el formulario, de modo que la persona pueda simplemente verificar que dijo todo correctamente y hacer clic en Aceptar.
Decidimos mostrar cómo se puede hacer esto usando el ejemplo de Habitica : esta es una aplicación de código abierto escrita en Kotlin casi puro. "Habitika" es perfecto para un caso con un asistente de voz; aquí también, para comenzar una nueva tarea, debe completar un formulario bastante voluminoso. Tratemos de reemplazar este aburrido proceso con una frase con preguntas capciosas.



He dividido el tutorial en dos partes. En este artículo, descubriremos cómo agregar un asistente de voz a una aplicación móvil e implementar un escenario básico (en nuestro caso, este es un escenario listo para aclarar el pronóstico del tiempo y el tiempo, una de las solicitudes más populares de asistentes de voz en el mundo). En el segundo artículo, y se publicará próximamente, aprenderemos cómo llamar a ciertas pantallas por voz e implementar consultas complejas dentro de la aplicación.



Lo que necesitas para trabajar



SDK. Tomamos Aimybox como un SDK para crear interfaces de diálogo. Fuera de la caja, Aimybox proporciona un asistente SDK y una interfaz de usuario lacónica y personalizable (que se puede modificar si se desea). Al mismo tiempo , puede elegir entre los existentes o crear su propio módulo como motores de reconocimiento , síntesis y PNL .



Básicamente, Aimybox implementa la arquitectura del asistente de voz, estandarizando las interfaces de todos estos módulos y organizando su interacción de la manera correcta. Por lo tanto, al implementar esta solución, puede reducir significativamente el tiempo para desarrollar una interfaz de voz dentro de su aplicación. Puedes leer más sobre Aimybox aquí oaquí .



Herramienta de creación de guiones. Escribiremos el script en JAICF (este es un marco de código abierto y completamente gratuito para desarrollar aplicaciones de voz desde Just AI), y reconoceremos las intenciones usando Caila (servicio NLU) en JAICP (Just AI Conversational Platform). Te contaré más sobre ellos en la siguiente parte del tutorial, cuando empecemos a usarlos.



Smartphone. Para las pruebas, necesitamos un teléfono inteligente Android, en el que ejecutaremos y probaremos Habitika.



Procedimiento



Primero, bifurcamos "Habitika" (rama Release) y buscamos los archivos que son más importantes para nosotros. Usé el IDE de Android Studio:



Find MainActivity .kt; insertaremos la lógica allí.



HabiticaBaseApplication .kt: allí inicializaremos Aimybox.



Activity_main .xml: inserta el elemento de interfaz allí.



AndroidManifest .xml: la estructura completa de la aplicación y sus permisos se almacenan allí.



De acuerdo con las instrucciones del nabo "Habitiki", cambiamos el nombre de habitica.properties.example y habitica.resources.example, eliminando el ejemplo de ellos, iniciamos el proyecto en firebase para la aplicación y copiamos el archivo google-services.json a la raíz.



Lanzamos la aplicación para comprobar que el montaje está funcionando. ¡Voila!



imagen



Primero, agreguemos las dependencias de Aimybox.



implementation 'com.justai.aimybox:core:0.11.0'
    implementation("com.justai.aimybox:components:0.1.8")


en dependencias y



    maven { url 'https://dl.bintray.com/aimybox/aimybox-android-sdk/' }
    maven { url "https://dl.bintray.com/aimybox/aimybox-android-assistant/" }
 


en repositorios.



Y agregue la siguiente línea justo después de compileOptions para que todo funcione correctamente



    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }


Ahora permisos.



Elimine los indicadores de los permisos RECORD_AUDIO y MODIFY_AUDIO_SETTINGS en AndroidManifest .xml para que las opciones se vean así.




    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="com.android.vending.BILLING" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>


Ahora inicialicemos Aimybox en BaseApplication.



Agregue AimyboxProvider al inicializar la clase.



imagen



Y hacemos la inicialización real.



private fun createAimybox (context: Context): Aimybox {
        
        val unitId = UUID.randomUUID().toString()

        val textToSpeech = GooglePlatformTextToSpeech(context, Locale("Ru"))
        val speechToText = GooglePlatformSpeechToText(context, Locale("Ru"))
        val dialogApi = AimyboxDialogApi(
                "YOUR KEY", unitId)
        
        return Aimybox(Config.create(speechToText, textToSpeech, dialogApi))
    }


En lugar de YOUR_KEY, su código de la consola Aimybox será posteriormente.



Ahora incrustamos el fragmento en mainActivity.kt. Inserte previamente el FrameLayout en activity_main.xml, justo debajo del frameLayout con id bottom_navigation



<FrameLayout
                                android:id="@+id/assistant_container"
                                android:layout_width="match_parent"
                                android:layout_height="match_parent"/>


En MainActivity, primero agregue una solicitud de permiso explícito a OnCreate

        ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.RECORD_AUDIO), 1)


Y cuando los reciba, agregue un fragmento al marco anterior.



    @SuppressLint("MissingPermission")
    override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<out String>,
            grantResults: IntArray
    ) {
        val fragmentManager = supportFragmentManager
        val fragmentTransaction = fragmentManager.beginTransaction()

        fragmentTransaction.add(R.id.assistant_container, AimyboxAssistantFragment())
        fragmentTransaction.commit()
    }


No olvide agregar a OnBackPressed la capacidad de salir del asistente después de ingresarlo.



        val assistantFragment = (supportFragmentManager.findFragmentById(R.id.assistant_container)
                as? AimyboxAssistantFragment)
        if (assistantFragment?.onBackPressed() != true) {
            return
        }


Además, agregue estilos (styles.xml) en AppTheme



<item name="aimybox_assistantButtonTheme">@style/CustomAssistantButtonTheme</item>
        <item name="aimybox_recognitionTheme">@style/CustomRecognitionWidgetTheme</item>
        <item name="aimybox_responseTheme">@style/CustomResponseWidgetTheme</item>
        <item name="aimybox_imageReplyTheme">@style/CustomImageReplyWidgetTheme</item>
        <item name="aimybox_buttonReplyTheme">@style/CustomButtonReplyWidgetTheme</item>


Y los estilos individuales están justo debajo:



 <style name="CustomAssistantButtonTheme" parent="DefaultAssistantTheme.AssistantButton">
    </style>

    <style name="CustomRecognitionWidgetTheme" parent="DefaultAssistantTheme.Widget.Recognition">
    </style>

    <style name="CustomResponseWidgetTheme" parent="DefaultAssistantTheme.Widget.Response">
    </style>

    <style name="CustomButtonReplyWidgetTheme" parent="DefaultAssistantTheme.Widget.ButtonReply">
    </style>

    <style name="CustomImageReplyWidgetTheme" parent="DefaultAssistantTheme.Widget.ImageReply">
    </style>


Comprobemos si se ha añadido un micrófono. Lanzamos la aplicación.



Tenemos un montón de errores relacionados con la sintaxis incorrecta. Arreglamos todo como aconseja el IDE.



¡Trabajando!



imagen



Pero el micrófono se está infiltrando en la navegación inferior. Vamos a subirlo un poco. Agregue a los estilos anteriores en CustomAssistantButtonTheme:



        <item name="aimybox_buttonMarginBottom">72dp</item>


¡Mejor!



imagen



Ahora conectemos a un asistente allí y verifiquemos si responde normalmente. Para ello necesitamos la consola Aimybox.



Comencemos por ir a app.aimybox.com en nuestra cuenta de github, hacer un nuevo proyecto, conectar un par de habilidades (conecté DateTime para la prueba) e intentar hacer las preguntas apropiadas en el asistente. Aquí en la configuración, en la esquina superior derecha, tomamos apiKey, que insertamos en createAimybox en lugar de YOUR KEY.



private fun createAimybox (context: Context): Aimybox {
        
        val unitId = UUID.randomUUID().toString()

        val textToSpeech = GooglePlatformTextToSpeech(context)
        val speechToText = GooglePlatformSpeechToText(context)
        val dialogApi = AimyboxDialogApi(
                "YOUR KEY", unitId)
        
        return Aimybox(Config.create(speechToText, textToSpeech, dialogApi))
    }


¡Trabajando!



imagen



Solo texto en inglés, cambiemos el mensaje de bienvenida en strings.constants.xml.



<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--  Prefs -->
    <string name="SP_userID" translatable="false">UserID</string>
    <string name="SP_APIToken" translatable="false">APIToken</string>
    <string name="base_url" translatable="false">https://habitica.com</string>
    <string name="initial_phrase">"!   ?</string>


¡Hurra!



imagen



Aquí hay un enlace al repositorio de código.



En el próximo artículo sobre el asistente de "Habitika", te diré cómo usar tu voz no solo para averiguar el clima, sino también para controlar la aplicación directamente: navega por las páginas y agrega hábitos y tareas.



All Articles