Ali2206 commited on
Commit
41eb6bd
·
verified ·
1 Parent(s): 3deb36c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -397
app.py CHANGED
@@ -4,27 +4,13 @@ import pandas as pd
4
  import pdfplumber
5
  import json
6
  import gradio as gr
7
- from typing import List, Dict, Any
8
  from concurrent.futures import ThreadPoolExecutor, as_completed
9
  import hashlib
10
  import shutil
11
  import re
12
  import psutil
13
  import subprocess
14
- import logging
15
- import traceback
16
- from datetime import datetime
17
-
18
- # Configure logging
19
- logging.basicConfig(
20
- level=logging.INFO,
21
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
22
- handlers=[
23
- logging.StreamHandler(),
24
- logging.FileHandler('clinical_oversight.log')
25
- ]
26
- )
27
- logger = logging.getLogger(__name__)
28
 
29
  # Persistent directory
30
  persistent_dir = "/data/hf_cache"
@@ -55,429 +41,169 @@ MEDICAL_KEYWORDS = {'diagnosis', 'assessment', 'plan', 'results', 'medications',
55
  'allergies', 'summary', 'impression', 'findings', 'recommendations'}
56
 
57
  def sanitize_utf8(text: str) -> str:
58
- """Ensure text is UTF-8 encoded and clean."""
59
- try:
60
- return text.encode("utf-8", "ignore").decode("utf-8")
61
- except Exception as e:
62
- logger.error(f"UTF-8 sanitization failed: {str(e)}")
63
- return ""
64
 
65
  def file_hash(path: str) -> str:
66
- """Generate MD5 hash of file content."""
67
- try:
68
- with open(path, "rb") as f:
69
- return hashlib.md5(f.read()).hexdigest()
70
- except Exception as e:
71
- logger.error(f"File hash generation failed for {path}: {str(e)}")
72
- return ""
73
 
74
  def extract_priority_pages(file_path: str, max_pages: int = 20) -> str:
75
- """Extract pages from PDF with priority given to pages containing medical keywords."""
76
  try:
77
  text_chunks = []
78
- logger.info(f"Extracting pages from {file_path}")
79
-
80
  with pdfplumber.open(file_path) as pdf:
81
- # Always extract first 3 pages
82
  for i, page in enumerate(pdf.pages[:3]):
83
- try:
84
- text = page.extract_text() or ""
85
- text_chunks.append(f"=== Page {i+1} ===\n{text.strip()}")
86
- except Exception as page_error:
87
- logger.warning(f"Error processing page {i+1}: {str(page_error)}")
88
- text_chunks.append(f"=== Page {i+1} ===\n[Error extracting content]")
89
-
90
- # Extract remaining pages that contain medical keywords
91
  for i, page in enumerate(pdf.pages[3:max_pages], start=4):
92
- try:
93
- page_text = page.extract_text() or ""
94
- if any(re.search(rf'\b{kw}\b', page_text.lower()) for kw in MEDICAL_KEYWORDS):
95
- text_chunks.append(f"=== Page {i} ===\n{page_text.strip()}")
96
- except Exception as page_error:
97
- logger.warning(f"Error processing page {i}: {str(page_error)}")
98
-
99
  return "\n\n".join(text_chunks)
100
  except Exception as e:
101
- logger.error(f"PDF processing error for {file_path}: {str(e)}")
102
  return f"PDF processing error: {str(e)}"
103
 
104
  def convert_file_to_json(file_path: str, file_type: str) -> str:
105
- """Convert different file types to JSON format with caching."""
106
  try:
107
  h = file_hash(file_path)
108
- if not h:
109
- return json.dumps({"error": "Could not generate file hash"})
110
-
111
  cache_path = os.path.join(file_cache_dir, f"{h}.json")
112
-
113
- # Check cache first
114
  if os.path.exists(cache_path):
 
 
 
 
 
 
 
 
 
 
 
 
115
  try:
