Canal & Accès
🔹 Canal & Accès
comment on peut décomposer la phase Canal & Accès dans l’architecture du chatbot agricole :
1. WhatsApp Business
- Utilisation de l’API Cloud de Meta (ou passerelle équivalente type Twilio / 360Dialog).
- Sert de canal principal pour l’étudiant : toutes les questions et réponses transitent par WhatsApp.
- Avantage : pas besoin d’application supplémentaire, adoption immédiate par les étudiants.
2. Webhook
- Point d’entrée technique : reçoit chaque message WhatsApp et le transfère au backend.
- Fonctionne comme un pont entre WhatsApp et votre système pédagogique.
- Peut filtrer les métadonnées (expéditeur, langue détectée, type de contenu : texte, audio, image).
3. Backend (API)
-
Gère la logique centrale :
- Normalisation du message (texte/audio → texte via ASR si nécessaire).
- Identification de l’utilisateur (numéro WhatsApp ↔ profil étudiant).
- Envoi vers le module de routage pour déterminer la matière.
- Expose aussi une API pour répondre via WhatsApp avec le bon format (texte enrichi, boutons, lien vidéo).
⚙️ Exemple de flux
- Étudiant envoie un message "Comment installer un goutte-à-goutte pour tomates ?"
- Message → WhatsApp Business Cloud API
- Transmission → Webhook (JSON payload avec texte, numéro, timestamp)
- Passage → Backend API (normalisation + routage vers RAG irrigation)
- Réponse générée → renvoyée via WhatsApp API → étudiant.
Diagramme de séquence clair et complet pour la phase Canal & Accès (WhatsApp → Webhook → Backend → RAG),
voici un diagramme de séquence clair et complet pour la phase Canal & Accès (WhatsApp → Webhook → Backend → RAG), avec les variantes texte / audio / image et le retour de réponse.
sequenceDiagram autonumber actor Etu as Étudiant participant WA as WhatsApp Business Cloud API participant WH as Webhook (Receiver) participant BE as Backend API (Core) participant AUTH as Profil & Auth (DB) participant ASR as ASR (Speech-to-Text) participant VSN as Vision (OCR/Caption) participant RT as Router (détection matière) participant RAG as RAG <matière> participant LLM as LLM Génératif participant FMT as Post-traitement & Formatage rect rgb(245,245,245) note over Etu: Exemple :<br/>"Comment installer un goutte-à-goutte pour tomates ?" Etu->>WA: Message WhatsApp (texte / audio / image) WA-->>WH: POST /webhook {payload JSON, HMAC-SHA256} end WH->>WH: Validation signature, idempotency check alt payload audio? WH->>BE: POST /ingest {media_id, from, ts, type:"audio"} BE->>WA: GET /media/{media_id} WA-->>BE: audio file (OGG/MP3) BE->>ASR: audio stream ASR-->>BE: transcript (texte) else payload image? WH->>BE: POST /ingest {media_id, from, ts, type:"image"} BE->>WA: GET /media/{media_id} WA-->>BE: image file (JPEG) BE->>VSN: OCR + caption (optionnel) VSN-->>BE: texte extrait + tags else texte WH->>BE: POST /ingest {text, from, ts, type:"text"} end BE->>AUTH: GET /profiles?phone=+261... AUTH-->>BE: profil {id_etudiant, langue_pref, niveau, historique} BE->>RT: detect_matiere(text, meta:langue, niveau, médias) RT-->>BE: route = "Irrigation" (score, fallbackTop2) BE->>RAG: retrieve(context="Irrigation", query=text, topk=8) RAG-->>BE: passages + citations + snippets BE->>LLM: prompt( user=text, contexte=passages, langue=FR/MG ) LLM-->>BE: brouillon réponse structurée BE->>FMT: validate + safety + structuration (bullets, étapes, liens) FMT-->>BE: message final (texte enrichi + CTA/boutons) BE->>WA: POST /messages {to: phone, type:text, body: message} WA-->>Etu: Réponse affichée (WhatsApp) opt journalisation & métriques BE->>AUTH: log interaction (latences, score route, ids docs) end alt erreur LLM ou RAG BE->>WA: POST /messages {fallback: demander précision ou proposer Top-2 matières} WA-->>Etu: "Parlez-vous d'Irrigation ou de Botanique ?" end
Points d’implémentation clés (résumé)
- Sécurité Webhook : vérification HMAC-SHA256 de Meta, horodatage, idempotency key (message_id) pour éviter les doublons.
- Normalisation : tout devient texte (ASR pour audio, OCR/caption pour image) avec langue détectée (FR/MG/EN).
- Routage : classifieur léger (mots-clés + modèle) retournant matière, score, Top-2 pour fallback.
- RAG : index par matière (collections séparées), top-k + re-ranking, citations ↔️ sources.
- LLM + Post-traitement : gabarit de réponse (étapes numérotées, glossaire, “pour aller plus loin”), garde-fous (hallucination).
- Réponse WhatsApp : texte enrichi + éventuellement boutons (ex. “Voir schéma”, “Vidéo 2 min”, “Quiz rapide”).
- Logs & métriques : latences par étape, taux de fallback, qualité perçue (feedback emoji).
B- ’architecture technique (composants & réseaux) + des exemples de payloads
’architecture technique (composants & réseaux) + des exemples de payloads (Webhook entrant, appels sortants WhatsApp, et réponses avec boutons), ainsi que les points de sécurisation/idempotence.
Architecture (composants & réseaux)
flowchart LR subgraph MetaCloud[Meta Cloud] WAAPI[WhatsApp Business Cloud API] end subgraph Edge[Votre infra - Edge/DMZ] WAF[WAF/Reverse Proxy<br/>(TLS, rate limit)] WH[Webhook Receiver<br/>(/webhook)] end subgraph Core[VPC / Réseau privé] BE[Backend API (Core)<br/>Auth + Orchestration] MQ[Queue / Stream<br/>(idempotence, retries)] ASR[ASR (Speech-to-Text)] VSN[VISION (OCR/Caption)] RT[Router (détection matière)] RAG[RAG par matière<br/>(Vector DB: pgvector/Qdrant)] LLM[LLM Gateway] FMT[Post-traitement & Formatage] DB[(Profiles & Logs<br/>Postgres)] OBS[(Object Storage<br/>S3/MinIO)] MON[Monitoring & Traces<br/>Prom/Grafana/OTel] SEC[KMS/Vault<br/>(secrets, tokens)] end WAAPI -->|POST JSON<br/>HMAC-SHA256| WAF --> WH WH -->|validate & enqueue| MQ --> BE BE --> DB BE -->|download media| WAAPI BE --> ASR BE --> VSN BE --> RT --> RAG --> LLM --> FMT --> BE BE -->|POST /messages| WAAPI BE --> OBS BE --> MON BE --> SEC
Chemin critique (résumé)
- Meta → Webhook : réception payload HMAC, contrôle d’idempotence → enqueue (MQ).
- Backend : normalise (ASR/OCR), identifie l’étudiant, route vers la matière, RAG+LLM, post-traitement.
- Réponse : envoi via /messages (texte/boutons/document).
- Logs : traces, latences, feedback, stockage pièces jointes.
Exemples de payloads & appels
1) Webhook entrant (texte)
Exemple minimaliste (structure type Meta). Les clés et valeurs changent selon votre app.
{ "object": "whatsapp_business_account", "entry": [{ "id": "WABA_ID", "changes": [{ "field": "messages", "value": { "messaging_product": "whatsapp", "metadata": { "phone_number_id": "1234567890", "display_phone_number": "+14155552671" }, "contacts": [{ "wa_id": "261341234567", "profile": { "name": "Rabe Ando" } }], "messages": [{ "from": "261341234567", "id": "wamid.HBgM...", "timestamp": "1725185150", "type": "text", "text": { "body": "Comment installer un goutte-à-goutte pour tomates ?" }, "context": { "from": "26134...", "id": "wamid..." } }] } }] }] }
Validation HMAC côté Webhook (pseudo-code)
# headers['X-Hub-Signature-256'] = "sha256=..." expected = "sha256=" + hmac_sha256(app_secret, raw_body) if not hmac_compare(headers['X-Hub-Signature-256'], expected): return 401 # Idempotence msg_id = value.messages[0].id if cache.exists(msg_id): return 200 cache.set(msg_id, 1, ttl=86400)
2) Webhook entrant (audio → ASR)
{ "object": "whatsapp_business_account", "entry": [{ "changes": [{ "value": { "messages": [{ "from": "261341234567", "id": "wamid.HBgM...", "timestamp": "1725185250", "type": "audio", "audio": { "id": "MEDIA_ID_ABC", "mime_type": "audio/ogg; codecs=opus", "voice": true } }] } }] }] }
Backend :
- GET /{phone_number_id}/media/MEDIA_ID_ABC → URL de téléchargement signé
- Téléchargement binaire → ASR → texte normalisé
3) Webhook entrant (image → OCR/Caption)
{ "entry": [{ "changes": [{ "value": { "messages": [{ "type": "image", "image": { "id": "MEDIA_ID_IMG", "caption": "maladies feuilles tomate ?" }, "from": "261341234567", "id": "wamid.XYZ" }] } }] }] }
Backend : téléchargement → VISION (OCR/caption) → enrichit la requête texte.
4) Appel sortant : réponse texte enrichi (étapes + citations)
{ "messaging_product": "whatsapp", "to": "261341234567", "type": "text", "text": { "preview_url": false, "body": "Installation goutte-à-goutte (tomates) – en 6 étapes :\n1) Préparer la ligne principale (PE 16–20 mm)…\n2) Poser les dérivations (4 mm)…\n3) Débit cible : 1–2 L/pl/j…\n4) Programmation : matin/soir…\n5) Filtration 120 mesh…\n6) Test de pression (1 bar)…\n\n➡️ Pour aller plus loin : fiche PDF, schéma 2 min." } }
5) Appel sortant : boutons (CTA rapides)
{ "messaging_product": "whatsapp", "to": "261341234567", "type": "interactive", "interactive": { "type": "button", "body": { "text": "Vous voulez un schéma résumé ou une vidéo 2 min ?" }, "action": { "buttons": [ { "type": "reply", "reply": { "id": "CTA_SCHEMA", "title": "📄 Schéma" } }, { "type": "reply", "reply": { "id": "CTA_VIDEO", "title": "🎬 Vidéo 2 min" } }, { "type": "reply", "reply": { "id": "CTA_QUIZ", "title": "📝 Quiz rapide" } } ] } } }
Webhook des réponses bouton : vous recevrez un message type: "button" → button.text/id, à router sur votre backend (ex. générer le PDF/URL ou lancer un mini-quiz).
6) Appel sortant : envoi d’un document (schéma PDF)
{ "messaging_product": "whatsapp", "to": "261341234567", "type": "document", "document": { "link": "https://cdn.votre-domaine.edu/docs/goutte-a-goutte-tomates-v1.pdf", "filename": "schema_goutte_a_goutte_tomates.pdf", "caption": "Schéma A4 prêt à imprimer" } }
Contrats d’API internes (extraits)
-
POST /webhook
- Entrée : payload Meta (voir ci-dessus)
- Traitement : vérif HMAC, idempotence, push MQ
- Sortie : 200 OK immédiat (no retry)
-
POST /ingest
- Entrée : { from, message_id, type, text|media_id, ts }
- Effets : téléchargement média si besoin, normalisation, enrichissement (langue, niveau), route = matière
- Sortie : 202 Accepted (traitement async)
-
POST /respond
- Entrée : { to, payload_whatsapp }
- Effets : signature Bearer Token, POST → WA Cloud /messages
- Sortie : 200 OK avec message_id
Sécurité, Résilience & Observabilité
-
Sécurité
- HMAC-SHA256 (header X-Hub-Signature-256), TLS only.
- Vault/KMS pour secrets (app secret, access tokens WhatsApp).
- Allowlist IP Meta (optionnel) + WAF (rate limit, bot rules).
-
Idempotence & retrys
- Cache/DB clé message_id (TTL 24h).
- Files d’attente (ex. SQS/Kafka/Rabbit) pour backpressure.
- Politique retry exponentiel (ASR/Vision/LLM).
-
Observabilité
- TraceIDs corrélés (Webhook → ASR → RAG → LLM → WhatsApp).
- Métriques : latence p95/p99, taux fallback, % multimodal, erreurs par étape.
- Journaux PII-minimisés (hash des numéros, stockage minimal).
Variables d’environnement (exemple)
WA_APP_ID=... WA_PHONE_NUMBER_ID=... WA_VERIFY_TOKEN=... WA_APP_SECRET=... # pour HMAC WA_ACCESS_TOKEN=... # Graph API MEDIA_MAX_MB=20 ASR_ENDPOINT=https://asr.internal/recognize VISION_ENDPOINT=https://vision.internal/ocr RAG_ENDPOINT=https://rag.internal/retrieve LLM_ENDPOINT=https://llm.internal/generate DB_URL=postgres://... S3_ENDPOINT=https://s3.internal S3_BUCKET=edu-bot
Schéma de séquence (récap ultra-synthèse)
sequenceDiagram autonumber participant Meta as WhatsApp Cloud participant Webhook as Webhook (Edge) participant MQ as Queue participant Core as Backend Core participant ASR as ASR/OCR participant RAG as RAG+LLM participant MetaOut as WhatsApp Cloud Meta->>Webhook: POST /webhook (JSON + HMAC) Webhook->>Webhook: Validate HMAC + Idempotence Webhook->>MQ: Enqueue (event) MQ->>Core: Dequeue (event) alt audio/image Core->>ASR: audio→texte / image→texte ASR-->>Core: texte normalisé end Core->>RAG: retrieve+generate (matière) RAG-->>Core: réponse structurée Core->>MetaOut: POST /messages (texte/boutons/document)
C- mapping routage (mots-clés → matière, avec scores & fallback) prêt à coller dans votre backend
Les grandes histoires ont une personnalité. Envisagez de raconter une belle histoire qui donne de la personnalité. Écrire une histoire avec de la personnalité pour des clients potentiels aidera à établir un lien relationnel. Cela se traduit par de petites spécificités comme le choix des mots ou des phrases. Écrivez de votre point de vue, pas de l'expérience de quelqu'un d'autre.
Les grandes histoires sont pour tout le monde, même lorsqu'elles ne sont écrites que pour une seule personne. Si vous essayez d'écrire en pensant à un public large et général, votre histoire sonnera fausse et manquera d'émotion. Personne ne sera intéressé. Ecrire pour une personne en particulier signifie que si c'est authentique pour l'un, c'est authentique pour le reste.