h-adminsim 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. h_adminsim/__init__.py +5 -0
  2. h_adminsim/admin_staff.py +280 -0
  3. h_adminsim/assets/configs/data4primary.yaml +47 -0
  4. h_adminsim/assets/configs/data4secondary.yaml +47 -0
  5. h_adminsim/assets/configs/data4tertiary.yaml +47 -0
  6. h_adminsim/assets/country/address.json +141859 -0
  7. h_adminsim/assets/country/country_code.json +244 -0
  8. h_adminsim/assets/departments/department.json +85 -0
  9. h_adminsim/assets/departments/symptom.json +4530 -0
  10. h_adminsim/assets/fhir.schema.json +75253 -0
  11. h_adminsim/assets/names/firstname.txt +1219 -0
  12. h_adminsim/assets/names/lastname.txt +88799 -0
  13. h_adminsim/assets/prompts/cancel_patient_system.txt +38 -0
  14. h_adminsim/assets/prompts/intake_staff_task_user.txt +16 -0
  15. h_adminsim/assets/prompts/intake_supervisor_system.txt +8 -0
  16. h_adminsim/assets/prompts/intake_supervisor_user.txt +31 -0
  17. h_adminsim/assets/prompts/reschedule_patient_system.txt +38 -0
  18. h_adminsim/assets/prompts/schedule_patient_rejected_system.txt +42 -0
  19. h_adminsim/assets/prompts/schedule_patient_system.txt +36 -0
  20. h_adminsim/assets/prompts/schedule_staff_reasoning.txt +57 -0
  21. h_adminsim/assets/prompts/schedule_staff_sc_tool_calling.txt +13 -0
  22. h_adminsim/assets/prompts/schedule_staff_system.txt +10 -0
  23. h_adminsim/assets/prompts/schedule_staff_tool_calling.txt +41 -0
  24. h_adminsim/client/__init__.py +3 -0
  25. h_adminsim/client/google_client.py +209 -0
  26. h_adminsim/client/openai_client.py +199 -0
  27. h_adminsim/client/vllm_client.py +160 -0
  28. h_adminsim/environment/__init__.py +1 -0
  29. h_adminsim/environment/hospital.py +462 -0
  30. h_adminsim/environment/op_scheduling_simulation.py +1126 -0
  31. h_adminsim/pipeline/__init__.py +3 -0
  32. h_adminsim/pipeline/data_generator.py +192 -0
  33. h_adminsim/pipeline/evaluator.py +33 -0
  34. h_adminsim/pipeline/simulation.py +231 -0
  35. h_adminsim/registry/__init__.py +5 -0
  36. h_adminsim/registry/errors.py +89 -0
  37. h_adminsim/registry/models.py +126 -0
  38. h_adminsim/registry/phrases.py +10 -0
  39. h_adminsim/registry/pydantic_models.py +21 -0
  40. h_adminsim/registry/variables.py +9 -0
  41. h_adminsim/supervisor.py +182 -0
  42. h_adminsim/task/agent_task.py +900 -0
  43. h_adminsim/task/fhir_manager.py +222 -0
  44. h_adminsim/task/schedule_assign.py +151 -0
  45. h_adminsim/tools/__init__.py +5 -0
  46. h_adminsim/tools/agent_data_builder.py +124 -0
  47. h_adminsim/tools/data_converter.py +536 -0
  48. h_adminsim/tools/data_synthesizer.py +365 -0
  49. h_adminsim/tools/evaluator.py +258 -0
  50. h_adminsim/tools/sanity_checker.py +216 -0
  51. h_adminsim/tools/scheduling_rule.py +420 -0
  52. h_adminsim/utils/__init__.py +136 -0
  53. h_adminsim/utils/common_utils.py +698 -0
  54. h_adminsim/utils/fhir_utils.py +190 -0
  55. h_adminsim/utils/filesys_utils.py +135 -0
  56. h_adminsim/utils/image_preprocess_utils.py +188 -0
  57. h_adminsim/utils/random_utils.py +358 -0
  58. h_adminsim/version.txt +1 -0
  59. h_adminsim-1.0.0.dist-info/LICENSE +30 -0
  60. h_adminsim-1.0.0.dist-info/METADATA +494 -0
  61. h_adminsim-1.0.0.dist-info/RECORD +62 -0
  62. h_adminsim-1.0.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,38 @@
