medicafe 0.250725.18__py3-none-any.whl → 0.250728.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.

Potentially problematic release.


This version of medicafe might be problematic. Click here for more details.

MediBot/MediBot_UI.py CHANGED
@@ -1,311 +1,349 @@
1
- #MediBot_UI.py
2
- import ctypes, time, re, os, sys, msvcrt
3
- from ctypes import wintypes
4
- from sys import exit
5
- project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
6
- if project_dir not in sys.path:
7
- sys.path.append(project_dir)
8
-
9
- try:
10
- from MediLink import MediLink_ConfigLoader
11
- except ImportError:
12
- import MediLink_ConfigLoader
13
-
14
- # Load configuration
15
- config, crosswalk = MediLink_ConfigLoader.load_configuration()
16
-
17
- # Function to check if a specific key is pressed
18
- VK_END = int(config.get('VK_END', ""), 16) # Try F12 (7B). Virtual key code for 'End' (23)
19
- VK_PAUSE = int(config.get('VK_PAUSE', ""), 16) # Try F11 (7A). Virtual-key code for 'Home' (24)
20
-
21
-
22
-
23
- class AppControl:
24
- def __init__(self):
25
- self.script_paused = False
26
- self.mapat_med_path = ''
27
- self.medisoft_shortcut = ''
28
- # PERFORMANCE FIX: Add configuration caching to reduce lookup overhead
29
- self._config_cache = {} # Cache for Medicare vs Private configuration lookups
30
- # Load initial paths from config when instance is created
31
- self.load_paths_from_config()
32
-
33
- def get_pause_status(self):
34
- return self.script_paused
35
-
36
- def set_pause_status(self, status):
37
- self.script_paused = status
38
-
39
- def get_mapat_med_path(self):
40
- return self.mapat_med_path
41
-
42
- def set_mapat_med_path(self, path):
43
- self.mapat_med_path = path
44
-
45
- def get_medisoft_shortcut(self):
46
- return self.medisoft_shortcut
47
-
48
- def set_medisoft_shortcut(self, path):
49
- self.medisoft_shortcut = path
50
-
51
- def load_paths_from_config(self, medicare=False):
52
- # Assuming `config` is a module or a globally accessible configuration dictionary
53
- # TODO Is this where the MAINS paths should also be set?
54
-
55
- # PERFORMANCE FIX: Cache configuration lookups to reduce Medicare vs Private overhead
56
- cache_key = 'medicare' if medicare else 'private'
57
-
58
- if cache_key not in self._config_cache:
59
- # Build cache entry for this configuration type
60
- if medicare:
61
- cached_config = {
62
- 'mapat_path': config.get('MEDICARE_MAPAT_MED_PATH', ""),
63
- 'shortcut': config.get('MEDICARE_SHORTCUT', "")
64
- }
65
- else:
66
- cached_config = {
67
- 'mapat_path': config.get('MAPAT_MED_PATH', ""),
68
- 'shortcut': config.get('PRIVATE_SHORTCUT', "")
69
- }
70
- self._config_cache[cache_key] = cached_config
71
-
72
- # Use cached values to avoid repeated config lookups
73
- cached = self._config_cache[cache_key]
74
- self.mapat_med_path = cached['mapat_path']
75
- self.medisoft_shortcut = cached['shortcut']
76
-
77
- app_control = AppControl()
78
-
79
- def is_key_pressed(key_code):
80
- user32 = ctypes.WinDLL('user32', use_last_error=True)
81
- user32.GetAsyncKeyState.restype = wintypes.SHORT
82
- user32.GetAsyncKeyState.argtypes = [wintypes.INT]
83
- return user32.GetAsyncKeyState(key_code) & 0x8000 != 0
84
-
85
- def manage_script_pause(csv_data, error_message, reverse_mapping):
86
- user_action = 0 # initialize as 'continue'
87
-
88
- if not app_control.get_pause_status() and is_key_pressed(VK_PAUSE):
89
- app_control.set_pause_status(True)
90
- print("Script paused. Opening menu...")
91
- interaction_mode = 'normal' # Assuming normal interaction mode for script pause
92
- user_action = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
93
-
94
- while app_control.get_pause_status():
95
- if is_key_pressed(VK_END):
96
- app_control.set_pause_status(False)
97
- print("Continuing...")
98
- elif is_key_pressed(VK_PAUSE):
99
- user_action = user_interaction(csv_data, 'normal', error_message, reverse_mapping)
100
- time.sleep(0.1)
101
-
102
- return user_action
103
-
104
- # Menu Display & User Interaction
105
- def display_patient_selection_menu(csv_data, reverse_mapping, proceed_as_medicare):
106
- selected_patient_ids = []
107
- selected_indices = []
108
-
109
- def display_menu_header(title):
110
- print("\n" + "-" * 60)
111
- print(title)
112
- print("-" * 60)
113
-
114
- def display_patient_list(csv_data, reverse_mapping, medicare_filter=False, exclude_medicare=False):
115
- medicare_policy_pattern = r"^[a-zA-Z0-9]{11}$" # Regex pattern for 11 alpha-numeric characters
116
- primary_policy_number_header = reverse_mapping.get('Primary Policy Number', 'Primary Policy Number')
117
- primary_insurance_header = reverse_mapping.get('Primary Insurance', 'Primary Insurance') # Adjust field name as needed
118
-
119
- displayed_indices = []
120
- displayed_patient_ids = []
121
-
122
- for index, row in enumerate(csv_data):
123
- policy_number = row.get(primary_policy_number_header, "")
124
- primary_insurance = row.get(primary_insurance_header, "").upper()
125
-
126
- if medicare_filter and (not re.match(medicare_policy_pattern, policy_number) or "MEDICARE" not in primary_insurance):
127
- continue
128
- if exclude_medicare and re.match(medicare_policy_pattern, policy_number) and "MEDICARE" in primary_insurance:
129
- continue
130
-
131
- patient_id_header = reverse_mapping['Patient ID #2']
132
- patient_name_header = reverse_mapping['Patient Name']
133
- patient_id = row.get(patient_id_header, "N/A")
134
- patient_name = row.get(patient_name_header, "Unknown")
135
- surgery_date = row.get('Surgery Date', "Unknown Date") # Access 'Surgery Date' as string directly from the row
136
-
137
- print("{0:03d}: {3:%m-%d} (ID: {2}) {1} ".format(index+1, patient_name, patient_id, surgery_date))
138
-
139
- displayed_indices.append(index)
140
- displayed_patient_ids.append(patient_id)
141
-
142
- return displayed_indices, displayed_patient_ids
143
-
144
- if proceed_as_medicare:
145
- display_menu_header("MEDICARE Patient Selection for Today's Data Entry")
146
- selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, medicare_filter=True)
147
- else:
148
- display_menu_header("PRIVATE Patient Selection for Today's Data Entry")
149
- selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, exclude_medicare=True)
150
-
151
- print("-" * 60)
152
- print("\nDo you want to proceed with the selected patients? (yes/no): ", end='', flush=True)
153
- time.sleep(0.1) # Reduced delay for Windows XP compatibility
154
-
155
- # Clear any leftover input
156
- while msvcrt.kbhit():
157
- msvcrt.getch()
158
-
159
- # Use input() for more reliable input on Windows XP
160
- proceed = input().lower().strip() in ['yes', 'y']
161
-
162
- if not proceed:
163
- display_menu_header("Patient Selection for Today's Data Entry")
164
- selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping)
165
- print("-" * 60)
166
-
167
- while True:
168
- while True:
169
- print("\nEnter the number(s) of the patients you wish to proceed with \n(e.g., 1,3,5): ", end='', flush=True)
170
- time.sleep(0.1) # Reduced delay for Windows XP compatibility
171
-
172
- # Clear any leftover input
173
- while msvcrt.kbhit():
174
- msvcrt.getch()
175
-
176
- # Use input() for more reliable input on Windows XP
177
- selection = input().strip()
178
- if not selection:
179
- print("Invalid entry. Please provide at least one number.")
180
- continue
181
-
182
- selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
183
- selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
184
-
185
- if not selected_indices:
186
- print("Invalid entry. Please provide at least one integer.")
187
- continue
188
-
189
- proceed = True
190
- break
191
-
192
- if not selection:
193
- print("Invalid entry. Please provide at least one number.")
194
- continue
195
-
196
- selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
197
- selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
198
-
199
- if not selected_indices:
200
- print("Invalid entry. Please provide at least one integer.")
201
- continue
202
-
203
- proceed = True
204
- break
205
-
206
- patient_id_header = reverse_mapping['Patient ID #2']
207
- selected_patient_ids = [csv_data[i][patient_id_header] for i in selected_indices if i < len(csv_data)]
208
-
209
- return proceed, selected_patient_ids, selected_indices
210
-
211
- def display_menu_header(title):
212
- print("\n" + "-" * 60)
213
- print(title)
214
- print("-" * 60)
215
-
216
- def handle_user_interaction(interaction_mode, error_message):
217
- # Import here to avoid circular imports
218
- try:
219
- from MediBot import current_patient_context
220
- except ImportError:
221
- current_patient_context = None
222
-
223
- while True:
224
- # If interaction_mode is neither 'triage' nor 'error', then it's normal mode.
225
- title = "Error Occurred" if interaction_mode == 'error' else "Data Entry Options"
226
- display_menu_header(title)
227
-
228
- if interaction_mode == 'error':
229
- print("\nERROR: ", error_message)
230
-
231
- # PERFORMANCE FIX: Display patient context to address "won't be obvious anymore" issue
232
- # Show user which patient and field they're working with for better F11 menu usability
233
- if current_patient_context:
234
- patient_name = current_patient_context.get('patient_name', 'Unknown Patient')
235
- surgery_date = current_patient_context.get('surgery_date', 'Unknown Date')
236
- last_field = current_patient_context.get('last_field', 'Unknown Field')
237
- print("\nCurrent Context:")
238
- print(" Patient: {}".format(patient_name))
239
- print(" Surgery Date: {}".format(surgery_date))
240
- print(" Last Field: {}".format(last_field))
241
- print("")
242
-
243
- # Menu options with improved context
244
- print("1: Retry last entry")
245
- print("2: Skip to next patient and continue")
246
- print("3: Go back two patients and redo")
247
- print("4: Exit script")
248
- print("-" * 60)
249
- print("Enter your choice (1/2/3/4): ", end='', flush=True)
250
- time.sleep(0.1) # Reduced delay for Windows XP compatibility
251
-
252
- # Clear any leftover input
253
- while msvcrt.kbhit():
254
- msvcrt.getch()
255
-
256
- # Use input() for more reliable input on Windows XP
257
- choice = input().strip()
258
-
259
- if choice == '1':
260
- print("Selected: 'Retry last entry'. Please press 'F12' to continue.")
261
- return -1
262
- elif choice == '2':
263
- print("Selected: 'Skip to next patient and continue'. Please press 'F12' to continue.")
264
- return 1
265
- elif choice == '3':
266
- print("Selected: 'Go back two patients and redo'. Please press 'F12' to continue.")
267
- # Returning a specific value to indicate the action of going back two patients
268
- # but we might run into a problem if we stop mid-run on the first row?
269
- return -2
270
- elif choice == '4':
271
- print("Exiting the script.")
272
- exit()
273
- else:
274
- print("Invalid choice. Please enter a valid number.")
275
-
276
- def user_interaction(csv_data, interaction_mode, error_message, reverse_mapping):
277
- global app_control # Use the instance of AppControl
278
- selected_patient_ids = []
279
- selected_indices = []
280
-
281
- if interaction_mode == 'triage':
282
- display_menu_header(" =(^.^)= Welcome to MediBot! =(^.^)=")
283
-
284
- while True:
285
- try:
286
- print("PRESS ENTER!")
287
- response = input("\nAm I processing Medicare patients? (yes/no): ").strip().lower()
288
-
289
- if response in ['yes', 'y']:
290
- app_control.load_paths_from_config(medicare=True)
291
- break
292
- elif response in ['no', 'n']:
293
- app_control.load_paths_from_config(medicare=False)
294
- break
295
- elif response == '':
296
- print("No input detected. Please enter 'yes' or 'no'.")
297
- else:
298
- print("Invalid entry. Please enter 'yes' or 'no'.")
299
- except KeyboardInterrupt:
300
- print("\nOperation cancelled by user. Exiting script.")
301
- sys.exit(0)
302
-
303
- fixed_values = config.get('fixed_values', {}) # Get fixed values from config json
304
- if response in ['yes', 'y']:
305
- medicare_added_fixed_values = config.get('medicare_added_fixed_values', {})
306
- fixed_values.update(medicare_added_fixed_values) # Add any medicare-specific fixed values from config
307
-
308
- proceed, selected_patient_ids, selected_indices = display_patient_selection_menu(csv_data, reverse_mapping, response in ['yes', 'y'])
309
- return proceed, selected_patient_ids, selected_indices, fixed_values
310
-
1
+ #MediBot_UI.py
2
+ import ctypes, time, re, os, sys, msvcrt
3
+ from ctypes import wintypes
4
+ from sys import exit
5
+ project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
6
+ if project_dir not in sys.path:
7
+ sys.path.append(project_dir)
8
+
9
+ try:
10
+ from MediLink import MediLink_ConfigLoader
11
+ except ImportError:
12
+ import MediLink_ConfigLoader
13
+
14
+ # Load configuration
15
+ config, crosswalk = MediLink_ConfigLoader.load_configuration()
16
+
17
+ # Function to check if a specific key is pressed
18
+ VK_END = int(config.get('VK_END', ""), 16) # Try F12 (7B). Virtual key code for 'End' (23)
19
+ VK_PAUSE = int(config.get('VK_PAUSE', ""), 16) # Try F11 (7A). Virtual-key code for 'Home' (24)
20
+
21
+
22
+
23
+ class AppControl:
24
+ def __init__(self):
25
+ self.script_paused = False
26
+ self.mapat_med_path = ''
27
+ self.medisoft_shortcut = ''
28
+ # PERFORMANCE FIX: Add configuration caching to reduce lookup overhead
29
+ self._config_cache = {} # Cache for Medicare vs Private configuration lookups
30
+ # Load initial paths from config when instance is created
31
+ self.load_paths_from_config()
32
+
33
+ def get_pause_status(self):
34
+ return self.script_paused
35
+
36
+ def set_pause_status(self, status):
37
+ self.script_paused = status
38
+
39
+ def get_mapat_med_path(self):
40
+ return self.mapat_med_path
41
+
42
+ def set_mapat_med_path(self, path):
43
+ self.mapat_med_path = path
44
+
45
+ def get_medisoft_shortcut(self):
46
+ return self.medisoft_shortcut
47
+
48
+ def set_medisoft_shortcut(self, path):
49
+ self.medisoft_shortcut = path
50
+
51
+ def load_paths_from_config(self, medicare=False):
52
+ # Assuming `config` is a module or a globally accessible configuration dictionary
53
+ # TODO Is this where the MAINS paths should also be set?
54
+
55
+ # PERFORMANCE FIX: Cache configuration lookups to reduce Medicare vs Private overhead
56
+ cache_key = 'medicare' if medicare else 'private'
57
+
58
+ if cache_key not in self._config_cache:
59
+ # Build cache entry for this configuration type
60
+ if medicare:
61
+ cached_config = {
62
+ 'mapat_path': config.get('MEDICARE_MAPAT_MED_PATH', ""),
63
+ 'shortcut': config.get('MEDICARE_SHORTCUT', "")
64
+ }
65
+ else:
66
+ cached_config = {
67
+ 'mapat_path': config.get('MAPAT_MED_PATH', ""),
68
+ 'shortcut': config.get('PRIVATE_SHORTCUT', "")
69
+ }
70
+ self._config_cache[cache_key] = cached_config
71
+
72
+ # Use cached values to avoid repeated config lookups
73
+ cached = self._config_cache[cache_key]
74
+ self.mapat_med_path = cached['mapat_path']
75
+ self.medisoft_shortcut = cached['shortcut']
76
+
77
+ app_control = AppControl()
78
+
79
+ def windows_xp_input(prompt=""):
80
+ """
81
+ Windows XP-specific input function that uses msvcrt.getch()
82
+ to avoid console buffer issues after cls command.
83
+
84
+ Use this instead of input() when:
85
+ - The input call happens shortly after os.system('cls')
86
+ - The standard input() is not capturing user input on first try
87
+ - You need reliable input capture on Windows XP SP3
88
+ """
89
+ if prompt:
90
+ print(prompt, end='', flush=True)
91
+
92
+ # Clear any pending keystrokes
93
+ while msvcrt.kbhit():
94
+ msvcrt.getch()
95
+
96
+ input_chars = []
97
+ while True:
98
+ char = msvcrt.getch()
99
+
100
+ # Handle Enter key (carriage return)
101
+ if char == b'\r':
102
+ print() # New line
103
+ return ''.join(input_chars)
104
+
105
+ # Handle backspace
106
+ elif char == b'\x08':
107
+ if input_chars:
108
+ input_chars.pop()
109
+ # Move cursor back, overwrite with space, move back again
110
+ print('\b \b', end='', flush=True)
111
+
112
+ # Handle regular characters
113
+ elif 32 <= ord(char) <= 126: # Printable ASCII characters
114
+ input_chars.append(char.decode('ascii', errors='ignore'))
115
+ print(char.decode('ascii', errors='ignore'), end='', flush=True)
116
+
117
+ def is_key_pressed(key_code):
118
+ user32 = ctypes.WinDLL('user32', use_last_error=True)
119
+ user32.GetAsyncKeyState.restype = wintypes.SHORT
120
+ user32.GetAsyncKeyState.argtypes = [wintypes.INT]
121
+ return user32.GetAsyncKeyState(key_code) & 0x8000 != 0
122
+
123
+ def manage_script_pause(csv_data, error_message, reverse_mapping):
124
+ user_action = 0 # initialize as 'continue'
125
+
126
+ if not app_control.get_pause_status() and is_key_pressed(VK_PAUSE):
127
+ app_control.set_pause_status(True)
128
+ print("Script paused. Opening menu...")
129
+ interaction_mode = 'normal' # Assuming normal interaction mode for script pause
130
+ user_action = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
131
+
132
+ while app_control.get_pause_status():
133
+ if is_key_pressed(VK_END):
134
+ app_control.set_pause_status(False)
135
+ print("Continuing...")
136
+ elif is_key_pressed(VK_PAUSE):
137
+ user_action = user_interaction(csv_data, 'normal', error_message, reverse_mapping)
138
+ time.sleep(0.1)
139
+
140
+ return user_action
141
+
142
+ # Menu Display & User Interaction
143
+ def display_patient_selection_menu(csv_data, reverse_mapping, proceed_as_medicare):
144
+ selected_patient_ids = []
145
+ selected_indices = []
146
+
147
+ def display_menu_header(title):
148
+ print("\n" + "-" * 60)
149
+ print(title)
150
+ print("-" * 60)
151
+
152
+ def display_patient_list(csv_data, reverse_mapping, medicare_filter=False, exclude_medicare=False):
153
+ medicare_policy_pattern = r"^[a-zA-Z0-9]{11}$" # Regex pattern for 11 alpha-numeric characters
154
+ primary_policy_number_header = reverse_mapping.get('Primary Policy Number', 'Primary Policy Number')
155
+ primary_insurance_header = reverse_mapping.get('Primary Insurance', 'Primary Insurance') # Adjust field name as needed
156
+
157
+ displayed_indices = []
158
+ displayed_patient_ids = []
159
+
160
+ for index, row in enumerate(csv_data):
161
+ policy_number = row.get(primary_policy_number_header, "")
162
+ primary_insurance = row.get(primary_insurance_header, "").upper()
163
+
164
+ if medicare_filter and (not re.match(medicare_policy_pattern, policy_number) or "MEDICARE" not in primary_insurance):
165
+ continue
166
+ if exclude_medicare and re.match(medicare_policy_pattern, policy_number) and "MEDICARE" in primary_insurance:
167
+ continue
168
+
169
+ patient_id_header = reverse_mapping['Patient ID #2']
170
+ patient_name_header = reverse_mapping['Patient Name']
171
+ patient_id = row.get(patient_id_header, "N/A")
172
+ patient_name = row.get(patient_name_header, "Unknown")
173
+ surgery_date = row.get('Surgery Date', "Unknown Date") # Access 'Surgery Date' as string directly from the row
174
+
175
+ print("{0:03d}: {3:%m-%d} (ID: {2}) {1} ".format(index+1, patient_name, patient_id, surgery_date))
176
+
177
+ displayed_indices.append(index)
178
+ displayed_patient_ids.append(patient_id)
179
+
180
+ return displayed_indices, displayed_patient_ids
181
+
182
+ if proceed_as_medicare:
183
+ display_menu_header("MEDICARE Patient Selection for Today's Data Entry")
184
+ selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, medicare_filter=True)
185
+ else:
186
+ display_menu_header("PRIVATE Patient Selection for Today's Data Entry")
187
+ selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, exclude_medicare=True)
188
+
189
+ print("-" * 60)
190
+ print("\nDo you want to proceed with the selected patients? (yes/no): ", end='', flush=True)
191
+ time.sleep(0.1) # Reduced delay for Windows XP compatibility
192
+
193
+ # Clear any leftover input
194
+ while msvcrt.kbhit():
195
+ msvcrt.getch()
196
+
197
+ # Use input() for more reliable input on Windows XP
198
+ proceed = input().lower().strip() in ['yes', 'y']
199
+
200
+ if not proceed:
201
+ display_menu_header("Patient Selection for Today's Data Entry")
202
+ selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping)
203
+ print("-" * 60)
204
+
205
+ while True:
206
+ while True:
207
+ print("\nEnter the number(s) of the patients you wish to proceed with \n(e.g., 1,3,5): ", end='', flush=True)
208
+ time.sleep(0.1) # Reduced delay for Windows XP compatibility
209
+
210
+ # Clear any leftover input
211
+ while msvcrt.kbhit():
212
+ msvcrt.getch()
213
+
214
+ # Use input() for more reliable input on Windows XP
215
+ selection = input().strip()
216
+ if not selection:
217
+ print("Invalid entry. Please provide at least one number.")
218
+ continue
219
+
220
+ selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
221
+ selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
222
+
223
+ if not selected_indices:
224
+ print("Invalid entry. Please provide at least one integer.")
225
+ continue
226
+
227
+ proceed = True
228
+ break
229
+
230
+ if not selection:
231
+ print("Invalid entry. Please provide at least one number.")
232
+ continue
233
+
234
+ selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
235
+ selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
236
+
237
+ if not selected_indices:
238
+ print("Invalid entry. Please provide at least one integer.")
239
+ continue
240
+
241
+ proceed = True
242
+ break
243
+
244
+ patient_id_header = reverse_mapping['Patient ID #2']
245
+ selected_patient_ids = [csv_data[i][patient_id_header] for i in selected_indices if i < len(csv_data)]
246
+
247
+ return proceed, selected_patient_ids, selected_indices
248
+
249
+ def display_menu_header(title):
250
+ print("\n" + "-" * 60)
251
+ print(title)
252
+ print("-" * 60)
253
+
254
+ def handle_user_interaction(interaction_mode, error_message):
255
+ # Import here to avoid circular imports
256
+ try:
257
+ from MediBot import current_patient_context
258
+ except ImportError:
259
+ current_patient_context = None
260
+
261
+ while True:
262
+ # If interaction_mode is neither 'triage' nor 'error', then it's normal mode.
263
+ title = "Error Occurred" if interaction_mode == 'error' else "Data Entry Options"
264
+ display_menu_header(title)
265
+
266
+ if interaction_mode == 'error':
267
+ print("\nERROR: ", error_message)
268
+
269
+ # PERFORMANCE FIX: Display patient context to address "won't be obvious anymore" issue
270
+ # Show user which patient and field they're working with for better F11 menu usability
271
+ if current_patient_context:
272
+ patient_name = current_patient_context.get('patient_name', 'Unknown Patient')
273
+ surgery_date = current_patient_context.get('surgery_date', 'Unknown Date')
274
+ last_field = current_patient_context.get('last_field', 'Unknown Field')
275
+ print("\nCurrent Context:")
276
+ print(" Patient: {}".format(patient_name))
277
+ print(" Surgery Date: {}".format(surgery_date))
278
+ print(" Last Field: {}".format(last_field))
279
+ print("")
280
+
281
+ # Menu options with improved context
282
+ print("1: Retry last entry")
283
+ print("2: Skip to next patient and continue")
284
+ print("3: Go back two patients and redo")
285
+ print("4: Exit script")
286
+ print("-" * 60)
287
+ print("Enter your choice (1/2/3/4): ", end='', flush=True)
288
+ time.sleep(0.1) # Reduced delay for Windows XP compatibility
289
+
290
+ # Clear any leftover input
291
+ while msvcrt.kbhit():
292
+ msvcrt.getch()
293
+
294
+ # Use input() for more reliable input on Windows XP
295
+ choice = input().strip()
296
+
297
+ if choice == '1':
298
+ print("Selected: 'Retry last entry'. Please press 'F12' to continue.")
299
+ return -1
300
+ elif choice == '2':
301
+ print("Selected: 'Skip to next patient and continue'. Please press 'F12' to continue.")
302
+ return 1
303
+ elif choice == '3':
304
+ print("Selected: 'Go back two patients and redo'. Please press 'F12' to continue.")
305
+ # Returning a specific value to indicate the action of going back two patients
306
+ # but we might run into a problem if we stop mid-run on the first row?
307
+ return -2
308
+ elif choice == '4':
309
+ print("Exiting the script.")
310
+ exit()
311
+ else:
312
+ print("Invalid choice. Please enter a valid number.")
313
+
314
+ def user_interaction(csv_data, interaction_mode, error_message, reverse_mapping):
315
+ global app_control # Use the instance of AppControl
316
+ selected_patient_ids = []
317
+ selected_indices = []
318
+
319
+ if interaction_mode == 'triage':
320
+ display_menu_header(" =(^.^)= Welcome to MediBot! =(^.^)=")
321
+
322
+ while True:
323
+ try:
324
+ # Use Windows XP-specific input to avoid console buffer issues
325
+ response = windows_xp_input("\nAm I processing Medicare patients? (yes/no): ").strip().lower()
326
+
327
+ if response in ['yes', 'y']:
328
+ app_control.load_paths_from_config(medicare=True)
329
+ break
330
+ elif response in ['no', 'n']:
331
+ app_control.load_paths_from_config(medicare=False)
332
+ break
333
+ elif response == '':
334
+ print("No input detected. Please enter 'yes' or 'no'.")
335
+ else:
336
+ print("Invalid entry. Please enter 'yes' or 'no'.")
337
+ except KeyboardInterrupt:
338
+ print("\nOperation cancelled by user. Exiting script.")
339
+ sys.exit(0)
340
+
341
+ fixed_values = config.get('fixed_values', {}) # Get fixed values from config json
342
+ if response in ['yes', 'y']:
343
+ medicare_added_fixed_values = config.get('medicare_added_fixed_values', {})
344
+ fixed_values.update(medicare_added_fixed_values) # Add any medicare-specific fixed values from config
345
+
346
+ proceed, selected_patient_ids, selected_indices = display_patient_selection_menu(csv_data, reverse_mapping, response in ['yes', 'y'])
347
+ return proceed, selected_patient_ids, selected_indices, fixed_values
348
+
311
349
  return handle_user_interaction(interaction_mode, error_message)