Wire up query history: localStorage session persistence + sidebar UI
This commit is contained in:
@@ -118,6 +118,31 @@ SECTION_KEY_HINTS: dict[str, str] = {
|
||||
"thong_tin_quy_che": "thông tin quy chế/pháp lý",
|
||||
}
|
||||
|
||||
# Short, chip-sized Vietnamese section names — SECTION_KEY_HINTS above is
|
||||
# full-sentence disambiguation text for the model, well over
|
||||
# _QUICK_REPLY_MAX_CHARS, so it cannot double as a quick_reply label.
|
||||
_SECTION_SHORT_LABEL: dict[str, str] = {
|
||||
"ten_chung_quoc_te": "Tên chung quốc tế",
|
||||
"ten_thuong_mai": "Tên thương mại",
|
||||
"ma_atc": "Mã ATC",
|
||||
"loai_thuoc": "Loại thuốc",
|
||||
"dang_thuoc_va_ham_luong": "Dạng thuốc và hàm lượng",
|
||||
"duoc_ly_va_co_che_tac_dung": "Dược lý, cơ chế tác dụng",
|
||||
"chi_dinh": "Chỉ định",
|
||||
"chong_chi_dinh": "Chống chỉ định",
|
||||
"than_trong": "Thận trọng",
|
||||
"thoi_ky_mang_thai": "Thời kỳ mang thai",
|
||||
"thoi_ky_cho_con_bu": "Thời kỳ cho con bú",
|
||||
"tac_dung_khong_mong_muon": "Tác dụng không mong muốn",
|
||||
"huong_dan_xu_tri_adr": "Xử trí ADR",
|
||||
"lieu_luong_va_cach_dung": "Liều lượng và cách dùng",
|
||||
"tuong_tac_thuoc": "Tương tác thuốc",
|
||||
"qua_lieu_va_xu_tri": "Quá liều và xử trí",
|
||||
"do_on_dinh_va_bao_quan": "Độ ổn định, bảo quản",
|
||||
"tuong_ky": "Tương kỵ",
|
||||
"thong_tin_quy_che": "Thông tin quy chế",
|
||||
}
|
||||
|
||||
# What kind of turn this is — the router branches on it. Deliberately explicit so a
|
||||
# symptom lookup is never silently treated as a failed drug lookup, and a two-drug
|
||||
# interaction never collapses to an "ambiguous drug" abstain.
|
||||
@@ -294,7 +319,7 @@ _ALLOWED_ROUTES = {
|
||||
"uong", "tiem_tinh_mach", "tiem_bap", "tiem_duoi_da",
|
||||
"dat_truc_trang", "boi_ngoai_da", "nho_mat", "nho_mui", "khac",
|
||||
}
|
||||
_QUICK_REPLY_MAX_ITEMS = 18 # one per monograph section (see rag/sections.py SECTION_ORDER)
|
||||
_QUICK_REPLY_MAX_ITEMS = 19 # one per monograph section (see rag/sections.py SECTION_ORDER)
|
||||
_QUICK_REPLY_MAX_CHARS = 40
|
||||
|
||||
_SYSTEM = """Bạn là bộ HIỂU CÂU HỎI cho một chatbot tra cứu Dược thư Quốc gia Việt Nam.
|
||||
@@ -577,6 +602,7 @@ class LlmQueryUnderstander:
|
||||
resolved_section_key=(section_match.section_key if section_match else None),
|
||||
resolved_section_phrase=(section_match.phrase if section_match else None),
|
||||
)
|
||||
frame = _apply_multi_section_clarify(frame, turn)
|
||||
return _merge_with_prior_frame(frame, prior_frame)
|
||||
|
||||
@staticmethod
|
||||
@@ -856,6 +882,51 @@ def _apply_named_drug_cues(
|
||||
return frame
|
||||
|
||||
|
||||
def _apply_multi_section_clarify(frame: QueryFrame, turn: str) -> QueryFrame:
|
||||
"""A turn naming two-or-more distinct monograph sections for one drug
|
||||
("chỉ định và chống chỉ định của X") cannot be served by narrowing
|
||||
`attribute` to a single value: both the model's own JSON output and
|
||||
`_apply_named_drug_cues` above only ever produce one `attribute`, so
|
||||
retrieval silently fetches evidence for whichever section wins while the
|
||||
question handed to generation still promises both. The completeness check
|
||||
then correctly reports a real, quote-backed gap against the one section
|
||||
actually retrieved, generation retries with the same mismatched scope,
|
||||
and the turn fails closed as a confusing `incomplete_answer` abstain —
|
||||
found live 2026-08-14, reproduced 2/2 on "Chỉ định và chống chỉ định của
|
||||
Aspirin là gì?". Answering every named section at once is a larger,
|
||||
separate change (multi-attribute retrieval); asking which one first is
|
||||
the safe interim behavior, using the generic `needs_clarify`+
|
||||
`clarify_reason` clarify path `RagAgent` already has (checked ahead of
|
||||
the narrower `attribute is None` -> `missing_attribute` branch, and the
|
||||
only one of the two that forwards `quick_replies`).
|
||||
|
||||
Scoped to turns already read as a single named drug's own attribute(s)
|
||||
— `_apply_named_drug_cues` runs first, so by this point `turn_type` is
|
||||
already "drug_attribute"/"drug_overview" for exactly the cases this
|
||||
bug affects; interaction/condition/dosing turns are untouched.
|
||||
"""
|
||||
if frame.turn_type not in ("drug_attribute", "drug_overview") or not frame.drugs:
|
||||
return frame
|
||||
matches = _SECTION_RESOLVER.resolve_all(turn)
|
||||
distinct_sections = tuple(dict.fromkeys(match.section_key for match in matches))
|
||||
if len(distinct_sections) < 2:
|
||||
return frame
|
||||
options = tuple(
|
||||
_SECTION_SHORT_LABEL.get(key, key) for key in distinct_sections
|
||||
)[:_QUICK_REPLY_MAX_ITEMS]
|
||||
return replace(
|
||||
frame,
|
||||
turn_type="drug_attribute",
|
||||
attribute=None,
|
||||
needs_clarify=True,
|
||||
clarify_reason=(
|
||||
"Câu hỏi nêu nhiều mục cùng lúc — anh/chị muốn xem mục nào trước?"
|
||||
),
|
||||
quick_replies=options,
|
||||
system_error=None,
|
||||
)
|
||||
|
||||
|
||||
_KNOWN_FACT_LABELS: tuple[tuple[str, str], ...] = (
|
||||
("population", "Đối tượng"),
|
||||
("age_text", "Tuổi"),
|
||||
|
||||
Reference in New Issue
Block a user