PatientSim / patientsim /checker.py
dek924's picture
feat: sanitize response by escaping braces to prevent formatting errors & add exception
e42bc71
Raw
History Blame Contribute Delete
3.45 kB
import os
from typing import Optional
from .registry.persona import VISIT_TYPE
from .utils import colorstr, log
from .client import GeminiClient, GeminiVertexClient, GPTClient, GPTAzureClient
_PROMPT_DIR = os.path.join(os.path.dirname(__file__), "assets", "prompt")
class CheckerAgent:
def __init__(self,
model: str,
visit_type: str = 'emergency_department',
api_key: Optional[str] = None,
use_azure: bool = False,
use_vertex: bool = False,
azure_endpoint: Optional[str] = None,
user_prompt_path: Optional[str] = None,
**kwargs) -> None:
self.visit_type = visit_type.lower()
self.__sanity_check()
self.model = model
self.random_seed = kwargs.get('random_seed', None)
self.temperature = kwargs.get('temperature', 0.0)
self._init_model(
model=self.model,
api_key=api_key,
use_azure=use_azure,
use_vertex=use_vertex,
azure_endpoint=azure_endpoint,
)
self.prompt_template = self._init_prompt(self.visit_type, user_prompt_path)
log("CheckerAgent initialized successfully", color=True)
def _init_model(self,
model: str,
api_key: Optional[str] = None,
use_azure: bool = False,
use_vertex: bool = False,
azure_endpoint: Optional[str] = None) -> None:
if 'gemini' in self.model.lower():
self.client = GeminiVertexClient(model, api_key) if use_vertex else GeminiClient(model, api_key)
elif 'gpt' in self.model.lower():
self.client = GPTAzureClient(model, api_key, azure_endpoint) if use_azure else GPTClient(model, api_key)
else:
raise ValueError(colorstr("red", f"Unsupported model: {self.model}. Supported models are 'gemini' and 'gpt'."))
def _init_prompt(self, visit_type: str, user_prompt_path: Optional[str] = None) -> str:
if not user_prompt_path:
fname = "op_terminate_user.txt" if visit_type == 'outpatient' else "ed_terminate_user.txt"
with open(os.path.join(_PROMPT_DIR, fname), 'r') as f:
return f.read()
else:
if not os.path.exists(user_prompt_path):
raise FileNotFoundError(colorstr("red", f"User prompt file not found: {user_prompt_path}"))
with open(user_prompt_path, 'r') as f:
return f.read()
def reset_history(self, verbose: bool = True) -> None:
self.client.reset_history(verbose=verbose)
def __sanity_check(self) -> None:
if self.visit_type not in VISIT_TYPE:
raise ValueError(colorstr("red", f"Invalid visiting type: {self.visit_type}. Supported types: {', '.join(VISIT_TYPE)}"))
def __call__(self, response: str, **kwargs) -> str:
# Escape braces in `response` before substitution to prevent unintended
# format-string expansion if the LLM output contains `{...}` patterns.
safe_response = response.replace("{", "{{").replace("}", "}}")
return self.client(
user_prompt=self.prompt_template.format(response=safe_response),
using_multi_turn=False,
verbose=False,
temperature=self.temperature,
seed=self.random_seed,
**kwargs
)