116
- with open(cache_path, "r", encoding="utf-8") as f:
117
- return f.read()
118
- except Exception as cache_error:
119
- logger.error(f"Cache read error for {file_path}: {str(cache_error)}")
120
-
121
- result = {}
122
- try:
123
- if file_type == "pdf":
124
- text = extract_priority_pages(file_path)
125
- result = {
126
- "filename": os.path.basename(file_path),
127
- "content": text,
128
- "status": "initial",
129
- "file_type": "pdf"
130
- }
131
- elif file_type == "csv":
132
- df = pd.read_csv(
133
- file_path,
134
- encoding_errors="replace",
135
- header=None,
136
- dtype=str,
137
- skip_blank_lines=False,
138
- on_bad_lines="skip"
139
- )
140
- content = df.fillna("").astype(str).values.tolist()
141
- result = {
142
- "filename": os.path.basename(file_path),
143
- "rows": content,
144
- "file_type": "csv"
145
- }
146
- elif file_type in ["xls", "xlsx"]:
147
- try:
148
- df = pd.read_excel(file_path, engine="openpyxl", header=None, dtype=str)
149
- except Exception:
150
- try:
151
- df = pd.read_excel(file_path, engine="xlrd", header=None, dtype=str)
152
- except Exception as excel_error:
153
- logger.error(f"Excel read error for {file_path}: {str(excel_error)}")
154
- raise
155
- content = df.fillna("").astype(str).values.tolist()
156
- result = {
157
- "filename": os.path.basename(file_path),
158
- "rows": content,
159
- "file_type": "excel"
160
- }
161
- else:
162
- result = {"error": f"Unsupported file type: {file_type}"}
163
-
164
- json_result = json.dumps(result)
165
-
166
- # Save to cache
167
- try:
168
- with open(cache_path, "w", encoding="utf-8") as f:
169
- f.write(json_result)
170
- except Exception as cache_write_error:
171
- logger.error(f"Cache write error for {file_path}: {str(cache_write_error)}")
172
-
173
- return json_result
174
- except Exception as processing_error:
175
- logger.error(f"Error processing {file_path}: {str(processing_error)}")
176
- return json.dumps({"error": f"Error processing {os.path.basename(file_path)}: {str(processing_error)}"})
177
  except Exception as e:
178
- logger.error(f"Unexpected error in convert_file_to_json: {str(e)}")
179
- return json.dumps({"error": f"Unexpected error processing file: {str(e)}"})
180
 
181
  def log_system_usage(tag=""):
182
- """Log system resource usage including CPU, RAM, and GPU."""
183
  try:
184
  cpu = psutil.cpu_percent(interval=1)
185
  mem = psutil.virtual_memory()
186
- logger.info(f"[{tag}] CPU: {cpu}% | RAM: {mem.used // (1024**2)}MB / {mem.total // (1024**2)}MB")
187
-
188
- try:
189
- result = subprocess.run(
190
- ["nvidia-smi", "--query-gpu=memory.used,memory.total,utilization.gpu", "--format=csv,nounits,noheader"],
191
- capture_output=True, text=True
192
- )
193
- if result.returncode == 0:
194
- used, total, util = result.stdout.strip().split(", ")
195
- logger.info(f"[{tag}] GPU: {used}MB / {total}MB | Utilization: {util}%")
196
- except Exception as gpu_error:
197
- logger.warning(f"[{tag}] GPU monitor failed: {gpu_error}")
198
  except Exception as e:
199
- logger.error(f"System usage logging failed: {str(e)}")
200
 
201
  def init_agent():
202
- """Initialize the TxAgent with proper configuration."""
203
- logger.info("Initializing model...")
204
  log_system_usage("Before Load")
205
-
206
  default_tool_path = os.path.abspath("data/new_tool.json")
207
  target_tool_path = os.path.join(tool_cache_dir, "new_tool.json")
