更新
This commit is contained in:
@@ -98,10 +98,15 @@ class DoctorRepository(Protocol):
|
||||
) -> PageResult[Patient]:
|
||||
"""Return a doctor-scoped patient page."""
|
||||
|
||||
def list_consultations(
|
||||
self, *, page_no: int = 1, page_size: int = 20, **filters: Any
|
||||
) -> PageResult[Consultation]:
|
||||
"""Return a diagnosis/consultation page."""
|
||||
def list_consultations(
|
||||
self, *, page_no: int = 1, page_size: int = 20, **filters: Any
|
||||
) -> PageResult[Consultation]:
|
||||
"""Return a diagnosis/consultation page."""
|
||||
|
||||
def list_ai_patient_options(
|
||||
self, *, page_no: int = 1, page_size: int = 20, keyword: str = ""
|
||||
) -> PageResult[dict[str, Any]]:
|
||||
"""Return privacy-safe diagnosis choices for patient AI workflows."""
|
||||
|
||||
def list_prescription_templates(
|
||||
self, *, page_no: int = 1, page_size: int = 20, **filters: Any
|
||||
@@ -206,6 +211,9 @@ class DoctorRepository(Protocol):
|
||||
) -> Iterator[dict[str, Any]]:
|
||||
"""Yield normalized ``start``/``delta``/``done`` assistant events."""
|
||||
|
||||
def generate_ai_prescription(self, diagnosis_id: int) -> dict[str, Any]:
|
||||
"""Generate a server-validated prescription draft for doctor review."""
|
||||
|
||||
def get_diagnosis_ai_analysis(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
@@ -1422,6 +1430,15 @@ class RemoteDoctorRepository:
|
||||
yield {"event": "delta", "text": answer, "fallback": True}
|
||||
yield {**result, "event": "done", "fallback": True}
|
||||
|
||||
def generate_ai_prescription(self, diagnosis_id: int) -> dict[str, Any]:
|
||||
"""Generate a structured draft using the server's full patient context."""
|
||||
|
||||
return self.analyze_diagnosis_ai(
|
||||
diagnosis_id,
|
||||
"请依据患者全部纵向资料生成一份可复核的中医处方草稿。",
|
||||
task="prescription_generate",
|
||||
)
|
||||
|
||||
def get_diagnosis_ai_analysis(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
@@ -1992,10 +2009,10 @@ class RemoteDoctorRepository:
|
||||
|
||||
return self.get_diagnosis_detail(diagnosis_id, readonly=True)
|
||||
|
||||
def list_consultations(
|
||||
self, *, page_no: int = 1, page_size: int = 20, **filters: Any
|
||||
) -> PageResult[Consultation]:
|
||||
"""List diagnosis records using ``tcm.diagnosis/lists``."""
|
||||
def list_consultations(
|
||||
self, *, page_no: int = 1, page_size: int = 20, **filters: Any
|
||||
) -> PageResult[Consultation]:
|
||||
"""List diagnosis records using ``tcm.diagnosis/lists``."""
|
||||
|
||||
request_filters = dict(filters)
|
||||
start_date = str(request_filters.pop("start_date", "") or "").strip()
|
||||
@@ -2017,9 +2034,26 @@ class RemoteDoctorRepository:
|
||||
"tcm.diagnosis/lists",
|
||||
_page_params(page_no, page_size, request_filters),
|
||||
)
|
||||
return PageResult.from_payload(
|
||||
payload, Consultation.from_dict, page_no=page_no, page_size=page_size
|
||||
)
|
||||
return PageResult.from_payload(
|
||||
payload, Consultation.from_dict, page_no=page_no, page_size=page_size
|
||||
)
|
||||
|
||||
def list_ai_patient_options(
|
||||
self, *, page_no: int = 1, page_size: int = 20, keyword: str = ""
|
||||
) -> PageResult[dict[str, Any]]:
|
||||
"""List privacy-safe diagnosis choices through the dedicated AI endpoint."""
|
||||
|
||||
clean_keyword = str(keyword or "").strip()
|
||||
payload = self.client.get(
|
||||
"tcm.diagnosis/aiPatientOptions",
|
||||
_page_params(page_no, page_size, {"keyword": clean_keyword}),
|
||||
)
|
||||
return PageResult.from_payload(
|
||||
payload,
|
||||
_ai_patient_option,
|
||||
page_no=page_no,
|
||||
page_size=page_size,
|
||||
)
|
||||
|
||||
def get_diagnosis_detail(self, diagnosis_id: int, *, readonly: bool = False) -> dict[str, Any]:
|
||||
"""Load a full diagnosis using the appropriate routed endpoint."""
|
||||
@@ -2791,6 +2825,7 @@ def _diagnosis_ai_request(diagnosis_id: int, prompt: str, task: str) -> tuple[st
|
||||
"summary",
|
||||
"tcm_pattern",
|
||||
"prescription_review",
|
||||
"prescription_generate",
|
||||
"medication_review",
|
||||
"exam_review",
|
||||
"complication_risk",
|
||||
@@ -2845,8 +2880,39 @@ def _page_params(page_no: int, page_size: int, filters: Mapping[str, Any]) -> di
|
||||
for key, value in filters.items()
|
||||
if value is not None and not (isinstance(value, (list, tuple, set)) and not value)
|
||||
}
|
||||
result.update({"page_no": page_no, "page_size": page_size})
|
||||
return result
|
||||
result.update({"page_no": page_no, "page_size": page_size})
|
||||
return result
|
||||
|
||||
|
||||
def _ai_patient_option(row: Mapping[str, Any]) -> dict[str, Any]:
|
||||
"""Project one AI patient option without exposing a plaintext phone number."""
|
||||
|
||||
diagnosis_id = _to_int(row.get("diagnosis_id", row.get("id")), 0)
|
||||
source_patient_id = _to_int(row.get("source_patient_id", row.get("patient_id")), 0)
|
||||
phone = str(row.get("phone_masked") or "").strip()
|
||||
digits = re.sub(r"\D", "", phone)
|
||||
if len(digits) >= 7 and "*" not in phone:
|
||||
phone = f"{digits[:3]}****{digits[-4:]}"
|
||||
option: dict[str, Any] = {
|
||||
"diagnosis_id": diagnosis_id,
|
||||
"source_patient_id": source_patient_id,
|
||||
"patient_name": str(row.get("patient_name", row.get("name")) or "").strip(),
|
||||
"phone_masked": phone,
|
||||
}
|
||||
for key in (
|
||||
"gender",
|
||||
"gender_desc",
|
||||
"age",
|
||||
"diagnosis_date",
|
||||
"diagnosis_summary",
|
||||
"syndrome_type",
|
||||
"clinical_diagnosis",
|
||||
"last_visit_at",
|
||||
"next_appointment_at",
|
||||
):
|
||||
if key in row:
|
||||
option[key] = row[key]
|
||||
return option
|
||||
|
||||
|
||||
def _require_mapping(value: object, endpoint: str) -> Mapping[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user