Skip to content
Support

Sentiment & Emotions

Hub can classify open-text feedback into a sentiment label and score, and into the emotions it expresses, and store them on the feedback record for analytics and filtering.

Hub can enrich open-text feedback with two related classifications: sentiment — the overall polarity of the text — and emotions — the specific emotions it expresses. Both run asynchronously and are stored on the same feedback record, so you can filter, segment, and aggregate qualitative feedback without reading every response.

They are independent enrichments: a deployment can run either, both, or neither, and each is separately gated per tenant.

Sentiment and emotions add three read-only fields to every feedback record. All are server-generated — you never set them when creating or updating a record — and are null until the record is enriched.

FieldTypeDescription
sentimentStringOverall sentiment label of the text (for example positive, neutral, negative).
sentiment_scoreNumberSigned polarity from -1.0 (most negative) to 1.0 (most positive).
emotionsArray of StringThe emotions the text expresses; empty when none clearly apply (stored as null, never []).

See the API Reference for the exact sentiment and emotions value sets.

Each enrichment runs only where the deployment has a provider configured — an operator sets SENTIMENT_PROVIDER + SENTIMENT_MODEL and/or EMOTIONS_PROVIDER + EMOTIONS_MODEL (plus provider credentials); see Environment Variables. With no provider, that enrichment is off for the whole deployment.

Where a provider is configured, each enrichment is on by default per tenant and can be turned off with the sentiment_enabled / emotions_enabled switches. Setting a switch to false stops Hub producing that enrichment for the tenant going forward; unset (or null) means enabled.

When a text feedback record is created, or its value_text changes, Hub enqueues the enrichment jobs for whichever of sentiment and emotions are enabled. A background worker calls the provider and writes the result back to the record. The work happens off the ingestion path, so creating feedback is never slowed down or blocked.

  • Only open text is classified — records whose field_type is text with a non-empty value_text. Numeric, boolean, date, and categorical answers are left untouched.
  • Edits re-classify. Changing value_text clears the stored sentiment/emotions and re-runs the classification; emptying value_text clears them without re-running. During the brief window between the edit and the worker finishing, the fields read back as null (recomputing) rather than a stale value.
  • A record can express several emotions, or none. emotions is a set (order is not significant); “no clear emotion” is null, not an empty array.

Enrichment runs automatically on new and edited records. To (re)classify an existing backlog — after first enabling an enrichment, or to recover records whose job was lost or finally failed — run the bundled backfill for the type, which enqueues jobs for records missing that classification:

Terminal window
# Run inside the Hub deployment, with the SENTIMENT_*/EMOTIONS_* provider and DATABASE_URL configured
./backfill-classify -type sentiment
./backfill-classify -type emotions

It is safe to re-run: records already classified are skipped. Re-enabling a tenant’s switch does not re-classify its backlog on its own — run the backfill to catch records edited while the enrichment was off.

Relationship to translation and embeddings

Section titled “Relationship to translation and embeddings”

Sentiment and emotions are independent of translation and of the embeddings used for semantic search. All classify the original, source-language value_text; enabling or disabling one does not affect the others.

Because the results live on the record, you can filter and aggregate straight from SQL or any connected BI tool:

SELECT sentiment, COUNT(*)
FROM feedback_records
WHERE field_type = 'text'
AND tenant_id = 'org-123'
AND sentiment IS NOT NULL
GROUP BY sentiment;