Commit ·
5d87234
1
Parent(s): 6dc8a0d
Expose rejected ASL candidates in intent
Browse files- signspeak/asl/pipeline.py +19 -1
- tests/test_asl_pipeline.py +30 -0
signspeak/asl/pipeline.py
CHANGED
|
@@ -52,6 +52,10 @@ def process_asl_frames(
|
|
| 52 |
def build_intent_input(asl: dict[str, Any], emotion: dict[str, Any]) -> dict[str, Any]:
|
| 53 |
glosses = asl.get("gloss_sequence", []) or []
|
| 54 |
dominant_emotion = emotion.get("dominant_emotion", "unknown")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
return {
|
| 56 |
"detected_glosses": glosses,
|
| 57 |
"detected_facial_expression": dominant_emotion,
|
|
@@ -61,12 +65,26 @@ def build_intent_input(asl: dict[str, Any], emotion: dict[str, Any]) -> dict[str
|
|
| 61 |
"scores": emotion.get("emotion_scores", {}),
|
| 62 |
},
|
| 63 |
"communication_intent": "derived_from_asl_video",
|
| 64 |
-
"sign_confidence":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
"pipeline_stage": "asl_video_to_llama_cpp_intent",
|
| 66 |
"diagnostics": {
|
| 67 |
"asl_status": asl.get("status", "unknown"),
|
| 68 |
"emotion_status": emotion.get("status", "unknown"),
|
| 69 |
"frames_used": int(asl.get("frames_used", 0) or 0),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
},
|
| 71 |
}
|
| 72 |
|
|
|
|
| 52 |
def build_intent_input(asl: dict[str, Any], emotion: dict[str, Any]) -> dict[str, Any]:
|
| 53 |
glosses = asl.get("gloss_sequence", []) or []
|
| 54 |
dominant_emotion = emotion.get("dominant_emotion", "unknown")
|
| 55 |
+
confidence = float(asl.get("confidence", 0.0) or 0.0)
|
| 56 |
+
threshold = float(asl.get("confidence_threshold", 0.0) or 0.0)
|
| 57 |
+
top_prediction = asl.get("top_prediction")
|
| 58 |
+
top_predictions = asl.get("top_predictions", [])
|
| 59 |
return {
|
| 60 |
"detected_glosses": glosses,
|
| 61 |
"detected_facial_expression": dominant_emotion,
|
|
|
|
| 65 |
"scores": emotion.get("emotion_scores", {}),
|
| 66 |
},
|
| 67 |
"communication_intent": "derived_from_asl_video",
|
| 68 |
+
"sign_confidence": confidence,
|
| 69 |
+
"sign_detection": {
|
| 70 |
+
"accepted": bool(glosses),
|
| 71 |
+
"status": asl.get("status", "unknown"),
|
| 72 |
+
"top_prediction": top_prediction,
|
| 73 |
+
"confidence": confidence,
|
| 74 |
+
"confidence_threshold": threshold,
|
| 75 |
+
"top_predictions": top_predictions,
|
| 76 |
+
"landmarks_status": asl.get("landmarks_status"),
|
| 77 |
+
"landmarks_detector": asl.get("landmarks_detector"),
|
| 78 |
+
},
|
| 79 |
"pipeline_stage": "asl_video_to_llama_cpp_intent",
|
| 80 |
"diagnostics": {
|
| 81 |
"asl_status": asl.get("status", "unknown"),
|
| 82 |
"emotion_status": emotion.get("status", "unknown"),
|
| 83 |
"frames_used": int(asl.get("frames_used", 0) or 0),
|
| 84 |
+
"top_prediction": top_prediction,
|
| 85 |
+
"sign_confidence": confidence,
|
| 86 |
+
"confidence_threshold": threshold,
|
| 87 |
+
"accepted": bool(glosses),
|
| 88 |
},
|
| 89 |
}
|
| 90 |
|
tests/test_asl_pipeline.py
CHANGED
|
@@ -26,6 +26,35 @@ def test_build_intent_input_matches_llm_schema():
|
|
| 26 |
assert intent["emotion_profile"]["confidence"] == 0.82
|
| 27 |
assert intent["sign_confidence"] == 0.91
|
| 28 |
assert intent["diagnostics"]["asl_status"] == "ok"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
def test_process_asl_frames_preserves_detector_diagnostics(monkeypatch):
|
|
@@ -61,6 +90,7 @@ def test_process_asl_frames_preserves_detector_diagnostics(monkeypatch):
|
|
| 61 |
assert result["asl"]["confidence_threshold"] == 0.70
|
| 62 |
assert result["asl"]["top_predictions"] == [{"label": "talk", "confidence": 0.96}]
|
| 63 |
assert result["intent_input"]["detected_glosses"] == ["talk"]
|
|
|
|
| 64 |
|
| 65 |
|
| 66 |
def test_summarize_asl_result_is_stable_for_missing_fields():
|
|
|
|
| 26 |
assert intent["emotion_profile"]["confidence"] == 0.82
|
| 27 |
assert intent["sign_confidence"] == 0.91
|
| 28 |
assert intent["diagnostics"]["asl_status"] == "ok"
|
| 29 |
+
assert intent["sign_detection"]["accepted"] is True
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def test_build_intent_input_exposes_rejected_top_prediction():
|
| 33 |
+
asl = {
|
| 34 |
+
"status": "low_confidence",
|
| 35 |
+
"gloss_sequence": [],
|
| 36 |
+
"top_prediction": "talk",
|
| 37 |
+
"confidence": 0.138,
|
| 38 |
+
"confidence_threshold": 0.70,
|
| 39 |
+
"top_predictions": [{"label": "talk", "confidence": 0.138}],
|
| 40 |
+
"frames_used": 30,
|
| 41 |
+
"landmarks_status": "ok",
|
| 42 |
+
"landmarks_detector": "holistic",
|
| 43 |
+
}
|
| 44 |
+
emotion = {
|
| 45 |
+
"status": "ok",
|
| 46 |
+
"dominant_emotion": "neutral",
|
| 47 |
+
"intensity": 0.29,
|
| 48 |
+
"emotion_scores": {"neutral": 0.29},
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
intent = build_intent_input(asl, emotion)
|
| 52 |
+
|
| 53 |
+
assert intent["detected_glosses"] == []
|
| 54 |
+
assert intent["sign_detection"]["accepted"] is False
|
| 55 |
+
assert intent["sign_detection"]["top_prediction"] == "talk"
|
| 56 |
+
assert intent["sign_detection"]["confidence_threshold"] == 0.70
|
| 57 |
+
assert intent["diagnostics"]["top_prediction"] == "talk"
|
| 58 |
|
| 59 |
|
| 60 |
def test_process_asl_frames_preserves_detector_diagnostics(monkeypatch):
|
|
|
|
| 90 |
assert result["asl"]["confidence_threshold"] == 0.70
|
| 91 |
assert result["asl"]["top_predictions"] == [{"label": "talk", "confidence": 0.96}]
|
| 92 |
assert result["intent_input"]["detected_glosses"] == ["talk"]
|
| 93 |
+
assert result["intent_input"]["sign_detection"]["top_prediction"] == "talk"
|
| 94 |
|
| 95 |
|
| 96 |
def test_summarize_asl_result_is_stable_for_missing_fields():
|