208
-
209
- try:
210
- if not os.path.exists(target_tool_path):
211
- shutil.copy(default_tool_path, target_tool_path)
212
- logger.info("Copied default tool configuration")
213
- except Exception as e:
214
- logger.error(f"Tool configuration copy failed: {str(e)}")
215
- raise
216
-
217
- try:
218
- agent = TxAgent(
219
- model_name="mims-harvard/TxAgent-T1-Llama-3.1-8B",
220
- rag_model_name="mims-harvard/ToolRAG-T1-GTE-Qwen2-1.5B",
221
- tool_files_dict={"new_tool": target_tool_path},
222
- force_finish=True,
223
- enable_checker=True,
224
- step_rag_num=8,
225
- seed=100,
226
- additional_default_tools=[],
227
- )
228
- agent.init_model()
229
- log_system_usage("After Load")
230
- logger.info("Agent initialization successful")
231
- return agent
232
- except Exception as e:
233
- logger.error(f"Agent initialization failed: {str(e)}")
234
- raise
235
-
236
- def save_report(content: str, file_hash_value: str = "") -> str:
237
- """Save analysis report to file and return path."""
238
- try:
239
- if not file_hash_value:
240
- file_hash_value = hashlib.md5(content.encode()).hexdigest()
241
-
242
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
243
- report_filename = f"report_{timestamp}_{file_hash_value[:8]}.txt"
244
- report_path = os.path.join(report_dir, report_filename)
245
-
246
- with open(report_path, "w", encoding="utf-8") as f:
247
- f.write(content)
248
-
249
- logger.info(f"Report saved to {report_path}")
250
- return report_path
251
- except Exception as e:
252
- logger.error(f"Failed to save report: {str(e)}")
253
- return ""
254
-
255
- def clean_response(content: str) -> str:
256
- """Clean up model response by removing tool call artifacts."""
257
- if not content:
258
- return "⚠️ No content generated."
259
-
260
- try:
261
- # Remove tool call artifacts
262
- cleaned = re.sub(r"\[TOOL_CALLS\].*?(?=(\[|\Z))", "", content, flags=re.DOTALL).strip()
263
- # Remove excessive whitespace
264
- cleaned = re.sub(r"\n{3,}", "\n\n", cleaned)
265
- return cleaned or "⚠️ Empty response after cleaning."
266
- except Exception as e:
267
- logger.error(f"Response cleaning failed: {str(e)}")
268
- return content
269
-
270
- def process_model_response(chunk: Any, history: List[Dict[str, str]]) -> List[Dict[str, str]]:
271
- """Process model response chunk and update chat history."""
272
- try:
273
- if chunk is None:
274
- return history
275
-
276
- if isinstance(chunk, list) and all(hasattr(m, 'role') and hasattr(m, 'content') for m in chunk):
277
- for m in chunk:
278
- cleaned_content = clean_response(m.content)
279
- history.append({"role": m.role, "content": cleaned_content})
280
- elif isinstance(chunk, str):
281
- cleaned_chunk = clean_response(chunk)
282
- if history and history[-1]["role"] == "assistant":
283
- history[-1]["content"] += cleaned_chunk
284
- else:
285
- history.append({"role": "assistant", "content": cleaned_chunk})
286
- else:
287
- logger.warning(f"Unexpected response type: {type(chunk)}")
288
-
289
- return history
290
- except Exception as e:
291
- logger.error(f"Error processing model response: {str(e)}")
292
- history.append({"role": "assistant", "content": f"⚠️ Error processing response: {str(e)}"})
293
- return history
294
 
295
- def analyze(message: str, history: list, files: list):
296
- """Main analysis function that processes files and generates responses."""
297
- try:
298
- # Initial response
299
- new_history = history.copy()
300
- new_history.append({"role": "user", "content": message})
301
- new_history.append({"role": "assistant", "content": "⏳ Analyzing records for potential oversights..."})
302
- yield new_history, None
303
-
304
- # Process files
305
- extracted = ""
306
- file_hash_value = ""
307
- if files:
308
- logger.info(f"Processing {len(files)} files...")
309
- with ThreadPoolExecutor(max_workers=4) as executor:
310
- futures = []
311
- for f in files:
312
- try:
313
- file_type = f.name.split(".")[-1].lower()
314
- futures.append(executor.submit(convert_file_to_json, f.name, file_type))
315
- except Exception as e:
316
- logger.error(f"Error submitting file {f.name} for processing: {str(e)}")
317
- new_history.append({"role": "system", "content": f"⚠️ Error processing {f.name}: {str(e)}"})
318
-
319
- results = []
320
- for f in as_completed(futures):
321
- try:
322
- results.append(sanitize_utf8(f.result()))
323
- except Exception as e:
324
- logger.error(f"Error getting file processing result: {str(e)}")
325
- results.append(json.dumps({"error": "File processing failed"}))
326
-
327
- extracted = "\n".join(results)
328
- try:
329
- file_hash_value = file_hash(files[0].name) if files else ""
330
- except Exception as e:
331
- logger.error(f"Error generating file hash: {str(e)}")
332
- file_hash_value = ""
333
-
334
- # Prepare prompt
335
- prompt = f"""Review these medical records and identify EXACTLY what might have been missed:
336
  1. List potential missed diagnoses
337
  2. Flag any medication conflicts
338
  3. Note incomplete assessments
339
  4. Highlight abnormal results needing follow-up
340
-
341
  Medical Records:
342
  {extracted[:12000]}
343
-
344
  ### Potential Oversights:
345
  """
