add on-task-bert as source for mathWord
Browse filesNew measures/OnTaskAnalyser.py (mirrors VocabularyAnalyser's shape:
self-contained, owns its own model instance, no shared handler
device/tokenizer/input-builder) runs edsi-umd/on-task-bert on student
utterances. moments.mathWord is now derived from that classifier
instead of bool(vocabulary_terms).
vocabularyTerms/vocabularyMatches/vocabularyTable are untouched -
VocabularyAnalyser keeps running as-is, since the frontend's
MathVocabularyTable needs the per-word match data the classifier
can't produce.
TODO: confirm the exact label string on-task-bert's pipeline returns
for "on-task" (see ON_TASK_LABEL in OnTaskAnalyser.py) with a real
inference call before relying on this in production.
- handler.py +8 -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,7 +94,7 @@ 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.
|
| 96 |
},
|
| 97 |
'unitMeasure': self.unit_measure,
|
| 98 |
'aggregateUnitMeasure': self.aggregate_unit_measure,
|
|
@@ -537,7 +539,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 |
+
'mathWord': bool(self.on_task) and self.on_task.get('label') == ON_TASK_LABEL
|
| 98 |
},
|
| 99 |
'unitMeasure': self.unit_measure,
|
| 100 |
'aggregateUnitMeasure': self.aggregate_unit_measure,
|
|
|
|
| 539 |
vocabulary_analyser = VocabularyAnalyser(str(glossary_path))
|
| 540 |
vocabulary_analyser.run_analysis(transcript)
|
| 541 |
del vocabulary_analyser
|
| 542 |
+
|
| 543 |
+
on_task_analyser = OnTaskAnalyser()
|
| 544 |
+
on_task_analyser.run_analysis(transcript, uptake_speaker=uptake_speaker)
|
| 545 |
+
del on_task_analyser
|
| 546 |
+
|
| 547 |
transcript.update_utterance_roles(uptake_speaker)
|
| 548 |
sorted_math_cloud, teacher_math_cloud, student_math_cloud = run_math_density(transcript)
|
| 549 |
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 = 'LABEL_1' # TODO: confirm against a real inference call before relying on this
|
| 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
|