Discourse AI Sentiment auto-hébergé : options GPU et CPU

# Sentiment Discourse AI auto-hébergé : options GPU et CPU

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 exactement cuda-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 :

  1. discourse_ai_enabled = true
  2. ai_sentiment_enabled = true
  3. 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