EmotiSpace-128 is a BERT-based hybrid emotion model that maps text into a 128-dimensional emotional embedding space and also predicts GoEmotions-style emotion labels.
It is not only a classifier. The main goal is to produce a reusable emotional latent space where similar emotional meanings are close together, while still exposing readable emotion probabilities.
1import torch
2from transformers import AutoModel, AutoTokenizer
34model_id ="lunahr/emotispace-128"5tokenizer = AutoTokenizer.from_pretrained(model_id)6model = AutoModel.from_pretrained(7 model_id,8 trust_remote_code=True,9)10device ="cuda"if torch.cuda.is_available()else"cpu"11model.to(device)12model.eval()1314@torch.no_grad()15defanalyze(texts, top_k=5):16ifisinstance(texts,str):17 texts =[texts]18 tokens = tokenizer(19 texts,20 return_tensors="pt",21 padding=True,22 truncation=True,23 max_length=128,24).to(device)25 out = model(**tokens)26 embeddings = out["embeddings"].cpu()27 probs = out["probs"].cpu()28 results =[]29for i, text inenumerate(texts):30 top = torch.topk(probs[i], k=top_k)31 results.append({32"text": text,33"embedding": embeddings[i],34"labels":[35{36"label": model.config.label_names[idx.item()],37"score": score.item(),38}39for score, idx inzip(top.values, top.indices)40],41})42return results
4344for item in analyze([45"I feel devastated.",46"This is amazing, I am so happy!",47]):48print(item["text"])49print(item["embedding"].shape)50print(item["labels"])51print()
Example behavior
Example output:
py
1I feel devastated.2embedding shape: torch.Size([128])3sadness, remorse, disappointment, grief
4This is amazing, I am so happy!
5embedding shape: torch.Size([128])6joy, excitement, admiration, love
The embedding space can also separate emotional and non-emotional text. For example, emotionally charged text can be far away from factual neutral sentences like:
The table is made of wood.
Notes on embeddings
The 128D embedding is normalized and can be compared with cosine similarity.
Example use:
similarity = embedding_a @ embedding_b.T
The embedding space is designed to support emotional similarity, not just exact label matching.
For example:
"I feel devastated."
should be close to:
"I am so sad I could cry."
and far from:
"This is amazing, I am so happy!"
Limitations
This model is trained from English text and should be treated as English-first.
It is based on GoEmotions-style labels, so the classifier output is limited to that label space. The embedding space is more flexible, but custom emotion anchors should still be tested carefully.
The model does not actually “feel” emotions. It estimates emotional meaning from text.
Embeddings are useful for similarity and downstream control, but they are not a psychological diagnosis or a reliable mental health assessment tool.
Suggested downstream design
A recommended pattern is:
text
1recent messages
2-> EmotiSpace embeddings
3-> weighted rolling mood embedding
4-> compare against persona-agnostic emotion anchors
5-> map to character response style or TTS controls
Keep emotion anchors persona-agnostic. Define what the emotion means generally, not how a specific character expresses it.
Good anchor style:
A calm emotional state with low tension, steady energy, and no urgency.
Avoid persona-specific anchors like:
Luna feels calm and wants to comfort you.
This prevents one character’s style from leaking into unrelated characters.
Citation
This model is based on BERT and trained using GoEmotions-style emotion supervision.