sonuprasad23 commited on
Commit
34c8f66
·
1 Parent(s): 66e21a5

Trying again

Browse files
Files changed (1) hide show
  1. server.py +75 -45
server.py CHANGED
@@ -56,26 +56,49 @@ def extract_patient_name(raw_name):
56
  return ""
57
  # Remove everything after (and including) 'DOB'
58
  name_only = raw_name.split('DOB').strip()
59
- # Clean up leftover colon or numbers
60
- # Remove trailing colon/spaces/numbers if present
61
  name_only = re.sub(r'[:\d\-\s]+$', '', name_only).strip()
62
  return name_only
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  def create_prn_lookup(df_app):
 
 
 
 
65
  prn_dict = {}
66
  for _, row in df_app.iterrows():
67
- pure_name = extract_patient_name(row['Patient Name'])
68
- if pure_name:
69
- prn_dict[pure_name] = row['PRN']
 
 
 
70
  return prn_dict
71
 
72
- def get_email_list():
73
- try:
74
- with open('config/emails.conf', 'r') as f:
75
- return [line.strip() for line in f if line.strip()]
76
- except FileNotFoundError:
77
- return []
78
-
79
  class GmailApiService:
80
  def __init__(self):
81
  self.sender_email = os.getenv('EMAIL_SENDER')
@@ -283,9 +306,8 @@ def status_page():
283
  @app.route('/process_and_initialize', methods=['POST'])
284
  def handle_file_processing_and_init():
285
  """
286
- HTTP alternative for uploading files. Keeps backward compatibility.
287
- Emits both 'data_processed' and 'data_processed_and_ready' for client compatibility.
288
- Uses the provided file-handling logic.
289
  """
290
  session_id = 'user_session'
291
  try:
@@ -295,43 +317,46 @@ def handle_file_processing_and_init():
295
  return jsonify({"error": "Both files are required."}), 400
296
 
297
  # Read files
298
- app_data_file = request.files['app_data']
299
- quantum_data_file = request.files['quantum_data']
300
-
301
  df_app = (
302
- pd.read_excel(app_data_file)
303
- if app_data_file.filename.lower().endswith('.xlsx')
304
- else pd.read_csv(app_data_file)
305
  )
306
  df_quantum = (
307
- pd.read_excel(quantum_data_file)
308
- if quantum_data_file.filename.lower().endswith('.xlsx')
309
- else pd.read_csv(quantum_data_file)
310
  )
311
 
312
  # Validations
313
  if 'Patient Name' not in df_app.columns or 'PRN' not in df_app.columns:
314
- return jsonify({"error": "App Data file must contain 'Patient Name' and 'PRN' columns."}), 400
315
  if 'Name' not in df_quantum.columns:
316
- return jsonify({"error": "Quantum Data file must contain a 'Name' column."}), 400
317
 
318
- # Filter and build lookup using provided logic
319
- df_app_filtered = df_app.dropna(subset=['PRN'])
320
- df_app_filtered = df_app_filtered[df_app_filtered['PRN'].astype(str).str.strip() != '']
321
- prn_lookup_dict = create_prn_lookup(df_app_filtered)
322
 
323
- # Map PRN for each Quantum name (case-sensitive, as provided)
324
- df_quantum = df_quantum.copy()
325
- df_quantum['PRN'] = [prn_lookup_dict.get(name, "") for name in df_quantum['Name']]
326
 
327
- master_df = df_quantum.copy()
 
 
 
 
 
 
 
328
  master_df['Status'] = ''
329
 
330
  data['patient_data_for_report'] = master_df
331
  data['patient_data'] = master_df.to_dict('records')
332
  session_data[session_id] = data
333
 
334
- # Notify clients
335
  socketio.emit('data_processed')
336
  socketio.emit('data_processed_and_ready')
337
 
@@ -364,7 +389,7 @@ def handle_init(data):
364
  def handle_process_and_initialize(payload):
365
  """
366
  NEW: Socket.IO path for the same workflow the UI currently uses.
367
- Decodes base64 files, builds master DF using the provided logic, stores session, and emits 'data_processed_and_ready'.
368
  """
