File size: 8,621 Bytes
00bd0c6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | import pytest
import numpy as np
from unittest.mock import patch
from intent_classification.intent_router_ml import route_intent
from intent_classification.intent_classification_ml import classify_intent
def mock_classify_ready(label="PATIENT_EVIDENCE_QUERY", confidence=0.85):
"""Returns a mock confident classification result."""
return {"status": "READY", "label": label, "confidence": confidence}
def mock_classify_uncertain(label="PATIENT_EVIDENCE_QUERY", confidence=0.40):
"""Returns a mock uncertain classification result."""
return {"status": "UNCERTAIN", "label": label, "confidence": confidence}
#ββββ route_intent ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestRouteIntent:
def test_confident_classification_returns_route_status(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_ready()):
result = route_intent("patient has persistent cough", 1, 1)
assert result["status"] == "ROUTE"
def test_confident_classification_returns_correct_intent(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_ready()):
result = route_intent("patient has persistent cough", 1, 1)
assert result["intent"] == "PATIENT_EVIDENCE_QUERY"
def test_confident_classification_returns_confidence(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_ready()):
result = route_intent("patient has persistent cough", 1, 1)
assert result["confidence"] == 0.85
def test_uncertain_classification_returns_needs_clarification(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_uncertain()):
result = route_intent("something ambiguous", 1, 1)
assert result["status"] == "NEEDS_CLARIFICATION"
def test_uncertain_classification_returns_options(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_uncertain()):
result = route_intent("something ambiguous", 1, 1)
assert "options" in result
assert isinstance(result["options"], list)
assert len(result["options"]) > 0
def test_uncertain_classification_options_are_strings(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_uncertain()):
result = route_intent("something ambiguous", 1, 1)
for opt in result["options"]:
assert isinstance(opt, str)
def test_uncertain_classification_returns_confidence(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_uncertain()):
result = route_intent("something ambiguous", 1, 1)
assert result["confidence"] == 0.40
def test_clarification_options_contain_expected_labels(self):
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_uncertain()):
result = route_intent("something ambiguous", 1, 1)
assert "Add new evidence" in result["options"]
assert "Ask for explanation" in result["options"]
assert "Request source" in result["options"]
assert "General help" in result["options"]
def test_all_intents_route_correctly(self):
intents = [
"PATIENT_EVIDENCE_QUERY",
"FOLLOW_UP_EXPLANATION",
"SOURCE_REQUEST",
"HELP_OR_OTHER"
]
for intent in intents:
with patch("intent_classification.intent_router_ml.classify_intent",
return_value=mock_classify_ready(label=intent)):
result = route_intent("some input", 1, 1)
assert result["intent"] == intent
#ββββββ classify_intentββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestClassifyIntent:
@patch("intent_classification.intent_classification_ml.embedder")
@patch("intent_classification.intent_classification_ml.classifier")
def test_status_is_ready_when_confident(self, mock_classifier, mock_embedder):
mock_embedder.encode.return_value = np.zeros((1, 384))
mock_probs = np.array([0.05, 0.85, 0.05, 0.05])
mock_classifier.predict_proba.return_value = [mock_probs]
mock_id_to_label = {0: "HELP_OR_OTHER", 1: "PATIENT_EVIDENCE_QUERY",
2: "FOLLOW_UP_EXPLANATION", 3: "SOURCE_REQUEST"}
with patch("intent_classification.intent_classification_ml.id_to_label", mock_id_to_label):
result = classify_intent("patient has a fever")
assert result["status"] == "READY"
@patch("intent_classification.intent_classification_ml.embedder")
@patch("intent_classification.intent_classification_ml.classifier")
def test_status_is_uncertain_when_low_confidence(self, mock_classifier, mock_embedder):
mock_embedder.encode.return_value = np.zeros((1, 384))
mock_probs = np.array([0.30, 0.35, 0.20, 0.15])
mock_classifier.predict_proba.return_value = [mock_probs]
mock_id_to_label = {0: "HELP_OR_OTHER", 1: "PATIENT_EVIDENCE_QUERY",
2: "FOLLOW_UP_EXPLANATION", 3: "SOURCE_REQUEST"}
with patch("intent_classification.intent_classification_ml.id_to_label", mock_id_to_label):
result = classify_intent("patient has a cough")
assert result["status"] == "UNCERTAIN"
@patch("intent_classification.intent_classification_ml.embedder")
@patch("intent_classification.intent_classification_ml.classifier")
def test_returns_correct_label(self, mock_classifier, mock_embedder):
mock_embedder.encode.return_value = np.zeros((1, 384))
mock_probs = np.array([0.05, 0.05, 0.85, 0.05])
mock_classifier.predict_proba.return_value = [mock_probs]
mock_id_to_label = {0: "HELP_OR_OTHER", 1: "PATIENT_EVIDENCE_QUERY",
2: "FOLLOW_UP_EXPLANATION", 3: "SOURCE_REQUEST"}
with patch("intent_classification.intent_classification_ml.id_to_label", mock_id_to_label):
result = classify_intent("why does smoking cause cancer?")
assert result["label"] == "FOLLOW_UP_EXPLANATION"
@patch("intent_classification.intent_classification_ml.embedder")
@patch("intent_classification.intent_classification_ml.classifier")
def test_exactly_at_threshold_is_uncertain(self, mock_classifier, mock_embedder):
"""Confidence exactly at CONFIDENCE_THRESHOLD (0.55) should be UNCERTAIN
since the check is confidence < CONFIDENCE_THRESHOLD."""
mock_embedder.encode.return_value = np.zeros((1, 384))
mock_probs = np.array([0.15, 0.55, 0.15, 0.15])
mock_classifier.predict_proba.return_value = [mock_probs]
mock_id_to_label = {0: "HELP_OR_OTHER", 1: "PATIENT_EVIDENCE_QUERY",
2: "FOLLOW_UP_EXPLANATION", 3: "SOURCE_REQUEST"}
with patch("intent_classification.intent_classification_ml.id_to_label", mock_id_to_label):
result = classify_intent("some borderline threshold input")
assert result["status"] == "READY"
@patch("intent_classification.intent_classification_ml.embedder")
@patch("intent_classification.intent_classification_ml.classifier")
def test_below_threshold_is_uncertain(self, mock_classifier, mock_embedder):
mock_embedder.encode.return_value = np.zeros((1, 384))
mock_probs = np.array([0.18, 0.54, 0.16, 0.12])
mock_classifier.predict_proba.return_value = [mock_probs]
mock_id_to_label = {0: "HELP_OR_OTHER", 1: "PATIENT_EVIDENCE_QUERY",
2: "FOLLOW_UP_EXPLANATION", 3: "SOURCE_REQUEST"}
with patch("intent_classification.intent_classification_ml.id_to_label", mock_id_to_label):
result = classify_intent("borderline input")
assert result["status"] == "UNCERTAIN" |