Marwan-Tamer commited on
Commit
1997a7a
·
1 Parent(s): adf1a37

Use local emotion model only

Browse files
src/models/emotion_classifier.py CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
2
 
3
  import argparse
4
  import json
 
5
  import re
6
  from pathlib import Path
7
  from typing import Any
@@ -27,8 +28,12 @@ def _load_transformer_stack() -> tuple[Any, Any, Any]:
27
  class EmotionClassifier:
28
  """Transformer emotion classifier with confidence and simple word-occlusion explanations."""
29
 
30
- def __init__(self, model_dir: str | Path = DEFAULT_MODEL_DIR) -> None:
31
- self.model_dir = Path(model_dir)
 
 
 
 
32
  self.torch = None
33
  self.tokenizer = None
34
  self.model = None
@@ -46,6 +51,7 @@ class EmotionClassifier:
46
  self.tokenizer = tokenizer_cls.from_pretrained(self.model_dir)
47
  self.model = model_cls.from_pretrained(self.model_dir)
48
  self.model.eval()
 
49
 
50
  config_labels = self.model.config.id2label
51
  self.id2label = {int(key): value for key, value in config_labels.items()}
 
2
 
3
  import argparse
4
  import json
5
+ import os
6
  import re
7
  from pathlib import Path
8
  from typing import Any
 
28
  class EmotionClassifier:
29
  """Transformer emotion classifier with confidence and simple word-occlusion explanations."""
30
 
31
+ def __init__(
32
+ self,
33
+ model_dir: str | Path | None = None,
34
+ ) -> None:
35
+ self.model_dir = Path(model_dir or os.getenv("EMOTION_MODEL_DIR", DEFAULT_MODEL_DIR))
36
+ self.active_model_source = str(self.model_dir)
37
  self.torch = None
38
  self.tokenizer = None
39
  self.model = None
 
51
  self.tokenizer = tokenizer_cls.from_pretrained(self.model_dir)
52
  self.model = model_cls.from_pretrained(self.model_dir)
53
  self.model.eval()
54
+ self.active_model_source = str(self.model_dir)
55
 
56
  config_labels = self.model.config.id2label
57
  self.id2label = {int(key): value for key, value in config_labels.items()}
src/models/emotion_detector_ui.py CHANGED
@@ -30,46 +30,63 @@ CSS = """
30
  padding: 12px 14px;
31
  background: #fff1f2;
32
  }
 
 
 
 
 
 
 
 
 
 
33
  """
34
 
35
 
36
  def model_status() -> str:
37
- model_dir = Path(DEFAULT_MODEL_DIR)
38
  if model_dir.exists():
39
- return f"<div class='status-box'>Model ready: <code>{model_dir}</code></div>"
 
 
 
 
 
 
 
 
 
40
  return (
41
- "<div class='missing-box'>Emotion model is not available locally yet. "
42
- "Run the Module 2 Colab notebook, then copy the generated "
43
- "<code>saved_emotion_model</code> folder to "
44
- f"<code>{model_dir}</code>.</div>"
45
  )
46
 
47
 
48
- def predict_emotion(text: str) -> tuple[dict, str]:
 
 
 
49
  try:
50
  result = classifier.explain(text or "", top_k=6)
51
  emotion = result["prediction"]["emotion"]
52
  confidence = result["prediction"]["confidence"]
53
- status = f"<div class='status-box'>Predicted <b>{emotion}</b> with {confidence:.1%} confidence.</div>"
54
- return result, status
55
- except FileNotFoundError:
56
- return (
57
- {
58
- "error": "Emotion model not found locally.",
59
- "expected_model_path": str(DEFAULT_MODEL_DIR),
60
- "next_step": "Run notebooks/module_2_emotion_training.ipynb in Colab and copy src/models/saved_emotion_model back into this project.",
61
- },
62
- model_status(),
63
  )
 
 
 
 
 
64
  except ImportError as exc:
65
- return (
66
- {
67
- "error": "Missing Python dependency.",
68
- "details": str(exc),
69
- "next_step": "Install dependencies with python -m pip install -r requirements.txt.",
70
- },
71
- "<div class='missing-box'>Missing dependency. Install project requirements.</div>",
72
- )
73
 