369
  try:
370
  session_id = 'user_session'
@@ -374,7 +399,6 @@ def handle_process_and_initialize(payload):
374
  raw = base64.b64decode(file_obj['content'])
375
  if name.lower().endswith('.xlsx'):
376
  return pd.read_excel(io.BytesIO(raw))
377
- # CSV path
378
  text = raw.decode('utf-8', errors='replace')
379
  return pd.read_csv(io.StringIO(text))
380
 
@@ -389,16 +413,22 @@ def handle_process_and_initialize(payload):
389
  emit('error', {'message': "Quantum Data file must contain a 'Name' column."}, room=request.sid)
390
  return
391
 
392
- # Filter and build lookup using provided logic
393
- df_app_filtered = df_app.dropna(subset=['PRN'])
394
- df_app_filtered = df_app_filtered[df_app_filtered['PRN'].astype(str).str.strip() != '']
395
- prn_lookup_dict = create_prn_lookup(df_app_filtered)
 
 
 
396
 
397
- # Map PRN for each Quantum name (case-sensitive, as provided)
398
- df_quantum = df_quantum.copy()
399
- df_quantum['PRN'] = [prn_lookup_dict.get(name, "") for name in df_quantum['Name']]
400
 
401
- master_df = df_quantum.copy()
 
 
 
402
  master_df['Status'] = ''
403
 
404
  # Persist session data (includes meta from payload)
 
56
  return ""
57
  # Remove everything after (and including) 'DOB'
58
  name_only = raw_name.split('DOB').strip()
59
+ # Clean up leftover colon or numbers; remove trailing colon/spaces/numbers if present
 
60
  name_only = re.sub(r'[:\d\-\s]+$', '', name_only).strip()
61
  return name_only
62
 
63
+ def normalize_str(v):
64
+ """
65
+ Safely convert any value (NaN/None/list/number/string) into a clean string.
66
+ Prevents attribute errors when later trimming or matching.
67
+ """
68
+ try:
69
+ import math
70
+ # None or NaN -> empty
71
+ if v is None:
72
+ return ""
73
+ if isinstance(v, float) and math.isnan(v):
74
+ return ""
75
+ # Join list-like values into a single string
76
+ if isinstance(v, list):
77
+ try:
78
+ return " ".join("" if x is None else str(x).strip() for x in v).strip()
79
+ except Exception:
80
+ return str(v).strip()
81
+ # Default string conversion + strip
82
+ return str(v).strip()
83
+ except Exception:
84
+ # As a last resort, stringify
85
+ return f"{v}".strip()
86
+
87
  def create_prn_lookup(df_app):
88
+ """
89
+ Build a lookup from pure patient name (extracted from 'Patient Name') to PRN.
90
+ Both keys and values are normalized to robustly handle mixed cell types.
91
+ """
92
  prn_dict = {}
93
  for _, row in df_app.iterrows():
94
+ # Normalize inputs
95
+ pn_raw = normalize_str(row.get('Patient Name', ''))
96
+ prn_raw = normalize_str(row.get('PRN', ''))
97
+ pure_name = extract_patient_name(pn_raw)
98
+ if pure_name and prn_raw:
99
+ prn_dict[pure_name] = prn_raw
100
  return prn_dict
101
 
 
 
 
 
 
 
 
102
  class GmailApiService:
103
  def __init__(self):
104
  self.sender_email = os.getenv('EMAIL_SENDER')
 
306
  @app.route('/process_and_initialize', methods=['POST'])
307
  def handle_file_processing_and_init():
308
  """
309
+ HTTP alternative for uploading files (kept for compatibility).
310
+ Emits both 'data_processed' and 'data_processed_and_ready' for client alignment.
 
311
  """
312
  session_id = 'user_session'
313
  try:
 
317
  return jsonify({"error": "Both files are required."}), 400
318
 
319
  # Read files
 
 
 
320
  df_app = (
321
+ pd.read_excel(request.files['app_data'])
322
+ if request.files['app_data'].filename.lower().endswith('.xlsx')
323
+ else pd.read_csv(request.files['app_data'])
324
  )