346
- logger.info(f"Prompt length: {len(prompt)} characters")
347
-
348
- # Initialize agent response
349
- agent = init_agent()
350
- response_content = ""
351
- report_path = ""
352
-
353
- # Process agent response
354
- for chunk in agent.run_gradio_chat(
355
- message=prompt,
356
- history=[],
357
- temperature=0.2,
358
- max_new_tokens=2048,
359
- max_token=4096,
360
- call_agent=False,
361
- conversation=[],
362
- ):
363
- try:
364
- new_history = process_model_response(chunk, new_history)
365
- if isinstance(chunk, str):
366
- response_content += clean_response(chunk)
367
-
368
- yield new_history, None
369
- except Exception as chunk_error:
370
- logger.error(f"Error processing chunk: {str(chunk_error)}")
371
- new_history.append({"role": "assistant", "content": f"⚠️ Error processing response chunk: {str(chunk_error)}"})
372
- yield new_history, None
373
-
374
- # Save final report
375
- if response_content:
376
- try:
377
- report_path = save_report(response_content, file_hash_value)
378
- except Exception as report_error:
379
- logger.error(f"Error saving report: {str(report_error)}")
380
- new_history.append({"role": "system", "content": "⚠️ Failed to save full report"})
381
-
382
- yield new_history, report_path if report_path and os.path.exists(report_path) else None
383
-
384
- except Exception as e:
385
- logger.error(f"Analysis error: {str(e)}\n{traceback.format_exc()}")
386
- error_history = history.copy()
387
- error_history.append({"role": "assistant", "content": f"❌ Critical error occurred: {str(e)}"})
388
- yield error_history, None
389
 
390
- def create_ui(agent):
391
- """Create Gradio UI interface."""
392
- with gr.Blocks(theme=gr.themes.Soft(), title="Clinical Oversight Assistant") as demo:
393
- gr.Markdown("<h1 style='text-align: center;'>🩺 Clinical Oversight Assistant</h1>")
394
- gr.Markdown("""
395
- <div style='text-align: center; margin-bottom: 20px;'>
396
- Upload medical records and ask about potential oversights or missed diagnoses.
397
- </div>
398
- """)
399
-
400
- with gr.Row():
401
- with gr.Column(scale=2):
402
- chatbot = gr.Chatbot(
403
- label="Analysis Conversation",
404
- height=600,
405
- bubble_full_width=False,
406
- show_copy_button=True
407
- )
408
- msg_input = gr.Textbox(
409
- placeholder="Ask about potential oversights...",
410
- show_label=False,
411
- container=False
412
- )
413
- with gr.Row():
414
- send_btn = gr.Button("Analyze", variant="primary")
415
- clear_btn = gr.Button("Clear")
416
-
417
- with gr.Column(scale=1):
418
- file_upload = gr.File(
419
- file_types=[".pdf", ".csv", ".xls", ".xlsx"],
420
- file_count="multiple",
421
- label="Upload Medical Records"
422
- )
423
- download_output = gr.File(
424
- label="Download Full Report",
425
- interactive=False
426
- )
427
- gr.Markdown("""
428
- <div style='margin-top: 20px; font-size: 0.9em; color: #666;'>
429
- <b>Note:</b> The system analyzes PDFs, CSVs, and Excel files for potential clinical oversights.
430
- </div>
431
- """)
432
-
433
- # Event handlers
434
- send_btn.click(
435
- analyze,
436
- inputs=[msg_input, gr.State([]), file_upload],
437
- outputs=[chatbot, download_output]
438
- )
439
-
440
- msg_input.submit(
441
- analyze,
442
- inputs=[msg_input, gr.State([]), file_upload],
443
- outputs=[chatbot, download_output]
444
- )
445
-
446
- clear_btn.click(
447
- lambda: ([], None),
448
- inputs=[],
449
- outputs=[chatbot, download_output]
450
- )
451
-
452
- # Add some examples
453
- gr.Examples(
454
- examples=[
455
- ["What potential diagnoses might have been missed in these records?"],
456
- ["Are there any medication conflicts I should be aware of?"],
457
- ["What abnormal results need follow-up in these reports?"]
458
- ],
459
- inputs=msg_input,
460
- label="Example Questions"
461
- )
462
-
463
  return demo
464
 
465
  if __name__ == "__main__":
466
- try:
467
- logger.info("🚀 Launching Clinical Oversight Assistant...")
468
- agent = init_agent()
469
- demo = create_ui(agent)
470
-
471
- demo.queue(
472
- api_open=False,
473
- concurrency_count=2
474
- ).launch(
475
- server_name="0.0.0.0",
476
- server_port=7860,
477
- show_error=True,
478
- allowed_paths=[report_dir],
479
- share=False
480
- )
481
- except Exception as e:
482
- logger.error(f"Application failed to start: {str(e)}\n{traceback.format_exc()}")
483
- raise
 
