Ir al contenido

EmoParse

Análisis semiótico de emociones en discursos

v0.7.0BetaLicencia MIT

Empezar

EmoParse se instala una vez y se usa escribiendo comandos en la consola de la computadora. Los tutoriales del repositorio indican exactamente qué escribir en cada paso. Esta página describe qué hace cada cosa.

La consola

La consola, también llamada terminal o línea de comandos, es una ventana donde se le dan órdenes escritas a la computadora en lugar de hacer clic. Viene incluida en Windows, macOS y Linux. Todo lo que sigue son líneas para escribir ahí y apretar Enter.

1Qué hace falta

Python 3.11 o posterior
El lenguaje en el que está escrito EmoParse. Se descarga del sitio oficial y se instala como cualquier otro programa.
Git
Un programa para descargar y mantener actualizado el código desde el repositorio.
Alrededor de 20 GB de disco
Los modelos de lenguaje son archivos grandes y se guardan en la computadora.
Una placa de video, recomendada
La placa de video es el componente que hace muchos cálculos en paralelo. Los modelos de lenguaje están hechos para aprovecharla, así que con placa el análisis va bastante más rápido. Sin placa el programa funciona igual, con el procesador común, pero un corpus grande puede tardar mucho.1

2Instalar

Tres pasos: traer el código, armarle un espacio propio, e instalarlo.

# 1. Traer el código
git clone https://github.com/alexdcolman/EmoParse.git
cd EmoParse

# 2. Crear un espacio aislado para las bibliotecas del programa
python -m venv .venv
source .venv/bin/activate        # Linux y macOS
# .venv\Scripts\activate       # Windows

# 3. Instalar
pip install -e ".[llamacpp,ui,scraping]"

El espacio aislado del segundo paso evita que las bibliotecas de EmoParse interfieran con las de otros programas de la misma computadora. Hay que activarlo cada vez que se abra una consola nueva.

Lo que va entre corchetes en el tercer paso son los agregados opcionales. Cada uno suma una capacidad y se instala solo si hace falta.

AgregadoPara qué
llamacppCorrer modelos de lenguaje localmente.
lmstudioUsar modelos a través de LM Studio, mediante su API compatible con OpenAI.
openai / anthropicUsar APIs remotas de forma explícita por stage. No requieren un extra de Python.
uiEl tablero de exploración.
scrapingBajar discursos presidenciales y artículos periodísticos de sitios web.
nlpAnálisis gramatical, que usa la etapa de modalidad referencial.
blueskyAdquirir posts de Bluesky. Mastodon no requiere agregado.
technoLectura de emojis compuestos de varios símbolos.
networkAnálisis de redes entre cuentas.
embeddingsAgrupamiento de textos por parecido de contenido. Pesado; opcional.
allTodo lo anterior.

El backend llama_server usa el cliente HTTP incluido en la instalación base; no necesita un agregado de Python. El ejecutable llama-server se obtiene con llama.cpp. Una compilación CUDA mínima puede hacerse fuera del repositorio de EmoParse:

git clone https://github.com/ggml-org/llama.cpp.git ~/tools/llama.cpp
cd ~/tools/llama.cpp
cmake -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release --target llama-server -j "$(nproc)"
./build/bin/llama-server --version

Si el alias del modelo declara también la ruta del GGUF, EmoParse puede mostrar el comando efectivo, iniciarlo en primer plano y comprobar después la salud y los slots observables del servidor. Si el binario no está en PATH, se puede pasar su ruta con --binary.

# Revisar sin iniciar nada
emoparse server --config config.yaml --model mi-modelo-server --dry-run

# Iniciar en primer plano
emoparse server --config config.yaml --model mi-modelo-server

# Comprobar desde otra terminal
emoparse server --config config.yaml --model mi-modelo-server --check

server_parallel declara los slots del servidor y pipeline.parallel la concurrencia solicitada por EmoParse. En modelos MoE, cpu_moe o n_cpu_moe permiten declarar la descarga de expertos a CPU para llama_server; no se aplican al backend en proceso llama_cpp. cache_reuse sólo debe activarse cuando el contexto del modelo lo admite; si llama.cpp informa que lo desactiva al iniciar, conviene declararlo en 0.

APIs remotas opcionales

EmoParse también puede ejecutar una stage con OpenAI o Anthropic. Es una opción explícita: el routing local no cambia y sólo los prompts de las stages asignadas a un alias remoto se envían al proveedor. Las claves se leen desde variables de entorno y se omiten del snapshot persistido del run.

export OPENAI_API_KEY="..."
export ANTHROPIC_API_KEY="..."

# En config.yaml
models:
  mi-openai:
    backend: openai
    model_id: gpt-model-id
    api_key_env: OPENAI_API_KEY

  mi-anthropic:
    backend: anthropic
    model_id: claude-model-id
    api_key_env: ANTHROPIC_API_KEY

