Configuration de l’analyse de tonalité et d’émotions des posts dans Discourse AI via l’inférence self-hosted HuggingFace Text Embeddings Inference (TEI).
Qu’est-ce que ceci
Le sentiment dans Discourse AI n’est pas un modèle LLM de type chat/completions. Il repose sur deux petites modèles classificateurs RoBERTa (~125M de paramètres chacun), exécutés via HuggingFace TEI. Les noms des modèles sont hardcodés dans les requêtes SQL des dashboards Discourse — ils ne peuvent pas être modifiés.
Source : Self-Hosting Sentiment and Emotion for DiscourseAI (Falco, équipe Discourse).
| Modèle | model_name (exactement tel que dans le code) | Fonction |
|---|---|---|
| Sentiment | cardiffnlp/twitter-roberta-base-sentiment-latest |
positif / négatif / neutre |
| Émotion | SamLowe/roberta-base-go_emotions |
28 émotions (joie, colère, surprise…) |
Format API : POST {\"inputs\": \"text\", \"truncate\": true} → tableau [{\"label\": \"...\", \"score\": 0.95}, ...]
Particularité : le modèle cardiffnlp n’a pas de tokenizer.json
TEI nécessite un tokenizer.json, mais le modèle cardiffnlp/twitter-roberta-base-sentiment-latest ne le fournit pas (ancien format : vocab.json + merges.txt). Solution : télécharger les fichiers du modèle localement et ajouter le tokenizer.json issu de SamLowe/roberta-base-go_emotions (même tokéniseur RoBERTa-base).
Préparation (une seule fois)
sudo mkdir -p /opt/tei-sentiment-cache/model
cd /opt/tei-sentiment-cache/model
for f in config.json vocab.json merges.txt special_tokens_map.json pytorch_model.bin; do
sudo curl -sL -o "$f" "https://huggingface.co/cardiffnlp/twitter-roberta-base-sentiment-latest/resolve/main/$f"
done
sudo curl -sL -o tokenizer.json "https://huggingface.co/SamLowe/roberta-base-go_emotions/resolve/main/tokenizer.json"
sudo curl -sL -o tokenizer_config.json "https://huggingface.co/SamLowe/roberta-base-go_emotions/resolve/main/tokenizer_config.json"
Option A : GPU
Image : ghcr.io/huggingface/text-embeddings-inference:cuda-1.9.3
Le tag standard
:latest(et:1.9) est compilé pour la capacité de calcul 80 (Ampere) et ne fonctionne pas sur Blackwell (RTX 50x0, capacité de calcul 120). Utilisez exactementcuda-1.9.3.
docker pull ghcr.io/huggingface/text-embeddings-inference:cuda-1.9.3
sudo mkdir -p /opt/tei-emotion-cache
docker run -d --name tei-sentiment --gpus all --shm-size 1g -p 8081:80 -v /opt/tei-sentiment-cache/model:/data/model --restart unless-stopped ghcr.io/huggingface/text-embeddings-inference:cuda-1.9.3 --model-id /data/model
docker run -d --name tei-emotion --gpus all --shm-size 1g -p 8082:80 -v /opt/tei-emotion-cache:/data --restart unless-stopped ghcr.io/huggingface/text-embeddings-inference:cuda-1.9.3 --model-id SamLowe/roberta-base-go_emotions
Première exécution sur Blackwell : la compilation JIT CUDA des noyaux prend environ 5 minutes par conteneur. Cela se fait une seule fois.
Performances GPU (RTX 5060 Ti)
| Métrique | Valeur |
|---|---|
| Inférence Sentiment | ~14 ms |
| Inférence Émotion | ~60 ms |
| VRAM par conteneur | ~428 Mo |
| VRAM pour les deux | ~856 Mo |
Option B : CPU (fallback)
Image : ghcr.io/huggingface/text-embeddings-inference:cpu-1.9
Utilisez cette option si le GPU n’est pas disponible ou si la mémoire vidéo n’est pas suffisante. Ne nécessite pas les pilotes NVIDIA.
docker pull ghcr.io/huggingface/text-embeddings-inference:cpu-1.9
sudo mkdir -p /opt/tei-emotion-cache
docker run -d --name tei-sentiment --shm-size 1g -p 8081:80 -v /opt/tei-sentiment-cache/model:/data/model --restart unless-stopped ghcr.io/huggingface/text-embeddings-inference:cpu-1.9 --model-id /data/model --dtype float32
docker run -d --name tei-emotion --shm-size 1g -p 8082:80 -v /opt/tei-emotion-cache:/data --restart unless-stopped ghcr.io/huggingface/text-embeddings-inference:cpu-1.9 --model-id SamLowe/roberta-base-go_emotions --dtype float32
```Lorsque le LA est élevé, il est possible de limiter le CPU :
```bash
docker update --cpus=0.1 tei-sentiment tei-emotion
Performance CPU
| Métrique | Valeur |
|---|---|
| Inférence sentiment | ~270 ms |
| Inférence émotion | ~205 ms |
| RAM par conteneur | ~500 Mo |
| Avec --cpus=0.1 | ~2-3 s par post |
Switch GPU ↔ CPU
docker stop tei-sentiment tei-emotion
docker rm tei-sentiment tei-emotion
Ensuite, lancez les conteneurs selon le mode souhaité. Il n’est pas nécessaire de modifier les paramètres de Discourse — les endpoints restent identiques.
Vérification
curl -s http://localhost:8081/ -X POST -H 'Content-Type: application/json' -d '{"inputs": "I am happy"}'
curl -s http://localhost:8082/ -X POST -H 'Content-Type: application/json' -d '{"inputs": "I am happy"}'
Réponse attendue pour sentiment : [{\"label\":\"positive\",\"score\":0.96},...]
Configuration de Discourse
Dans /admin/plugins/discourse-ai/settings?filter=sentiment :
- discourse_ai_enabled = true
- ai_sentiment_enabled = true
- ai_sentiment_model_configs — deux objets :
| Champ | Modèle 1 | Modèle 2 |
|---|---|---|
| model_name | cardiffnlp/twitter-roberta-base-sentiment-latest |
SamLowe/roberta-base-go_emotions |
| endpoint | http://<votre-hôte>:8081 |
http://<votre-hôte>:8082 |
| api_key | (vide) | (vide) |
Tableaux de bord
/admin/reports/overall_sentiment— sentiment général (positif - négatif)/admin/reports/emotion_joy(et d’autres 27 émotions)- Backfill : ~2500 posts/h, les posts ne doivent pas être plus anciens que 60 jours
Conditions et risques
- Les modèles ont été entraînés en anglais. Pour le texte russe, les résultats sont approximatifs, mais le sentiment de base fonctionne.
- L’endpoint est ouvert sans clé API — pour la production, fermer via un reverse proxy.
- Surveillance de la VRAM :
nvidia-smi --query-compute-apps=pid,name,used_memory --format=csv,noheader