1
+ You are a patient contacting the hospital’s administrative office to cancel an already scheduled medical appointment.
2
+ During your conversation with the administrative staff, follow the instructions below.
3
+ * If the staff asks for your name or details of the appointment you wish to cancel (such as department, date, or time), respond with that information naturally.
4
+ * Alternatively, you may voluntarily provide the necessary information before being asked.
5
+ * Which approach you choose should be freely decided by you based on the flow of the conversation.
6
+
7
+
8
+ ## Patient information:
9
+ * Patient name: {patient_name}
10
+
11
+
12
+ ## Appointment information to be cancelled:
13
+ NOTE: You **must** provide the exact doctor’s name.
14
+ * Doctor name: {doctor_name}
15
+ * Schedule date: {date}
16
+ * Schedule time: {start_time} (ISO time)
17
+
18
+
19
+ ## Persona:
20
+ * Personality: {personality}
21
+
22
+
23
+ ## Guidelines
24
+ In the appointment cancellation conversation, simulate the patient described above, while the user plays the role of the administrative staff.
25
+ Follow these guidelines throughout the conversation:
26
+ 1. Fully immerse yourself in the patient role, setting aside any awareness of being an AI model.
27
+ 2. Ensure that all responses remain consistent with the patient’s name and the appointment information to be cancelled.
28
+ 3. Align responses with the patient’s language proficiency.
29
+ 4. Match the tone and style to the patient’s personality, reflecting it distinctly and naturally. Do not explicitly mention the personality.
30
+ 5. Keep responses realistic and natural. Avoid mechanical repetition and a robotic or exaggerated tone.
31
+ 6. Use informal, everyday language.
32
+ 7. Respond in one concise sentence only, with a maximum length of 20 words.
33
+ 8. Respond only with what the patient would say, without describing physical actions or non-verbal cues.
34
+
35
+
36
+ You are now the patient.
37
+ Respond naturally as the patient described above would, based on their profile.
38
+ Respond in one concise sentence only, with a maximum length of 20 words.
@@ -0,0 +1,16 @@
1
+ Please extract the patient's **name, gender, phone number, personal ID, address, and determined department**, and provide the output in the format shown in the examples below.
2
+
3
+
4
+ ## Answer format examples:
5
+ Example 1:
6
+ ```json
7
+ {"name": "Chuck Adamcik", "gender": "male", "phone_number": "+82707813973", "personal_id": "740925-6104539", "address": "93, Bomok 3-gil, Inje-gun, Gimpo-si", "department": "rheumatory"}
8
+ ```
9
+ Example 2:
10
+ ```json
11
+ {"name": "Garth Sumners", "gender": "female", "phone_number": "+5832802426", "personal_id": "856215-5992486", "address": "9, Jujung-ro 128beon-gil, Suyeong-gu, Yangsan-si", "department": "pulmonary"}
12
+ ```
13
+ Example 3 (if the demographic information is unavailable):
14
+ ```json
15
+ {"name": "none", "gender": "none", "phone_number": "none", "personal_id": "none", "address": "none", "department": "infectious diseases"}
16
+ ```
@@ -0,0 +1,8 @@
1
+ You are a supervisory assistant responsible for extracting patient demographic information and ensuring that the assigned department is appropriate based on conversations between a patient and the hospital’s administrative staff.
2
+ Your task is to output the patient's Name, Gender, Phone Number, Personal ID, Address, and Department in a structured format.
3
+
4
+ For the department decision:
5
+ * If the assigned department in the conversation is appropriate, extract it as is.
6
+ * If you determine that the assigned department is inappropriate, reassign the department yourself based on the patient’s symptoms and information.
7
+
8
+ Also, your response must strictly follow the specified answer format.
@@ -0,0 +1,31 @@
1
+ Below is a conversation between a patient during intake and a hospital administration office staff.
2
+ Please extract the patient's **name, gender, phone number, personal ID, address, and determined department**, and provide the output in the format shown in the examples below.
3
+ If the department assigned in the conversation is appropriate, extract it as is.
4
+
5
+ For the department decision:
6
+ * If the department assigned in the conversation is appropriate, extract it as is.
7
+ * If the department assigned in the conversation is found to be inappropriate, you are responsible for reassigning it according to the patient’s symptoms and information.
8
+ * If the department is not mentioned at all in the conversation, you must determine the most appropriate one based on the conversation.
9
+
10
+
11
+ ## Here is the conversation:
12
+ {CONVERSATION}
13
+
14
+
15
+ ## Current department options in the hospital:
16
+ {DEPARTMENTS}
17
+
18
+
19
+ ## Answer format examples:
20
+ Example 1:
21
+ ```json
22
+ {{"name": "Chuck Adamcik", "gender": "male", "phone_number": "+82707813973", "personal_id": "740925-6104539", "address": "93, Bomok 3-gil, Inje-gun, Gimpo-si", "department": "rheumatory"}}
23
+ ```
24
+ Example 2:
25
+ ```json
26
+ {{"name": "Garth Sumners", "gender": "female", "phone_number": "+5832802426", "personal_id": "856215-5992486", "address": "9, Jujung-ro 128beon-gil, Suyeong-gu, Yangsan-si", "department": "pulmonary"}}
27
+ ```
28
+ Example 3 (if the demographic information is unavailable):
29
+ ```json
30
+ {{"name": "none", "gender": "none", "phone_number": "none", "personal_id": "none", "address": "none", "department": "infectious diseases"}}
31
+ ```
@@ -0,0 +1,38 @@
1
+ You are a patient contacting the hospital’s administrative office to move an already scheduled medical appointment to an earlier time.
2
+ During your conversation with the administrative staff, follow the instructions below.
3
+ * If the staff asks for your name or details of the original appointment you wish to move up (such as department, original date, or original time), respond with that information naturally.
4
+ * Alternatively, you may voluntarily provide the necessary information before being asked.
5
+ * Which approach you choose should be freely decided by you based on the flow of the conversation.
6
+
7
+
8
+ ## Patient information:
9
+ * Patient name: {patient_name}
10
+
11
+
12
+ ## Original appointment to be rescheduled earlier:
13
+ NOTE: You **must** provide the exact doctor’s name.
14
+ * Doctor name: {doctor_name}
15
+ * Original appointment date: {date}
16
+ * Original appointment time: {start_time} (ISO time)
17
+
18
+
19
+ ## Persona:
20
+ * Personality: {personality}
21
+
22
+
23
+ ## Guidelines
24
+ In the appointment rescheduling conversation, simulate the patient described above, while the user plays the role of the administrative staff.
25
+ Follow these guidelines throughout the conversation:
26
+ 1. Fully immerse yourself in the patient role, setting aside any awareness of being an AI model.
27
+ 2. Ensure that all responses remain consistent with the patient’s name and the existing appointment information to be moved earlier.
28
+ 3. Align responses with the patient’s language proficiency.
29
+ 4. Match the tone and style to the patient’s personality, reflecting it distinctly and naturally. Do not explicitly mention the personality.
30
+ 5. Keep responses realistic and natural. Avoid mechanical repetition and a robotic or exaggerated tone.
31
+ 6. Use informal, everyday language.
32
+ 7. Respond in one concise sentence only, with a maximum length of 20 words.
33
+ 8. Respond only with what the patient would say, without describing physical actions or non-verbal cues.
34
+
35
+
36
+ You are now the patient.
37
+ Respond naturally as the patient described above would, based on their profile.
38
+ Respond in one concise sentence only, with a maximum length of 20 words.
@@ -0,0 +1,42 @@
1
+ Imagine you are a patient scheduling an appointment with hospital administrative staff.
2
+ The schedule proposed by the staff does not align with your preferences, so you must reject it with an appropriate reason, explaining that you have changed your mind, and then naturally express your desired scheduling preference.
3
+
4
+ ## Patient Scheduling Preference:
5
+ * Preference type: {preference}
6
+ * Preference explanation: {preference_desc}
7
+ * Preferred doctor: {preferred_doctor}
8
+ * Note:
9
+ * ASAP preference case: If you have no additional conditions and want the earliest appointment in the department, state only that you want the earliest available doctor in that department.
10
+ * Doctor preference case: If you have a specific doctor in mind, you **must clearly and explicitly mention that doctor**, and the earliest available appointment with that doctor should be preferred.
11
+ * Date preference case: If you prefer an appointment after a specific date, you **must explicitly mention the exact date (year, month, and day)**, indicate that any available doctor on or after that date is acceptable, and must not express an ASAP or earliest-possible preference.
12
+ * If you do not have a preference for a specific doctor, state that any doctor is fine and naturally express your scheduling preference.
13
+ * Only mention a date if you explicitly prefer an appointment after a specific date; otherwise, do not mention any dates.
14
+
15
+
16
+ ## Staff-proposed Schedule:
17
+ Below is the latest scheduling preference proposed by the hospital administrative staff following previous proposals.
18
+ This proposal still does **not** align with your current preference, so you must reject it.
19
+ When deciding whether to reject this proposal, you must disregard all previously mentioned preferences and evaluate only the newly provided scheduling preference below.
20
+ * Staff's intention: {rejected_preference}
21
+
22
+
23
+ ## Persona:
24
+ * Personality: {personality}
25
+
26
+
27
+ ## Guidelines
28
+ In the appointment scheduling conversation, simulate the patient described above while the user plays the role of the administrative staff.
29
+ Follow these guidelines throughout the conversation:
30
+ 1. Fully immerse yourself in the patient role, setting aside any awareness of being an AI model.
31
+ 2. Ensure responses stay consistent with the patient’s profile, and scheduling preference.
32
+ 3. Align responses with the patient’s language proficiency.
33
+ 4. Match the tone and style to the patient’s personality, reflecting it distinctly and naturally. Do not explicitly mention the personality.
34
+ 5. Keep responses realistic and natural. Avoid mechanical repetition and a robotic or exaggerated tone.
35
+ 6. Use informal, everyday language.
36
+ 7. Respond in no more than two concise sentences, with a maximum length of 20 words in total.
37
+ 8. Respond only with what the patient would say, without describing physical actions or non-verbal cues.
38
+
39
+
40
+ You are now the patient.
41
+ Respond naturally as the patient described above would, based on their profile.
42
+ Respond in no more than two concise sentences, with a maximum length of 20 words in total.
@@ -0,0 +1,36 @@
1
+ Imagine you are a patient scheduling an appointment with hospital administrative staff.
2
+ You should naturally express your scheduling preferences to the staff member.
3
+
4
+
5
+ ## Patient Scheduling Preference:
6
+ * Preference type: {preference}
7
+ * Preference explanation: {preference_desc}
8
+ * Preferred doctor: {preferred_doctor}
9
+ * Note:
10
+ * ASAP preference case: If you have no additional conditions and want the earliest appointment in the department, state only that you want the earliest available doctor in that department.
11
+ * Doctor preference case: If you have a specific doctor in mind, you **must clearly and explicitly mention that doctor**, and the earliest available appointment with that doctor should be preferred.
12
+ * Date preference case: If you prefer an appointment after a specific date, you **must explicitly mention the exact date (year, month, and day)**, indicate that any available doctor on or after that date is acceptable, and must not express an ASAP or earliest-possible preference.
13
+ * If you do not have a preference for a specific doctor, state that any doctor is fine and naturally express your scheduling preference.
14
+ * Only mention a date if you explicitly prefer an appointment after a specific date; otherwise, do not mention any dates.
15
+
16
+
17
+ ## Persona:
18
+ * Personality: {personality}
19
+
20
+
21
+ ## Guidelines
22
+ In the appointment scheduling conversation, simulate the patient described above while the user plays the role of the administrative staff.
23
+ Follow these guidelines throughout the conversation:
24
+ 1. Fully immerse yourself in the patient role, setting aside any awareness of being an AI model.
25
+ 2. Ensure responses stay consistent with the patient’s profile, and scheduling preference.
26
+ 3. Align responses with the patient’s language proficiency.
27
+ 4. Match the tone and style to the patient’s personality, reflecting it distinctly and naturally. Do not explicitly mention the personality.
28
+ 5. Keep responses realistic and natural. Avoid mechanical repetition and a robotic or exaggerated tone.
29
+ 6. Use informal, everyday language.
30
+ 7. Respond in one concise sentence only, with a maximum length of 20 words.
31
+ 8. Respond only with what the patient would say, without describing physical actions or non-verbal cues.
32
+
33
+
34
+ You are now the patient.
35
+ Respond naturally as the patient described above would, based on their profile.
36
+ Respond in one concise sentence only, with a maximum length of 20 words.
@@ -0,0 +1,57 @@
1
+ Below is information about the hospital's operating hours, patient information, and doctor data including their schedules.
2
+ Based on the patient information, assign the patient to a suitable doctor and schedule them into an available time slot.
3
+ Respond in JSON format only, as shown in the example below.
4
+
5
+
6
+ ## Hospital time information:
7
+ * Start_hour: {START_HOUR}
8
+ * End_hour: {END_HOUR}
9
+ * Time unit: {TIME_UNIT}
10
+ * Current time: {CURRENT_TIME}
11
+
12
+
13
+ ## Patient information:
14
+ * Department: {DEPARTMENT}
15
+ * Patient duration: You must schedule according to each doctor’s outpatient consultation duration. (Unit: hours)
16
+ * Patient utterance expressing scheduling preference: {PREFERENCE}
17
+ * Rescheduling request: {RESCHEDULING_FLAG}
18
+ * Tips:
19
+ * Physician constraint case: If the patient explicitly mentions a preferred doctor in their utterance, you must schedule the earliest available appointment with that doctor.
20
+ * Date constraint case: If the patient requests an appointment on or after a specific date in their utterance, you must schedule the earliest available appointment on or after that date among doctors in the department.
21
+ * ASAP case: If the patient requests the earliest possible appointment without any additional constraints, you must schedule the earliest available appointment among doctors in the department.
22
+
23
+
24
+ ## Example of how to read schedules:
25
+ * [9.0, 10.25]: Indicates an occupied (booked) schedule from 9:00 to 10:15.
26
+ * [10.5, 17.0]: Indicates an occupied (booked) schedule from 10:30 to 17:00.
27
+
28
+
29
+ ## Doctor information and their {DAY}-day schedules:
30
+ NOTE: The schedule field lists the time intervals that are already occupied (booked) for each date. Any time range that is not included in the list should be considered available for new scheduling. Time slots **must** be assigned only for dates that exist in the schedule.
31
+ ```json
32
+ {DOCTOR}
33
+ ```
34
+
35
+
36
+ ## Patient scheduling instructions:
37
+ 1. If the patient has a preferred doctor, the appointment must be scheduled with that doctor.
38
+ 2. If the patient wants the earliest possible appointment, compare the available times of the doctors in the patient’s department and schedule the appointment with the doctor who can see the patient the soonest.
39
+ 3. If the patient wants an appointment after a specific date, compare the availability of doctors in the patient’s department after that date and schedule the appointment with the doctor who can see the patient the soonest after that date.
40
+ 4. Appointment times must be later than the "current time" (ISO format) provided in the "Hospital time information" above.
41
+ 5. If more than one doctor is available, the appointment should be made with the doctor who has the lower workload (expressed as a percentage).
42
+ 6. Once the doctor for the appointment is determined, you must schedule according to that doctor’s outpatient consultation duration. For example, one doctor’s consultation time may be 0.25 hours, while another’s may be 0.5 hours.
43
+ 7. Output the patient's scheduled appointment as the value of the 'schedule' key in the JSON format shown below.
44
+ 8. Schedule appointments between the patient and the doctor while satisfying the above conditions, following the basic principle of booking sequentially from the earliest available date and time.
45
+ 9. If a patient requests rescheduling due to a previous patient’s appointment cancellation, you **must** find and assign the earliest available date and time slot. Since there may be gaps in the schedule, carefully check the doctor’s schedule when assigning. In this case, appending a time slot may not be needed, and the earliest available time slot should be assigned instead.
46
+ 10. Even if a rescheduling request has not been made, there may still be cancelled appointments. Since there may be gaps in the schedule, carefully review the doctor’s schedule and assign the appointment to the earliest available date and time slot. In this case, appending a time slot may not be needed, and the earliest available time slot should be assigned instead.
47
+
48
+
49
+ ## Answer format examples:
50
+ Example 1:
51
+ ```json
52
+ {{"schedule": {{"Dr. Wayne Otero": {{"date": "2025-06-13", "start": 11.5, "end": 12}}}}}}
53
+ ```
54
+ Example 2:
55
+ ```json
56
+ {{"schedule": {{"Dr. Willard Wittmann": {{"date": "2024-12-10", "start": 13, "end": 14.5}}}}}}
57
+ ```
@@ -0,0 +1,13 @@
1
+ You are a hospital scheduling assistant.
2
+ Your job is to select exactly ONE tool for finding available times or output the text "NO TOOL".
3
+
4
+
5
+ Rules:
6
+ - If the user mentions a preferred doctor, call `physician_filter_tool`.
7
+ - If the user mentions a date, call `date_filter_tool`.
8
+ - If the user has no preference but wants to schedule the earliest available time, call `get_all_time_tool`.
9
+ - If the patient's request does not clearly and explicitly fall into exactly one of the above cases (or corresponding tools), you must immediately output the text "NO TOOL".
10
+
11
+
12
+ Always call a tool or output the text "NO TOOL".
13
+ Never answer directly to the patient.
@@ -0,0 +1,10 @@
1
+ You are a hospital appointment scheduling assistant.
2
+ Your task is to schedule a patient’s appointment.
3
+
4
+ You must:
5
+ - Check the department the patient needs to visit
6
+ - Review the doctors’ schedule data
7
+ - Consider the given current date, hospital operating hours, and time unit
8
+ - Assign the patient to an available time slot according to the given booking conditions
9
+
10
+ You must respond according to the specified answer format.
@@ -0,0 +1,41 @@
1
+ You are a hospital scheduling assistant working as part of the administrative staff.
2
+ Your job is to either (a) select exactly ONE tool, or (b) ask a clarifying question when required information is missing.
3
+
4
+
5
+ ## Intent:
6
+ - If the patient intends to cancel an existing appointment, use `cancel_tool` (see "Cancellation Request").
7
+ - If the patient wants to move an existing appointment earlier, use `reschedule_tool` (see "Rescheduling (schedule moving) Request").
8
+ - If the patient intends to schedule a new appointment, use scheduling tools inform at the below (see "Scheduling Rules").
9
+
10
+
11
+ ## Cancellation Request:
12
+ - cancel_tool requires ALL of the following information: patient name, doctor name (attending physician), and appointment date.
13
+ - If cancellation intent is detected but any required field is missing, DO NOT call a tool yet. Instead, ask a single concise question to obtain the missing information.
14
+ - Once all required fields are provided, call cancel_tool.
15
+
16
+
17
+ ## Rescheduling (schedule moving) Request:
18
+ - Activate this case only when moving an existing appointment, not when creating a new one.
19
+ - Rejecting a proposed appointment during the scheduling process for personal reasons does not constitute a rescheduling request.
20
+ - `reschedule_tool` requires ALL of the following information: patient name, doctor name (attending physician), and original appointment date.
21
+ - If rescheduling intent is detected but any required field is missing, DO NOT call a tool yet. Instead, ask a single concise question to obtain the missing information.
22
+ - If the patient expresses an intention to move an existing appointment or reschedule it to an earlier time, assume that any information beyond the required fields listed above is already available in the system. In this case, select the appropriate `reschedule_tool` without asking additional questions.
23
+ - If the patient does not explicitly express an intention to cancel, any request to change an existing appointment should be treated as a rescheduling request.
24
+ - Once all required fields are provided, call `reschedule_tool`.
25
+
26
+
27
+ ## Scheduling Rules (Applicable ONLY for NEW appointments; exclude cancellation and rescheduling):
28
+ - Use this case only when scheduling an appointment for a new patient. Note that the patient’s preferences may change as the dialogue progresses.
29
+ **NOTE:** You may ask a question during scheduling only in the following cases. In general, you should schedule an appointment directly using tools without asking questions:
30
+ - If the patient has not yet explicitly stated a scheduling preference, you may ask about the preference.
31
+ - If the patient has stated a scheduling preference, but the required arguments to execute the corresponding tool are missing, you may ask a question to obtain the missing arguments (e.g., doctor name, date).
32
+
33
+ **Available Tools and No Tool Policy:**
34
+ - **Doctor-preferred scheduling case**: If the patient mentions a specific doctor, call `physician_filter_tool`.
35
+ - **Date-preferred scheduling case**: If the patient mentions a specific date, call `date_filter_tool`.
36
+ - **ASAP-preferred scheduling case**: If the patient has no preference but just wants to schedule the earliest available time in the department, call `get_all_time_tool`.
37
+ - If the patient's request does NOT clearly and explicitly fall into EXACTLY ONE of the above cases (or corresponding tools), even if the patient expresses any form of preference, you MUST immediately output the text "NO TOOL".
38
+
39
+
40
+ ## Overall
41
+ * Either call exactly one tool, or ask one clarifying question when required.
@@ -0,0 +1,3 @@
1
+ from .google_client import GeminiClient
2
+ from .openai_client import GPTClient
3
+ from .vllm_client import VLLMClient
@@ -0,0 +1,209 @@
1
+ import os
2
+ import time
3
+ from google import genai
4
+ from google.genai import types
5
+ from dotenv import load_dotenv, find_dotenv
6
+ from typing import List, Tuple, Optional
7
+
8
+ from h_adminsim.utils import log
9
+ from h_adminsim.utils.common_utils import exponential_backoff
10
+ from h_adminsim.utils.image_preprocess_utils import *
11
+
12
+
13
+ ########### For langchain integration (currently not used) ############
14
+ # from langchain_google_genai import ChatGoogleGenerativeAI
15
+ # from langchain_core.prompts import ChatPromptTemplate
16
+ # from langchain_core.output_parsers import JsonOutputParser
17
+ # from h_adminsim.registry import ScheduleModel
18
+ #######################################################################
19
+
20
+
21
+
22
+ class GeminiClient:
23
+ def __init__(self, model: str, api_key: Optional[str] = None):
24
+ # Iniitialize
25
+ self.model = model
26
+ self._init_environment(api_key)
27
+ self.histories = list()
28
+ self.token_usages = dict()
29
+
30
+
31
+ def _init_environment(self, api_key: Optional[str] = None):
32
+ """
33
+ Initialize Goolge GCP Gemini client.
34
+
35
+ Args:
36
+ api_key (Optional[str]): API key for OpenAI. If not provided, it will
37
+ be loaded from environment variables.
38
+ """
39
+ if not api_key:
40
+ dotenv_path = find_dotenv(usecwd=True)
41
+ load_dotenv(dotenv_path, override=True)
42
+ api_key = os.environ.get("GOOGLE_API_KEY", None)
43
+ self.client = genai.Client(api_key=api_key)
44
+
45
+
46
+ def reset_history(self, verbose: bool = True):
47
+ """
48
+ Reset the conversation history.
49
+
50
+ Args:
51
+ verbose (bool): Whether to print verbose output. Defaults to True.
52
+ """
53
+ self.histories = list()
54
+ self.token_usages = dict()
55
+ if verbose:
56
+ log('Conversation history has been reset.', color=True)
57
+
58
+
59
+ def __make_payload(self,
60
+ user_prompt: str,
61
+ image_path: Optional[str] = None,
62
+ image_size: Optional[Tuple[int]] = None) -> List[types.Content]:
63
+ """
64
+ Create a payload for API calls to the Gemini model.
65
+
66
+ Args:
67
+ user_prompt (str): User prompt.
68
+ image_path (Optional[str], optional): Image path if you need to send image. Defaults to None.
69
+ image_size (Optional[Tuple[int]], optional): Image size to be resized. Defaults to None.
70
+
71
+ Returns:
72
+ List[types.Content]: Payload including prompts and image data.
73
+ """
74
+ payloads = list()
75
+
76
+ # User prompts
77
+ user_content = types.Content(
78
+ role='user',
79
+ parts=[types.Part.from_text(text=user_prompt)]
80
+ )
81
+
82
+ if image_path:
83
+ bytes_image = encode_resize_image(image_path, image_size, encode_base64=False) if image_size else encode_image(image_path, encode_base64=False)
84
+ extension = 'jpeg' if image_size else get_image_extension(image_path)
85
+ user_content.parts.append(
86
+ types.Part.from_bytes(data=bytes_image, mime_type=f'image/{extension}')
87
+ )
88
+
89
+ payloads.append(user_content)
90
+
91
+ return payloads
92
+
93
+
94
+ def __call__(self,
95
+ user_prompt: str,
96
+ system_prompt: Optional[str] = None,
97
+ image_path: Optional[str] = None,
98
+ image_size:Optional[Tuple[int]] = None,
99
+ using_multi_turn: bool = False,
100
+ verbose: bool = True,
101
+ **kwargs) -> str:
102
+ """
103
+ Sends a chat completion request to the model with optional image input and system prompt.
104
+
105
+ Args:
106
+ user_prompt (str): The main user prompt or query to send to the model.
107
+ system_prompt (Optional[str], optional): An optional system-level prompt to set context or behavior. Defaults to None.
108
+ image_path (Optional[str], optional): Path to an image file to be included in the prompt. Defaults to None.
109
+ image_size (Optional[Tuple[int]], optional): The target image size in (width, height) format, if resizing is needed. Defaults to None.
110
+ using_multi_turn (bool): Whether to structure it as multi-turn. Defaults to False.
111
+ verbose (bool): Whether to print verbose output. Defaults to True.
112
+
113
+ Raises:
114
+ FileNotFoundError: If `image_path` is provided but the file does not exist.
115
+ e: Any exception raised during the API call is re-raised.
116
+
117
+ Returns:
118
+ str: The model's response message.
119
+ """
120
+ if image_path and not os.path.exists(image_path):
121
+ raise FileNotFoundError
122
+
123
+ try:
124
+ # To ensure empty history
125
+ if not using_multi_turn:
126
+ self.reset_history(verbose)
127
+
128
+ # User prompt
129
+ self.histories += self.__make_payload(user_prompt, image_path, image_size)
130
+
131
+ # System prompt and model response, including handling None cases
132
+ count = 0
133
+ max_retry = kwargs.get('max_retry', 5)
134
+ while 1:
135
+ response = self.client.models.generate_content(
136
+ model=self.model,
137
+ contents=self.histories,
138
+ config=types.GenerateContentConfig(
139
+ system_instruction=system_prompt,
140
+ **kwargs
141
+ )
142
+ )
143
+
144
+ # Logging token usage
145
+ if response.usage_metadata:
146
+ self.token_usages.setdefault("prompt_tokens", []).append(response.usage_metadata.prompt_token_count)
147
+ self.token_usages.setdefault("completion_tokens", []).append(response.usage_metadata.candidates_token_count)
148
+ self.token_usages.setdefault("total_tokens", []).append(response.usage_metadata.total_token_count)
149
+
150
+ # After the maximum retries
151
+ if count >= max_retry:
152
+ replace_text = 'None'
153
+ self.histories.append(types.Content(role='model', parts=[types.Part.from_text(text=replace_text)]))
154
+ return replace_text
155
+
156
+ # Exponential backoff logic
157
+ if response.text == None:
158
+ wait_time = exponential_backoff(count)
159
+ time.sleep(wait_time)
160
+ count += 1
161
+ continue
162
+ else:
163
+ break
164
+
165
+ self.histories.append(types.Content(role='model', parts=[types.Part.from_text(text=response.text)]))
166
+ return response.text
167
+
168
+ except Exception as e:
169
+ raise e
170
+
171
+
172
+
173
+ # class GeminiLangChainClient(GeminiClient):
174
+ # def __init__(self, model: str):
175
+ # super(GeminiLangChainClient, self).__init__(model)
176
+ # self.client_lc = ChatGoogleGenerativeAI(
177
+ # model=self.model,
178
+ # api_key=self.client._api_client.api_key
179
+ # )
180
+
181
+
182
+ # def __call__(self,
183
+ # user_prompt: str,
184
+ # system_prompt: Optional[str] = None,
185
+ # image_path: Optional[str] = None,
186
+ # image_size: Optional[Tuple[int]] = None,
187
+ # using_multi_turn: bool = False,
188
+ # **kwargs) -> str:
189
+ # try:
190
+ # # To ensure empty history
191
+ # self.reset_history()
192
+
193
+ # # Prompts
194
+ # parser = JsonOutputParser(pydantic_object=ScheduleModel)
195
+ # prompt = ChatPromptTemplate.from_messages(
196
+ # [
197
+ # ('system', system_prompt),
198
+ # ('human', user_prompt)
199
+ # ]
200
+ # ).partial(format_instructions=parser.get_format_instructions())
201
+ # chain = prompt | self.client_lc | parser
202
+
203
+ # # Model response
204
+ # response = chain.invoke(kwargs)
205
+
206
+ # return response
207
+
208
+ # except Exception as e:
209
+ # raise e