74
 
75
  with gr.Blocks(title="Emotion Classifier") as interface:
@@ -91,13 +108,19 @@ with gr.Blocks(title="Emotion Classifier") as interface:
91
  )
92
  analyze_button = gr.Button("Analyze emotion", variant="primary")
93
  with gr.Column(scale=4):
94
- result_output = gr.JSON(label="Prediction")
 
 
 
 
 
 
95
  summary_output = gr.HTML()
96
 
97
  analyze_button.click(
98
  fn=predict_emotion,
99
  inputs=text_input,
100
- outputs=[result_output, summary_output],
101
  )
102
 
103
 
 
30
  padding: 12px 14px;
31
  background: #fff1f2;
32
  }
33
+ .emotion-card {
34
+ border: 1px solid #d4d4d8;
35
+ padding: 16px;
36
+ background: white;
37
+ }
38
+ .emotion-value {
39
+ font-size: 28px;
40
+ font-weight: 700;
41
+ color: #0f766e;
42
+ }
43
  """
44
 
45
 
46
  def model_status() -> str:
47
+ model_dir = Path(os.getenv("EMOTION_MODEL_DIR", DEFAULT_MODEL_DIR))
48
  if model_dir.exists():
49
+ return f"<div class='status-box'>Using local trained model: <code>{model_dir}</code></div>"
50
+ return (
51
+ "<div class='missing-box'>Local emotion model is not available at "
52
+ f"<code>{model_dir}</code>. Copy the trained "
53
+ "<code>saved_emotion_model</code> folder there, or set "
54
+ "<code>EMOTION_MODEL_DIR</code> to its current location.</div>"
55
+ )
56
+
57
+
58
+ def _empty_result(message: str) -> tuple[str, list[list[str | float]], str]:
59
  return (
60
+ f"<div class='missing-box'>{message}</div>",
61
+ [],
62
+ model_status(),
 
63
  )
64
 
65
 
66
+ def predict_emotion(text: str) -> tuple[str, list[list[str | float]], str]:
67
+ if not (text or "").strip():
68
+ return _empty_result("Please enter a message to analyze.")
69
+
70
  try:
71
  result = classifier.explain(text or "", top_k=6)
72
  emotion = result["prediction"]["emotion"]
73
  confidence = result["prediction"]["confidence"]
74
+ card = (
75
+ "<div class='emotion-card'>"
76
+ "<div>Predicted emotion</div>"
77
+ f"<div class='emotion-value'>{emotion.title()}</div>"
78
+ f"<div>Confidence: <b>{confidence:.1%}</b></div>"
79
+ "</div>"
 
 
 
 
80
  )
81
+ evidence = [[item["word"], item["impact"]] for item in result["top_evidence"]]
82
+ status = f"<div class='status-box'>Model source: <code>{classifier.active_model_source}</code></div>"
83
+ return card, evidence, status
84
+ except FileNotFoundError:
85
+ return _empty_result("Local emotion model is not available yet.")
86
  except ImportError as exc:
87
+ return _empty_result(f"Missing dependency: {exc}")
88
+ except Exception as exc:
89
+ return _empty_result(f"Emotion analysis is unavailable right now: {exc}")
 
 
 
 
 
90
 
91
 
92
  with gr.Blocks(title="Emotion Classifier") as interface:
 
108
  )
109
  analyze_button = gr.Button("Analyze emotion", variant="primary")
110
  with gr.Column(scale=4):
111
+ result_output = gr.HTML(label="Prediction")
112
+ evidence_output = gr.Dataframe(
113
+ headers=["Word", "Impact"],
114
+ datatype=["str", "number"],
115
+ label="Word Evidence",
116
+ interactive=False,
117
+ )
118
  summary_output = gr.HTML()
119
 
120
  analyze_button.click(
121
  fn=predict_emotion,
122
  inputs=text_input,
123
+ outputs=[result_output, evidence_output, summary_output],
124
  )
125
 
126