Los campos opcionales precio_input y precio_output expresan USD por millón de tokens y permiten guardar un costo estimado en las métricas. No hay precios predefinidos porque cambian según proveedor y modelo. El cache de EmoParse se mantiene y --budget-tokens sigue contando únicamente tokens nuevos.

La etapa de modalidad referencial necesita además un modelo gramatical del español, que se baja una vez:

pip install -e ".[nlp]"
python -m spacy download es_core_news_md

Instalar dentro de un contenedor

También se puede aislar la instalación con Docker. El perfil cpu sirve para el tablero y para backends accesibles por API; el perfil cuda agrega llama-cpp-python compilado con CUDA para modelos locales. Ambos se construyen desde el repositorio y mantienen los modelos, corpus, configuraciones y bases fuera de la imagen.

docker build -f docker/Dockerfile.cpu -t emoparse:cpu .
docker build -f docker/Dockerfile.cuda -t emoparse:cuda .

# Comprobar la imagen sin cargar un modelo
python scripts/container_smoke.py --profile cpu --image emoparse:cpu --no-build
python scripts/container_smoke.py --profile cuda --image emoparse:cuda --no-build

Las etiquetas se crean en la computadora donde se hace el build. Los modelos GGUF se montan desde afuera, por ejemplo sobre /models; los resultados persistentes se escriben en un directorio montado sobre /runs. El perfil CUDA requiere NVIDIA Container Toolkit y acceso explícito a la GPU con --gpus all; las bibliotecas del driver se inyectan desde el host al iniciar el contenedor.

3Los modelos

EmoParse no incluye los modelos de lenguaje: se descargan por separado y se guardan en la carpeta models/. Vienen en un formato comprimido que permite usarlos en computadoras comunes, a costa de una pérdida mínima de precisión.2

ModeloTamañoPara qué etapas
qwen3-14b~9 GBDetección de emociones, actores, situación de habla, caracterización.
qwen3-30b-a3b~18 GBResumen de textos largos.
phi-4-mini-instruct~2 GBTareas de ficha simple, como el tipo de discurso.

Un modelo distinto por etapa es la configuración habitual: las tareas de ficha breve no justifican un modelo grande. Con el backend llama_cpp, el programa carga y descarga los modelos dentro del mismo proceso a medida que cambia de etapa. También puede conectarse a un servidor local llama-server o a LM Studio mediante una API compatible con OpenAI; en los tres casos las respuestas mantienen el mismo contrato estructurado.

4Configurar

La configuración vive en un archivo de texto que se copia del ejemplo incluido y se edita. Ahí se indican dónde están los modelos, qué modelo usa cada etapa, de a cuántas unidades se procesa por vez y dónde se guardan los resultados.

cp config.example.yaml config.yaml

5Un primer análisis

La entrada mínima es una planilla con dos columnas: un identificador único por texto y el texto en sí. El género elegido determina cómo se segmenta y qué contexto acompaña cada unidad.

Discursos presidenciales

# Bajar discursos de Casa Rosada
emoparse scrape --source casarosada \
  --output data/discursos.csv \
  --from 2024-01-01 --to 2024-12-31

# Correr el análisis
emoparse run \
  --config config.yaml \
  --input data/discursos.csv \
  --genre discurso_presidencial \
  --run-id mi_primer_analisis

Artículos periodísticos

# Bajar artículos de Página/12
emoparse scrape --source pagina12 \
  --max 24 \
  --output data/articulos.csv

# Correr el análisis por párrafos
emoparse run \
  --config config.yaml \
  --input data/articulos.csv \
  --genre articulo_periodistico \
  --run-id articulos01

Corpus tabulares propios

Un CSV no tiene que usar de antemano los mismos nombres de columnas que EmoParse. Antes de analizarlo, doctor puede revisar codificación, delimitador, fila de encabezado, identificadores, contenido, fechas y restos de HTML sin modificar el archivo. ingest-map propone después un YAML editable de correspondencia de columnas; solo ese archivo, cuando se pasa explícitamente a run, se usa para la ingesta.

# Diagnosticar sin escribir el corpus
emoparse doctor --input corpus_externo.csv --genre discurso_presidencial

# Crear una propuesta y revisarla a mano
emoparse ingest-map --input corpus_externo.csv --out mapping.yaml

# Verificar el mapping editado
emoparse doctor --input corpus_externo.csv --mapping mapping.yaml

# Usarlo en la corrida
emoparse run --config config.yaml --input corpus_externo.csv \
  --run-id corpus01 --mapping mapping.yaml

Las columnas que no forman parte de esa correspondencia se conservan como metadata del input. El archivo original no se reescribe.

El tutorial de discursos presidenciales y el tutorial de artículos periodísticos desarrollan ambos recorridos paso por paso.

# Ver cómo viene, desde otra consola
emoparse status --db runs/mi_primer_analisis.sqlite

# Abrir el tablero
emoparse app

