Flutter
Le package kavchat_flutter ajoute à votre application Flutter un chat d’assistance basé sur des scripts : boutons, reconnaissance de texte libre, formulaire de création de ticket, copie du bot utilisable hors ligne et affichage de droite à gauche en hébreu et en arabe.
Installation
dependencies:
kavchat_flutter: ^0.0.11Le package inclut http, shared_preferences (cache de la version et conversation enregistrée) et url_launcher (liens dans les scripts). Pour ouvrir les liens tel: sur Android 11 et versions ultérieures, ajoutez dans AndroidManifest.xml une entrée <queries> pour le schéma tel, et une autre pour https afin d’ouvrir les liens vers des sites (voir le README de url_launcher). Sur iOS, LSApplicationQueriesSchemes n’est nécessaire que si vous appelez vous-même canLaunchUrl.
Utilisation
final kavchat = KavchatController(
publicKey: 'pk_live_...',
// apiBase: 'https://api.kavchat.com', // default
// locale: 'he', // default: device language if translated, else the bot language
onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);
Scaffold(
floatingActionButton: KavchatLauncher(controller: kavchat), // hidden while the bot is off
);
// or open it yourself
showKavchat(context, kavchat);
// or embed the screen in your own route
KavchatChat(controller: kavchat, onClose: () => Navigator.pop(context));Créez le contrôleur une seule fois (par exemple dans un State ou un provider) et appelez dispose() lorsque le composant qui le détient est détruit.
KavchatLauncher est un FloatingActionButton que vous positionnez avec Scaffold.floatingActionButtonLocation. Le paramètre kavchat.settings?.position (start ou end) indique le côté choisi dans le tableau de bord.
Lorsqu’un message à côté du bouton de chat est défini dans l’interface d’administration (bulle de dialogue, texte courbé au-dessus du bouton, bouton qui s’étire en capsule pour afficher un message, ou ligne qui s’élève depuis le bouton pour présenter les premières options du bot), KavchatLauncher l’affiche après le délai défini, au maximum une fois par jour. Appuyer sur une option de la ligne ouvre le chat avec cette option sélectionnée, comme si elle avait été choisie dans le chat. Fermer le message ou ouvrir le chat masque le message jusqu’au lendemain. Le message n’apparaît pas lorsque le chat est ouvert. Si la réduction des animations est activée sur l’appareil, le message s’affiche sans animation. Lorsque l’option « Ne pas afficher sur les téléphones » est activée, le message apparaît uniquement sur les tablettes (dont le côté le plus court de l’écran mesure au moins 600 points). Sur téléphone, la ligne affiche jusqu’à deux options. KavchatLauncher(controller: kavchat, attention: false) désactive l’affichage du message.
Lorsque l’icône du bouton dans le thème est un visage, celui-ci cligne des yeux de temps en temps quand le bouton est au repos. Il ne cligne pas des yeux lorsque le chat est ouvert, lorsque l’application est en arrière-plan ou lorsque la réduction des animations est activée.
Le bot n’est pas affiché (le bouton flottant n’apparaît pas et KavchatChat affiche « Indisponible ») lorsque la version indique enabled: false : le bot est désactivé, il est réservé aux utilisateurs de test et l’utilisateur n’en fait pas partie, ou le quota est épuisé (reason: 'quota').
Jeton d’identité
Pour les utilisateurs connectés, signez un JWT de courte durée sur votre serveur avec la clé secrète (jamais dans l’application, voir Identification des utilisateurs), puis transmettez-le :
KavchatController(publicKey: 'pk_live_...', userToken: jwt, userName: 'Dana');
await kavchat.setUser(token: newJwt, name: 'Dana'); // after login
await kavchat.setUser(token: null); // after logoutLe jeton est envoyé dans l’en-tête Authorization: Bearer <token> à chaque appel. Avec un jeton, le formulaire de contact n’exige ni adresse e-mail ni numéro de téléphone, et le ciblage des utilisateurs de test reconnaît l’utilisateur. setUser recharge la version, et un utilisateur différent démarre une nouvelle conversation. Ainsi, une conversation enregistrée sur l’appareil n’est jamais transférée à un autre compte.
Liens, écrans et formulaire de contact
- Les boutons de type
links’ouvrent avecurl_launcher, uniquement pour les adresseshttps:ettel:. Les liens dans les messages du bot sont limités àhttps:. - Les boutons de type
screenappellentonScreen(screen, targetId). Sans cette fonction, ils n’ont aucun effet. - Le bouton « Contacter l’équipe » ouvre le formulaire intégré (nom, e-mail, téléphone, sujet et message, avec la conversation jointe), puis affiche le numéro du ticket après l’envoi.
Liste des écrans dans l’éditeur
Déclarez une seule fois les écrans que votre application peut ouvrir dans KavchatController(screens: ...). Le SDK transmet lui-même la liste à Kavchat. L’éditeur de scripts propose alors ces écrans dans une liste déroulante avec leurs noms, à la place d’un champ de texte libre. Il demande aussi un identifiant d’élément lorsqu’un écran en a besoin et signale les boutons qui mènent à un écran non déclaré. Personne n’a à saisir manuellement la liste des écrans dans le tableau de bord.
final kavchat = KavchatController(
publicKey: 'pk_live_...',
screens: const [
KavchatScreen(id: 'orders', label: 'My orders'),
KavchatScreen(id: 'product', label: 'Product page', needsTarget: true), // the button carries a targetId
],
onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);
// later, to replace the list: await kavchat.registerScreens([...]);idest la valeur reçue paronScreen: lettres latines, chiffres,_,.et-, jusqu’à 40 caractères.labelest le nom visible par l’administrateur, jusqu’à 60 caractères. La limite est de 100 écrans. Les entrées non valides et les identifiants en double sont ignorés.needsTarget: le bouton contient aussi un identifiant d’élément (par exemple, un identifiant de produit), transmis àonScreensous la formetargetId.- La liste est envoyée en arrière-plan après le chargement de la version, uniquement lorsqu’elle a changé ou une fois par semaine. Un échec reste invisible et l’envoi est retenté au prochain lancement. Rien ne s’affiche pour l’utilisateur.
- Les écrans enregistrés apparaissent dans le tableau de bord sous Bot, Paramètres, « Écrans de l’application », avec les plateformes qui ont signalé chaque écran. Vous pouvez y supprimer un écran retiré de l’application.
RTL
Le chat définit sa propre Directionality selon la langue de l’interface : de droite à gauche pour he et ar, de gauche à droite pour toutes les autres langues. Il ne modifie pas le sens d’affichage de votre application. Chaque bulle choisit aussi son sens selon la première lettre à direction forte, pour que les contenus mixtes restent lisibles. La langue de l’interface et celle du script sont indépendantes : un bot en anglais peut afficher des boutons en arabe, comme « Retour », lorsque locale: 'ar'.
Couleurs et identité de marque
Les couleurs proviennent du paramètre primaryColor du bot. Le texte affiché sur cette couleur est noir ou blanc selon les critères de contraste WCAG. Une couleur trop claire est remplacée par une couleur foncée lorsqu’elle sert à afficher du texte. Pour modifier les couleurs :
KavchatLauncher(controller: kavchat, theme: KavchatThemeData.fromColor(const Color(0xFF0F766E)));
KavchatChat(controller: kavchat, theme: KavchatThemeData.fromHex('#0f766e').copyWith(background: Colors.white));La mention « Propulsé par Kavchat by maxsave » apparaît dans toutes les offres, avec un lien vers kavchat.com. Avec Premium, vous pouvez la masquer dans les paramètres du bot.
Chat avec un conseiller
Aucune configuration n’est nécessaire pour démarrer. Lorsque vous activez le chat avec des conseillers dans l’interface d’administration, l’option apparaît dans le chat de l’application, exactement comme dans le widget du site.
- L’option : « Parler à un conseiller » apparaît avant « Contacter l’équipe », uniquement après confirmation par le serveur qu’un conseiller est disponible. La disponibilité est vérifiée à nouveau lorsque l’utilisateur appuie sur le bouton. En dehors des horaires d’ouverture, ou lorsque tous les conseillers sont occupés, seul le formulaire de contact s’affiche, avec une brève explication et l’heure de retour de l’équipe si elle est connue. Lorsque le quota mensuel est épuisé, le formulaire s’affiche sans explication.
- La demande : les visiteurs laissent une adresse e-mail ou un numéro de téléphone au cas où aucun conseiller ne se libérerait à temps. Ils peuvent aussi ajouter un nom et un premier message. Lorsque plusieurs services sont ouverts, ils choisissent un service. Les utilisateurs identifiés (
userToken) n’ont pas à renseigner leurs coordonnées. Si aucun conseiller ne peut prendre la conversation, le formulaire de contact s’ouvre avec les informations déjà saisies. - L’attente : le message « En attente d’un conseiller » s’affiche avec un compte à rebours jusqu’à la fin du délai d’attente que vous avez défini, ainsi que les boutons « Laisser plutôt un message » et « Terminer la conversation ». L’utilisateur peut déjà écrire pendant l’attente. À la fin du délai, la conversation est automatiquement transformée en ticket. Le numéro du ticket s’affiche avec une explication indiquant qu’aucun conseiller ne s’est libéré à temps.
- La conversation : nom du conseiller, messages, indicateur de saisie, transfert vers un autre conseiller et fin de la conversation. Tout ce qui provient du serveur s’affiche en texte brut, sans liens.
- En temps réel : une connexion Server-Sent Events via une réponse
httpen streaming. Si la connexion est interrompue, le chat se reconnecte à intervalles croissants et récupère tout ce qui a été manqué. Ainsi, aucun message n’est perdu ni affiché deux fois. Sur les réseaux qui bloquent cette connexion, ainsi que sur Flutter Web, le chat utilise des requêtes répétées (long-poll). Chaque message possède un identifiant, pour qu’une nouvelle tentative ne crée pas de doublon. Un message non envoyé est signalé et peut être renvoyé d’un simple appui. - Passage en arrière-plan et redémarrage : lorsque l’application passe en arrière-plan (
paused,hidden), la connexion est fermée. Lorsqu’elle revient au premier plan (resumed), le chat récupère ce qui a été manqué. Le jeton d’accès à la conversation est valable jusqu’à 12 heures ou jusqu’à la fin de la conversation, et il est conservé dans le stockage de votre choix. Ainsi, une conversation en cours réapparaît à l’écran après le redémarrage de l’application. Le jeton n’est ni placé dans une URL ni écrit dans les journaux. - Pas de notifications push dans cette version : les messages du conseiller arrivent uniquement lorsque l’application est ouverte.
Il est recommandé de conserver le jeton d’accès dans un stockage sécurisé (Keychain sur iOS, Keystore sur Android), par exemple avec flutter_secure_storage. Si vous ne définissez pas secureStorage, le jeton est conservé dans le même stockage que la conversation. Votre propre bouton de chat avec un conseiller ouvre le formulaire de demande lorsqu’un conseiller est disponible. Sinon, le formulaire de contact s’ouvre avec l’explication :
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureKavchatStorage implements KavchatStorage {
final _s = const FlutterSecureStorage();
@override
Future<String?> read(String key) => _s.read(key: key);
@override
Future<void> write(String key, String value) => _s.write(key: key, value: value);
@override
Future<void> remove(String key) => _s.delete(key: key);
}
final kavchat = KavchatController(
publicKey: 'pk_live_...',
secureStorage: SecureKavchatStorage(),
livePage: 'checkout',
onLivePhase: (phase) => debugPrint('live chat: $phase'),
);
// your own button
FilledButton(onPressed: kavchat.openLive, child: const Text('Chat with us'));La même logique, sans Flutter, se trouve dans kavchat_engine (KavchatClient, LiveSession et la machine à états partagée liveApplyEvent, liveLines et liveStatus, qui passe les mêmes vecteurs de test que le widget du site).
Questions, conditions et prospects
Aucune configuration n’est nécessaire dans l’application. Un script peut demander des informations (nom, téléphone, e-mail, nombre ou texte), choisir la suite selon des conditions (Premium) et transmettre une fiche prospect. Tout s’exécute sur l’appareil.
- Clavier adapté : lorsque le bot attend une réponse, le champ de texte affiche un clavier adapté au téléphone, à l’e-mail ou aux nombres, avec saisie automatique. Si la réponse n’est pas valide, le bot explique ce qui manque et le champ est signalé. Les questions facultatives affichent un bouton « Passer ».
- Fiche prospect : lorsqu’un texte de consentement est présent, les boutons « Envoyer » et « Non, merci » s’affichent. Sans connexion réseau, la fiche prospect est enregistrée sur l’appareil, puis envoyée au retour de la connexion, sans doublons.
- Préremplissage : les réponses déjà fournies par l’utilisateur préremplissent le formulaire de contact et le formulaire de demande de chat avec un conseiller. Elles sont jointes au ticket et à la conversation avec le conseiller. Le nom, l’e-mail et le téléphone issus du jeton d’identité sont considérés comme des réponses connues : le bot ne les demande pas à nouveau.
- Écran actuel :
livePageindique aussi l’écran vérifié par les conditions et transmis avec les fiches prospects. Lorsque l’utilisateur change d’écran, appelezsetPage('checkout').
Réponses de l’IA (Premium)
Il n’y a rien à configurer dans l’application. Lorsque vous activez les réponses de l’IA dans l’interface d’administration (avec votre propre clé de fournisseur d’IA), une question à laquelle aucun script ne répond est envoyée à Kavchat. Pendant l’attente, jusqu’à 20 secondes, le chat indique que le bot est en train d’écrire. La réponse s’affiche en texte brut avec une petite mention « Réponse de l’IA » dans la langue de l’interface. En dessous apparaissent un bouton vers un sujet connexe, s’il y en a un, et un bouton « Contacter l’équipe ».
Si aucune réponse n’est disponible, ou si la requête échoue, prend trop de temps ou dépasse la limite (10 réponses par conversation toutes les 15 minutes), le chat affiche son message habituel « Je n’ai pas trouvé de réponse ». La question figure toujours dans le rapport des questions sans réponse, et les réponses de l’IA sont conservées dans la conversation enregistrée comme tout autre message.
Fonctionnement hors ligne et cache
La version est mise en cache avec son ETag (If-None-Match, 304). En l’absence de réseau ou en cas d’erreur du serveur, la copie enregistrée est utilisée et un message le signale. La conversation est enregistrée pour chaque bot et restaurée pendant 24 heures, tant que la version n’a pas changé. Le déroulement de la conversation est transmis au serveur 2 secondes après la dernière action, ainsi que lorsque l’application passe en arrière-plan.