medicafe 0.250728.8__py3-none-any.whl → 0.250805.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.

Files changed (58) hide show
  1. MediBot/MediBot.bat +233 -19
  2. MediBot/MediBot.py +138 -46
  3. MediBot/MediBot_Crosswalk_Library.py +127 -623
  4. MediBot/MediBot_Crosswalk_Utils.py +618 -0
  5. MediBot/MediBot_Preprocessor.py +72 -17
  6. MediBot/MediBot_Preprocessor_lib.py +470 -76
  7. MediBot/MediBot_UI.py +32 -17
  8. MediBot/MediBot_dataformat_library.py +68 -20
  9. MediBot/MediBot_docx_decoder.py +120 -19
  10. MediBot/MediBot_smart_import.py +180 -0
  11. MediBot/__init__.py +89 -0
  12. MediBot/get_medicafe_version.py +25 -0
  13. MediBot/update_json.py +35 -6
  14. MediBot/update_medicafe.py +19 -1
  15. MediCafe/MediLink_ConfigLoader.py +160 -0
  16. MediCafe/__init__.py +171 -0
  17. MediCafe/__main__.py +222 -0
  18. MediCafe/api_core.py +1098 -0
  19. MediCafe/api_core_backup.py +427 -0
  20. MediCafe/api_factory.py +306 -0
  21. MediCafe/api_utils.py +356 -0
  22. MediCafe/core_utils.py +450 -0
  23. MediCafe/graphql_utils.py +445 -0
  24. MediCafe/logging_config.py +123 -0
  25. MediCafe/logging_demo.py +61 -0
  26. MediCafe/migration_helpers.py +463 -0
  27. MediCafe/smart_import.py +436 -0
  28. MediLink/MediLink.py +66 -26
  29. MediLink/MediLink_837p_cob_library.py +28 -28
  30. MediLink/MediLink_837p_encoder.py +33 -34
  31. MediLink/MediLink_837p_encoder_library.py +243 -151
  32. MediLink/MediLink_837p_utilities.py +129 -5
  33. MediLink/MediLink_API_Generator.py +83 -60
  34. MediLink/MediLink_API_v3.py +1 -1
  35. MediLink/MediLink_ClaimStatus.py +177 -31
  36. MediLink/MediLink_DataMgmt.py +405 -72
  37. MediLink/MediLink_Decoder.py +20 -1
  38. MediLink/MediLink_Deductible.py +155 -28
  39. MediLink/MediLink_Display_Utils.py +72 -0
  40. MediLink/MediLink_Down.py +127 -5
  41. MediLink/MediLink_Gmail.py +712 -653
  42. MediLink/MediLink_PatientProcessor.py +257 -0
  43. MediLink/MediLink_UI.py +85 -61
  44. MediLink/MediLink_Up.py +28 -4
  45. MediLink/MediLink_insurance_utils.py +227 -264
  46. MediLink/MediLink_main.py +248 -0
  47. MediLink/MediLink_smart_import.py +264 -0
  48. MediLink/__init__.py +93 -0
  49. MediLink/insurance_type_integration_test.py +66 -76
  50. MediLink/test.py +1 -1
  51. MediLink/test_timing.py +59 -0
  52. {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/METADATA +1 -1
  53. medicafe-0.250805.0.dist-info/RECORD +81 -0
  54. medicafe-0.250805.0.dist-info/entry_points.txt +2 -0
  55. {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/top_level.txt +1 -0
  56. medicafe-0.250728.8.dist-info/RECORD +0 -59
  57. {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/LICENSE +0 -0
  58. {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/WHEEL +0 -0
MediBot/MediBot_UI.py CHANGED
@@ -2,21 +2,38 @@
2
2
  import ctypes, time, re, os, sys
3
3
  from ctypes import wintypes
4
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
5
 
9
- try:
10
- from MediLink import MediLink_ConfigLoader
6
+ # Set up paths using core utilities
7
+
8
+ from MediCafe.core_utils import get_config_loader_with_fallback
9
+ MediLink_ConfigLoader = get_config_loader_with_fallback()
10
+
11
+ # Ensure MediLink_ConfigLoader is available
12
+ if MediLink_ConfigLoader is None:
13
+ print("Warning: MediLink_ConfigLoader not available. Some functionality may be limited.")
14
+ # Create a minimal fallback logger
15
+ class FallbackLogger:
16
+ def log(self, message, level="INFO"):
17
+ print("[{}] {}".format(level, message))
18
+ MediLink_ConfigLoader = FallbackLogger()
19
+
20
+ # Import current_patient_context with fallback
21
+ try:
22
+ from MediBot import current_patient_context
11
23
  except ImportError:
12
- import MediLink_ConfigLoader
24
+ current_patient_context = None
13
25
 
14
- # Load configuration
15
- config, crosswalk = MediLink_ConfigLoader.load_configuration()
26
+ # Set up lazy configuration loading using core utilities
27
+ from MediCafe.core_utils import create_config_cache
28
+ _get_config, (_config_cache, _crosswalk_cache) = create_config_cache()
16
29
 
17
30
  # 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)
31
+ def _get_vk_codes():
32
+ """Get VK codes from config."""
33
+ config, _ = _get_config()
34
+ VK_END = int(config.get('VK_END', "23"), 16) # Default to 23 if not in config
35
+ VK_PAUSE = int(config.get('VK_PAUSE', "24"), 16) # Default to 24 if not in config
36
+ return VK_END, VK_PAUSE
20
37
 
21
38
 
22
39
 
@@ -49,8 +66,8 @@ class AppControl:
49
66
  self.medisoft_shortcut = path
50
67
 
51
68
  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?
69
+ # Load configuration when needed
70
+ config, _ = _get_config()
54
71
 
55
72
  # PERFORMANCE FIX: Cache configuration lookups to reduce Medicare vs Private overhead
56
73
  cache_key = 'medicare' if medicare else 'private'
@@ -86,6 +103,7 @@ def is_key_pressed(key_code):
86
103
 
87
104
  def manage_script_pause(csv_data, error_message, reverse_mapping):
88
105
  user_action = 0 # initialize as 'continue'
106
+ VK_END, VK_PAUSE = _get_vk_codes()
89
107
 
90
108
  if not app_control.get_pause_status() and is_key_pressed(VK_PAUSE):
91
109
  app_control.set_pause_status(True)
@@ -200,11 +218,6 @@ def display_menu_header(title):
200
218
  print("-" * 60)
201
219
 
202
220
  def handle_user_interaction(interaction_mode, error_message):
203
- # Import here to avoid circular imports
204
- try:
205
- from MediBot import current_patient_context
206
- except ImportError:
207
- current_patient_context = None
208
221
 
209
222
  while True:
210
223
  # If interaction_mode is neither 'triage' nor 'error', then it's normal mode.
@@ -279,6 +292,8 @@ def user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
279
292
  except KeyboardInterrupt:
280
293
  print("\nOperation cancelled by user. Exiting script.")
281
294
 
295
+ # Load configuration when needed
296
+ config, _ = _get_config()
282
297
  fixed_values = config.get('fixed_values', {}) # Get fixed values from config json
283
298
  if response in ['yes', 'y']:
284
299
  medicare_added_fixed_values = config.get('medicare_added_fixed_values', {})
@@ -1,27 +1,73 @@
1
- #MediBot_dataformat_library.py
2
- import re
3
- from datetime import datetime
4
- import re #for addresses
1
+ # MediBot_dataformat_library.py
2
+ """
3
+ Data formatting library for MediBot
4
+ Contains functions for formatting various data types and handling CSV operations.
5
+ """
5
6
 
6
- # Add parent directory of the project to the Python path
7
7
  import os
8
8
  import sys
9
- project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
10
- sys.path.append(project_dir)
11
-
12
- try:
13
- from MediLink import MediLink_ConfigLoader
14
- config, crosswalk = MediLink_ConfigLoader.load_configuration()
15
- except ImportError:
16
- from MediLink_ConfigLoader import load_configuration
17
- config, crosswalk = load_configuration()
18
-
19
- from MediBot_Preprocessor_lib import open_csv_for_editing, initialize
20
- from MediBot_UI import manage_script_pause, app_control
21
-
9
+ import csv
10
+ import json
11
+ import re
12
+ from datetime import datetime
22
13
 
23
- # Bring in all the constants
24
- initialize(config)
14
+ # Add parent directory and current directory to the Python path
15
+ project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
16
+ current_dir = os.path.abspath(os.path.dirname(__file__))
17
+ if project_dir not in sys.path:
18
+ sys.path.append(project_dir)
19
+ if current_dir not in sys.path:
20
+ sys.path.append(current_dir)
21
+
22
+ # Use core utilities for standardized imports
23
+ from MediCafe.core_utils import (
24
+ import_medibot_module,
25
+ get_config_loader_with_fallback,
26
+ create_config_cache
27
+ )
28
+
29
+ # Initialize configuration loader with fallback
30
+ MediLink_ConfigLoader = get_config_loader_with_fallback()
31
+
32
+ # Import MediBot modules using centralized import functions
33
+ MediBot_Preprocessor_lib = import_medibot_module('MediBot_Preprocessor_lib')
34
+ if MediBot_Preprocessor_lib:
35
+ open_csv_for_editing = getattr(MediBot_Preprocessor_lib, 'open_csv_for_editing', None)
36
+ initialize = getattr(MediBot_Preprocessor_lib, 'initialize', None)
37
+ else:
38
+ open_csv_for_editing = None
39
+ initialize = None
40
+
41
+ MediBot_UI = import_medibot_module('MediBot_UI')
42
+ if MediBot_UI:
43
+ manage_script_pause = getattr(MediBot_UI, 'manage_script_pause', None)
44
+ app_control = getattr(MediBot_UI, 'app_control', None)
45
+ else:
46
+ manage_script_pause = None
47
+ app_control = None
48
+
49
+ # Configuration will be loaded when needed
50
+ _get_config, (_config_cache, _crosswalk_cache) = create_config_cache()
51
+
52
+ # Ensure MediLink_ConfigLoader is available
53
+ if MediLink_ConfigLoader is None:
54
+ print("Warning: MediLink_ConfigLoader not available. Some functionality may be limited.")
55
+ # Create a minimal fallback logger
56
+ class FallbackLogger:
57
+ def log(self, message, level="INFO"):
58
+ print("[{}] {}".format(level, message))
59
+ MediLink_ConfigLoader = FallbackLogger()
60
+
61
+ # Initialize constants when needed
62
+ _initialized = False
63
+
64
+ def _ensure_initialized():
65
+ """Ensure initialization has been done."""
66
+ global _initialized
67
+ if not _initialized:
68
+ config, _ = _get_config()
69
+ initialize(config)
70
+ _initialized = True
25
71
 
26
72
  # Format Data
27
73
  def format_name(value):
@@ -98,6 +144,7 @@ def enforce_significant_length(output):
98
144
  return temp_output.replace(' ', '{Space}')
99
145
 
100
146
  def format_street(value, csv_data, reverse_mapping, parsed_address_components):
147
+ _ensure_initialized()
101
148
  # Temporarily disable script pause status
102
149
  app_control.set_pause_status(False)
103
150
 
@@ -109,6 +156,7 @@ def format_street(value, csv_data, reverse_mapping, parsed_address_components):
109
156
  try:
110
157
  MediLink_ConfigLoader.log("Attempting to resolve address via regex...")
111
158
  # Retrieve common city names from configuration and prepare a regex pattern
159
+ config, _ = _get_config()
112
160
  common_cities = config.get('cities', [])
113
161
  city_pattern = '|'.join(re.escape(city) for city in common_cities)
114
162
  city_regex_pattern = r'(?P<City>{})'.format(city_pattern)
@@ -1,19 +1,34 @@
1
1
  #MediBot_docx_decoder.py
2
2
  from datetime import datetime
3
3
  from collections import OrderedDict
4
- import os, re, sys, zipfile, pprint
5
- from docx import Document
6
- from lxml import etree
4
+ import os, re, zipfile, pprint, time, sys
7
5
 
8
- # Add parent directory of the project to the Python path
9
- project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
10
- sys.path.append(project_dir)
6
+ # Add workspace directory to Python path for MediCafe imports
7
+ current_dir = os.path.dirname(os.path.abspath(__file__))
8
+ workspace_dir = os.path.dirname(current_dir)
9
+ if workspace_dir not in sys.path:
10
+ sys.path.insert(0, workspace_dir)
11
11
 
12
12
  try:
13
- import MediLink_ConfigLoader
13
+ from docx import Document
14
14
  except ImportError:
15
- from MediLink import MediLink_ConfigLoader
16
-
15
+ Document = None
16
+ try:
17
+ from lxml import etree
18
+ except ImportError:
19
+ etree = None
20
+
21
+ from MediCafe.core_utils import get_shared_config_loader
22
+ MediLink_ConfigLoader = get_shared_config_loader()
23
+
24
+ # Ensure MediLink_ConfigLoader is available
25
+ if MediLink_ConfigLoader is None:
26
+ print("Warning: MediLink_ConfigLoader not available. Some functionality may be limited.")
27
+ # Create a minimal fallback logger
28
+ class FallbackLogger:
29
+ def log(self, message, level="INFO"):
30
+ print("[{}] {}".format(level, message))
31
+ MediLink_ConfigLoader = FallbackLogger()
17
32
  # Pre-compile regex patterns for better performance (XP/3.4.4 compatible)
18
33
  _DIAGNOSIS_CODE_PATTERN = re.compile(r'H\d{2}\.\d+')
19
34
  _DAY_WEEK_PATTERN = re.compile(r"(MONDAY|TUESDAY|WEDNESDAY|THURSDAY|FRIDAY|SATURDAY|SUNDAY)")
@@ -66,8 +81,19 @@ _DAY_MAP = {
66
81
 
67
82
 
68
83
  def parse_docx(filepath, surgery_dates): # Accept surgery_dates as a parameter
84
+ if Document is None:
85
+ MediLink_ConfigLoader.log("docx module not available, cannot parse .docx files", level="WARNING")
86
+ return {}
87
+
88
+ # TIMING: Start individual DOCX file processing
89
+ file_start_time = time.time()
90
+
69
91
  try:
92
+ # TIMING: Start document opening
93
+ doc_open_start = time.time()
70
94
  doc = Document(filepath) # Open the .docx file
95
+ doc_open_end = time.time()
96
+ doc_open_duration = doc_open_end - doc_open_start
71
97
  except Exception as e:
72
98
  MediLink_ConfigLoader.log("Error opening document: {}".format(e), level="ERROR") # Log error
73
99
  return {}
@@ -75,9 +101,16 @@ def parse_docx(filepath, surgery_dates): # Accept surgery_dates as a parameter
75
101
  patient_data = OrderedDict() # Initialize OrderedDict to store data
76
102
  MediLink_ConfigLoader.log("Extracting Date of Service from {}".format(filepath), level="DEBUG")
77
103
 
104
+ # TIMING: Start date extraction
105
+ date_extraction_start = time.time()
78
106
  date_of_service = extract_date_of_service(filepath) # Extract date of service
107
+ date_extraction_end = time.time()
108
+ date_extraction_duration = date_extraction_end - date_extraction_start
79
109
  MediLink_ConfigLoader.log("Date of Service recorded as: {}".format(date_of_service), level="DEBUG")
80
110
 
111
+ # TIMING: Start date conversion and validation
112
+ date_validation_start = time.time()
113
+
81
114
  # Convert date_of_service to match the format of surgery_dates
82
115
  date_of_service = datetime.strptime(date_of_service, '%m-%d-%Y') # Convert to datetime object
83
116
  # Check if the date_of_service is in the passed surgery_dates
@@ -89,9 +122,20 @@ def parse_docx(filepath, surgery_dates): # Accept surgery_dates as a parameter
89
122
  # Convert back to MM-DD-YYYY format.
90
123
  # TODO in the future, maybe just do the treatment to surgery_dates, no need to convert back and forth..
91
124
  date_of_service = date_of_service.strftime('%m-%d-%Y')
125
+
126
+ date_validation_end = time.time()
127
+ date_validation_duration = date_validation_end - date_validation_start
128
+
129
+ # TIMING: Start table processing
130
+ table_processing_start = time.time()
131
+ tables_processed = 0
132
+ rows_processed = 0
133
+ patients_found = 0
92
134
 
93
135
  for table in doc.tables: # Iterate over tables in the document
136
+ tables_processed += 1
94
137
  for row in table.rows:
138
+ rows_processed += 1
95
139
  cells = [cell.text.strip() for cell in row.cells]
96
140
  if len(cells) > 4 and cells[3].startswith('#'):
97
141
  try:
@@ -102,6 +146,7 @@ def parse_docx(filepath, surgery_dates): # Accept surgery_dates as a parameter
102
146
 
103
147
  if patient_id not in patient_data:
104
148
  patient_data[patient_id] = {}
149
+ patients_found += 1
105
150
 
106
151
  if date_of_service in patient_data[patient_id]:
107
152
  MediLink_ConfigLoader.log("Duplicate entry for patient ID {} on date {}. Skipping.".format(patient_id, date_of_service), level="WARNING")
@@ -110,10 +155,34 @@ def parse_docx(filepath, surgery_dates): # Accept surgery_dates as a parameter
110
155
  except Exception as e:
111
156
  MediLink_ConfigLoader.log("Error processing row: {}. Error: {}".format(cells, e), level="ERROR")
112
157
 
158
+ table_processing_end = time.time()
159
+ table_processing_duration = table_processing_end - table_processing_start
160
+
161
+ # TIMING: Start validation
162
+ validation_start = time.time()
163
+
113
164
  # Validation steps
114
165
  validate_unknown_entries(patient_data)
115
166
  validate_diagnostic_code(patient_data)
116
167
 
168
+ validation_end = time.time()
169
+ validation_duration = validation_end - validation_start
170
+
171
+ # TIMING: End total file processing
172
+ file_end_time = time.time()
173
+ total_duration = file_end_time - file_start_time
174
+
175
+ # Log timing details for slow files (more than 0.5 seconds)
176
+ if total_duration > 0.5:
177
+ print(" - DOCX file timing breakdown:")
178
+ print(" * Document opening: {:.3f}s".format(doc_open_duration))
179
+ print(" * Date extraction: {:.3f}s".format(date_extraction_duration))
180
+ print(" * Date validation: {:.3f}s".format(date_validation_duration))
181
+ print(" * Table processing: {:.3f}s ({} tables, {} rows, {} patients)".format(
182
+ table_processing_duration, tables_processed, rows_processed, patients_found))
183
+ print(" * Validation: {:.3f}s".format(validation_duration))
184
+ print(" * Total: {:.3f}s".format(total_duration))
185
+
117
186
  return patient_data
118
187
 
119
188
 
@@ -148,6 +217,9 @@ def log_and_warn(patient_id, date, diagnostic_code, eye):
148
217
 
149
218
 
150
219
  def extract_date_of_service(docx_path, use_in_memory=True):
220
+ # TIMING: Start date extraction process
221
+ extraction_start_time = time.time()
222
+
151
223
  extract_to = "extracted_docx_debug"
152
224
  in_memory_result = None
153
225
  directory_based_result = None
@@ -160,6 +232,9 @@ def extract_date_of_service(docx_path, use_in_memory=True):
160
232
 
161
233
  # Directory-Based Extraction
162
234
  if not use_in_memory: # Only perform directory-based extraction if in-memory is not selected
235
+ # TIMING: Start directory-based extraction
236
+ dir_extraction_start = time.time()
237
+
163
238
  try:
164
239
  if not os.path.exists(extract_to):
165
240
  os.makedirs(extract_to)
@@ -181,14 +256,23 @@ def extract_date_of_service(docx_path, use_in_memory=True):
181
256
  MediLink_ConfigLoader.log("BadZipFile Error opening DOCX file {}: {}".format(docx_path, e), level="ERROR")
182
257
  except Exception as e:
183
258
  MediLink_ConfigLoader.log("Error opening DOCX file {}: {}".format(docx_path, e), level="ERROR")
259
+
260
+ # TIMING: End directory-based extraction
261
+ dir_extraction_end = time.time()
262
+ dir_extraction_duration = dir_extraction_end - dir_extraction_start
184
263
 
185
264
  # In-Memory Extraction // Single-Pass Processing is typically more efficient in terms of both time and memory compared to list creation for header isolation.
186
265
  if use_in_memory: # Only perform in-memory extraction if selected
266
+ # TIMING: Start in-memory extraction
267
+ mem_extraction_start = time.time()
268
+
187
269
  try:
188
270
  with zipfile.ZipFile(docx_path, 'r') as docx:
189
271
  MediLink_ConfigLoader.log("Opened DOCX file for In-Memory extraction: {}".format(docx_path), level="DEBUG")
272
+ xml_files_processed = 0
190
273
  for file_info in docx.infolist():
191
274
  if file_info.filename.endswith('.xml'):
275
+ xml_files_processed += 1
192
276
  MediLink_ConfigLoader.log("Processing XML file in-memory: {}".format(file_info.filename), level="DEBUG")
193
277
  with docx.open(file_info) as file:
194
278
  try:
@@ -208,6 +292,10 @@ def extract_date_of_service(docx_path, use_in_memory=True):
208
292
  MediLink_ConfigLoader.log("BadZipFile Error opening DOCX file for In-Memory extraction {}: {}".format(docx_path, e), level="ERROR")
209
293
  except Exception as e:
210
294
  MediLink_ConfigLoader.log("Error during In-Memory extraction of DOCX file {}: {}".format(docx_path, e), level="ERROR")
295
+
296
+ # TIMING: End in-memory extraction
297
+ mem_extraction_end = time.time()
298
+ mem_extraction_duration = mem_extraction_end - mem_extraction_start
211
299
 
212
300
  # Clean up the extracted directory if it exists
213
301
  try:
@@ -217,6 +305,19 @@ def extract_date_of_service(docx_path, use_in_memory=True):
217
305
  except Exception as e:
218
306
  MediLink_ConfigLoader.log("Error cleaning up extraction directory {}: {}".format(extract_to, e), level="ERROR")
219
307
 
308
+ # TIMING: End total extraction process
309
+ extraction_end_time = time.time()
310
+ total_extraction_duration = extraction_end_time - extraction_start_time
311
+
312
+ # Log timing details for slow extractions (more than 0.2 seconds)
313
+ if total_extraction_duration > 0.2:
314
+ print(" - Date extraction timing:")
315
+ if not use_in_memory and 'dir_extraction_duration' in locals():
316
+ print(" * Directory-based: {:.3f}s".format(dir_extraction_duration))
317
+ if use_in_memory and 'mem_extraction_duration' in locals():
318
+ print(" * In-memory: {:.3f}s ({} XML files)".format(mem_extraction_duration, xml_files_processed if 'xml_files_processed' in locals() else 0))
319
+ print(" * Total: {:.3f}s".format(total_extraction_duration))
320
+
220
321
  # Decide which result to return (prefer in-memory if available)
221
322
  if in_memory_result:
222
323
  return in_memory_result
@@ -389,7 +490,7 @@ def remove_directory(path):
389
490
 
390
491
 
391
492
  def normalize_text(text):
392
- # Optimized single-pass processing to avoid O() complexity
493
+ # Optimized single-pass processing to avoid O(n2) complexity
393
494
  # Process all abbreviations in one pass instead of multiple regex calls
394
495
  for abbr, pattern in _MONTH_ABBR_PATTERNS.items():
395
496
  text = pattern.sub(_MONTH_MAP[abbr], text)
@@ -485,18 +586,18 @@ def rotate_docx_files(directory, surgery_dates=None):
485
586
  Returns:
486
587
  - dict: Combined patient data from all processed files
487
588
  """
488
- # PERFORMANCE OPTIMIZATION: Use os.scandir() for more efficient file system operations
589
+ # PERFORMANCE OPTIMIZATION: Use os.listdir() for more efficient file system operations
489
590
  # This reduces the number of file system calls and improves performance with large directories
490
591
  valid_files = []
491
592
  try:
492
- # Use os.scandir() for better performance (XP/3.4.4 compatible)
493
- with os.scandir(directory) as entries:
494
- for entry in entries:
495
- # Filter files that contain "DR" and "SS" in the filename
496
- if (entry.name.endswith('.docx') and
497
- "DR" in entry.name and
498
- "SS" in entry.name):
499
- valid_files.append(entry.path)
593
+ # Use os.listdir() for better performance (XP/3.4.4 compatible)
594
+ for filename in os.listdir(directory):
595
+ # Filter files that contain "DR" and "SS" in the filename
596
+ if (filename.endswith('.docx') and
597
+ "DR" in filename and
598
+ "SS" in filename):
599
+ filepath = os.path.join(directory, filename)
600
+ valid_files.append(filepath)
500
601
  except OSError as e:
501
602
  print("Error accessing directory '{}': {}".format(directory, e))
502
603
  return {}
@@ -0,0 +1,180 @@
1
+ #MediBot_smart_import.py
2
+ """
3
+ Upgraded MediBot main module using MediCafe Smart Import System
4
+
5
+ This is a demonstration of how MediBot.py should be migrated to use the
6
+ new centralized smart import system, eliminating sys.path manipulation
7
+ and circular import risks.
8
+ """
9
+
10
+ import os, subprocess, tempfile, traceback, re, time, sys
11
+
12
+ # Add workspace directory to Python path for MediCafe imports
13
+ current_dir = os.path.dirname(os.path.abspath(__file__))
14
+ workspace_dir = os.path.dirname(current_dir)
15
+ if workspace_dir not in sys.path:
16
+ sys.path.insert(0, workspace_dir)
17
+
18
+ try:
19
+ import msvcrt # Windows-specific module
20
+ except ImportError:
21
+ msvcrt = None # Not available on non-Windows systems
22
+ from collections import OrderedDict
23
+
24
+ # NEW SMART IMPORT APPROACH - Replace all MediCafe and MediBot imports with this
25
+ from MediCafe import setup_for_medibot, get_components
26
+
27
+ # Get everything needed for MediBot main functionality
28
+ print("[*] Loading MediBot components via smart import system...")
29
+ try:
30
+ components = setup_for_medibot('medibot_preprocessor')
31
+ print("[+] Loaded {} components successfully".format(len(components)))
32
+
33
+ # Extract components we need
34
+ core_utils = components.get('core_utils')
35
+ logging_config = components.get('logging_config')
36
+ api_core = components.get('api_core')
37
+
38
+ # MediBot specific components
39
+ medibot_dataformat_library = components.get('medibot_dataformat_library')
40
+ medibot_preprocessor = components.get('medibot_preprocessor')
41
+ medibot_preprocessor_lib = components.get('medibot_preprocessor_lib')
42
+ medibot_ui = components.get('medibot_ui')
43
+ medibot_crosswalk_library = components.get('medibot_crosswalk_library')
44
+
45
+ print("[+] Core components extracted")
46
+
47
+ except Exception as e:
48
+ print("[!] Some components unavailable (expected in dev): {}".format(e))
49
+ # Fallback imports for development
50
+ try:
51
+ core_utils = get_components('core_utils', silent_fail=True)
52
+ logging_config = get_components('logging_config', silent_fail=True)
53
+ api_core = get_components('api_core', silent_fail=True)
54
+ # Initialize other components as None for fallback
55
+ medibot_dataformat_library = None
56
+ medibot_preprocessor = None
57
+ medibot_preprocessor_lib = None
58
+ medibot_ui = None
59
+ medibot_crosswalk_library = None
60
+ print("[+] Fallback to individual component loading")
61
+ except:
62
+ print("[-] Smart import system not available - using legacy approach")
63
+ core_utils = None
64
+ logging_config = None
65
+ api_core = None
66
+ medibot_dataformat_library = None
67
+ medibot_preprocessor = None
68
+ medibot_preprocessor_lib = None
69
+ medibot_ui = None
70
+ medibot_crosswalk_library = None
71
+
72
+ # Configuration loader setup
73
+ MediLink_ConfigLoader = None
74
+ if core_utils:
75
+ try:
76
+ get_config_loader_with_fallback = getattr(core_utils, 'get_config_loader_with_fallback', None)
77
+ if get_config_loader_with_fallback:
78
+ MediLink_ConfigLoader = get_config_loader_with_fallback()
79
+ print("[+] Configuration loader initialized via smart import")
80
+ except Exception as e:
81
+ print("[!] Configuration loader setup issue: {}".format(e))
82
+
83
+ # API client setup
84
+ api_client = None
85
+ factory = None
86
+
87
+ if api_core and core_utils:
88
+ try:
89
+ get_api_client_factory = getattr(core_utils, 'get_api_client_factory', None)
90
+ if get_api_client_factory:
91
+ factory = get_api_client_factory()
92
+ if factory:
93
+ api_client = factory.get_shared_client()
94
+ print("[+] API client initialized via smart import")
95
+ except Exception as e:
96
+ print("[!] API client setup issue: {}".format(e))
97
+
98
+ # Function extraction from components (if available)
99
+ app_control = None
100
+ manage_script_pause = None
101
+ user_interaction = None
102
+ crosswalk_update = None
103
+
104
+ if medibot_ui:
105
+ try:
106
+ app_control = getattr(medibot_ui, 'app_control', None)
107
+ manage_script_pause = getattr(medibot_ui, 'manage_script_pause', None)
108
+ user_interaction = getattr(medibot_ui, 'user_interaction', None)
109
+ print("[+] UI functions extracted")
110
+ except Exception as e:
111
+ print("[!] UI function extraction issue: {}".format(e))
112
+
113
+ if medibot_crosswalk_library:
114
+ try:
115
+ crosswalk_update = getattr(medibot_crosswalk_library, 'crosswalk_update', None)
116
+ print("[+] Crosswalk functions extracted")
117
+ except Exception as e:
118
+ print("[!] Crosswalk function extraction issue: {}".format(e))
119
+
120
+ # Legacy functions for backward compatibility
121
+ def import_medibot_module_with_debug(module_name):
122
+ """Legacy function wrapper for backwards compatibility."""
123
+ try:
124
+ component_name = "medibot_{}".format(module_name.lower().replace('medibot_', ''))
125
+ return get_components(component_name, silent_fail=True)
126
+ except:
127
+ print("[!] Could not load {} via smart import".format(module_name))
128
+ return None
129
+
130
+ def get_config_loader_with_fallback():
131
+ """Legacy function wrapper for backwards compatibility."""
132
+ return MediLink_ConfigLoader
133
+
134
+ def get_api_client_factory():
135
+ """Legacy function wrapper for backwards compatibility."""
136
+ return factory
137
+
138
+ # Rest of the MediBot functionality would continue here...
139
+ # This demonstrates the pattern for migrating the entire file
140
+
141
+ def main():
142
+ """Main MediBot function using smart imports."""
143
+ print("\n[*] MediBot Starting with Smart Import System")
144
+ print("=" * 50)
145
+
146
+ if MediLink_ConfigLoader:
147
+ print("[+] Configuration system ready")
148
+ else:
149
+ print("[!] Configuration system not available")
150
+
151
+ if api_client:
152
+ print("[+] API client ready")
153
+ else:
154
+ print("[!] API client not available")
155
+
156
+ if medibot_preprocessor:
157
+ print("[+] Preprocessor ready")
158
+ else:
159
+ print("[!] Preprocessor not available")
160
+
161
+ if medibot_ui and app_control:
162
+ print("[+] UI system ready")
163
+ else:
164
+ print("[!] UI system not available")
165
+
166
+ print("\n[i] Benefits of Smart Import System:")
167
+ print(" - No sys.path manipulation needed")
168
+ print(" - No circular import risks")
169
+ print(" - Centralized component management")
170
+ print(" - Graceful fallback for missing components")
171
+ print(" - Easy to test and validate")
172
+
173
+ return True
174
+
175
+ if __name__ == "__main__":
176
+ success = main()
177
+ if success:
178
+ print("\n[+] MediBot smart import demonstration completed successfully!")
179
+ else:
180
+ print("\n[-] MediBot smart import demonstration had issues")