Ali2206 commited on
Commit
d16299c
·
verified ·
1 Parent(s): 70e5ae6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +320 -292
app.py CHANGED
@@ -1,311 +1,262 @@
1
  import sys
2
  import os
3
  import pandas as pd
 
4
  import gradio as gr
5
- import re
6
  import hashlib
7
  import shutil
 
8
  from datetime import datetime
 
9
  from collections import defaultdict
10
- from typing import List, Dict, Tuple
11
 
12
- # Configuration
13
- WORKING_DIR = os.getcwd()
14
- REPORT_DIR = os.path.join(WORKING_DIR, "reports")
15
- os.makedirs(REPORT_DIR, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
16
 
17
- # Model configuration
18
- MODEL_CACHE_DIR = os.path.join(WORKING_DIR, "model_cache")
19
- os.makedirs(MODEL_CACHE_DIR, exist_ok=True)
20
- os.environ["HF_HOME"] = MODEL_CACHE_DIR
21
- os.environ["TRANSFORMERS_CACHE"] = MODEL_CACHE_DIR
22
 
23
- # Import TxAgent after setting up environment
24
- sys.path.append(os.path.join(WORKING_DIR, "src"))
25
  from txagent.txagent import TxAgent
26
 
27
- class PatientHistoryAnalyzer:
28
- def __init__(self):
29
- self.max_token_length = 2000
30
- self.max_text_length = 500
31
- self.agent = self._initialize_agent()
32
-
33
- def _initialize_agent(self):
34
- """Initialize the TxAgent with proper configuration"""
35
- tool_path = os.path.join(WORKING_DIR, "data", "new_tool.json")
36
- if not os.path.exists(tool_path):
37
- raise FileNotFoundError(f"Tool file not found at {tool_path}")
38
-
39
- return TxAgent(
40
- model_name="mims-harvard/TxAgent-T1-Llama-3.1-8B",
41
- rag_model_name="mims-harvard/ToolRAG-T1-GTE-Qwen2-1.5B",
42
- tool_files_dict={"new_tool": tool_path},
43
- force_finish=True,
44
- enable_checker=True,
45
- step_rag_num=4,
46
- seed=100,
47
- additional_default_tools=[],
48
- )
49
 
50
- def clean_text(self, text: str) -> str:
51
- """Clean and normalize text fields"""
52
- if not isinstance(text, str):
53
- text = str(text)
54
- text = re.sub(r'\s+', ' ', text).strip()
55
- return text[:self.max_text_length]
56
-
57
- def process_excel(self, file_path: str) -> Dict[str, List]:
58
- """Process Excel file into structured patient data"""
59
- try:
60
- df = pd.read_excel(file_path)
61
- df = df.sort_values('Interview Date')
62
-
63
- data = {
64
- 'timeline': [],
65
- 'medications': defaultdict(list),
66
- 'diagnoses': defaultdict(list),
67
- 'tests': defaultdict(list),
68
- 'doctors': set(),
69
- 'all_entries': []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
71
 
72
- for _, row in df.iterrows():
73
- entry = {
74
- 'date': self.clean_text(row.get('Interview Date', '')),
75
- 'doctor': self.clean_text(row.get('Interviewer', '')),
76
- 'form': self.clean_text(row.get('Form Name', '')),
77
- 'item': self.clean_text(row.get('Form Item', '')),
78
- 'response': self.clean_text(row.get('Item Response', '')),
79
- 'notes': self.clean_text(row.get('Description', ''))
80
- }
81
-
82
- data['timeline'].append(entry)
83
- data['doctors'].add(entry['doctor'])
84
- data['all_entries'].append(entry)
85
-
86
- form_lower = entry['form'].lower()
87
- if 'medication' in form_lower or 'drug' in form_lower:
88
- data['medications'][entry['item']].append(entry)
89
- elif 'diagnosis' in form_lower:
90
- data['diagnoses'][entry['item']].append(entry)
91
- elif 'test' in form_lower or 'lab' in form_lower:
92
- data['tests'][entry['item']].append(entry)
93
 
94
- return data
95
-
96
- except Exception as e:
97
- raise ValueError(f"Error processing Excel file: {str(e)}")
 
 
 
 
 
 
98
 
99
- def generate_analysis_prompt(self, patient_data: Dict) -> List[Dict]:
100
- """Generate analysis prompts that respect token limits"""
101
- prompts = []
102
-
103
- # Current Status Prompt
104
- current_prompt = self._create_current_status_prompt(patient_data)
105
- prompts.append({
106
- 'type': 'current_status',
107
- 'content': current_prompt
108
- })
109
-
110
- # Historical Analysis Prompt
111
- if len(patient_data['all_entries']) > 10:
112
- history_prompt = self._create_historical_prompt(patient_data)
113
- prompts.append({
114
- 'type': 'historical',
115
- 'content': history_prompt
116
- })
117
-
118
- # Medication-Specific Prompt
119
- if len(patient_data['medications']) > 3:
120
- meds_prompt = self._create_medication_prompt(patient_data)
121
- prompts.append({
122
- 'type': 'medications',
123
- 'content': meds_prompt
124
- })
125
-
126
- return prompts
127
 
128
- def _create_current_status_prompt(self, data: Dict) -> str:
129
- """Create prompt for current patient status"""
130
- recent_entries = data['timeline'][-10:]
131
-
132
- prompt_lines = [
133
- "**Comprehensive Patient Status Analysis**",
134
- "Focus on RECENT appointments and CURRENT health status.",
135
- "Analyze for:",
136
- "- Medication consistency",
137
- "- Diagnostic agreement between providers",
138
- "- Recent concerning findings",
139
- "- Immediate follow-up needs",
140
- "",
141
- "**Recent Timeline (last 10 entries):**"
142
- ]
143
-
144
- for entry in recent_entries:
145
- prompt_lines.append(
146
- f"- {entry['date']}: {entry['form']} - {entry['item']} = {entry['response']} (by {entry['doctor']})"
147
- )
148
-
149
- prompt_lines.extend([
150
- "",
151
- "**Current Medications:**",
152
- *[f"- {med}: {entries[-1]['response']} (last updated {entries[-1]['date']})"
153
- for med, entries in data['medications'].items()],
154
- "",
155
- "**Active Diagnoses:**",
156
- *[f"- {diag}: {entries[-1]['response']} (last updated {entries[-1]['date']})"
157
- for diag, entries in data['diagnoses'].items()],
158
- "",
159
- "**Required Output Format:**",
160
- "### Summary of Current Status",
161
- "### Medication Review",
162
- "### Diagnostic Consistency",
163
- "### Urgent Concerns",
164
- "### Recommended Actions"
165
- ])
 
 
 
 
 
166
 
167
- return "\n".join(prompt_lines)
168
-
169
- def _create_historical_prompt(self, data: Dict) -> str:
170
- """Create prompt for historical analysis"""
171
- return "\n".join([
172
- "**Historical Patient Analysis**",
173
- "Focus on LONG-TERM PATTERNS and HISTORY.",
174
- "",
175
- "**Key Analysis Points:**",
176
- "- Treatment changes over time",
177
- "- Recurring symptoms/issues",
178
- "- Diagnostic evolution",
179
- "- Medication history",
180
- "",
181
- "**Historical Timeline (condensed):**",
182
- *[f"- {entry['date'][:7]}: {entry['form']} - {entry['response']}"
183
- for entry in data['all_entries'][:-10]],
184
- "",
185
- "**Required Output Format:**",
186
- "### Historical Patterns",
187
- "### Treatment Evolution",
188
- "### Chronic Issues",
189
- "### Long-term Recommendations"
190
- ])
191
-
192
- def _create_medication_prompt(self, data: Dict) -> str:
193
- """Create medication-specific prompt"""
194
- return "\n".join([
195
- "**Medication-Specific Analysis**",
196
- "Focus on MEDICATION HISTORY and POTENTIAL ISSUES.",
197
- "",
198
- "**Medication History:**",
199
- *[f"- {med}: " + ", ".join(
200
- f"{e['date']}: {e['response']} (by {e['doctor']})"
201
- for e in entries
202
- ) for med, entries in data['medications'].items()],
203
- "",
204
- "**Analysis Focus:**",
205
- "- Potential interactions",
206
- "- Dosage changes",
207
- "- Prescriber patterns",
208
- "- Adherence issues",
209
- "",
210
- "**Required Output Format:**",
211
- "### Medication Summary",
212
- "### Potential Issues",
213
- "### Prescriber Patterns",
214
- "### Recommendations"
215
- ])
216
-
217
- def _call_agent(self, prompt: str) -> str:
218
- """Call TxAgent with proper error handling"""
219
- try:
220
- response = ""
221
- for result in self.agent.run_gradio_chat(
222
- message=prompt,
223
- history=[],
224
- temperature=0.2,
225
- max_new_tokens=1024,
226
- max_token=2048,
227
- call_agent=False,
228
- conversation=[],
229
- ):
230
- if isinstance(result, list):
231
- for r in result:
232
- if hasattr(r, 'content') and r.content:
233
- response += r.content + "\n"
234
- elif isinstance(result, str):
235
- response += result + "\n"
236
 
237
- return response.strip()
238
- except Exception as e:
239
- return f"Error in model response: {str(e)}"
240
-
241
- def generate_report(self, analysis_results: List[str]) -> Tuple[str, str]:
242
- """Combine analysis results into final report"""
243
- report = [
244
- "# Comprehensive Patient History Analysis",
245
- f"**Generated on**: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
246
- ""
247
- ]
248
-
249
- for result in analysis_results:
250
- report.extend(["", "---", "", result])
251
-
252
- report.extend([
253
- "",
254
- "## Overall Clinical Summary",
255
- "This report combines analyses of:",
256
- "- Current health status",
257
- "- Historical patterns",
258
- "- Medication history",
259
- "",
260
- "**Key Takeaways:**",
261
- "[Generated summary of most critical findings would appear here]"
262
- ])
263
-
264
- full_report = "\n".join(report)
265
-
266
- # Save to file in working directory
267
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
268
- report_filename = f"patient_report_{timestamp}.md"
269
- report_path = os.path.join(REPORT_DIR, report_filename)
270
 
271
- with open(report_path, 'w') as f:
272
- f.write(full_report)
 
 
 
 
273
 
274
- return full_report, report_path
275
-
276
- def analyze(self, file_path: str) -> Tuple[str, str]:
277
- """Main analysis workflow"""
278
- try:
279
- patient_data = self.process_excel(file_path)
280
- prompts = self.generate_analysis_prompt(patient_data)
281
-
282
- # Call TxAgent for each prompt
283
- analysis_results = []
284
- for prompt in prompts:
285
- response = self._call_agent(prompt['content'])
286
- analysis_results.append(response)
287
-
288
- return self.generate_report(analysis_results)
289
-
290
- except Exception as e:
291
- return f"Error during analysis: {str(e)}", ""
292
 
293
- def create_interface():
294
- analyzer = PatientHistoryAnalyzer()
 
 
 
 
 
295
 
296
- with gr.Blocks(title="Patient History Analyzer", theme=gr.themes.Soft()) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  gr.Markdown("# 🏥 Comprehensive Patient History Analysis")
298
 
299
- with gr.Tabs():
300
  with gr.TabItem("Analysis"):
301
  with gr.Row():
302
  with gr.Column(scale=1):
303
- file_input = gr.File(
304
- label="Upload Patient Records (Excel)",
305
  file_types=[".xlsx"],
306
- type="filepath"
307
  )
308
- analyze_btn = gr.Button("Analyze Full History", variant="primary")
 
309
 
310
  with gr.Column(scale=2):
311
  output_display = gr.Markdown(
@@ -321,25 +272,96 @@ def create_interface():
321
  gr.Markdown("""
322
  ## How to Use This Tool
323
 
324
- 1. **Upload** your patient's Excel file
325
- 2. **Click Analyze** to process the history
326
- 3. **Review** the comprehensive analysis
327
- 4. **Download** the full report
328
 
329
- ### File Requirements
330
- Excel file must contain:
331
  - Booking Number
 
 
332
  - Form Name
333
- - Form Item
334
  - Item Response
335
- - Interview Date
336
- - Interviewer
337
  - Description
 
 
 
 
 
 
 
338
  """)
339
 
340
- analyze_btn.click(
341
- fn=analyzer.analyze,
342
- inputs=file_input,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  outputs=[output_display, report_download],
344
  api_name="analyze"
345
  )
@@ -348,13 +370,19 @@ def create_interface():
348
 
349
  if __name__ == "__main__":
350
  try:
351
- demo = create_interface()
352
- demo.launch(
 
 
 
 
 
353
  server_name="0.0.0.0",
354
  server_port=7860,
355
  show_error=True,
356
- allowed_paths=[WORKING_DIR, REPORT_DIR]
 
357
  )
358
  except Exception as e:
359
- print(f"Error launching application: {str(e)}")
360
  sys.exit(1)
 
1
  import sys
2
  import os
3
  import pandas as pd
4
+ import json
5
  import gradio as gr
6
+ from typing import List, Tuple, Dict, Any
7
  import hashlib
8
  import shutil
9
+ import re
10
  from datetime import datetime
11
+ import time
12
  from collections import defaultdict
 
13
 
14
+ # Configuration and setup
15
+ persistent_dir = "/data/hf_cache"
16
+ os.makedirs(persistent_dir, exist_ok=True)
17
+
18
+ model_cache_dir = os.path.join(persistent_dir, "txagent_models")
19
+ tool_cache_dir = os.path.join(persistent_dir, "tool_cache")
20
+ file_cache_dir = os.path.join(persistent_dir, "cache")
21
+ report_dir = os.path.join(persistent_dir, "reports")
22
+
23
+ for directory in [model_cache_dir, tool_cache_dir, file_cache_dir, report_dir]:
24
+ os.makedirs(directory, exist_ok=True)
25
+
26
+ os.environ["HF_HOME"] = model_cache_dir
27
+ os.environ["TRANSFORMERS_CACHE"] = model_cache_dir
28
 
29
+ current_dir = os.path.dirname(os.path.abspath(__file__))
30
+ src_path = os.path.abspath(os.path.join(current_dir, "src"))
31
+ sys.path.insert(0, src_path)
 
 
32
 
 
 
33
  from txagent.txagent import TxAgent
34
 
35
+ # Constants
36
+ MAX_TOKENS = 32768 # TxAgent's maximum token limit
37
+ CHUNK_SIZE = 3000 # Target chunk size to stay under token limit
38
+ MAX_NEW_TOKENS = 1024
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ def file_hash(path: str) -> str:
41
+ """Generate MD5 hash of file contents"""
42
+ with open(path, "rb") as f:
43
+ return hashlib.md5(f.read()).hexdigest()
44
+
45
+ def clean_response(text: str) -> str:
46
+ """Clean and normalize text output"""
47
+ try:
48
+ text = text.encode('utf-8', 'surrogatepass').decode('utf-8')
49
+ except UnicodeError:
50
+ text = text.encode('utf-8', 'replace').decode('utf-8')
51
+
52
+ text = re.sub(r"\[.*?\]|\bNone\b", "", text, flags=re.DOTALL)
53
+ text = re.sub(r"\n{3,}", "\n\n", text)
54
+ text = re.sub(r"[^\n#\-\*\w\s\.,:\(\)]+", "", text)
55
+ return text.strip()
56
+
57
+ def estimate_tokens(text: str) -> int:
58
+ """Approximate token count (1 token ~ 4 characters)"""
59
+ return len(text) // 4
60
+
61
+ def process_patient_data(df: pd.DataFrame) -> Dict[str, Any]:
62
+ """Process raw patient data into structured format"""
63
+ data = {
64
+ 'bookings': defaultdict(list),
65
+ 'medications': defaultdict(list),
66
+ 'diagnoses': defaultdict(list),
67
+ 'tests': defaultdict(list),
68
+ 'doctors': set(),
69
+ 'timeline': []
70
+ }
71
+
72
+ # Sort by date and group by booking
73
+ df = df.sort_values('Interview Date')
74
+ for booking, group in df.groupby('Booking Number'):
75
+ for _, row in group.iterrows():
76
+ entry = {
77
+ 'booking': booking,
78
+ 'date': str(row['Interview Date']),
79
+ 'doctor': str(row['Interviewer']),
80
+ 'form': str(row['Form Name']),
81
+ 'item': str(row['Form Item']),
82
+ 'response': str(row['Item Response']),
83
+ 'notes': str(row['Description'])
84
  }
85
 
86
+ data['bookings'][booking].append(entry)
87
+ data['timeline'].append(entry)
88
+ data['doctors'].add(entry['doctor'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
+ # Categorize entries
91
+ form_lower = entry['form'].lower()
92
+ if 'medication' in form_lower or 'drug' in form_lower:
93
+ data['medications'][entry['item']].append(entry)
94
+ elif 'diagnosis' in form_lower:
95
+ data['diagnoses'][entry['item']].append(entry)
96
+ elif 'test' in form_lower or 'lab' in form_lower:
97
+ data['tests'][entry['item']].append(entry)
98
+
99
+ return data
100
 
101
+ def generate_analysis_prompt(patient_data: Dict[str, Any], booking: str) -> str:
102
+ """Generate focused analysis prompt for a booking"""
103
+ booking_entries = patient_data['bookings'][booking]
104
+
105
+ # Build timeline string
106
+ timeline = "\n".join(
107
+ f"- {entry['date']}: {entry['form']} - {entry['item']} = {entry['response']} (by {entry['doctor']})"
108
+ for entry in booking_entries
109
+ )
110
+
111
+ # Get current medications
112
+ current_meds = []
113
+ for med, entries in patient_data['medications'].items():
114
+ if any(e['booking'] == booking for e in entries):
115
+ latest = max((e for e in entries if e['booking'] == booking), key=lambda x: x['date'])
116
+ current_meds.append(f"- {med}: {latest['response']} (as of {latest['date']})")
117
+
118
+ # Get current diagnoses
119
+ current_diags = []
120
+ for diag, entries in patient_data['diagnoses'].items():
121
+ if any(e['booking'] == booking for e in entries):
122
+ latest = max((e for e in entries if e['booking'] == booking), key=lambda x: x['date'])
123
+ current_diags.append(f"- {diag}: {latest['response']} (as of {latest['date']})")
124
+
125
+ prompt = f"""
126
+ **Comprehensive Patient Analysis - Booking {booking}**
 
 
127
 
128
+ **Patient Timeline:**
129
+ {timeline}
130
+
131
+ **Current Medications:**
132
+ {'\n'.join(current_meds) if current_meds else "None recorded"}
133
+
134
+ **Current Diagnoses:**
135
+ {'\n'.join(current_diags) if current_diags else "None recorded"}
136
+
137
+ **Analysis Instructions:**
138
+ 1. Review the patient's complete history across all visits
139
+ 2. Identify any potential missed diagnoses based on symptoms and test results
140
+ 3. Check for medication conflicts or inappropriate prescriptions
141
+ 4. Note any incomplete assessments or missing tests
142
+ 5. Flag any urgent follow-up needs
143
+ 6. Compare findings across different doctors for consistency
144
+
145
+ **Required Output Format:**
146
+ ### Missed Diagnoses
147
+ [Potential diagnoses that were not identified]
148
+
149
+ ### Medication Issues
150
+ [Conflicts, side effects, inappropriate prescriptions]
151
+
152
+ ### Assessment Gaps
153
+ [Missing tests or incomplete evaluations]
154
+
155
+ ### Follow-up Recommendations
156
+ [Urgent and non-urgent follow-up needs]
157
+
158
+ ### Doctor Consistency
159
+ [Discrepancies between different providers]
160
+ """
161
+ return prompt
162
+
163
+ def chunk_patient_data(patient_data: Dict[str, Any]) -> List[Dict[str, Any]]:
164
+ """Split patient data into manageable chunks"""
165
+ chunks = []
166
+ current_chunk = defaultdict(list)
167
+ current_size = 0
168
+
169
+ for booking, entries in patient_data['bookings'].items():
170
+ booking_size = sum(estimate_tokens(str(e)) for e in entries)
171
 
172
+ if current_size + booking_size > CHUNK_SIZE and current_chunk:
173
+ chunks.append(dict(current_chunk))
174
+ current_chunk = defaultdict(list)
175
+ current_size = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
+ current_chunk['bookings'][booking] = entries
178
+ current_size += booking_size
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
+ # Add related data
181
+ for med, med_entries in patient_data['medications'].items():
182
+ if any(e['booking'] == booking for e in med_entries):
183
+ current_chunk['medications'][med].extend(
184
+ e for e in med_entries if e['booking'] == booking
185
+ )
186
 
187
+ for diag, diag_entries in patient_data['diagnoses'].items():
188
+ if any(e['booking'] == booking for e in diag_entries):
189
+ current_chunk['diagnoses'][diag].extend(
190
+ e for e in diag_entries if e['booking'] == booking
191
+ )
192
+
193
+ if current_chunk:
194
+ chunks.append(dict(current_chunk))
195
+
196
+ return chunks
 
 
 
 
 
 
 
 
197
 
198
+ def init_agent():
199
+ """Initialize TxAgent with proper configuration"""
200
+ default_tool_path = os.path.abspath("data/new_tool.json")
201
+ target_tool_path = os.path.join(tool_cache_dir, "new_tool.json")
202
+
203
+ if not os.path.exists(target_tool_path):
204
+ shutil.copy(default_tool_path, target_tool_path)
205
 
206
+ agent = TxAgent(
207
+ model_name="mims-harvard/TxAgent-T1-Llama-3.1-8B",
208
+ rag_model_name="mims-harvard/ToolRAG-T1-GTE-Qwen2-1.5B",
209
+ tool_files_dict={"new_tool": target_tool_path},
210
+ force_finish=True,
211
+ enable_checker=True,
212
+ step_rag_num=4,
213
+ seed=100,
214
+ additional_default_tools=[],
215
+ )
216
+ agent.init_model()
217
+ return agent
218
+
219
+ def analyze_with_agent(agent, prompt: str) -> str:
220
+ """Run analysis with proper error handling"""
221
+ try:
222
+ response = ""
223
+ for result in agent.run_gradio_chat(
224
+ message=prompt,
225
+ history=[],
226
+ temperature=0.2,
227
+ max_new_tokens=MAX_NEW_TOKENS,
228
+ max_token=MAX_TOKENS,
229
+ call_agent=False,
230
+ conversation=[],
231
+ ):
232
+ if isinstance(result, list):
233
+ for r in result:
234
+ if hasattr(r, 'content') and r.content:
235
+ response += clean_response(r.content) + "\n"
236
+ elif isinstance(result, str):
237
+ response += clean_response(result) + "\n"
238
+ elif hasattr(result, 'content'):
239
+ response += clean_response(result.content) + "\n"
240
+
241
+ return response.strip()
242
+ except Exception as e:
243
+ return f"Error in analysis: {str(e)}"
244
+
245
+ def create_ui(agent):
246
+ with gr.Blocks(theme=gr.themes.Soft(), title="Patient History Analyzer") as demo:
247
  gr.Markdown("# 🏥 Comprehensive Patient History Analysis")
248
 
249
+ -With gr.Tabs():
250
  with gr.TabItem("Analysis"):
251
  with gr.Row():
252
  with gr.Column(scale=1):
253
+ file_upload = gr.File(
254
+ label="Upload Patient Excel File",
255
  file_types=[".xlsx"],
256
+ file_count="single"
257
  )
258
+ analysis_btn = gr.Button("Analyze Patient History", variant="primary")
259
+ status = gr.Markdown("Ready for analysis")
260
 
261
  with gr.Column(scale=2):
262
  output_display = gr.Markdown(
 
272
  gr.Markdown("""
273
  ## How to Use This Tool
274
 
275
+ 1. **Upload Excel File**: Patient history Excel file
276
+ 2. **Click Analyze**: System will process all bookings
277
+ 3. **Review Results**: Comprehensive analysis appears
278
+ 4. **Download Report**: Full report with all findings
279
 
280
+ ### Excel Requirements
281
+ Must contain these columns:
282
  - Booking Number
283
+ - Interview Date
284
+ - Interviewer (Doctor)
285
  - Form Name
286
+ - Form Item
287
  - Item Response
 
 
288
  - Description
289
+
290
+ ### Analysis Includes:
291
+ - Missed diagnoses across visits
292
+ - Medication conflicts over time
293
+ - Incomplete assessments
294
+ - Doctor consistency checks
295
+ - Follow-up recommendations
296
  """)
297
 
298
+ def analyze_patient(file) -> Tuple[str, str]:
299
+ if not file:
300
+ raise gr.Error("Please upload an Excel file first")
301
+
302
+ try:
303
+ # Process Excel file
304
+ df = pd.read_excel(file.name)
305
+ patient_data = process_patient_data(df)
306
+
307
+ # Generate and process prompts
308
+ full_report = []
309
+ bookings_processed = 0
310
+
311
+ for booking in patient_data['bookings']:
312
+ prompt = generate_analysis_prompt(patient_data, booking)
313
+ response = analyze_with_agent(agent, prompt)
314
+
315
+ if "Error in analysis" not in response:
316
+ bookings_processed += 1
317
+ full_report.append(f"## Booking {booking}\n{response}\n")
318
+
319
+ yield "\n".join(full_report), None
320
+ time.sleep(0.1) # Prevent UI freezing
321
+
322
+ # Generate overall summary
323
+ if bookings_processed > 1:
324
+ summary_prompt = f"""
325
+ **Comprehensive Patient Summary**
326
+
327
+ Analyze all bookings ({bookings_processed} total) to identify:
328
+ 1. Patterns across the entire treatment history
329
+ 2. Chronic issues that may have been missed
330
+ 3. Medication changes over time
331
+ 4. Doctor consistency across visits
332
+ 5. Long-term recommendations
333
+
334
+ **Required Format:**
335
+ ### Chronic Health Patterns
336
+ [Recurring issues over time]
337
+
338
+ ascopy
339
+
340
+ ### Treatment Evolution
341
+ [How treatment has changed]
342
+
343
+ ### Long-term Concerns
344
+ [Issues needing ongoing attention]
345
+
346
+ ### Comprehensive Recommendations
347
+ [Overall care plan]
348
+ """
349
+ summary = analyze_with_agent(agent, summary_prompt)
350
+ full_report.append(f"## Overall Patient Summary\n{summary}\n")
351
+
352
+ # Save report
353
+ report_path = os.path.join(report_dir, f"patient_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md")
354
+ with open(report_path, 'w', encoding='utf-8') as f:
355
+ f.write("\n".join(full_report))
356
+
357
+ yield "\n".join(full_report), report_path
358
+
359
+ except Exception as e:
360
+ raise gr.Error(f"Analysis failed: {str(e)}")
361
+
362
+ analysis_btn.click(
363
+ analyze_patient,
364
+ inputs=file_upload,
365
  outputs=[output_display, report_download],
366
  api_name="analyze"
367
  )
 
370
 
371
  if __name__ == "__main__":
372
  try:
373
+ agent = init_agent()
374
+ demo = create_ui(agent)
375
+
376
+ demo.queue(
377
+ api_open=False,
378
+ max_size=20
379
+ ).launch(
380
  server_name="0.0.0.0",
381
  server_port=7860,
382
  show_error=True,
383
+ allowed_paths=[report_dir],
384
+ share=False
385
  )
386
  except Exception as e:
387
+ print(f"Failed to launch application: {str(e)}")
388
  sys.exit(1)