Text Classification
Transformers
Safetensors
English
Russian
xlm-roberta
emotion-classification
multi-label-classification
goemotions
english
russian
affective-computing
text-embeddings-inference
Instructions to use proxy3d/multi-motions-28 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use proxy3d/multi-motions-28 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="proxy3d/multi-motions-28")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("proxy3d/multi-motions-28") model = AutoModelForSequenceClassification.from_pretrained("proxy3d/multi-motions-28", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download app.py from proxy3d/multi-motions-28: direct link, hf CLI and curl.
- Browser
- Download file 6.08 kB
-
https://huggingface.co/proxy3d/multi-motions-28/resolve/main/app.py
- Command line
-
hf download hf://proxy3d/multi-motions-28/app.py
-
curl -L -o app.py https://huggingface.co/proxy3d/multi-motions-28/resolve/main/app.py
6.08 kB
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| import gradio as gr | |
| import pandas as pd | |
| import torch | |
| from huggingface_hub import hf_hub_download | |
| from transformers import AutoModelForSequenceClassification, AutoTokenizer | |
| MODEL_ID = "proxy3d/multi-motions-28" | |
| MAX_LENGTH = 64 | |
| DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, use_fast=True) | |
| model = AutoModelForSequenceClassification.from_pretrained(MODEL_ID) | |
| model.to(DEVICE) | |
| model.eval() | |
| # Prefer the thresholds published with the model. Fall back to 0.5 if unavailable. | |
| try: | |
| thresholds_path = hf_hub_download( | |
| repo_id=MODEL_ID, | |
| filename="thresholds.json", | |
| repo_type="model", | |
| ) | |
| with open(thresholds_path, "r", encoding="utf-8") as f: | |
| THRESHOLDS = json.load(f) | |
| except Exception: | |
| THRESHOLDS = {} | |
| ID2LABEL = { | |
| int(k): v for k, v in model.config.id2label.items() | |
| } | |
| LABELS = [ID2LABEL[i] for i in range(len(ID2LABEL))] | |
| def _predict_scores(text: str) -> list[tuple[str, float]]: | |
| text = (text or "").strip() | |
| if not text: | |
| return [] | |
| encoded = tokenizer( | |
| text, | |
| return_tensors="pt", | |
| truncation=True, | |
| max_length=MAX_LENGTH, | |
| ) | |
| encoded = {k: v.to(DEVICE) for k, v in encoded.items()} | |
| with torch.inference_mode(): | |
| logits = model(**encoded).logits[0] | |
| probs = torch.sigmoid(logits).detach().cpu().float().tolist() | |
| return [(ID2LABEL[i], float(probs[i])) for i in range(len(probs))] | |
| def predict(text: str): | |
| scores = _predict_scores(text) | |
| if not scores: | |
| empty = pd.DataFrame(columns=["emotion", "score", "threshold", "active"]) | |
| return ( | |
| "Введите текст / Enter text.", | |
| empty, | |
| empty, | |
| ) | |
| rows = [] | |
| active = [] | |
| for label, score in scores: | |
| threshold = float(THRESHOLDS.get(label, 0.5)) | |
| is_active = score >= threshold | |
| rows.append( | |
| { | |
| "emotion": label, | |
| "score": score, | |
| "threshold": threshold, | |
| "active": "✓" if is_active else "", | |
| } | |
| ) | |
| if is_active: | |
| active.append((label, score)) | |
| rows.sort(key=lambda x: x["score"], reverse=True) | |
| top_df = pd.DataFrame(rows[:10]) | |
| all_df = pd.DataFrame(rows) | |
| if active: | |
| active.sort(key=lambda x: x[1], reverse=True) | |
| active_text = ", ".join(f"**{label}** ({score:.3f})" for label, score in active) | |
| summary = f"### Активные эмоции / Active labels\n{active_text}" | |
| else: | |
| top_label, top_score = rows[0]["emotion"], rows[0]["score"] | |
| summary = ( | |
| "### Активные эмоции / Active labels\n" | |
| "Ни один класс не превысил свой tuned threshold. " | |
| f"Максимальный score: **{top_label}** ({top_score:.3f})." | |
| ) | |
| return summary, top_df, all_df | |
| EXAMPLES = [ | |
| ["Я боюсь опоздать на рейс."], | |
| ["Мне наконец ответили — какое облегчение."], | |
| ["Спасибо, это действительно очень помогло."], | |
| ["Я совсем не понимаю, почему это произошло."], | |
| ["I'm worried I'll miss my flight."], | |
| ["Thank you so much, this really helped me."], | |
| ["I can't believe this actually happened!"], | |
| ["I'm disappointed, but I understand the decision."], | |
| ] | |
| with gr.Blocks(title="Multi-Motions 28 — EN/RU Emotion Classifier") as demo: | |
| gr.Markdown( | |
| """ | |
| # Multi-Motions 28 | |
| **English + Russian · 28 GoEmotions classes · multi-label emotion classification** | |
| Введите английский или русский текст. Модель возвращает полный вектор confidence scores, | |
| а также labels, прошедшие индивидуальные tuned thresholds. | |
| **Model:** [proxy3d/multi-motions-28](https://huggingface.co/proxy3d/multi-motions-28) | |
| **Author:** Ilya Zelenskiy (proxy3d) / Илья Зеленский (proxy3d) | |
| **Telegram:** [t.me/greenruff](https://t.me/greenruff) | |
| **Communication Styles LLM:** | |
| [Article](https://iproxy3d.github.io/communication-styles-llm/) · | |
| [GitHub](https://github.com/iproxy3d/communication-styles-llm) | |
| """ | |
| ) | |
| text = gr.Textbox( | |
| label="Text / Текст", | |
| placeholder="Введите сообщение на русском или английском...", | |
| lines=4, | |
| ) | |
| run = gr.Button("Analyze / Анализировать", variant="primary") | |
| summary = gr.Markdown() | |
| gr.Markdown("### Top-10 scores") | |
| top_table = gr.Dataframe( | |
| headers=["emotion", "score", "threshold", "active"], | |
| datatype=["str", "number", "number", "str"], | |
| interactive=False, | |
| ) | |
| with gr.Accordion("All 28 scores / Все 28 классов", open=False): | |
| all_table = gr.Dataframe( | |
| headers=["emotion", "score", "threshold", "active"], | |
| datatype=["str", "number", "number", "str"], | |
| interactive=False, | |
| ) | |
| gr.Examples( | |
| examples=EXAMPLES, | |
| inputs=text, | |
| label="Examples / Примеры", | |
| ) | |
| gr.Markdown( | |
| """ | |
| --- | |
| ### Notes | |
| - Scores are sigmoid outputs for all 28 GoEmotions labels. | |
| - This is a **multi-label** classifier: more than one emotion may be active. | |
| - The `active` column uses the per-label thresholds published with the model. | |
| - Native-Russian transfer was additionally evaluated on CEDR and SemEval-2025 RU. | |
| For implementation details, benchmarks and usage examples, see the | |
| [model page](https://huggingface.co/proxy3d/multi-motions-28). | |
| """ | |
| ) | |
| run.click( | |
| fn=predict, | |
| inputs=text, | |
| outputs=[summary, top_table, all_table], | |
| ) | |
| text.submit( | |
| fn=predict, | |
| inputs=text, | |
| outputs=[summary, top_table, all_table], | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |