Ali2206 commited on
Commit
3213a0d
·
verified ·
1 Parent(s): 3af8921

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +151 -136
app.py CHANGED
@@ -51,152 +51,165 @@ def clean_response(text: str) -> str:
51
  text = re.sub(r"[^\n#\-\*\w\s\.,:\(\)]+", "", text)
52
  return text.strip()
53
 
54
- def extract_medical_data(df: pd.DataFrame) -> Dict[str, Any]:
55
- """Extract and organize medical data from DataFrame"""
56
- medical_data = defaultdict(list)
 
 
 
 
 
 
 
 
 
 
57
 
58
  for _, row in df.iterrows():
59
- record = {
60
- 'booking': row.get('Booking Number', ''),
61
- 'form_name': row.get('Form Name', ''),
62
- 'form_item': row.get('Form Item', ''),
63
- 'response': row.get('Item Response', ''),
64
  'date': row.get('Interview Date', ''),
65
- 'interviewer': row.get('Interviewer', ''),
66
- 'description': row.get('Description', '')
 
 
 
67
  }
68
- medical_data[row['Booking Number']].append(record)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
- return medical_data
71
 
72
- def identify_red_flags(records: List[Dict[str, Any]]) -> Dict[str, Any]:
73
- """Identify potential red flags across all medical records"""
74
- red_flags = {
75
- 'symptoms': defaultdict(list),
76
- 'medications': defaultdict(list),
77
- 'diagnoses': defaultdict(list),
78
- 'vitals': defaultdict(list),
79
- 'labs': defaultdict(list),
80
- 'patients': defaultdict(list)
81
- }
82
 
83
- for booking, patient_records in records.items():
84
- for record in patient_records:
85
- form_name = record['form_name'].lower()
86
- item = record['form_item'].lower()
87
- response = record['response'].lower()
88
-
89
- # Symptom patterns
90
- if 'pain' in item or 'symptom' in form_name:
91
- if 'severe' in response or 'chronic' in response:
92
- red_flags['symptoms'][item].append((booking, response))
93
-
94
- # Medication checks
95
- elif 'medication' in form_name or 'drug' in form_name:
96
- if 'interaction' in response or 'allergy' in response:
97
- red_flags['medications'][item].append((booking, response))
98
-
99
- # Diagnosis inconsistencies
100
- elif 'diagnosis' in form_name:
101
- if 'rule out' in response or 'possible' in response:
102
- red_flags['diagnoses'][item].append((booking, response))
103
-
104
- # Abnormal vitals
105
- elif 'vital' in form_name:
106
- try:
107
- value = float(re.search(r'\d+\.?\d*', response).group())
108
- if ('blood pressure' in item and value > 140) or \
109
- ('heart rate' in item and (value < 50 or value > 100)) or \
110
- ('temperature' in item and value > 38):
111
- red_flags['vitals'][item].append((booking, response))
112
- except:
113
- pass
114
-
115
- # Abnormal labs
116
- elif 'lab' in form_name or 'test' in form_name:
117
- if 'abnormal' in response or 'high' in response or 'low' in response:
118
- red_flags['labs'][item].append((booking, response))
119
 
120
- return red_flags
121
-
122
- def generate_combined_prompt(all_records: Dict[str, Any], red_flags: Dict[str, Any]]) -> str:
123
- """Generate a single comprehensive prompt for all patient data"""
124
- # Create summary of all records
125
- records_summary = []
126
- for booking, records in all_records.items():
127
- records_summary.append(f"\n## Patient {booking}")
128
- for r in records:
129
- records_summary.append(
130
- f"- {r['form_name']}: {r['form_item']} = {r['response']} "
131
- f"({r['date']} by {r['interviewer']})\n {r['description']}"
132
  )
133
 
