Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions _portfolio/cedd-hackathon-emotional-drift-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@ description: >-
modulation - 90% CV accuracy and 36/36 adversarial tests passing.
translation_url: /portfolio/hackathon-cedd-derive-emotionnelle/
translation_label: "🇫🇷 Lire cet article en français"
image: /assets/img/cedd/conversation-demo-en.png
---

A single message rarely tells you a young person is in trouble. Twelve messages that get shorter, darker, and further apart do. That shift - from "instant risk in one message" to "drift across a whole conversation" - is the idea behind **CEDD** (*Conversational Emotional Drift Detection*), the second system our team *404HarmNotFound* built at the March 2026 AI safety hackathon organized by [Mila](https://mila.quebec) with Bell and Kids Help Phone.

Where our [bilingual input guardrail](/portfolio/mila-hackathon-bilingual-guardrail/) classifies each conversation snapshot as `low_risk` or `high_risk` before it reaches the LLM, CEDD is the orthogonal layer: it monitors the **trajectory** of the user's messages in real time - length, tone, semantic drift, behavioral withdrawal - and adapts the chatbot's behavior *as the conversation degrades*, from warm support all the way to a crisis protocol with a warm handoff to a human.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/conversation-demo-en.png" alt="CEDD Streamlit interface at the end of the 9-message demo: chat on the left, dashboard with Orange alert gauge, class probabilities and active signals on the right" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">The CEDD interface at the end of the 9-message demo: the conversation has drifted, the gauge sits at Orange, and the dashboard shows class probabilities and the active signals behind the alert.</figcaption>
</figure>

## The problem: gradual deterioration is invisible to per-message classifiers

Emotional support chatbots for youth (the target population here is 16-22) can miss a slow slide into distress: no single message contains a crisis keyword, yet the conversation as a whole is unmistakably drifting. The signals are behavioral as much as lexical - messages getting shorter, hope vocabulary disappearing, topics being avoided, replies coming slower. CEDD turns that intuition into a feature space.
Expand All @@ -37,6 +43,11 @@ flowchart TD

**Classification with a safety-first contract.** A `StandardScaler → GradientBoostingClassifier` pipeline maps the 67D vector to one of four alert levels - Green, Yellow, Orange, Red. But the ML never has the last word: **7 safety gates** wrap it. Crisis keywords force Red instantly at any point; low ML confidence defaults to Yellow (precautionary principle); short conversations cap the ML at Orange; a lexical safety floor guarantees the prediction can never go *below* what keyword rules detected; and long response delays bump the level up. The design rule we kept from the guardrail project applies here too: safety rules can never be overridden by ML.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/dashboard-streamgraph-en.png" alt="Emotional flow streamgraph: stacked class probabilities per message, green giving way to yellow then orange, above the session statistics" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">The "emotional flow" streamgraph: class probabilities evolving message by message — green gives way to yellow and orange as the drift unfolds.</figcaption>
</figure>

**Adaptive response modulation.** The alert level selects one of four system prompts (in the user's language) injected into the conversational LLM: standard warmth at Green, enhanced emotional validation at Yellow, active support with resources at Orange, and at Red a **5-step warm handoff** - empathetic validation, permission-based transition, resources (Kids Help Phone 1-800-668-6868, text 686868, 9-8-8, 911), encouragement to connect, continued presence - plus an optional switch to "Alex", a simulated counselor persona using ASIST active-listening techniques. The LLM layer itself is resilient: a fallback chain (Cohere → Llama 3.3 70B via Groq → Gemini 2.5 Flash → Claude Haiku → static text) with per-model timeouts, so the UI never freezes on a slow provider.

**Longitudinal tracking.** A SQLite session tracker follows users *across* sessions: weighted risk score over the last 7 sessions, improving/stable/worsening trend, consecutive high-alert sessions, and withdrawal detection when a user disappears for more than 24 hours after a session without closure.
Expand Down Expand Up @@ -64,8 +75,18 @@ The adversarial suite is the part I would defend in front of a clinician: 36 han

**Explainability is a safety feature.** Every alert ships with its top-5 contributing features (model importance × scaled value), displayed as a bar chart in the bilingual Streamlit dashboard. In a mental-health context, "the system raised an alert because messages shortened 60% and finality vocabulary appeared" is actionable for a counselor; a bare probability is not.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/dashboard-radar-en.png" alt="Feature radar comparing message 1 and message 9, with the alert level history chart showing the escalation from Green to Orange" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">The feature radar compares message 1 with message 9, and the alert level history traces the Green → Yellow → Orange escalation a counselor can act on.</figcaption>
</figure>

**Document your failure modes.** The known-gaps table is part of the deliverable: conjugated crisis forms ("killing myself" vs "kill myself") that slip past the keyword gate, phrase-based identity detection, threshold-based withdrawal detection. In safety work, an honest limitation list is worth more than an inflated metric.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/dashboard-sombre.png" alt="CEDD dashboard in dark mode: alert level evolution, LLM fallback chain selector and active response mode" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">The dashboard in dark mode: alert level evolution, the LLM fallback chain selector (Cohere → Groq → Gemini → Claude → static) and the active response mode.</figcaption>
</figure>

## Full cedd-hackathon GitHub project

[CEDD Hackathon](https://github.com/dapiced/cedd-hackathon)
21 changes: 21 additions & 0 deletions _portfolio/hackathon-cedd-derive-emotionnelle.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ description: >-
validation croisée et 36/36 tests adversariaux réussis.
translation_url: /portfolio/cedd-hackathon-emotional-drift-detection/
translation_label: "🇬🇧 Read this article in English"
image: /assets/img/cedd/conversation-demo-fr.png
---

Un seul message dit rarement qu'un jeune va mal. Douze messages qui deviennent plus courts, plus sombres et plus espacés, oui. Ce déplacement - du « risque instantané dans un message » vers la « dérive sur l'ensemble d'une conversation » - est l'idée derrière **CEDD** (*Conversational Emotional Drift Detection*), le deuxième système que notre équipe *404HarmNotFound* a construit au hackathon sécurité de l'IA de mars 2026, organisé par [Mila](https://mila.quebec/fr) avec Bell et Jeunesse, J'écoute.

Là où notre [garde-fou d'entrée bilingue](/portfolio/hackathon-mila-garde-fou-bilingue/) classe chaque instantané de conversation en `low_risk` ou `high_risk` avant qu'il n'atteigne le LLM, CEDD est la couche orthogonale : il surveille en temps réel la **trajectoire** des messages de l'utilisateur - longueur, ton, dérive sémantique, retrait comportemental - et adapte le comportement du chatbot *au fur et à mesure que la conversation se dégrade*, du soutien chaleureux jusqu'au protocole de crise avec transfert accompagné vers un humain.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/conversation-demo-fr.png" alt="Interface Streamlit de CEDD à la fin de la démo de 9 messages : conversation à gauche, tableau de bord avec jauge d'alerte Orange, probabilités par classe et signaux actifs à droite" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">L'interface CEDD à la fin de la démo de 9 messages (Félix, 18 ans, CÉGEP) : la conversation a dérivé, la jauge est à l'Orange, et le tableau de bord montre les probabilités par classe et les signaux actifs derrière l'alerte.</figcaption>
</figure>

## Le problème : la détérioration graduelle est invisible pour un classifieur par message

Les chatbots de soutien émotionnel pour les jeunes (la population cible ici : 16-22 ans) peuvent manquer un glissement lent vers la détresse : aucun message pris isolément ne contient de mot-clé de crise, et pourtant la conversation dans son ensemble dérive de façon manifeste. Les signaux sont autant comportementaux que lexicaux - des messages qui raccourcissent, le vocabulaire d'espoir qui disparaît, des sujets évités, des réponses qui tardent. CEDD transforme cette intuition en espace de features.
Expand All @@ -38,6 +44,11 @@ flowchart TD

**Une classification sous contrat de sécurité.** Un pipeline `StandardScaler → GradientBoostingClassifier` projette le vecteur 67D sur quatre niveaux d'alerte - Vert, Jaune, Orange, Rouge. Mais le ML n'a jamais le dernier mot : **7 portes de sécurité** l'encadrent. Un mot-clé de crise force le Rouge instantanément à tout moment ; une confiance ML faible retombe par défaut sur Jaune (principe de précaution) ; les conversations courtes plafonnent le ML à Orange ; un plancher de sécurité lexical garantit que la prédiction ne peut jamais descendre *sous* ce que les règles à mots-clés ont détecté ; et un long délai de réponse fait monter le niveau d'un cran. La règle de conception héritée du projet garde-fou s'applique ici aussi : les règles de sécurité ne peuvent jamais être outrepassées par le ML.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/dashboard-streamgraph-en.png" alt="Streamgraph du flux émotionnel : probabilités par classe empilées message par message, le vert cédant la place au jaune puis à l'orange, au-dessus des statistiques de session" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">Le streamgraph du « flux émotionnel » : les probabilités par classe évoluent message par message — le vert cède la place au jaune puis à l'orange au fil de la dérive.</figcaption>
</figure>

**Modulation adaptative de la réponse.** Le niveau d'alerte sélectionne l'un des quatre prompts système (dans la langue de l'utilisateur) injectés dans le LLM conversationnel : chaleur standard au Vert, validation émotionnelle renforcée au Jaune, soutien actif avec ressources à l'Orange, et au Rouge un **transfert accompagné en 5 étapes** - validation empathique, transition avec demande de permission, présentation des ressources (Jeunesse, J'écoute 1-800-668-6868, texto 686868, 9-8-8, 911), encouragement à se connecter, présence continue - plus une bascule optionnelle vers « Alex », un·e intervenant·e simulé·e utilisant les techniques d'écoute active ASIST. La couche LLM elle-même est résiliente : une chaîne de fallback (Cohere → Llama 3.3 70B via Groq → Gemini 2.5 Flash → Claude Haiku → texte statique) avec timeout par modèle, pour que l'interface ne gèle jamais sur un fournisseur lent.

**Suivi longitudinal.** Un session tracker SQLite suit les utilisateurs *entre* les sessions : score de risque pondéré sur les 7 dernières sessions, tendance (amélioration / stable / aggravation), sessions consécutives à niveau élevé, et détection de retrait quand un utilisateur disparaît plus de 24 heures après une session restée sans clôture.
Expand Down Expand Up @@ -65,8 +76,18 @@ La suite adversariale est la partie que je défendrais devant un clinicien : 36

**L'explicabilité est une fonctionnalité de sécurité.** Chaque alerte est livrée avec son top 5 de features contributives (importance du modèle × valeur normalisée), affiché en barres dans le tableau de bord Streamlit bilingue. En contexte de santé mentale, « le système a levé une alerte parce que les messages ont raccourci de 60 % et que le vocabulaire de finalité est apparu » est actionnable pour un intervenant ; une probabilité nue ne l'est pas.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/dashboard-radar-en.png" alt="Radar des features comparant le message 1 et le message 9, avec l'historique des niveaux d'alerte montrant l'escalade du Vert à l'Orange" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">Le radar des features compare le message 1 au message 9, et l'historique des niveaux d'alerte trace l'escalade Vert → Jaune → Orange sur laquelle un intervenant peut agir.</figcaption>
</figure>

**Documenter ses modes de défaillance.** Le tableau des lacunes connues fait partie du livrable : formes de crise conjuguées (« killing myself » vs « kill myself ») qui échappent à la porte à mots-clés, détection identitaire par phrases plutôt que par contexte, détection de retrait par seuil. En sécurité, une liste de limites honnête vaut plus qu'une métrique gonflée.

<figure style="margin: 2rem 0; text-align: center;">
<img src="/assets/img/cedd/conversation-demo-fr-sombre.png" alt="Interface CEDD en mode sombre : conversation en français québécois avec badges de niveau d'alerte, jauge Orange et probabilités par classe" width="1600" height="950" loading="lazy" style="width: 100%; height: auto; border-radius: 12px;" />
<figcaption style="font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem;">L'interface en mode sombre : chaque réponse du bot porte son badge de niveau d'alerte, et les ressources de Jeunesse, J'écoute apparaissent dès l'Orange.</figcaption>
</figure>

## Projet Github cedd-hackathon complet

[CEDD Hackathon](https://github.com/dapiced/cedd-hackathon)
Binary file added assets/img/cedd/accueil-en.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cedd/accueil-fr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cedd/conversation-demo-en.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cedd/conversation-demo-fr-sombre.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cedd/conversation-demo-fr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cedd/dashboard-radar-en.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cedd/dashboard-sombre.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cedd/dashboard-streamgraph-en.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.