feature: on-off-tasks

#11
by ikarasz - opened
Files changed (2) hide show
  1. handler.py +14 -2
  2. measures/OnTaskAnalyser.py +23 -0
handler.py CHANGED
@@ -1,5 +1,6 @@
1
  from typing import Dict, List, Any
2
  from measures.VocabularyAnalyser import VocabularyAnalyser
 
3
  from scipy.special import softmax
4
  from collections import Counter, defaultdict
5
  import numpy as np
@@ -47,6 +48,7 @@ class Utterance:
47
  self.num_math_terms = None
48
  self.math_terms = None
49
  self.vocabulary_terms = None
 
50
 
51
  # moments
52
  self.uptake = None
@@ -92,8 +94,14 @@ class Utterance:
92
  'questioning': True if self.question else False,
93
  'uptake': True if self.uptake else False,
94
  'focusingQuestion': True if self.focusing_question else False,
95
- 'mathWord': bool(self.vocabulary_terms)
 
 
 
96
  },
 
 
 
97
  'unitMeasure': self.unit_measure,
98
  'aggregateUnitMeasure': self.aggregate_unit_measure,
99
  'wordCount': self.word_count,
@@ -537,7 +545,11 @@ class EndpointHandler():
537
  vocabulary_analyser = VocabularyAnalyser(str(glossary_path))
538
  vocabulary_analyser.run_analysis(transcript)
539
  del vocabulary_analyser
540
-
 
 
 
 
541
  transcript.update_utterance_roles(uptake_speaker)
542
  sorted_math_cloud, teacher_math_cloud, student_math_cloud = run_math_density(transcript)
543
  transcript.calculate_aggregate_word_count()
 
1
  from typing import Dict, List, Any
2
  from measures.VocabularyAnalyser import VocabularyAnalyser
3
+ from measures.OnTaskAnalyser import OnTaskAnalyser, ON_TASK_LABEL
4
  from scipy.special import softmax
5
  from collections import Counter, defaultdict
6
  import numpy as np
 
48
  self.num_math_terms = None
49
  self.math_terms = None
50
  self.vocabulary_terms = None
51
+ self.on_task = None
52
 
53
  # moments
54
  self.uptake = None
 
94
  'questioning': True if self.question else False,
95
  'uptake': True if self.uptake else False,
96
  'focusingQuestion': True if self.focusing_question else False,
97
+ # Legacy alias for onTask below. On/off-task is not a talk moment;
98
+ # this key is kept only so already-stored analyses and older
99
+ # frontends keep working, and is retired in the UI.
100
+ 'mathWord': bool(self.on_task) and self.on_task.get('label') == ON_TASK_LABEL
101
  },
102
+ # On/off-task classification: a measure in its own right, alongside
103
+ # vocabulary. None means not classified (teacher utterance or empty text).
104
+ 'onTask': None if self.on_task is None else self.on_task.get('label') == ON_TASK_LABEL,
105
  'unitMeasure': self.unit_measure,
106
  'aggregateUnitMeasure': self.aggregate_unit_measure,
107
  'wordCount': self.word_count,
 
545
  vocabulary_analyser = VocabularyAnalyser(str(glossary_path))
546
  vocabulary_analyser.run_analysis(transcript)
547
  del vocabulary_analyser
548
+
549
+ on_task_analyser = OnTaskAnalyser()
550
+ on_task_analyser.run_analysis(transcript, uptake_speaker=uptake_speaker)
551
+ del on_task_analyser
552
+
553
  transcript.update_utterance_roles(uptake_speaker)
554
  sorted_math_cloud, teacher_math_cloud, student_math_cloud = run_math_density(transcript)
555
  transcript.calculate_aggregate_word_count()
measures/OnTaskAnalyser.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline
2
+
3
+ ON_TASK_MODEL = 'edsi-umd/on-task-bert'
4
+ ON_TASK_LABEL = 'on_task' # from the model's config.json id2label: {"0": "off_task", "1": "on_task"}
5
+
6
+
7
+ class OnTaskAnalyser:
8
+ def __init__(self, model_path=ON_TASK_MODEL, max_length=256):
9
+ self.pipe = pipeline("text-classification", model=model_path,
10
+ truncation=True, max_length=max_length)
11
+
12
+ def predict_one(self, text: str):
13
+ return self.pipe(text)[0] # {'label': ..., 'score': ...}
14
+
15
+ def run_analysis(self, transcript, uptake_speaker=None):
16
+ """Mutate transcript utterances by setting on_task for student utterances."""
17
+ for utt in transcript.utterances:
18
+ if uptake_speaker is not None and utt.speaker == uptake_speaker:
19
+ continue # model trained on student utterances only
20
+ if not utt.text or not utt.text.strip():
21
+ continue
22
+ utt.on_task = self.predict_one(utt.text)
23
+ return transcript