Einrichtung der Stimmungs- und Emotionsanalyse von Posts in Discourse AI über den selbsthosteten HuggingFace Text Embeddings Inference (TEI).
Was ist das
Sentiment in Discourse AI ist kein chat/completions LLM. Unter der Haube laufen zwei kleine klassifizierende RoBERTa-Modelle (~125 Mio. Parameter jedes), die über HuggingFace TEI ausgeführt werden. Die Modellnamen sind im Code verankert und können in SQL-Abfragen der Discourse-Dashboards nicht geändert werden.
Quelle: Self-Hosting Sentiment and Emotion for DiscourseAI (Falco, Discourse-Team).
| Modell | model_name (genau wie im Code) | Zweck |
|---|---|---|
| Sentiment | cardiffnlp/twitter-roberta-base-sentiment-latest |
positive / negative / neutral |
| Emotion | SamLowe/roberta-base-go_emotions |
28 Emotionen (joy, anger, surprise…) |
API-Format: POST {\"inputs\": \"text\", \"truncate\": true} → Array [{\"label\": \"...\", \"score\": 0.95}, ...]
Besonderheit: Das Modell cardiffnlp hat keinen tokenizer.json
TEI erfordert tokenizer.json, aber cardiffnlp/twitter-roberta-base-sentiment-latest hat keinen (alter Format: vocab.json + merges.txt). Lösung: Laden Sie die Modell-Dateien lokal herunter und fügen Sie tokenizer.json aus SamLowe/roberta-base-go_emotions hinzu (gleicher RoBERTa-base Tokenizer).
Vorbereitung (einmalig)
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"
Variante A: GPU
Bild: ghcr.io/huggingface/text-embeddings-inference:cuda-1.9.3
Der Standard-Tag
:latest(und:1.9) wurde für compute cap 80 (Ampere) kompiliert und funktioniert nicht auf Blackwell (RTX 50x0, compute cap 120). Verwenden Sie genaucuda-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
Erster Start auf Blackwell: Die JIT-Kompilierung der CUDA-Kerne dauert ca. 5 Minuten pro Container. Dies ist einmalig.
Leistung GPU (RTX 5060 Ti)
| Metrik | Wert |
|---|---|
| Sentiment-Inferenz | ~14ms |
| Emotion-Inferenz | ~60ms |
| VRAM pro Container | ~428 MB |
| VRAM insgesamt | ~856 MB |
Variante B: CPU (Fallback)
Bild: ghcr.io/huggingface/text-embeddings-inference:cpu-1.9
Geeignet, wenn kein GPU verfügbar ist oder nicht genügend VRAM vorhanden ist. Erfordert keine NVIDIA-Treiber.
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
```Bei hohem LA kann der CPU-Beschleunigung eingeschränkt werden:
```bash
docker update --cpus=0.1 tei-sentiment tei-emotion
CPU-Leistung
| Metrik | Wert |
|---|---|
| Sentiment-Inferenz | ~270 ms |
| Emotion-Inferenz | ~205 ms |
| RAM pro Container | ~500 MB |
| Mit --cpus=0.1 | ~2–3 Sekunden pro Beitrag |
Wechsel GPU ↔ CPU
docker stop tei-sentiment tei-emotion
docker rm tei-sentiment tei-emotion
Starten Sie anschließend die Container entsprechend Ihrer Wahl. Es müssen keine Einstellungen in Discourse geändert werden – die Endpoints bleiben gleich.
Prüfung
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"}'
Erwarteter Antwortwert für Sentiment: [{\"label\":\"positive\",\"score\":0.96},...]
Discourse-Einstellungen
In /admin/plugins/discourse-ai/settings?filter=sentiment:
- discourse_ai_enabled = true
- ai_sentiment_enabled = true
- ai_sentiment_model_configs – zwei Objekte:
| Feld | Modell 1 | Modell 2 |
|---|---|---|
| model_name | cardiffnlp/twitter-roberta-base-sentiment-latest |
SamLowe/roberta-base-go_emotions |
| endpoint | http://<your-host>:8081 |
http://<your-host>:8082 |
| api_key | (leer) | (leer) |
Dashboards
/admin/reports/overall_sentiment– allgemeines Stimmungsbild (positive – negative)/admin/reports/emotion_joy(und weitere 27 Emotionen)- Backfill: ~2500 Beiträge pro Stunde, Beiträge nicht älter als 60 Tage
Bedingungen und Risiken
- Die Modelle wurden auf Englisch trainiert. Für russischen Text ist das Ergebnis nur approximativ, aber der grundlegende Sentiment-Test funktioniert.
- Der Endpoint ist ohne API-Key offen – für Produktivumgebungen sollte er über einen Reverse-Proxy geschützt werden.
- VRAM-Monitoring:
nvidia-smi --query-compute-apps=pid,name,used_memory --format=csv,noheader