325
  df_quantum = (
326
+ pd.read_excel(request.files['quantum_data'])
327
+ if request.files['quantum_data'].filename.lower().endswith('.xlsx')
328
+ else pd.read_csv(request.files['quantum_data'])
329
  )
330
 
331
  # Validations
332
  if 'Patient Name' not in df_app.columns or 'PRN' not in df_app.columns:
333
+ raise ValueError("App Data file must contain 'Patient Name' and 'PRN' columns.")
334
  if 'Name' not in df_quantum.columns:
335
+ raise ValueError("Quantum Data file must contain a 'Name' column.")
336
 
337
+ # Filter out empty PRN rows using normalization (robust against lists/mixed types)
338
+ df_app['__PN'] = df_app['Patient Name'].apply(normalize_str)
339
+ df_app['__PRN'] = df_app['PRN'].apply(normalize_str)
340
+ df_app_filtered = df_app[df_app['__PRN'] != ""].copy()
341
 
342
+ # Create lookup: pure name (from Patient Name) -> PRN, using provided logic pattern
343
+ prn_lookup_dict = create_prn_lookup(df_app_filtered.rename(columns={'__PN': 'Patient Name', '__PRN': 'PRN'}))
 
344
 
345
+ # Lookup PRN for each Quantum name (match as-is but normalized to avoid list issues)
346
+ df_quantum['__Name'] = df_quantum['Name'].apply(normalize_str)
347
+ prn_list = [prn_lookup_dict.get(n, "") for n in df_quantum['__Name']]
348
+
349
+ master_df = pd.DataFrame({
350
+ 'Name': df_quantum['Name'],
351
+ 'PRN': prn_list
352
+ })
353
  master_df['Status'] = ''
354
 
355
  data['patient_data_for_report'] = master_df
356
  data['patient_data'] = master_df.to_dict('records')
357
  session_data[session_id] = data
358
 
359
+ # Notify clients (both names for safety with current frontend)
360
  socketio.emit('data_processed')
361
  socketio.emit('data_processed_and_ready')
362
 
 
389
  def handle_process_and_initialize(payload):
390
  """
391
  NEW: Socket.IO path for the same workflow the UI currently uses.
392
+ Decodes base64 files, builds master DF via provided logic, stores session, and emits 'data_processed_and_ready'.
393
  """
394
  try:
395
  session_id = 'user_session'
 
399
  raw = base64.b64decode(file_obj['content'])
400
  if name.lower().endswith('.xlsx'):
401
  return pd.read_excel(io.BytesIO(raw))
 
402
  text = raw.decode('utf-8', errors='replace')
403
  return pd.read_csv(io.StringIO(text))
404
 
 
413
  emit('error', {'message': "Quantum Data file must contain a 'Name' column."}, room=request.sid)
414
  return
415
 
416
+ # Filter out empty PRN rows using normalization (robust against lists/mixed types)
417
+ df_app['__PN'] = df_app['Patient Name'].apply(normalize_str)
418
+ df_app['__PRN'] = df_app['PRN'].apply(normalize_str)
419
+ df_app_filtered = df_app[df_app['__PRN'] != ""].copy()
420
+
421
+ # Create lookup: pure name (from Patient Name) -> PRN, using provided logic pattern
422
+ prn_lookup_dict = create_prn_lookup(df_app_filtered.rename(columns={'__PN': 'Patient Name', '__PRN': 'PRN'}))
423
 
424
+ # Lookup PRN for each Quantum name (match as-is but normalized to avoid list issues)
425
+ df_quantum['__Name'] = df_quantum['Name'].apply(normalize_str)
426
+ prn_list = [prn_lookup_dict.get(n, "") for n in df_quantum['__Name']]
427
 
428
+ master_df = pd.DataFrame({
429
+ 'Name': df_quantum['Name'],
430
+ 'PRN': prn_list
431
+ })
432
  master_df['Status'] = ''
433
 
434
  # Persist session data (includes meta from payload)