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,536 @@
1
+ import os
2
+ from tqdm import tqdm
3
+ from typing import Optional
4
+
5
+ from h_adminsim.utils import Information, log
6
+ from h_adminsim.utils.fhir_utils import *
7
+ from h_adminsim.utils.filesys_utils import json_load, json_save_fast, get_files
8
+ from h_adminsim.utils.common_utils import (
9
+ get_iso_time,
10
+ get_utc_offset,
11
+ convert_time_to_segment,
12
+ convert_segment_to_time,
13
+ )
14
+
15
+
16
+
17
+ class DataConverter:
18
+ def __init__(self, config):
19
+ # Initialize configuration
20
+ self.fhir_url = config.fhir_url
21
+ data_dir = os.path.join(config.project, config.data_name, 'data')
22
+ self.data_files = get_files(data_dir, ext='json')
23
+
24
+
25
+ @staticmethod
26
+ def data_to_practitioner(data: dict, output_dir: Optional[str] = None, sanity_check: bool = False) -> list[dict]:
27
+ """
28
+ Convert synthetic hospital data into `Practitioner` FHIR resources.
29
+
30
+ Args:
31
+ data (dict): Synthetic hospital data containing doctor information.
32
+ output_dir (Optional[str], optional): Directory path to save the converted Practitioner resources
33
+ as `.fhir.json` files. If None, the resources are not saved to disk.
34
+ Defaults to None.
35
+ sanity_check (bool, optional): If True, performs a sanity check to ensure the uniqueness of the generated FHIR data.
36
+ This only applies when output_dir is specified. Defaults to False.
37
+
38
+ Returns:
39
+ list[dict]: A list of converted FHIR Practitioner resource objects.
40
+ """
41
+ save_dir = None
42
+ if output_dir:
43
+ os.makedirs(os.path.join(output_dir, 'practitioner'), exist_ok=True)
44
+ save_dir = os.path.join(output_dir, 'practitioner')
45
+
46
+ hospital_name = data.get('metadata')['hospital_name']
47
+ department_data = data.get('department')
48
+ practitioners = list()
49
+
50
+ for doctor_name, doctor_values in data['doctor'].items():
51
+ practitioner_id = get_individual_id(
52
+ hospital_name,
53
+ department_data[doctor_values['department']]['code'].lower(),
54
+ doctor_name
55
+ )
56
+ names = doctor_name.split()
57
+ practitioner_obj = {
58
+ 'resourceType': 'Practitioner',
59
+ 'id': practitioner_id,
60
+ 'active': True,
61
+ 'name': [
62
+ {
63
+ 'family': names[-1],
64
+ 'given': [' '.join(names[1:-1])],
65
+ 'prefix': [names[0]]
66
+ }
67
+ ],
68
+ 'gender': doctor_values['gender'],
69
+ 'telecom': doctor_values['telecom'],
70
+ 'birthDate': doctor_values['birthDate']
71
+ }
72
+ practitioners.append(practitioner_obj)
73
+
74
+ if save_dir:
75
+ save_path = os.path.join(save_dir, f'{practitioner_id}.fhir.json')
76
+ if sanity_check:
77
+ assert not os.path.exists(save_path), log(f"Same file exists: {save_path}", "error")
78
+ json_save_fast(
79
+ save_path,
80
+ practitioner_obj
81
+ )
82
+
83
+ return practitioners
84
+
85
+
86
+ @staticmethod
87
+ def data_to_practitionerrole(data: dict, output_dir: Optional[str] = None, sanity_check: bool = False) -> list[dict]:
88
+ """
89
+ Convert synthetic hospital data into `PractitionerRole` FHIR resources.
90
+
91
+ Args:
92
+ data (dict): Synthetic hospital data containing doctor information.
93
+ output_dir (Optional[str], optional): Directory path to save the converted PractitionerRole resources
94
+ as `.fhir.json` files. If None, the resources are not saved to disk.
95
+ Defaults to None.
96
+ sanity_check (bool, optional): If True, performs a sanity check to ensure the uniqueness of the generated FHIR data.
97
+ This only applies when output_dir is specified. Defaults to False.
98
+
99
+ Returns:
100
+ list[dict]: A list of converted FHIR PractitionerRole resource objects.
101
+ """
102
+ save_dir = None
103
+ if output_dir:
104
+ os.makedirs(os.path.join(output_dir, 'practitionerrole'), exist_ok=True)
105
+ save_dir = os.path.join(output_dir, 'practitionerrole')
106
+
107
+ hospital_name = data.get('metadata')['hospital_name']
108
+ department_data = data.get('department')
109
+ practitionerroles = list()
110
+
111
+ for doctor_name, doctor_values in data['doctor'].items():
112
+ practitioner_id = get_individual_id(
113
+ hospital_name,
114
+ department_data[doctor_values['department']]['code'].lower(),
115
+ doctor_name
116
+ )
117
+ practitionerrole_id = get_practitionerrole_id(practitioner_id)
118
+ practitionerrole_obj = {
119
+ 'resourceType': 'PractitionerRole',
120
+ 'id': practitionerrole_id,
121
+ 'active': True,
122
+ 'specialty': [
123
+ {
124
+ 'coding': [{
125
+ 'code': doctor_values['specialty']['code'],
126
+ 'display': doctor_values['specialty']['name']
127
+ }],
128
+ 'text': doctor_values['department']
129
+ }
130
+ ],
131
+ 'characteristic': [
132
+ {
133
+ 'coding': [{
134
+ 'code': 'capacity_per_hour',
135
+ 'display': str(doctor_values['capacity_per_hour'])
136
+ }],
137
+ 'text': 'capacity_per_hour'
138
+ },
139
+ {
140
+ 'coding': [{
141
+ 'code': 'capacity',
142
+ 'display': str(doctor_values['capacity'])
143
+ }],
144
+ 'text': 'capacity'
145
+ }
146
+ ],
147
+ 'practitioner': {'reference': f'Practitioner/{practitioner_id}'}
148
+ }
149
+ practitionerroles.append(practitionerrole_obj)
150
+
151
+ if save_dir:
152
+ save_path = os.path.join(save_dir, f'{practitionerrole_id}.fhir.json')
153
+ if sanity_check:
154
+ assert not os.path.exists(save_path), log(f"Same file exists: {save_path}", "error")
155
+ json_save_fast(
156
+ save_path,
157
+ practitionerrole_obj
158
+ )
159
+
160
+ return practitionerroles
161
+
162
+
163
+ @staticmethod
164
+ def data_to_patient(data: dict, output_dir: Optional[str] = None, sanity_check: bool = False) -> list[dict]:
165
+ """
166
+ Convert synthetic hospital data into `Patient` FHIR resources.
167
+
168
+ Args:
169
+ data (dict): Synthetic hospital data containing doctor information.
170
+ output_dir (Optional[str], optional): Directory path to save the converted Patient resources
171
+ as `.fhir.json` files. If None, the resources are not saved to disk.
172
+ Defaults to None.
173
+ sanity_check (bool, optional): If True, performs a sanity check to ensure the uniqueness of the generated FHIR data.
174
+ This only applies when output_dir is specified. Defaults to False.
175
+
176
+ Returns:
177
+ list[dict]: A list of converted FHIR Patient resource objects.
178
+ """
179
+ save_dir = None
180
+ if output_dir:
181
+ os.makedirs(os.path.join(output_dir, 'patient'), exist_ok=True)
182
+ save_dir = os.path.join(output_dir, 'patient')
183
+
184
+ hospital_name = data.get('metadata')['hospital_name']
185
+ department_data = data.get('department')
186
+ patients = list()
187
+
188
+ for patient_name, patient_values in data['patient'].items():
189
+ patient_id = get_individual_id(
190
+ hospital_name,
191
+ department_data[patient_values['department']]['code'].lower(),
192
+ patient_name
193
+ )
194
+ names = patient_name.split()
195
+ patient_obj = {
196
+ 'resourceType': 'Patient',
197
+ 'id': patient_id,
198
+ 'active': True,
199
+ 'name': [
200
+ {
201
+ 'family': names[-1],
202
+ 'given': [' '.join(names[:-1])],
203
+ }
204
+ ],
205
+ 'gender': patient_values['gender'],
206
+ 'telecom': patient_values['telecom'],
207
+ 'birthDate': patient_values['birthDate'],
208
+ 'identifier': patient_values['identifier'],
209
+ 'address': patient_values['address']
210
+ }
211
+ patients.append(patient_obj)
212
+
213
+ if save_dir:
214
+ save_path = os.path.join(save_dir, f'{patient_id}.fhir.json')
215
+ if sanity_check:
216
+ assert not os.path.exists(save_path), log(f"Same file exists: {save_path}", "error")
217
+ json_save_fast(
218
+ save_path,
219
+ patient_obj
220
+ )
221
+
222
+ return patients
223
+
224
+
225
+ @staticmethod
226
+ def data_to_schedule(data: dict, output_dir: Optional[str] = None, sanity_check: bool = False) -> list[dict]:
227
+ """
228
+ Convert synthetic hospital data into `Schedule` FHIR resources.
229
+
230
+ Args:
231
+ data (dict): Synthetic hospital data containing doctor information.
232
+ output_dir (Optional[str], optional): Directory path to save the converted Schedule resources
233
+ as `.fhir.json` files. If None, the resources are not saved to disk.
234
+ Defaults to None.
235
+ sanity_check (bool, optional): If True, performs a sanity check to ensure the uniqueness of the generated FHIR data.
236
+ This only applies when output_dir is specified. Defaults to False.
237
+
238
+ Returns:
239
+ list[dict]: A list of converted FHIR Schedule resource objects.
240
+ """
241
+ save_dir = None
242
+ if output_dir:
243
+ os.makedirs(os.path.join(output_dir, 'schedule'), exist_ok=True)
244
+ save_dir = os.path.join(output_dir, 'schedule')
245
+
246
+ hospital_name = data.get('metadata')['hospital_name']
247
+ department_data = data.get('department')
248
+ country_code = data.get('metadata').get('country_code', 'KR')
249
+ time_zone = data.get('metadata').get('timezone', None)
250
+ start_date = data.get('metadata').get('start_date', None)
251
+ end_date = data.get('metadata').get('end_date', start_date)
252
+ start = get_iso_time(data.get('metadata')['time']['start_hour'], start_date, get_utc_offset(country_code, time_zone))
253
+ end = get_iso_time(data.get('metadata')['time']['end_hour'], end_date, get_utc_offset(country_code, time_zone))
254
+ schedules = list()
255
+
256
+ for doctor_name, doctor_values in data['doctor'].items():
257
+ practitioner_id = get_individual_id(
258
+ hospital_name,
259
+ department_data[doctor_values['department']]['code'].lower(),
260
+ doctor_name
261
+ )
262
+ schedule_id = get_schedule_id(practitioner_id)
263
+ schedule_obj = {
264
+ 'resourceType': 'Schedule',
265
+ 'id': schedule_id,
266
+ 'active': True,
267
+ 'actor': [{'reference': f'Practitioner/{practitioner_id}'}],
268
+ 'planningHorizon': {'start': start, 'end': end}
269
+ }
270
+ schedules.append(schedule_obj)
271
+
272
+ if save_dir:
273
+ save_path = os.path.join(save_dir, f'{schedule_id}.fhir.json')
274
+ if sanity_check:
275
+ assert not os.path.exists(save_path), log(f"Same file exists: {save_path}", "error")
276
+ json_save_fast(
277
+ save_path,
278
+ schedule_obj
279
+ )
280
+
281
+ return schedules
282
+
283
+
284
+ @staticmethod
285
+ def data_to_slot(data: dict, output_dir: Optional[str] = None, sanity_check: bool = False) -> list[dict]:
286
+ """
287
+ Convert synthetic hospital data into `Slot` FHIR resources.
288
+
289
+ Args:
290
+ data (dict): Synthetic hospital data containing doctor information.
291
+ output_dir (Optional[str], optional): Directory path to save the converted Slot resources
292
+ as `.fhir.json` files. If None, the resources are not saved to disk.
293
+ Defaults to None.
294
+ sanity_check (bool, optional): If True, performs a sanity check to ensure the uniqueness of the generated FHIR data.
295
+ This only applies when output_dir is specified. Defaults to False.
296
+
297
+ Returns:
298
+ list[dict]: A list of converted FHIR Slot resource objects.
299
+ """
300
+ save_dir = None
301
+ if output_dir:
302
+ os.makedirs(os.path.join(output_dir, 'slot'), exist_ok=True)
303
+ save_dir = os.path.join(output_dir, 'slot')
304
+
305
+ hospital_name = data.get('metadata')['hospital_name']
306
+ department_data = data.get('department')
307
+ country_code = data.get('metadata').get('country_code', 'KR')
308
+ time_zone = data.get('metadata').get('timezone', None)
309
+ utc_offset = get_utc_offset(country_code, time_zone)
310
+ start_hour = data.get('metadata')['time']['start_hour']
311
+ end_hour = data.get('metadata')['time']['end_hour']
312
+ interval_hour = data.get('metadata')['time']['interval_hour']
313
+ entire_segments = convert_time_to_segment(start_hour, end_hour, interval_hour)
314
+ slots = list()
315
+
316
+ for doctor_name, doctor_values in data['doctor'].items():
317
+ practitioner_id = get_individual_id(
318
+ hospital_name,
319
+ department_data[doctor_values['department']]['code'].lower(),
320
+ doctor_name
321
+ )
322
+
323
+ for date, schedules in doctor_values['schedule'].items():
324
+ # Filtering fixed schedule
325
+ fixed_schedule = []
326
+ for schedule in schedules:
327
+ fixed_schedule += convert_time_to_segment(start_hour, end_hour, interval_hour, schedule)
328
+
329
+ # Appointment available time segments
330
+ free_schedule = sorted(list(set(entire_segments) - set(fixed_schedule)))
331
+
332
+ # Add slot as a `busy` status
333
+ for seg in fixed_schedule:
334
+ st, tr = convert_segment_to_time(start_hour, end_hour, interval_hour, [seg])
335
+ slot_id = get_slot_id(practitioner_id, date, seg)
336
+ slot_obj = {
337
+ 'resourceType': 'Slot',
338
+ 'id': slot_id,
339
+ 'schedule': {'reference': f'Schedule/{get_schedule_id(practitioner_id)}'},
340
+ 'status': 'busy',
341
+ 'start': get_iso_time(st, date, utc_offset),
342
+ 'end': get_iso_time(tr, date, utc_offset),
343
+ }
344
+ slots.append(slot_obj)
345
+
346
+ if save_dir:
347
+ save_path = os.path.join(save_dir, f'{slot_id}.fhir.json')
348
+ if sanity_check:
349
+ assert not os.path.exists(save_path), log(f"Same file exists: {save_path}", "error")
350
+ json_save_fast(
351
+ save_path,
352
+ slot_obj
353
+ )
354
+
355
+ # Add slot as a `free` status
356
+ for seg in free_schedule:
357
+ slot_id = get_slot_id(practitioner_id, date, seg)
358
+ st, tr = convert_segment_to_time(start_hour, end_hour, interval_hour, [seg])
359
+ slot_obj = {
360
+ 'resourceType': 'Slot',
361
+ 'id': slot_id,
362
+ 'schedule': {'reference': f'Schedule/{get_schedule_id(practitioner_id)}'},
363
+ 'status': 'free',
364
+ 'start': get_iso_time(st, date, utc_offset),
365
+ 'end': get_iso_time(tr, date, utc_offset),
366
+ }
367
+ slots.append(slot_obj)
368
+
369
+ if save_dir:
370
+ save_path = os.path.join(save_dir, f'{slot_id}.fhir.json')
371
+ if sanity_check:
372
+ assert not os.path.exists(save_path), log(f"Same file exists: {save_path}", "error")
373
+ json_save_fast(
374
+ save_path,
375
+ slot_obj
376
+ )
377
+
378
+ return slots
379
+
380
+
381
+ @staticmethod
382
+ def data_to_appointment(data: dict, output_dir: Optional[str] = None, sanity_check: bool = False) -> list[dict]:
383
+ """
384
+ Convert synthetic hospital data into `Appointment` FHIR resources.
385
+
386
+ Args:
387
+ data (dict): Synthetic hospital data containing doctor information.
388
+ output_dir (Optional[str], optional): Directory path to save the converted Appointment resources
389
+ as `.fhir.json` files. If None, the resources are not saved to disk.
390
+ Defaults to None.
391
+ sanity_check (bool, optional): If True, performs a sanity check to ensure the uniqueness of the generated FHIR data.
392
+ This only applies when output_dir is specified. Defaults to False.
393
+
394
+ Returns:
395
+ list[dict]: A list of converted FHIR Appointment resource objects.
396
+ """
397
+ save_dir = None
398
+ if output_dir:
399
+ os.makedirs(os.path.join(output_dir, 'appointment'), exist_ok=True)
400
+ save_dir = os.path.join(output_dir, 'appointment')
401
+
402
+ hospital_name = data.get('metadata')['hospital_name']
403
+ department_data = data.get('department')
404
+ country_code = data.get('metadata').get('country_code', 'KR')
405
+ time_zone = data.get('metadata').get('timezone', None)
406
+ utc_offset = get_utc_offset(country_code, time_zone)
407
+ start_hour = data.get('metadata')['time']['start_hour']
408
+ end_hour = data.get('metadata')['time']['end_hour']
409
+ interval_hour = data.get('metadata')['time']['interval_hour']
410
+ appointments = list()
411
+
412
+ for patient_name, patient_values in data['patient'].items():
413
+ doctor_name = patient_values['attending_physician']
414
+ practitioner_id = get_individual_id(
415
+ hospital_name,
416
+ department_data[patient_values['department']]['code'].lower(),
417
+ doctor_name
418
+ )
419
+ patient_id = get_individual_id(
420
+ hospital_name,
421
+ department_data[patient_values['department']]['code'].lower(),
422
+ patient_name
423
+ )
424
+ participant = [
425
+ {"actor": {"reference": f"Practitioner/{practitioner_id}", "display": doctor_name}, "status": "accepted"},
426
+ {"actor": {"reference": f"Patient/{patient_id}", "display": patient_name}, "status": "accepted"}
427
+ ]
428
+
429
+ # Filtering fixed schedule
430
+ date = patient_values['date']
431
+ schedule_time_range = patient_values['schedule']
432
+ schedule_segments = convert_time_to_segment(start_hour, end_hour, interval_hour, schedule_time_range)
433
+ appointment_id = get_appointment_id(practitioner_id, date, schedule_segments[0], schedule_segments[-1])
434
+ appointment_obj = {
435
+ 'resourceType': 'Appointment',
436
+ 'id': appointment_id,
437
+ 'status': 'booked',
438
+ 'start': get_iso_time(schedule_time_range[0], date, utc_offset),
439
+ 'end': get_iso_time(schedule_time_range[-1], date, utc_offset),
440
+ 'slot': [{'reference': f'Slot/{get_slot_id(practitioner_id, date, seg)}'} for seg in schedule_segments],
441
+ 'participant': participant
442
+ }
443
+ appointments.append(appointment_obj)
444
+
445
+ if save_dir:
446
+ save_path = os.path.join(save_dir, f'{appointment_id}.fhir.json')
447
+ if sanity_check:
448
+ assert not os.path.exists(save_path), log(f"Same file exists: {save_path}", "error")
449
+ json_save_fast(
450
+ save_path,
451
+ appointment_obj
452
+ )
453
+
454
+ return appointments
455
+
456
+
457
+ @staticmethod
458
+ def get_fhir_appointment(gt_resource_path: Optional[str] = None,
459
+ data: Optional[dict] = None) -> dict:
460
+ """
461
+ Load a FHIR Appointment resource from a file path if available, or generate it dynamically from the provided data.
462
+
463
+ Args:
464
+ gt_resource_path (Optional[str], optional):
465
+ Path to the ground-truth FHIR Appointment resource file.
466
+ If the file exists, it will be loaded and returned.
467
+ If not, a resource will be generated from the `data` argument.
468
+ data (Optional[dict], optional):
469
+ Dictionary containing the metadata and patient information
470
+ needed to generate the Appointment resource.
471
+ Expected to include 'metadata' and 'information' keys.
472
+
473
+ Returns:
474
+ dict: A FHIR Appointment resource in dictionary form.
475
+ """
476
+ try:
477
+ return json_load(gt_resource_path)
478
+ except:
479
+ metadata, info, department = data.get('metadata'), data.get('information'), data.get('department')
480
+ schedule = info.get('schedule')
481
+ if 'time' in schedule:
482
+ schedule = schedule.get('time')
483
+
484
+ gt_resource = DataConverter.data_to_appointment(
485
+ {
486
+ 'metadata': metadata,
487
+ 'department': department,
488
+ 'patient': {
489
+ info.get('patient'): {
490
+ 'department': info.get('department'),
491
+ 'attending_physician': info.get('attending_physician'),
492
+ 'date': info.get('date'),
493
+ 'schedule': schedule
494
+ }
495
+ }
496
+ }
497
+ )[0]
498
+ return gt_resource
499
+
500
+
501
+ def __call__(self, output_dir: Optional[str] = None, sanity_check: bool = False) -> list[Information]:
502
+ """
503
+ Convert synthetic hospital data files into FHIR resources and optionally save them to disk.
504
+
505
+ Args:
506
+ output_dir (Optional[str], optional): Directory to save the converted FHIR resources as `.fhir.json` files.
507
+ If None, the resources will not be saved. Defaults to None.
508
+ sanity_check (bool, optional): If True, performs a sanity check to ensure the uniqueness of the generated FHIR data.
509
+ This only applies when output_dir is specified. Defaults to False.
510
+
511
+ Returns:
512
+ list[Information]: An object containing the converted FHIR resources, including practitioners, schedules, slots, patients, and appointments.
513
+ """
514
+ os.makedirs(output_dir, exist_ok=True)
515
+ all_resources = list()
516
+
517
+ for data_file in tqdm(self.data_files, desc='Converting to FHIR data..'):
518
+ data = json_load(data_file)
519
+ practitioners = DataConverter.data_to_practitioner(data, output_dir, sanity_check)
520
+ practitionerroles = DataConverter.data_to_practitionerrole(data, output_dir, sanity_check)
521
+ schedules = DataConverter.data_to_schedule(data, output_dir, sanity_check)
522
+ slots = DataConverter.data_to_slot(data, output_dir, sanity_check)
523
+ patients = DataConverter.data_to_patient(data, output_dir, sanity_check)
524
+ appointments = DataConverter.data_to_appointment(data, output_dir, sanity_check)
525
+
526
+ information = Information(
527
+ practitioners=practitioners,
528
+ practitionerrole=practitionerroles,
529
+ schedules=schedules,
530
+ slots=slots,
531
+ patients=patients,
532
+ appointments=appointments
533
+ )
534
+ all_resources.append(information)
535
+
536
+ return all_resources