4
  import pdfplumber
5
  import json
6
  import gradio as gr
7
+ from typing import List
8
  from concurrent.futures import ThreadPoolExecutor, as_completed
9
  import hashlib
10
  import shutil
11
  import re
12
  import psutil
13
  import subprocess
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  # Persistent directory
16
  persistent_dir = "/data/hf_cache"
 
41
  'allergies', 'summary', 'impression', 'findings', 'recommendations'}
42
 
43
  def sanitize_utf8(text: str) -> str:
44
+ return text.encode("utf-8", "ignore").decode("utf-8")
 
 
 
 
 
45
 
46
  def file_hash(path: str) -> str:
47
+ with open(path, "rb") as f:
48
+ return hashlib.md5(f.read()).hexdigest()
 
 
 
 
 
49
 
50
  def extract_priority_pages(file_path: str, max_pages: int = 20) -> str:
 
51
  try:
52
  text_chunks = []
 
 
53
  with pdfplumber.open(file_path) as pdf:
 
54
  for i, page in enumerate(pdf.pages[:3]):
55
+ text = page.extract_text() or ""
56
+ text_chunks.append(f"=== Page {i+1} ===\n{text.strip()}")
 
 
 
 
 
 
57
  for i, page in enumerate(pdf.pages[3:max_pages], start=4):
58
+ page_text = page.extract_text() or ""
59
+ if any(re.search(rf'\\b{kw}\\b', page_text.lower()) for kw in MEDICAL_KEYWORDS):
60
+ text_chunks.append(f"=== Page {i} ===\n{page_text.strip()}")
 
 
 
 
61
  return "\n\n".join(text_chunks)
62
  except Exception as e:
 
63
  return f"PDF processing error: {str(e)}"
64
 
65
  def convert_file_to_json(file_path: str, file_type: str) -> str:
 
66
  try:
67
  h = file_hash(file_path)
 
 
 
68
  cache_path = os.path.join(file_cache_dir, f"{h}.json")
 
 
69
  if os.path.exists(cache_path):
70
+ with open(cache_path, "r", encoding="utf-8") as f:
71
+ return f.read()
72
+
73
+ if file_type == "pdf":
74
+ text = extract_priority_pages(file_path)
75
+ result = json.dumps({"filename": os.path.basename(file_path), "content": text, "status": "initial"})
76
+ elif file_type == "csv":
77
+ df = pd.read_csv(file_path, encoding_errors="replace", header=None, dtype=str,
78
+ skip_blank_lines=False, on_bad_lines="skip")
79
+ content = df.fillna("").astype(str).values.tolist()
80
+ result = json.dumps({"filename": os.path.basename(file_path), "rows": content})
81
+ elif file_type in ["xls", "xlsx"]:
82
  try:
83
+ df = pd.read_excel(file_path, engine="openpyxl", header=None, dtype=str)
84
+ except Exception:
85
+ df = pd.read_excel(file_path, engine="xlrd", header=None, dtype=str)
86
+ content = df.fillna("").astype(str).values.tolist()
87
+ result = json.dumps({"filename": os.path.basename(file_path), "rows": content})
88
+ else:
89
+ result = json.dumps({"error": f"Unsupported file type: {file_type}"})
90
+ with open(cache_path, "w", encoding="utf-8") as f:
91
+ f.write(result)
92
+ return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  except Exception as e:
94
+ return json.dumps({"error": f"Error processing {os.path.basename(file_path)}: {str(e)}"})
 
95
 
96
  def log_system_usage(tag=""):
 
97
  try:
98
  cpu = psutil.cpu_percent(interval=1)
99
  mem = psutil.virtual_memory()
100
+ print(f"[{tag}] CPU: {cpu}% | RAM: {mem.used // (1024**2)}MB / {mem.total // (1024**2)}MB")
101
+ result = subprocess.run(
102
+ ["nvidia-smi", "--query-gpu=memory.used,memory.total,utilization.gpu", "--format=csv,nounits,noheader"],
103
+ capture_output=True, text=True
104
+ )
105
+ if result.returncode == 0:
106
+ used, total, util = result.stdout.strip().split(", ")
107
+ print(f"[{tag}] GPU: {used}MB / {total}MB | Utilization: {util}%")
 
 
 
 
108
  except Exception as e:
109
+ print(f"[{tag}] GPU/CPU monitor failed: {e}")
110
 
111
  def init_agent():
112
+ print("🔁 Initializing model...")
 
113
  log_system_usage("Before Load")
 
114
  default_tool_path = os.path.abspath("data/new_tool.json")
115
  target_tool_path = os.path.join(tool_cache_dir, "new_tool.json")
116
+ if not os.path.exists(target_tool_path):
117
+ shutil.copy(default_tool_path, target_tool_path)
118
+
119
+ agent = TxAgent(
120
+ model_name="mims-harvard/TxAgent-T1-Llama-3.1-8B",
121
+ rag_model_name="mims-harvard/ToolRAG-T1-GTE-Qwen2-1.5B",
122
+ tool_files_dict={"new_tool": target_tool_path},
123
+ force_finish=True,
124
+ enable_checker=True,
125
+ step_rag_num=8,
126
+ seed=100,
127
+ additional_default_tools=[],
128
+ )
129
+ agent.init_model()
130
+ log_system_usage("After Load")
131
+ print("✅ Agent Ready")
132
+ return agent
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
+ def create_ui(agent):
135
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
136
+ gr.Markdown("<h1 style='text-align: center;'>🩺 Clinical Oversight Assistant</h1>")
137
+ chatbot = gr.Chatbot(label="Analysis", height=600, type="messages")
138
+ file_upload = gr.File(file_types=[".pdf", ".csv", ".xls", ".xlsx"], file_count="multiple")
139
+ msg_input = gr.Textbox(placeholder="Ask about potential oversights...", show_label=False)
140
+ send_btn = gr.Button("Analyze", variant="primary")
141
+ download_output = gr.File(label="Download Full Report")
142
+
143
+ def analyze(message: str, history: list, files: list):
144
+ history = history + [{"role": "user", "content": message}]
145
+ history.append({"role": "assistant", "content": "⏳ Analyzing records for potential oversights..."})
146
+ yield history, None
147
+
148
+ extracted = ""
149
+ file_hash_value = ""
150
+ if files:
151
+ with ThreadPoolExecutor(max_workers=4) as executor:
152
+ futures = [executor.submit(convert_file_to_json, f.name, f.name.split(".")[-1].lower()) for f in files]
153
+ results = [sanitize_utf8(f.result()) for f in as_completed(futures)]
154
+ extracted = "\n".join(results)
155
+ file_hash_value = file_hash(files[0].name)
156
+
157
+ prompt = f"""Review these medical records and identify EXACTLY what might have been missed:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  1. List potential missed diagnoses
159
  2. Flag any medication conflicts
160
  3. Note incomplete assessments
161
  4. Highlight abnormal results needing follow-up
 
162
  Medical Records:
163
  {extracted[:12000]}
 
164
  ### Potential Oversights:
165
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
+ try:
168
+ for chunk in agent.run_gradio_chat(
169
+ message=prompt,
170
+ history=[],
171
+ temperature=0.2,
172
+ max_new_tokens=2048,
173
+ max_token=4096,
174
+ call_agent=False,
175
+ conversation=[],
176
+ ):
177
+ if chunk is None:
178
+ continue
179
+ if isinstance(chunk, list):
180
+ for m in chunk:
181
+ history.append({"role": m.role, "content": m.content})
182
+ yield history, None
183
+ elif isinstance(chunk, str):
184
+ history[-1]["content"] += chunk
185
+ yield history, None
186
+
187
+ report_path = os.path.join(report_dir, f"{file_hash_value}_report.txt") if file_hash_value else None
188
+ yield history, report_path if report_path and os.path.exists(report_path) else None
189
+
190
+ except Exception as e:
191
+ print("🚨 ERROR:", e)
192
+ history.append({"role": "assistant", "content": f"❌ Error occurred: {str(e)}"})
193
+ yield history, None
194
+
195
+ send_btn.click(analyze, inputs=[msg_input, gr.State([]), file_upload], outputs=[chatbot, download_output])
196
+ msg_input.submit(analyze, inputs=[msg_input, gr.State([]), file_upload], outputs=[chatbot, download_output])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  return demo
198
 
199
  if __name__ == "__main__":
200
+ print("🚀 Launching app...")
201
+ agent = init_agent()
202
+ demo = create_ui(agent)
203
+ demo.queue(api_open=False).launch(
204
+ server_name="0.0.0.0",
205
+ server_port=7860,
206
+ show_error=True,
207
+ allowed_paths=[report_dir],
208
+ share=False
209
+ )