À l'aide de l'exemple d'Habitica (une application open source pour corriger les habitudes et atteindre les objectifs, écrite en Kotlin), Vitalya Gorbachev, architecte de solutions chez Just AI, montre comment intégrer rapidement et de manière transparente une interface vocale dans les fonctionnalités de n'importe quelle application.
Mais d'abord, expliquons pourquoi la commande vocale d'une application mobile est pratique? Commençons par l'évidence.
- Nous avons souvent besoin d'utiliser l'application lorsque nos mains sont occupées: cuisiner, conduire, porter des valises, lors de travaux mécaniques, etc.
- La voix est un outil essentiel pour les personnes ayant une déficience visuelle.
Les boîtiers sont déjà transparents, mais en réalité tout est encore plus simple: dans certains cas, la numérotation vocale est juste plus rapide ! Imaginez - commander un billet d'avion avec une phrase "Achetez-moi un billet pour demain pour deux à Samara" au lieu d'un long formulaire. En même temps, avec la possibilité de poser des questions de clarification à l'utilisateur: le soir ou l'après-midi? avec ou sans bagages?
La voix est utile lorsque nous passons par le scénario de "remplissage de formulaire" et est pratique pour remplir presque tous les longs formulaires qui nécessitent une certaine quantité d'informations de la part de l'utilisateur. Et ces formes sont présentes dans la plupart des applications mobiles.
De gauche à droite: application Prigorod Russian Railways, agenda alimentaire FatSecret (les utilisateurs doivent remplir un formulaire plusieurs fois par jour, en choisissant parmi des centaines de produits), application de boulangerie Korzhov.
Étant donné qu'aujourd'hui les assistants vocaux sont souvent introduits dans le chat d'assistance et qu'ils se développent à partir de là, la plupart des entreprises essaient de pousser la fonctionnalité de l'application dans le chat. Complétez la balance, renseignez-vous sur un produit ou un service ... C'est loin d'être toujours pratique et dans le cas de la saisie vocale, c'est complètement contre-productif, ne serait-ce que parce que la reconnaissance vocale ne fonctionne souvent pas parfaitement.
La bonne approche consiste à intégrer l'assistant de manière transparente dans la fonctionnalité existante de l'application, dans l'interface de laquelle le formulaire sera rempli, afin que la personne puisse simplement vérifier qu'elle a tout dit correctement et cliquer sur OK.Nous avons décidé de montrer comment cela peut être fait en utilisant l'exemple d' Habitica - il s'agit d'une application open source écrite en Kotlin presque pur. "Habitika" est parfait pour un cas avec un assistant vocal - ici aussi, pour commencer une nouvelle tâche, vous devez remplir un formulaire assez volumineux. Essayons de remplacer ce processus morne par une phrase avec des questions suggestives?
J'ai divisé le didacticiel en deux parties. Dans cet article, nous verrons comment ajouter un assistant vocal à une application mobile et implémenter un scénario de base (dans notre cas, il s'agit d'un scénario prêt à l'emploi pour clarifier les prévisions météorologiques et temporelles - l'une des demandes d'assistants vocaux les plus populaires au monde). Dans le deuxième article - et il sera publié prochainement - nous allons apprendre à appeler certains écrans par la voix et à implémenter des requêtes complexes au sein de l'application.
Ce dont vous avez besoin pour travailler
SDK. Nous avons pris Aimybox comme SDK pour créer des interfaces de dialogue. Hors de la boîte, Aimybox fournit un assistant SDK et une interface utilisateur laconique et personnalisable (qui peut être modifiée si vous le souhaitez). En même temps , vous pouvez choisir parmi les modules existants ou créer votre propre module en tant que moteurs de reconnaissance , de synthèse et de PNL .
Fondamentalement, Aimybox implémente l'architecture de l'assistant vocal, standardise les interfaces de tous ces modules et organise leur interaction de la bonne manière. Ainsi, en implémentant cette solution, vous pouvez réduire considérablement le temps de développement d'une interface vocale au sein de votre application. Vous pouvez en savoir plus sur Aimybox ici ouici .
Outil de création de script. Nous écrirons le script en JAICF (il s'agit d'un framework open source et totalement gratuit pour développer des applications vocales à partir de Just AI), et nous reconnaîtrons les intentions en utilisant Caila (service NLU) dans JAICP (Just AI Conversational Platform). Je vous en dirai plus à leur sujet dans la partie suivante du didacticiel - lorsque nous les utiliserons.
Téléphone intelligent. Pour les tests, nous avons besoin d'un smartphone Android, sur lequel nous allons exécuter et tester Habitika.
Procédure
Tout d'abord, nous forkons "Habitika" (branche Release) et cherchons les fichiers qui sont les plus importants pour nous. J'ai utilisé l'IDE Android Studio:
Find MainActivity .kt - nous y intégrerons la logique.
HabiticaBaseApplication .kt - là, nous initialiserons Aimybox.
Activity_main .xml - intégrez-y l'élément d'interface.
AndroidManifest .xml - la structure entière de l'application et ses autorisations y sont stockées.
Selon les instructions du navet "Habitiki", nous renommons habitica.properties.example et habitica.resources.example, en supprimant l'exemple, démarrons le projet dans firebase pour l'application et copions le fichier google-services.json à la racine.
Nous lançons l'application pour vérifier que l'assemblage fonctionne. Voila!
Tout d'abord, ajoutons les dépendances Aimybox.
implementation 'com.justai.aimybox:core:0.11.0'
implementation("com.justai.aimybox:components:0.1.8")
dans les dépendances et
maven { url 'https://dl.bintray.com/aimybox/aimybox-android-sdk/' }
maven { url "https://dl.bintray.com/aimybox/aimybox-android-assistant/" }
dans les référentiels.
Et ajoutez la ligne suivante juste après compileOptions pour que tout fonctionne correctement
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
Maintenant les autorisations.
Supprimez les indicateurs des autorisations RECORD_AUDIO et MODIFY_AUDIO_SETTINGS dans AndroidManifest .xml afin que les options ressemblent à ceci.
<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"/>
Initialisons maintenant Aimybox dans BaseApplication.
Ajoutez AimyboxProvider lors de l'initialisation de la classe.
Et nous faisons l'initialisation proprement dite.
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))
}
Au lieu de YOUR_KEY, votre code de la console Aimybox sera par la suite.
Maintenant, nous intégrons l'extrait de code dans mainActivity.kt. Pré-insérez le FrameLayout dans activity_main.xml, juste en dessous du frameLayout avec l'ID bottom_navigation
<FrameLayout
android:id="@+id/assistant_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Dans MainActivity lui-même, ajoutez d'abord une demande d'autorisation explicite à OnCreate
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.RECORD_AUDIO), 1)
Et lorsque vous les recevez, ajoutez un fragment au cadre ci-dessus.
@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()
}
N'oubliez pas d'ajouter à OnBackPressed la possibilité de quitter l'assistant après y être entré.
val assistantFragment = (supportFragmentManager.findFragmentById(R.id.assistant_container)
as? AimyboxAssistantFragment)
if (assistantFragment?.onBackPressed() != true) {
return
}
De plus, ajoutez aux styles (styles.xml) dans 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>
Et les styles individuels sont juste en dessous:
<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>
Vérifions si un microphone a été ajouté. Nous lançons l'application.
Nous avons eu un tas d'erreurs concernant une syntaxe incorrecte. Nous réparons tout comme le conseille l'IDE.
Travail!
Mais le microphone se glisse dans la navigation du bas. Élevons un peu. Ajoutez aux styles ci-dessus dans CustomAssistantButtonTheme:
<item name="aimybox_buttonMarginBottom">72dp</item>
Mieux!
Maintenant, connectons un assistant là-bas et vérifions s'il répond normalement. Pour cela, nous avons besoin de la console Aimybox.
Commençons par aller sur app.aimybox.com sous notre compte github, créez un nouveau projet, connectez quelques compétences (j'ai connecté DateTime pour le test) et essayez de poser les questions appropriées dans l'assistant. Ici, dans les paramètres, dans le coin supérieur droit, nous prenons l'apiKey, que nous insérons dans createAimybox au lieu de VOTRE CLÉ.
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))
}
Travail!
Texte en anglais uniquement, modifions le message de bienvenue dans 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>
Hourra!
Voici un lien vers le référentiel de code.
Dans le prochain article sur un assistant pour "Habitika", je vais vous dire comment utiliser votre voix non seulement pour connaître la météo, mais pour contrôler directement l'application - naviguer à travers les pages et ajouter des habitudes et des tâches.