Wire up query history: localStorage session persistence + sidebar UI

This commit is contained in:
2026-08-14 17:44:36 +07:00
parent 9be5819710
commit 057d4ed9dc
23 changed files with 1231 additions and 30 deletions
@@ -243,3 +243,79 @@ def test_search_lexical_excludes_non_matching_sections():
hits = retriever.search_lexical("loét dạ dày", "aspirin", limit=5)
assert hits == []
def _section_meta_payload(
drug_id: str, section_key: str, display_name: str, part_index: int = 0
) -> dict:
return {
"chunk_id": f"{drug_id}__{section_key}__{part_index}", "drug_id": drug_id,
"section_key": section_key, "section_display_name": display_name,
"part_index": part_index, "chunk_kind": "prose", "text": "nội dung",
}
def test_list_sections_returns_book_order_not_scroll_order():
client = _FakeScrollClient([
_section_meta_payload("aspirin", "qua_lieu_va_xu_tri", "Quá liều và xử trí"),
_section_meta_payload("aspirin", "chi_dinh", "Chỉ định"),
_section_meta_payload("aspirin", "ten_chung_quoc_te", "Tên chung quốc tế"),
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
sections = retriever.list_sections("aspirin")
assert [key for key, _ in sections] == [
"ten_chung_quoc_te", "chi_dinh", "qua_lieu_va_xu_tri",
]
assert dict(sections)["chi_dinh"] == "Chỉ định"
def test_list_sections_dedupes_multi_part_sections():
client = _FakeScrollClient([
_section_meta_payload("aspirin", "chi_dinh", "Chỉ định", part_index=0),
_section_meta_payload("aspirin", "chi_dinh", "Chỉ định", part_index=1),
_section_meta_payload("aspirin", "chi_dinh", "Chỉ định", part_index=2),
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
sections = retriever.list_sections("aspirin")
assert sections == [("chi_dinh", "Chỉ định")]
def test_list_sections_includes_quarantined_only_sections():
"""A section with no prose chunk at all (only a block_descriptor) is
still a real section of the monograph — must not be filtered out the
way `find_by_drug`'s prose-only overview deliberately is."""
client = _FakeScrollClient([
{
"chunk_id": "aspirin__lieu_luong_va_cach_dung__block__p1_t0",
"drug_id": "aspirin", "section_key": "lieu_luong_va_cach_dung",
"section_display_name": "Liều lượng và cách dùng",
"chunk_kind": "block_descriptor", "text": "bảng, trang 1.",
},
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
sections = retriever.list_sections("aspirin")
assert sections == [("lieu_luong_va_cach_dung", "Liều lượng và cách dùng")]
def test_list_sections_places_ten_thuong_mai_after_generic_name():
"""`ten_thuong_mai` isn't one of the book's own 19 numbered fields
(verified against the actual PDF, printed page 39) — placed right after
the generic name as the most natural adjacency."""
client = _FakeScrollClient([
_section_meta_payload("aspirin", "chi_dinh", "Chỉ định"),
_section_meta_payload("aspirin", "ten_thuong_mai", "Tên thương mại"),
_section_meta_payload("aspirin", "ten_chung_quoc_te", "Tên chung quốc tế"),
])
retriever = QdrantRetriever(client, "duocthu_v1", embedder=None)
sections = retriever.list_sections("aspirin")
assert [key for key, _ in sections] == [
"ten_chung_quoc_te", "ten_thuong_mai", "chi_dinh",
]