134
- # Format red flags with patient references
135
- red_flags_text = []
136
- for category, items in red_flags.items():
137
- if items:
138
- red_flags_text.append(f"\n### {category.capitalize()} Red Flags")
139
- for item, entries in items.items():
140
- patient_entries = defaultdict(list)
141
- for booking, response in entries:
142
- patient_entries[booking].append(response)
143
-
144
- for booking, responses in patient_entries.items():
145
- red_flags_text.append(
146
- f"- {item} (Patient {booking}): {', '.join(responses)}"
147
- )
148
 
149
  prompt = f"""
150
- **COMPREHENSIVE PATIENT ANALYSIS**
 
 
 
 
 
 
 
151
 
152
- **Medical Records Summary**:
153
- {"".join(records_summary)}
154
 
155
- **Identified Red Flags Across All Patients**:
156
- {"".join(red_flags_text) if red_flags_text else "No obvious red flags detected"}
157
 
158
  **Analysis Instructions**:
159
- 1. Review ALL patient data holistically
160
- 2. Identify patterns that might indicate systemic issues
161
- 3. Check for recurring medication problems across patients
162
- 4. Note any common missed diagnoses
163
- 5. Flag any urgent cases needing immediate attention
164
- 6. Provide overall clinical recommendations
 
165
 
166
  **Required Output Format**:
167
- ### Summary of Findings
168
- [Overview of most significant findings across all patients]
169
 
170
- ### Common Missed Diagnoses
171
- - [Conditions frequently overlooked across multiple patients]
172
- - [Specific patients affected: Booking numbers]
173
 
174
- ### Recurring Medication Issues
175
- - [Common drug interactions or inappropriate prescriptions]
176
- - [Patients affected]
 
177
 
178
- ### Systemic Assessment Gaps
179
- - [Patterns of incomplete assessments across patients]
180
- - [Recommended additional tests]
 
181
 
182
- ### Critical Cases Needing Follow-up
183
- - [Patients requiring urgent attention]
184
- - [Specific reasons]
185
 
186
- ### Overall Recommendations
187
- - [General recommendations for clinical practice]
188
- - [Specific actions for different patient groups]
 
189
  """
190
  return prompt
191
 
192
- def parse_excel_to_combined_prompt(file_path: str) -> str:
193
- """Parse Excel file into a single comprehensive analysis prompt"""
194
  try:
195
  xl = pd.ExcelFile(file_path)
196
  df = xl.parse(xl.sheet_names[0], header=0).fillna("")
197
- medical_data = extract_medical_data(df)
198
- red_flags = identify_red_flags(medical_data)
199
- prompt = generate_combined_prompt(medical_data, red_flags)
200
  return prompt
201
  except Exception as e:
202
  raise ValueError(f"Error parsing Excel file: {str(e)}")
@@ -224,8 +237,8 @@ def init_agent():
224
 
225
  def create_ui(agent):
226
  """Create Gradio UI interface"""
227
- with gr.Blocks(theme=gr.themes.Soft(), title="Clinical Oversight Assistant") as demo:
228
- gr.Markdown("# 🏥 Comprehensive Clinical Analysis")
229
 
230
  with gr.Tabs():
231
  with gr.TabItem("Analysis"):
@@ -233,7 +246,7 @@ def create_ui(agent):
233
  # Left column - Inputs
234
  with gr.Column(scale=1):
235
  file_upload = gr.File(
236
- label="Upload Excel File",
237
  file_types=[".xlsx"],
238
  file_count="single",
239
  interactive=True
@@ -245,12 +258,12 @@ def create_ui(agent):
245
  )
246
  with gr.Row():
247
  clear_btn = gr.Button("Clear", variant="secondary")
248
- send_btn = gr.Button("Analyze All Patients", variant="primary")
249
 
250
  # Right column - Outputs
251
  with gr.Column(scale=2):