Conviene correr por bloques y revisar cada resultado antes de seguir, en lugar de lanzar todo de una vez. Las etapas se eligen con --stages:

emoparse run \
  --config config.yaml \
  --input data/discursos.csv \
  --genre discurso_presidencial \
  --run-id mi_primer_analisis \
  --resume \
  --stages summarizer,metadata,enunciation,actors,emotions,explode_emotions

También se puede acotar una corrida con un YAML sin modificar el corpus original. Los campos del input se filtran al comienzo; los resultados de etapas anteriores se referencian con notación punto, como metadata.tipo_discurso o enunciation.enunciador.nombre, y empiezan a filtrar recién después de que la etapa productora queda completa. Una ejecución posterior sin selector retoma lo que quedó afuera sin repetir resultados persistidos.

emoparse run --config config.yaml --input data/discursos.csv \
  --run-id prueba_acotada \
  --select data/ejemplos/seleccion_payload_v070.yaml

El comando emoparse status distingue lo pendiente, lo no aplicable y lo excluido por el selector en cada etapa.

Si la corrida debe respetar un techo de uso, --budget-tokens N fija un presupuesto acumulado para esa base. Al alcanzarlo, el run queda pausado y se puede continuar con --resume y un techo mayor; las respuestas recuperadas de cache no vuelven a sumar tokens.

Dónde queda todo

Cada análisis produce un archivo único en la carpeta runs/, con el nombre que se le haya dado. Ese archivo contiene el texto de entrada, todos los resultados intermedios y las versiones exactas de las instrucciones y las categorías que se usaron. Copiarlo a otra computadora alcanza para reproducir la exploración completa.

6Un corpus de posts

Para posts de redes sociales, el corpus se adquiere primero y se analiza después, con la indicación del género. La adquisición admite Bluesky, Mastodon y la API oficial de X, además de importar dumps JSONL o CSV.

# 1. Adquirir
emoparse acquire --source bluesky --query "#tarifazo" --lang es \
    --max 500 --out data/tarifazo.jsonl

# 2. Analizar
emoparse run --config config.yaml --genre tuit \
    --input data/tarifazo.jsonl --run-id tarifazo01

# 3. Redes entre cuentas
emoparse network --db runs/tarifazo01.sqlite \
    --flujo --similitud --export-dir exports/red

Los detalles del género, sus etapas propias y las opciones de adquisición están en Posts y redes y en el tutorial de tuits y discurso nativo digital.

7Los comandos

El programa se maneja con un puñado de comandos. Los tres que se usan casi siempre son emoparse run, que corre el análisis; emoparse status, que informa qué quedó pendiente y qué falló; y emoparse app, que abre el tablero. Los demás cubren la adquisición de corpus, el análisis de redes, la validación y la exportación.

La lista completa, con todas las opciones de cada comando, está en Comandos. Todos aceptan además --help, que imprime lo mismo en la consola.

8Si algo falla

Se queda sin memoria al cargar el modelo

Hay tres salidas, de menor a mayor pérdida: reducir cuánto del modelo se carga en la placa de video, reducir el tamaño de texto que el modelo lee de una vez, o usar una versión más comprimida del mismo modelo.

Avisa que el texto excede el límite, pero el texto no parece largo

Puede ocurrir por dos razones. Una es que las instrucciones más el texto superen lo que el modelo admite de una vez. La otra es que el modelo no haya terminado de cerrar su respuesta dentro del límite de longitud fijado. El mensaje de error informa cuál de las dos fue. Las instrucciones de lectura se pueden acortar sin tocar el programa: están en archivos de texto aparte.

Algunas unidades salen sin ninguna emoción

Es un resultado legítimo si no hay emoción que detectar. Si ocurre de manera sistemática en unidades con emoción evidente, conviene revisar tres cosas: que la lista de categorías cubra ese tipo de emoción, que las indicaciones de lectura contemplen el caso, y que el modelo elegido no esté por debajo de lo que la tarea exige.

Los resultados no se repiten entre corridas

El manejo de la semilla de azar cambió entre versiones de la biblioteca que corre los modelos. Al actualizarla conviene volver a verificar que dos corridas idénticas den lo mismo.

El tablero no encuentra la corrida

El tablero busca en la carpeta indicada en la configuración. Conviene abrirlo desde el mismo directorio donde se corrió el análisis.

Los tres tutoriales del repositorio recorren casos completos paso a paso: discursos presidenciales, artículos periodísticos y posts de redes sociales.

Notas

  1. Para la configuración estándar hacen falta unos 12 GB de memoria en la placa de video. Los modelos más grandes requieren una placa mayor, o repartir el trabajo entre la placa y la memoria común, lo que funciona a menor velocidad. El análisis de redes y la adquisición de corpus no usan la placa en absoluto.
  2. La compresión se llama cuantización: reduce la precisión numérica interna del modelo, con lo que ocupa menos espacio y corre más rápido. Las variantes recomendadas conservan la calidad de las respuestas para estas tareas.