Fix ai-service Dockerfile: bake in drug_entities.json, override its path

This commit is contained in:
2026-08-10 10:35:13 +07:00
parent a4b8e1c4db
commit 60b4397032
51 changed files with 4302 additions and 2087 deletions
+115 -1
View File
@@ -1,4 +1,36 @@
from adapters.qdrant import _source_refs
from adapters.qdrant import QdrantRetriever, _source_refs
class _FakePoint:
def __init__(self, payload: dict) -> None:
self.payload = payload
self.score = 1.0
class _FakeScrollClient:
"""Mimics qdrant-client's `.scroll()` shape closely enough to exercise
`find_by_indication`'s keyword-matching logic directly — a fake filter
(not a real one), so it returns every payload handed to it regardless
of `scroll_filter`; the payloads given in each test already represent
what a real `section_key=chi_dinh, chunk_kind=prose` filter would have
returned, which is the part `find_by_indication` cannot get wrong on
its own (the filter construction itself is a one-line, inspectable
`Filter(must=[...])` — not worth a second fake layer to prove)."""
def __init__(self, payloads: list[dict]) -> None:
self._payloads = payloads
def scroll(self, collection_name, scroll_filter, limit, offset, with_payload): # noqa: ARG002
return [_FakePoint(p) for p in self._payloads], None
def _chi_dinh_payload(drug_id: str, text: str) -> dict:
return {
"chunk_id": f"{drug_id}__chi_dinh__0", "drug_id": drug_id,
"drug_name": drug_id.upper(), "section_key": "chi_dinh",
"chunk_kind": "prose", "text": text,
"heading_physical_page": 100, "printed_page_range": [101, 101],
}
def test_descriptor_source_ref_comes_from_attachment_not_heading_page():
@@ -45,3 +77,85 @@ def test_prose_ref_uses_exact_chunk_range_and_keeps_attachment_region():
assert refs[1].block_id == "p105_t0"
assert refs[1].physical_page == 105
assert refs[1].printed_page == 106
def test_find_by_indication_matches_a_drug_that_names_the_symptom():
client = _FakeScrollClient([
_chi_dinh_payload("paracetamol_acetaminophen", "Điều trị sốt, giảm đau nhẹ và vừa."),
_chi_dinh_payload("amoxicilin", "Điều trị nhiễm khuẩn đường hô hấp."),
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
hits = retriever.find_by_indication("sốt", limit=8)
assert [h.document.drug_id for h in hits] == ["paracetamol_acetaminophen"]
def test_find_by_indication_requires_the_whole_phrase_not_a_scattered_match():
""""sốt xuất huyết" (dengue) must not match a chunk that only says "sốt"
— the phrase itself has to appear, not just each of its words somewhere."""
client = _FakeScrollClient([
_chi_dinh_payload("paracetamol_acetaminophen", "Điều trị sốt, giảm đau."),
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
hits = retriever.find_by_indication("sốt xuất huyết", limit=8)
assert hits == []
def test_find_by_indication_matches_a_multi_word_phrase_contiguously():
client = _FakeScrollClient([
_chi_dinh_payload("paracetamol_acetaminophen", "Điều trị sốt cao ở người lớn."),
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
hits = retriever.find_by_indication("sốt cao", limit=8)
assert [h.document.drug_id for h in hits] == ["paracetamol_acetaminophen"]
def test_find_by_indication_rejects_a_scattered_bag_of_common_words():
"""Found live 2026-08-07: a token-SUBSET match (every word present
*somewhere*, any order) let a long nonsense phrase built from common
filler words false-positive against real chi_dinh text — the words are
common enough to appear scattered through nearly anything. Phrase
matching closes it: none of these words are contiguous in the target
text the way they are in the query."""
client = _FakeScrollClient([
_chi_dinh_payload(
"paracetamol_acetaminophen",
"Điều trị sốt. Không dùng quá liều khuyến cáo trong sách hướng dẫn.",
),
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
hits = retriever.find_by_indication(
"bệnh chưa từng ghi nhận trong sách abcxyz123", limit=8
)
assert hits == []
def test_find_by_indication_returns_at_most_one_hit_per_drug():
client = _FakeScrollClient([
_chi_dinh_payload("paracetamol_acetaminophen", "Điều trị sốt."),
{**_chi_dinh_payload("paracetamol_acetaminophen", "Điều trị sốt cao ở trẻ em."),
"chunk_id": "paracetamol_acetaminophen__chi_dinh__1"},
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
hits = retriever.find_by_indication("sốt", limit=8)
assert len(hits) == 1
def test_find_by_indication_respects_the_limit():
client = _FakeScrollClient([
_chi_dinh_payload(f"drug_{i}", "Điều trị đau.") for i in range(5)
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
hits = retriever.find_by_indication("đau", limit=2)
assert len(hits) == 2