Discourse AI Sentiment autogestionado: opciones GPU y CPU

# Discourse AI Sentiment Autogestionado: Opciones de GPU y CPU

Configuración del análisis de tono y emociones de los posts en Discourse AI mediante self-hosted HuggingFace Text Embeddings Inference (TEI).

¿Qué es esto?

Sentiment en Discourse AI no es un modelo LLM de chat/completions. Bajo el capó, hay dos pequeñas modelos clasificadores RoBERTa (~125M de parámetros cada uno), que se ejecutan a través de HuggingFace TEI. Los nombres de los modelos están hardcodeados en las consultas SQL de los dashboards de Discourse — no se pueden cambiar.

Fuente: Self-Hosting Sentiment and Emotion for DiscourseAI (Falco, equipo de Discourse).

Modelo model_name (exactamente como en el código) Propósito
Sentiment cardiffnlp/twitter-roberta-base-sentiment-latest positivo / negativo / neutral
Emotion SamLowe/roberta-base-go_emotions 28 emociones (alegría, ira, sorpresa…)

Formato de API: POST {\"inputs\": \"text\", \"truncate\": true} → array [{\"label\": \"...\", \"score\": 0.95}, ...]

Característica: el modelo cardiffnlp no tiene tokenizer.json

TEI requiere tokenizer.json, pero el modelo cardiffnlp/twitter-roberta-base-sentiment-latest no lo tiene (formato antiguo: vocab.json + merges.txt). Solución: descargar los archivos del modelo localmente y añadir tokenizer.json del modelo SamLowe/roberta-base-go_emotions (el mismo tokenizador RoBERTa-base).

Preparación (una sola vez)

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"

Opción A: GPU

Imagen: ghcr.io/huggingface/text-embeddings-inference:cuda-1.9.3

La etiqueta estándar :latest (y :1.9) está compilada para compute cap 80 (Ampere) y no funciona en Blackwell (RTX 50x0, compute cap 120). Usa específicamente 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

Primera ejecución en Blackwell: la compilación JIT de los núcleos CUDA toma ~5 minutos en el contenedor. Esto es una sola vez.

Rendimiento GPU (RTX 5060 Ti)

Métrica Valor
Inferencia de Sentiment ~14ms
Inferencia de Emotion ~60ms
VRAM por contenedor ~428 MB
VRAM por ambos ~856 MB

Opción B: CPU (fallback)

Imagen: ghcr.io/huggingface/text-embeddings-inference:cpu-1.9

Adecuado si no hay GPU disponible o si la VRAM es insuficiente. No requiere controladores 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
```Cuando el LA es alto, se puede limitar el CPU:

```bash
docker update --cpus=0.1 tei-sentiment tei-emotion

Rendimiento del CPU

Métrica Valor
Inferencia de Sentiment ~270ms
Inferencia de Emoción ~205ms
RAM por contenedor ~500 MB
Con --cpus=0.1 ~2-3s por post

Cambiar GPU ↔ CPU

docker stop tei-sentiment tei-emotion
docker rm tei-sentiment tei-emotion

Luego, inicie los contenedores según la configuración deseada. No es necesario cambiar las configuraciones de Discourse — los endpoints son los mismos.

Verificación

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"}'

Respuesta esperada para sentiment: [{\"label\":\"positive\",\"score\":0.96},...]

Configuración de Discourse

En /admin/plugins/discourse-ai/settings?filter=sentiment:

  1. discourse_ai_enabled = true
  2. ai_sentiment_enabled = true
  3. ai_sentiment_model_configs — dos objetos:
Campo Modelo 1 Modelo 2
model_name cardiffnlp/twitter-roberta-base-sentiment-latest SamLowe/roberta-base-go_emotions
endpoint http://<tu-host>:8081 http://<tu-host>:8082
api_key (vacío) (vacío)

Paneles de control

  • /admin/reports/overall_sentiment — estado general (positivo - negativo)
  • /admin/reports/emotion_joy (y otras 27 emociones)
  • Backfill: ~2500 posts/hora, posts no mayores a 60 días

Condiciones y riesgos

  • Los modelos están entrenados en inglés. Para texto en ruso, el resultado es aproximado, pero el sentiment básico funciona.
  • El endpoint está abierto sin api_key — para producción, cierre mediante un reverse proxy.
  • Monitoreo de VRAM: nvidia-smi --query-compute-apps=pid,name,used_memory --format=csv,noheader