252
  chatbot = gr.Chatbot(
253
- label="Comprehensive Analysis Results",
254
  height=600,
255
  bubble_full_width=False,
256
  show_copy_button=True,
@@ -265,32 +278,34 @@ def create_ui(agent):
265
  gr.Markdown("""
266
  ## How to Use This Tool
267
 
268
- 1. **Upload Excel File**: Select your patient records Excel file
269
  2. **Add Instructions** (Optional): Provide any specific analysis requests
270
- 3. **Click Analyze**: The system will process ALL patient records together
271
  4. **Review Results**: Comprehensive analysis appears in the chat window
272
  5. **Download Report**: Get a complete text report of all findings
273
 
274
- ### Key Features
275
- - **Holistic analysis** of all patient records
276
- - **Pattern detection** across multiple patients
277
- - **Systemic issues** identification
278
- - **Prioritized recommendations** based on severity
 
 
279
  """)
280
 
281
  def analyze(message: str, chat_history: List[Tuple[str, str]], file) -> Tuple[List[Tuple[str, str]], str]:
282
- """Main analysis function for all patients"""
283
  if not file:
284
  raise gr.Error("Please upload an Excel file first")
285
 
286
  try:
287
  # Initialize chat history
288
  new_history = chat_history + [(message, None)]
289
- new_history.append((None, "⏳ Processing all patient data..."))
290
  yield new_history, None
291
 
292
- # Generate combined prompt
293
- prompt = parse_excel_to_combined_prompt(file.name)
294
 
295
  # Run analysis
296
  full_output = ""
@@ -298,7 +313,7 @@ def create_ui(agent):
298
  message=prompt,
299
  history=[],
300
  temperature=0.2,
301
- max_new_tokens=2048, # Increased for comprehensive analysis
302
  max_token=4096,
303
  call_agent=False,
304
  conversation=[],
@@ -319,10 +334,10 @@ def create_ui(agent):
319
  # Save report
320
  file_hash_value = file_hash(file.name)
321
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
322
- report_path = os.path.join(report_dir, f"comprehensive_{file_hash_value}_{timestamp}_report.md")
323
 
324
  with open(report_path, "w", encoding="utf-8") as f:
325
- f.write("# Comprehensive Clinical Analysis Report\n\n")
326
  f.write(f"**Generated on**: {timestamp}\n\n")
327
  f.write(f"**Source file**: {file.name}\n\n")
328
  f.write(full_output)
 
51
  text = re.sub(r"[^\n#\-\*\w\s\.,:\(\)]+", "", text)
52
  return text.strip()
53
 
54
+ def extract_patient_data(df: pd.DataFrame) -> Dict[str, Any]:
55
+ """Extract and organize all medical data for a single patient"""
56
+ patient_data = {
57
+ 'appointments': [],
58
+ 'timeline': defaultdict(list),
59
+ 'doctors': set(),
60
+ 'medications': defaultdict(list),
61
+ 'diagnoses': defaultdict(list),
62
+ 'tests': defaultdict(list)
63
+ }
64
+
65
+ # Sort by interview date to create timeline
66
+ df = df.sort_values('Interview Date')
67
 
68
  for _, row in df.iterrows():
69
+ appointment = {
 
 
 
 
70
  'date': row.get('Interview Date', ''),
71
+ 'doctor': row.get('Interviewer', ''),
72
+ 'form': row.get('Form Name', ''),
73
+ 'item': row.get('Form Item', ''),
74
+ 'response': row.get('Item Response', ''),
75
+ 'notes': row.get('Description', '')
76
  }
77
+ patient_data['appointments'].append(appointment)
78
+ patient_data['doctors'].add(row.get('Interviewer', ''))
79
+
80
+ # Categorize data for analysis
81
+ form_name = row['Form Name'].lower()
82
+ item = row['Form Item'].lower()
83
+ response = row['Item Response']
84
+
85
+ if 'medication' in form_name or 'drug' in form_name:
86
+ patient_data['medications'][item].append({
87
+ 'date': row['Interview Date'],
88
+ 'doctor': row['Interviewer'],
89
+ 'response': response
90
+ })
91
+ elif 'diagnosis' in form_name:
92
+ patient_data['diagnoses'][item].append({
93
+ 'date': row['Interview Date'],
94
+ 'doctor': row['Interviewer'],
95
+ 'response': response
96
+ })
97
+ elif 'test' in form_name or 'lab' in form_name:
98
+ patient_data['tests'][item].append({
99
+ 'date': row['Interview Date'],
100
+ 'doctor': row['Interviewer'],
101
+ 'response': response
102
+ })
103
+
104
+ # Add to timeline by date
105
+ patient_data['timeline'][row['Interview Date']].append({
106
+ 'form': row['Form Name'],
107
+ 'item': row['Form Item'],
108
+ 'response': row['Item Response'],
109
+ 'doctor': row['Interviewer']
110
+ })
111
 
112
+ return patient_data
113
 
114
+ def generate_patient_prompt(patient_data: Dict[str, Any]) -> str:
115
+ """Generate comprehensive analysis prompt for a single patient"""
116
+ # Create timeline summary
117
+ timeline_text = []
118
+ for date, entries in patient_data['timeline'].items():
119
+ timeline_text.append(f"\n### {date}")
120
+ for entry in entries:
121
+ timeline_text.append(
122
+ f"- {entry['form']}: {entry['item']} = {entry['response']} (by Dr. {entry['doctor']})"
123
+ )
124
 
125
+ # Create medication history
126
+ meds_text = []
127
+ for med, records in patient_data['medications'].items():
128
+ meds_text.append(f"\n- {med}:")
129
+ for record in records:
130
+ meds_text.append(
131
+ f" - Prescribed on {record['date']} by Dr. {record['doctor']}: {record['response']}"
132
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
+ # Create diagnosis history
135
+ diag_text = []
136
+ for diag, records in patient_data['diagnoses'].items():
137
+ diag_text.append(f"\n- {diag}:")
138
+ for record in records:
139
+ diag_text.append(
140
+ f" - Diagnosed on {record['date']} by Dr. {record['doctor']}: {record['response']}"
 
 
 
 
 
141
  )
142
 
143
+ # Create test history
144
+ tests_text = []
145
+ for test, records in patient_data['tests'].items():
146
+ tests_text.append(f"\n- {test}:")
147
+ for record in records:
148
+ tests_text.append(
149
+ f" - Tested on {record['date']} by Dr. {record['doctor']}: {record['response']}"
150
+ )
 
 
 
 
 
 
151
 
152
  prompt = f"""
153
+ **COMPREHENSIVE PATIENT HISTORY ANALYSIS**
154
+
155
+ **Patient Timeline**:
156
+ {"".join(timeline_text)}
157
+
158
+ **Medical History Overview**:
159
+ ### Medications
160
+ {"".join(meds_text) if meds_text else "No medication records found"}
161
 
162
+ ### Diagnoses
163
+ {"".join(diag_text) if diag_text else "No diagnosis records found"}
164
 
165
+ ### Test Results
166
+ {"".join(tests_text) if tests_text else "No test records found"}
167
 
168
  **Analysis Instructions**:
169
+ 1. Review the complete patient history across all appointments
170
+ 2. Identify any inconsistencies in diagnoses or treatments
171
+ 3. Check for medication conflicts or changes over time
172
+ 4. Note any unresolved symptoms or conditions
173
+ 5. Evaluate test result patterns over time
174
+ 6. Flag any concerning trends or gaps in care
175
+ 7. Provide comprehensive recommendations
176
 
177
  **Required Output Format**:
178
+ ### Clinical Summary
179
+ [Overview of patient's medical journey]
180
 
181
+ ### Treatment Consistency
182
+ - [Evaluation of consistency across different doctors]
183
+ - [Notable changes in treatment approaches]
184
 
185
+ ### Medication Analysis
186
+ - [Current medication list]
187
+ - [Potential interactions or issues]
188
+ - [Changes over time]
189
 
190
+ ### Diagnostic Evaluation
191
+ - [Confirmed diagnoses]
192
+ - [Potential missed diagnoses]
193
+ - [Diagnostic consistency across providers]
194
 
195
+ ### Test Result Trends
196
+ - [Notable patterns in lab/test results]
197
+ - [Concerning values or changes]
198
 
199
+ ### Recommended Actions
200
+ - [Immediate follow-up needs]
201
+ - [Long-term management suggestions]
202
+ - [Referral recommendations if needed]
203
  """
204
  return prompt
205
 
206
+ def parse_excel_to_patient_prompt(file_path: str) -> str:
207
+ """Parse Excel file into a comprehensive patient analysis prompt"""
208
  try:
209
  xl = pd.ExcelFile(file_path)
210
  df = xl.parse(xl.sheet_names[0], header=0).fillna("")
211
+ patient_data = extract_patient_data(df)
212
+ prompt = generate_patient_prompt(patient_data)
 
213
  return prompt
214
  except Exception as e:
215
  raise ValueError(f"Error parsing Excel file: {str(e)}")
 
237
 
238
  def create_ui(agent):
239
  """Create Gradio UI interface"""
240
+ with gr.Blocks(theme=gr.themes.Soft(), title="Patient History Analyzer") as demo:
241
+ gr.Markdown("# 🏥 Comprehensive Patient History Analysis")
242
 
243
  with gr.Tabs():
244
  with gr.TabItem("Analysis"):
 
246
  # Left column - Inputs
247
  with gr.Column(scale=1):
248
  file_upload = gr.File(
249
+ label="Upload Patient Records (Excel)",
250
  file_types=[".xlsx"],
251
  file_count="single",
252
  interactive=True
 
258
  )
259
  with gr.Row():
260
  clear_btn = gr.Button("Clear", variant="secondary")
261
+ send_btn = gr.Button("Analyze Full History", variant="primary")
262
 
263
  # Right column - Outputs
264
  with gr.Column(scale=2):
265
  chatbot = gr.Chatbot(
266
+ label="Patient Analysis Results",
267
  height=600,
268
  bubble_full_width=False,
269
  show_copy_button=True,
 
278
  gr.Markdown("""
279
  ## How to Use This Tool
280
 
281
+ 1. **Upload Excel File**: Select the patient's medical records Excel file
282
  2. **Add Instructions** (Optional): Provide any specific analysis requests
283
+ 3. **Click Analyze**: The system will process ALL appointments together
284
  4. **Review Results**: Comprehensive analysis appears in the chat window
285
  5. **Download Report**: Get a complete text report of all findings
286
 
287
+ ### What This Analyzes
288
+ - Complete medical history across all appointments
289
+ - Treatment consistency across different doctors
290
+ - Medication changes and potential interactions
291
+ - Diagnostic patterns and potential oversights
292
+ - Test result trends over time
293
+ - Comprehensive care recommendations
294
  """)
295
 
296
  def analyze(message: str, chat_history: List[Tuple[str, str]], file) -> Tuple[List[Tuple[str, str]], str]:
297
+ """Main analysis function for patient history"""
298
  if not file:
299
  raise gr.Error("Please upload an Excel file first")
300
 
301
  try:
302
  # Initialize chat history
303
  new_history = chat_history + [(message, None)]
304
+ new_history.append((None, "⏳ Processing complete patient history..."))
305
  yield new_history, None
306
 
307
+ # Generate comprehensive prompt
308
+ prompt = parse_excel_to_patient_prompt(file.name)
309
 
310
  # Run analysis
311
  full_output = ""
 
313
  message=prompt,
314
  history=[],
315
  temperature=0.2,
316
+ max_new_tokens=2048,
317
  max_token=4096,
318
  call_agent=False,
319
  conversation=[],
 
334
  # Save report
335
  file_hash_value = file_hash(file.name)
336
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
337
+ report_path = os.path.join(report_dir, f"patient_{file_hash_value}_{timestamp}_report.md")
338
 
339
  with open(report_path, "w", encoding="utf-8") as f:
340
+ f.write("# Comprehensive Patient History Analysis\n\n")
341
  f.write(f"**Generated on**: {timestamp}\n\n")
342
  f.write(f"**Source file**: {file.name}\n\n")
343
  f.write(full_output)