更新
This commit is contained in:
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import mimetypes
|
||||
import re
|
||||
import time
|
||||
from collections.abc import Mapping
|
||||
from collections.abc import Mapping, Sequence
|
||||
from contextlib import suppress
|
||||
from datetime import date
|
||||
from io import BytesIO
|
||||
@@ -619,8 +619,38 @@ class DoctorRepository(Protocol):
|
||||
def end_call(self, diagnosis_id: int) -> Any:
|
||||
"""End the active diagnosis call."""
|
||||
|
||||
def bind_call_room(self, diagnosis_id: int, room_id: str) -> Any:
|
||||
"""Bind a TRTC room to the active call."""
|
||||
def bind_call_room(self, diagnosis_id: int, room_id: str) -> Any:
|
||||
"""Bind a TRTC room to the active call."""
|
||||
|
||||
def start_call_transcription(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
call_record_id: int | str,
|
||||
transcription_session_id: str,
|
||||
*,
|
||||
language: str = "zh-CN",
|
||||
) -> Any:
|
||||
"""Start a transcript stored on one exact call record."""
|
||||
|
||||
def upsert_call_transcript_segments(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
call_record_id: int | str,
|
||||
transcription_session_id: str,
|
||||
segments: Sequence[Mapping[str, Any]],
|
||||
) -> Any:
|
||||
"""Idempotently persist completed transcript segments."""
|
||||
|
||||
def finish_call_transcription(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
call_record_id: int | str,
|
||||
transcription_session_id: str,
|
||||
expected_segment_count: int,
|
||||
*,
|
||||
status: str = "completed",
|
||||
) -> Any:
|
||||
"""Finalize and materialize the transcript text on a call record."""
|
||||
|
||||
def my_self(self) -> Session:
|
||||
"""Compatibility alias for :meth:`get_session`."""
|
||||
@@ -2171,32 +2201,157 @@ class RemoteDoctorRepository:
|
||||
ticket.diagnosis_id = diagnosis_id
|
||||
return ticket
|
||||
|
||||
def start_call(self, diagnosis_id: int, patient_id: int, *, call_type: int = 2) -> Any:
|
||||
"""Create the server-side call record before ringing participants."""
|
||||
|
||||
return self.client.post(
|
||||
"tcm.diagnosis/startCall",
|
||||
{
|
||||
"diagnosis_id": diagnosis_id,
|
||||
"patient_id": patient_id,
|
||||
"call_type": call_type,
|
||||
},
|
||||
)
|
||||
def start_call(self, diagnosis_id: int, patient_id: int, *, call_type: int = 2) -> Any:
|
||||
"""Create the server-side call record before ringing participants."""
|
||||
|
||||
payload = self.client.post(
|
||||
"tcm.diagnosis/startCall",
|
||||
{
|
||||
"diagnosis_id": diagnosis_id,
|
||||
"patient_id": patient_id,
|
||||
"call_type": call_type,
|
||||
},
|
||||
)
|
||||
if not isinstance(payload, Mapping):
|
||||
raise ApiProtocolError(
|
||||
"tcm.diagnosis/startCall returned no valid call_record_id object", data=payload
|
||||
)
|
||||
raw_id = next(
|
||||
(
|
||||
payload[key]
|
||||
for key in ("call_record_id", "callRecordId", "id")
|
||||
if key in payload
|
||||
),
|
||||
None,
|
||||
)
|
||||
try:
|
||||
if isinstance(raw_id, bool):
|
||||
raise ValueError
|
||||
call_record_id = int(raw_id)
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ApiProtocolError(
|
||||
"tcm.diagnosis/startCall returned no valid call_record_id",
|
||||
data=dict(payload),
|
||||
) from exc
|
||||
if call_record_id <= 0:
|
||||
raise ApiProtocolError(
|
||||
"tcm.diagnosis/startCall returned no valid call_record_id",
|
||||
data=dict(payload),
|
||||
)
|
||||
return {"call_record_id": call_record_id}
|
||||
|
||||
def end_call(self, diagnosis_id: int) -> Any:
|
||||
"""End the active call/recording associated with a diagnosis."""
|
||||
|
||||
return self.client.post("tcm.diagnosis/endCall", {"diagnosis_id": diagnosis_id})
|
||||
|
||||
def bind_call_room(self, diagnosis_id: int, room_id: str) -> Any:
|
||||
"""Bind the actual TRTC room to the active call record."""
|
||||
def bind_call_room(self, diagnosis_id: int, room_id: str) -> Any:
|
||||
"""Bind the actual TRTC room to the active call record."""
|
||||
|
||||
if not room_id.strip():
|
||||
raise ValueError("room_id is required")
|
||||
return self.client.post(
|
||||
"tcm.diagnosis/bindCallRoom",
|
||||
{"diagnosis_id": diagnosis_id, "room_id": room_id.strip()},
|
||||
)
|
||||
return self.client.post(
|
||||
"tcm.diagnosis/bindCallRoom",
|
||||
{"diagnosis_id": diagnosis_id, "room_id": room_id.strip()},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _transcription_identity(
|
||||
diagnosis_id: int,
|
||||
call_record_id: int | str,
|
||||
transcription_session_id: str,
|
||||
) -> dict[str, Any]:
|
||||
if diagnosis_id <= 0:
|
||||
raise ValueError("diagnosis_id must be positive")
|
||||
if isinstance(call_record_id, bool) or not str(call_record_id).strip():
|
||||
raise ValueError("call_record_id is required")
|
||||
clean_session = transcription_session_id.strip()
|
||||
if not clean_session or len(clean_session) > 128:
|
||||
raise ValueError("transcription_session_id must contain 1 to 128 characters")
|
||||
return {
|
||||
"diagnosis_id": diagnosis_id,
|
||||
"call_record_id": call_record_id,
|
||||
"transcription_session_id": clean_session,
|
||||
}
|
||||
|
||||
def start_call_transcription(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
call_record_id: int | str,
|
||||
transcription_session_id: str,
|
||||
*,
|
||||
language: str = "zh-CN",
|
||||
) -> Any:
|
||||
"""Create the server transcript session for one call record."""
|
||||
|
||||
body = self._transcription_identity(
|
||||
diagnosis_id, call_record_id, transcription_session_id
|
||||
)
|
||||
body["language"] = language.strip()[:32] or "zh-CN"
|
||||
return self.client.post("tcm.diagnosis/startCallTranscription", body)
|
||||
|
||||
def upsert_call_transcript_segments(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
call_record_id: int | str,
|
||||
transcription_session_id: str,
|
||||
segments: Sequence[Mapping[str, Any]],
|
||||
) -> Any:
|
||||
"""Upsert a bounded batch using each segment_id as the idempotency key."""
|
||||
|
||||
body = self._transcription_identity(
|
||||
diagnosis_id, call_record_id, transcription_session_id
|
||||
)
|
||||
normalized: list[dict[str, Any]] = []
|
||||
if len(segments) > 50:
|
||||
raise ValueError("at most 50 transcript segments may be submitted at once")
|
||||
for segment in segments:
|
||||
segment_id = str(segment.get("segment_id") or "").strip()
|
||||
text = str(segment.get("text") or "").strip()
|
||||
if not segment_id or len(segment_id) > 160:
|
||||
raise ValueError("transcript segment_id is invalid")
|
||||
if not text or len(text) > 4_000:
|
||||
raise ValueError("transcript text is invalid")
|
||||
normalized.append(
|
||||
{
|
||||
"segment_id": segment_id,
|
||||
"speaker_user_id": str(segment.get("speaker_user_id") or "")[:160],
|
||||
"speaker_role": str(segment.get("speaker_role") or "unknown")[:20],
|
||||
"timestamp": max(int(segment.get("timestamp") or 0), 0),
|
||||
"text": text,
|
||||
}
|
||||
)
|
||||
if not normalized:
|
||||
raise ValueError("at least one transcript segment is required")
|
||||
body["segments"] = normalized
|
||||
return self.client.post("tcm.diagnosis/upsertCallTranscriptSegments", body)
|
||||
|
||||
def finish_call_transcription(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
call_record_id: int | str,
|
||||
transcription_session_id: str,
|
||||
expected_segment_count: int,
|
||||
*,
|
||||
status: str = "completed",
|
||||
) -> Any:
|
||||
"""Finalize a transcript; repeated requests use the same session identity."""
|
||||
|
||||
body = self._transcription_identity(
|
||||
diagnosis_id, call_record_id, transcription_session_id
|
||||
)
|
||||
clean_status = status.strip().lower()
|
||||
if clean_status not in {"completed", "partial", "failed"}:
|
||||
raise ValueError("transcription status is invalid")
|
||||
if expected_segment_count < 0:
|
||||
raise ValueError("expected_segment_count must not be negative")
|
||||
body.update(
|
||||
{
|
||||
"expected_segment_count": expected_segment_count,
|
||||
"status": clean_status,
|
||||
}
|
||||
)
|
||||
return self.client.post("tcm.diagnosis/finishCallTranscription", body)
|
||||
|
||||
# Compatibility aliases keep UI naming independent from endpoint history.
|
||||
def my_self(self) -> Session:
|
||||
|
||||
Reference in New Issue
Block a user