Rajan Sharma commited on
Commit
83c1ac8
·
verified ·
1 Parent(s): 0cc05cc

Update response_formatter.py

Browse files
Files changed (1) hide show
  1. response_formatter.py +777 -116
response_formatter.py CHANGED
@@ -1,8 +1,11 @@
1
  # response_formatter.py
2
- from typing import Dict, List, Any, Tuple
3
  import re
4
 
5
  class ResponseFormatter:
 
 
 
6
  @staticmethod
7
  def format_healthcare_response(scenario_text: str, analysis_results: Dict[str, Any]) -> str:
8
  """Format healthcare analysis response based on scenario tasks"""
@@ -38,8 +41,8 @@ class ResponseFormatter:
38
  return response
39
 
40
  @staticmethod
41
- def _extract_scenario_tasks(scenario_text: str) -> List[str]:
42
- """Extract specific tasks from scenario text"""
43
  tasks = []
44
  lines = scenario_text.split('\n')
45
  in_tasks = False
@@ -56,57 +59,268 @@ class ResponseFormatter:
56
  # Check if we're leaving the tasks section
57
  if in_tasks and (line.lower().startswith('operational recommendations') or
58
  line.lower().startswith('future integration') or
59
- line.lower().startswith('prepare your findings')):
 
 
60
  in_tasks = False
61
  if current_task:
62
- tasks.append(current_task)
 
63
  continue
64
 
65
  # Collect task content
66
  if in_tasks:
67
- if line and (line.startswith(('1.', '2.', '3.', '4.', '5.', '6.', '7.', '8.', '9.')) or
68
- line.startswith(('•', '-', '*'))):
69
  if current_task:
70
- tasks.append(current_task)
 
71
  current_task = line
72
  elif line:
73
  current_task += " " + line
74
 
75
  # Add the last task if exists
76
  if current_task:
77
- tasks.append(current_task)
 
78
 
79
  return tasks
80
 
81
  @staticmethod
82
- def _process_task(task: str, analysis_results: Dict[str, Any]) -> str:
83
- """Process a single task and return formatted content"""
84
- task_lower = task.lower()
85
-
86
- # Data Preparation Task
87
- if "data preparation" in task_lower or "load the data" in task_lower:
88
- return ResponseFormatter._handle_data_preparation_task(task, analysis_results)
89
-
90
- # Bed Capacity Analysis Tasks
91
- elif "bed capacity" in task_lower or "summarize bed capacity" in task_lower:
92
- return ResponseFormatter._handle_bed_capacity_task(task, analysis_results)
93
-
94
- elif "facilities with the greatest declines" in task_lower:
95
- return ResponseFormatter._handle_facility_declines_task(task, analysis_results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
- elif "long-term care capacity" in task_lower or "assess long-term care" in task_lower:
98
- return ResponseFormatter._handle_long_term_care_task(task, analysis_results)
99
-
100
- # Operational Recommendations Tasks
101
- elif "operational recommendations" in task_lower or "recommend actions" in task_lower:
102
- return ResponseFormatter._handle_recommendations_task(task, analysis_results)
103
-
104
- elif "future integration" in task_lower or "augmented ai" in task_lower:
105
- return ResponseFormatter._handle_integration_task(task, analysis_results)
106
-
107
- # Generic task handler
108
  else:
109
- return ResponseFormatter._handle_generic_task(task, analysis_results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  @staticmethod
112
  def _handle_data_preparation_task(task: str, analysis_results: Dict[str, Any]) -> str:
@@ -149,7 +363,7 @@ class ResponseFormatter:
149
  @staticmethod
150
  def _handle_bed_capacity_task(task: str, analysis_results: Dict[str, Any]) -> str:
151
  """Handle bed capacity analysis task"""
152
- response = "## Bed Capacity Analysis\n\n"
153
 
154
  if "capacity_analysis" not in analysis_results:
155
  return response + "No capacity analysis results available"
@@ -337,22 +551,536 @@ class ResponseFormatter:
337
  return response
338
 
339
  @staticmethod
340
- def _handle_generic_task(task: str, analysis_results: Dict[str, Any]) -> str:
341
- """Handle generic task"""
342
- # Try to match task to any available analysis results
343
- task_lower = task.lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
 
345
- if "distribution" in task_lower and "facility_distribution" in analysis_results:
346
- return "## Facility Distribution Analysis\n\n" + ResponseFormatter._format_facility_distribution(analysis_results["facility_distribution"])
 
 
 
 
 
 
 
 
347
 
348
- if "resource" in task_lower and "resource_allocation" in analysis_results:
349
- return "## Resource Allocation Analysis\n\n" + ResponseFormatter._format_resource_allocation(analysis_results["resource_allocation"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
 
351
- if "trend" in task_lower and "trends" in analysis_results:
352
- return "## Trend Analysis\n\n" + ResponseFormatter._format_trends(analysis_results["trends"])
 
 
 
 
 
 
 
 
353
 
354
- # If no specific match, return a generic section
355
- return f"## {task}\n\nNo specific analysis results available for this task."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
 
357
  @staticmethod
358
  def _generate_executive_summary(results: Dict[str, Any]) -> str:
@@ -397,71 +1125,4 @@ class ResponseFormatter:
397
  response += f"- {task}\n"
398
  response += "\n"
399
 
400
- return response
401
-
402
- # Legacy formatting methods for generic tasks
403
- @staticmethod
404
- def _format_facility_distribution(dist_results: Dict[str, Any]) -> str:
405
- """Format facility distribution analysis results"""
406
- response = ""
407
-
408
- if "total_facilities" in dist_results:
409
- response += f"**Total Facilities**: {dist_results['total_facilities']:,}\n\n"
410
-
411
- if "geographic_distribution" in dist_results:
412
- response += "### Geographic Distribution\n\n"
413
- response += "| Region | Facility Count |\n"
414
- response += "|--------|---------------|\n"
415
- for region, count in dist_results["geographic_distribution"].items():
416
- response += f"| {region} | {count} |\n"
417
- response += "\n"
418
-
419
- if "geographic_inequality" in dist_results:
420
- inequality = dist_results["geographic_inequality"]
421
- level = "High" if inequality > 0.4 else "Moderate" if inequality > 0.2 else "Low"
422
- response += f"**Geographic Inequality**: {level} (Gini coefficient: {inequality:.2f})\n\n"
423
-
424
- return response if response else "No facility distribution data available"
425
-
426
- @staticmethod
427
- def _format_resource_allocation(allocation_results: Dict[str, Any]) -> str:
428
- """Format resource allocation analysis results"""
429
- response = ""
430
-
431
- if "total_resources" in allocation_results:
432
- response += f"**Total Resources**: {allocation_results['total_resources']:,} units\n\n"
433
-
434
- if "allocation_by_facility" in allocation_results:
435
- response += "### Allocation by Facility Type\n\n"
436
- response += "| Facility Type | Resource Count | Percentage |\n"
437
- response += "|---------------|----------------|------------|\n"
438
- for ftype, count in allocation_results["allocation_by_facility"].items():
439
- percentage = count / allocation_results.get("total_resources", 1) * 100
440
- response += f"| {ftype} | {count:,} | {percentage:.1f}% |\n"
441
- response += "\n"
442
-
443
- return response if response else "No resource allocation data available"
444
-
445
- @staticmethod
446
- def _format_trends(trends_results: Dict[str, Any]) -> str:
447
- """Format trend analysis results"""
448
- response = ""
449
-
450
- if "summary" in trends_results:
451
- response += f"**Trend Summary**: {trends_results['summary']}\n\n"
452
-
453
- if "facility_growth" in trends_results:
454
- response += "### Facility Growth Trends\n\n"
455
- response += "| Year | Facility Count | Growth Rate |\n"
456
- response += "|------|----------------|-------------|\n"
457
- prev_count = None
458
- for year, count in trends_results["facility_growth"].items():
459
- if prev_count is not None:
460
- growth_rate = (count - prev_count) / prev_count
461
- response += f"| {year} | {count:,} | {growth_rate:.1%} |\n"
462
- else:
463
- response += f"| {year} | {count:,} | N/A |\n"
464
- prev_count = count
465
- response += "\n"
466
-
467
- return response if response else "No trend data available"
 
1
  # response_formatter.py
2
+ from typing import Dict, List, Any, Tuple, Callable
3
  import re
4
 
5
  class ResponseFormatter:
6
+ # Class-level handler map for extensibility
7
+ _handler_map = {}
8
+
9
  @staticmethod
10
  def format_healthcare_response(scenario_text: str, analysis_results: Dict[str, Any]) -> str:
11
  """Format healthcare analysis response based on scenario tasks"""
 
41
  return response
42
 
43
  @staticmethod
44
+ def _extract_scenario_tasks(scenario_text: str) -> List[Tuple[str, str]]:
45
+ """Extract specific tasks from scenario text and return as (section_header, task_description) tuples"""
46
  tasks = []
47
  lines = scenario_text.split('\n')
48
  in_tasks = False
 
59
  # Check if we're leaving the tasks section
60
  if in_tasks and (line.lower().startswith('operational recommendations') or
61
  line.lower().startswith('future integration') or
62
+ line.lower().startswith('prepare your findings') or
63
+ line.lower().startswith('conclusions') or
64
+ line.lower().startswith('next steps')):
65
  in_tasks = False
66
  if current_task:
67
+ section_header = ResponseFormatter._get_section_header(current_task)
68
+ tasks.append((section_header, current_task))
69
  continue
70
 
71
  # Collect task content
72
  if in_tasks:
73
+ # Check if this is a new task (starts with number or bullet)
74
+ if re.match(r'^\d+\.', line) or line.startswith(('•', '-', '*')):
75
  if current_task:
76
+ section_header = ResponseFormatter._get_section_header(current_task)
77
+ tasks.append((section_header, current_task))
78
  current_task = line
79
  elif line:
80
  current_task += " " + line
81
 
82
  # Add the last task if exists
83
  if current_task:
84
+ section_header = ResponseFormatter._get_section_header(current_task)
85
+ tasks.append((section_header, current_task))
86
 
87
  return tasks
88
 
89
  @staticmethod
90
+ def _get_section_header(task_description: str) -> str:
91
+ """Map task description to a clean section header with comprehensive keyword matching"""
92
+ task_lower = task_description.lower()
93
+
94
+ # Data Preparation patterns
95
+ if any(keyword in task_lower for keyword in [
96
+ "load the data", "data preparation", "data loading", "data import",
97
+ "data processing", "data cleaning", "data filtering"
98
+ ]):
99
+ return "Data Preparation"
100
+
101
+ # Capacity Analysis patterns
102
+ elif any(keyword in task_lower for keyword in [
103
+ "bed capacity", "bed utilization", "bed availability", "bed occupancy",
104
+ "capacity analysis", "resource capacity", "service capacity"
105
+ ]):
106
+ return "Capacity Analysis"
107
+
108
+ # Facility Decline patterns
109
+ elif any(keyword in task_lower for keyword in [
110
+ "facilities with the greatest declines", "facility decline",
111
+ "bed reduction", "capacity reduction", "facility closure"
112
+ ]):
113
+ return "Facilities with Greatest Declines"
114
+
115
+ # Long-Term Care patterns
116
+ elif any(keyword in task_lower for keyword in [
117
+ "assess long-term care", "long-term care capacity", "ltc assessment",
118
+ "nursing home capacity", "residential care capacity", "care facility assessment"
119
+ ]):
120
+ return "Long-Term Care Capacity Assessment"
121
+
122
+ # Recommendations patterns
123
+ elif any(keyword in task_lower for keyword in [
124
+ "recommend actions", "operational recommendations", "recommendations",
125
+ "action plan", "mitigation strategies", "improvement strategies"
126
+ ]):
127
+ return "Operational Recommendations"
128
+
129
+ # Integration patterns
130
+ elif any(keyword in task_lower for keyword in [
131
+ "future integration", "augmented ai", "decision support", "ai integration",
132
+ "system integration", "data integration", "predictive analytics"
133
+ ]):
134
+ return "Future Integration Opportunities"
135
+
136
+ # Patient Satisfaction patterns
137
+ elif any(keyword in task_lower for keyword in [
138
+ "patient satisfaction", "patient experience", "patient feedback",
139
+ "satisfaction analysis", "experience analysis"
140
+ ]):
141
+ return "Patient Satisfaction Analysis"
142
+
143
+ # Staff Utilization patterns
144
+ elif any(keyword in task_lower for keyword in [
145
+ "staff utilization", "workforce analysis", "staffing analysis",
146
+ "human resources", "staff productivity", "staff allocation"
147
+ ]):
148
+ return "Staff Utilization Analysis"
149
+
150
+ # Equipment patterns
151
+ elif any(keyword in task_lower for keyword in [
152
+ "equipment inventory", "medical equipment", "device utilization",
153
+ "equipment assessment", "resource inventory"
154
+ ]):
155
+ return "Equipment Inventory Assessment"
156
+
157
+ # Financial Analysis patterns
158
+ elif any(keyword in task_lower for keyword in [
159
+ "financial analysis", "cost analysis", "budget analysis",
160
+ "economic analysis", "resource costing"
161
+ ]):
162
+ return "Financial Analysis"
163
+
164
+ # Quality Metrics patterns
165
+ elif any(keyword in task_lower for keyword in [
166
+ "quality metrics", "performance metrics", "outcome measures",
167
+ "quality indicators", "performance indicators"
168
+ ]):
169
+ return "Quality Metrics Analysis"
170
+
171
+ # Geographic Distribution patterns
172
+ elif any(keyword in task_lower for keyword in [
173
+ "geographic distribution", "spatial analysis", "location analysis",
174
+ "regional distribution", "service distribution"
175
+ ]):
176
+ return "Geographic Distribution Analysis"
177
+
178
+ # Access patterns
179
+ elif any(keyword in task_lower for keyword in [
180
+ "access analysis", "accessibility", "service access",
181
+ "barriers to care", "equity analysis"
182
+ ]):
183
+ return "Healthcare Access Analysis"
184
+
185
+ # Wait Time patterns
186
+ elif any(keyword in task_lower for keyword in [
187
+ "wait time", "waiting time", "delay analysis",
188
+ "queue analysis", "timeliness"
189
+ ]):
190
+ return "Wait Time Analysis"
191
+
192
+ # Population Health patterns
193
+ elif any(keyword in task_lower for keyword in [
194
+ "population health", "epidemiology", "disease burden",
195
+ "health status", "community health"
196
+ ]):
197
+ return "Population Health Analysis"
198
+
199
+ # Emergency Services patterns
200
+ elif any(keyword in task_lower for keyword in [
201
+ "emergency services", "er analysis", "emergency department",
202
+ "urgent care", "emergency response"
203
+ ]):
204
+ return "Emergency Services Analysis"
205
+
206
+ # Specialized Care patterns
207
+ elif any(keyword in task_lower for keyword in [
208
+ "specialized care", "specialty services", "tertiary care",
209
+ "specialized services", "advanced care"
210
+ ]):
211
+ return "Specialized Care Analysis"
212
+
213
+ # Preventive Care patterns
214
+ elif any(keyword in task_lower for keyword in [
215
+ "preventive care", "prevention", "screening",
216
+ "wellness programs", "health promotion"
217
+ ]):
218
+ return "Preventive Care Analysis"
219
+
220
+ # Telehealth patterns
221
+ elif any(keyword in task_lower for keyword in [
222
+ "telehealth", "virtual care", "remote care",
223
+ "digital health", "e-health"
224
+ ]):
225
+ return "Telehealth Analysis"
226
+
227
+ # Research patterns
228
+ elif any(keyword in task_lower for keyword in [
229
+ "research", "clinical trials", "innovation",
230
+ "evidence-based practice", "research analysis"
231
+ ]):
232
+ return "Research and Innovation Analysis"
233
 
 
 
 
 
 
 
 
 
 
 
 
234
  else:
235
+ # Extract the first sentence as a fallback
236
+ first_sentence = task_description.split('.')[0]
237
+ return first_sentence.strip()
238
+
239
+ @staticmethod
240
+ def _process_task(task_tuple: Tuple[str, str], analysis_results: Dict[str, Any]) -> str:
241
+ """Process a single task and return formatted content"""
242
+ section_header, task_description = task_tuple
243
+
244
+ # Initialize default handler map
245
+ default_handler_map = {
246
+ "Data Preparation": ResponseFormatter._handle_data_preparation_task,
247
+ "Capacity Analysis": ResponseFormatter._handle_bed_capacity_task,
248
+ "Facilities with Greatest Declines": ResponseFormatter._handle_facility_declines_task,
249
+ "Long-Term Care Capacity Assessment": ResponseFormatter._handle_long_term_care_task,
250
+ "Operational Recommendations": ResponseFormatter._handle_recommendations_task,
251
+ "Future Integration Opportunities": ResponseFormatter._handle_integration_task,
252
+ "Patient Satisfaction Analysis": ResponseFormatter._handle_patient_satisfaction_task,
253
+ "Staff Utilization Analysis": ResponseFormatter._handle_staff_utilization_task,
254
+ "Equipment Inventory Assessment": ResponseFormatter._handle_equipment_task,
255
+ "Financial Analysis": ResponseFormatter._handle_financial_task,
256
+ "Quality Metrics Analysis": ResponseFormatter._handle_quality_metrics_task,
257
+ "Geographic Distribution Analysis": ResponseFormatter._handle_geographic_distribution_task,
258
+ "Healthcare Access Analysis": ResponseFormatter._handle_access_task,
259
+ "Wait Time Analysis": ResponseFormatter._handle_wait_time_task,
260
+ "Population Health Analysis": ResponseFormatter._handle_population_health_task,
261
+ "Emergency Services Analysis": ResponseFormatter._handle_emergency_services_task,
262
+ "Specialized Care Analysis": ResponseFormatter._handle_specialized_care_task,
263
+ "Preventive Care Analysis": ResponseFormatter._handle_preventive_care_task,
264
+ "Telehealth Analysis": ResponseFormatter._handle_telehealth_task,
265
+ "Research and Innovation Analysis": ResponseFormatter._handle_research_task
266
+ }
267
+
268
+ # Combine default handlers with any dynamically registered handlers
269
+ handler_map = {**default_handler_map, **ResponseFormatter._handler_map}
270
+
271
+ if section_header in handler_map:
272
+ return handler_map[section_header](task_description, analysis_results)
273
+ else:
274
+ # Use generic handler for unknown task types
275
+ return ResponseFormatter._handle_generic_task(section_header, task_description, analysis_results)
276
+
277
+ @staticmethod
278
+ def register_handler(section_header: str, handler_function: Callable):
279
+ """Register a new handler for a specific section header"""
280
+ ResponseFormatter._handler_map[section_header] = handler_function
281
+
282
+ @staticmethod
283
+ def _handle_generic_task(section_header: str, task_description: str, analysis_results: Dict[str, Any]) -> str:
284
+ """Handle generic tasks that don't match specific patterns"""
285
+ response = f"## {section_header}\n\n"
286
+
287
+ # Try to find relevant data in analysis_results
288
+ relevant_data = {}
289
+
290
+ # Look for data keys that might be related to the task
291
+ task_keywords = section_header.lower().split()
292
+ for key, value in analysis_results.items():
293
+ key_lower = key.lower()
294
+ if any(keyword in key_lower for keyword in task_keywords):
295
+ relevant_data[key] = value
296
+
297
+ if relevant_data:
298
+ for key, value in relevant_data.items():
299
+ if isinstance(value, dict) and value:
300
+ response += f"### {key.replace('_', ' ').title()}\n\n"
301
+ for subkey, subvalue in value.items():
302
+ if isinstance(subvalue, (int, float)):
303
+ response += f"**{subkey.replace('_', ' ').title()}**: {subvalue:,}\n\n"
304
+ elif isinstance(subvalue, str):
305
+ response += f"**{subkey.replace('_', ' ').title()}**: {subvalue}\n\n"
306
+ elif isinstance(subvalue, list):
307
+ response += f"**{subkey.replace('_', ' ').title()}**:\n\n"
308
+ for item in subvalue[:5]: # Show first 5 items
309
+ if isinstance(item, dict):
310
+ for item_key, item_value in item.items():
311
+ response += f"- {item_key.replace('_', ' ').title()}: {item_value}\n"
312
+ else:
313
+ response += f"- {item}\n"
314
+ response += "\n"
315
+ elif isinstance(value, (int, float)):
316
+ response += f"**{key.replace('_', ' ').title()}**: {value:,}\n\n"
317
+ elif isinstance(value, str):
318
+ response += f"**{key.replace('_', ' ').title()}**: {value}\n\n"
319
+ else:
320
+ response += "No specific analysis results available for this task.\n\n"
321
+ response += "This task requires specialized analysis that may not be available in the current dataset.\n"
322
+
323
+ return response
324
 
325
  @staticmethod
326
  def _handle_data_preparation_task(task: str, analysis_results: Dict[str, Any]) -> str:
 
363
  @staticmethod
364
  def _handle_bed_capacity_task(task: str, analysis_results: Dict[str, Any]) -> str:
365
  """Handle bed capacity analysis task"""
366
+ response = "## Capacity Analysis\n\n"
367
 
368
  if "capacity_analysis" not in analysis_results:
369
  return response + "No capacity analysis results available"
 
551
  return response
552
 
553
  @staticmethod
554
+ def _handle_patient_satisfaction_task(task: str, analysis_results: Dict[str, Any]) -> str:
555
+ """Handle patient satisfaction analysis task"""
556
+ response = "## Patient Satisfaction Analysis\n\n"
557
+
558
+ if "patient_satisfaction" not in analysis_results:
559
+ return response + "No patient satisfaction data available"
560
+
561
+ satisfaction = analysis_results["patient_satisfaction"]
562
+
563
+ # Overall satisfaction
564
+ if "overall_satisfaction" in satisfaction:
565
+ response += f"**Overall Patient Satisfaction**: {satisfaction['overall_satisfaction']:.1f}/5.0\n\n"
566
+
567
+ # Satisfaction by category
568
+ if "satisfaction_by_category" in satisfaction:
569
+ response += "### Satisfaction by Category\n\n"
570
+ response += "| Category | Score |\n"
571
+ response += "|----------|-------|\n"
572
+ for category, score in satisfaction["satisfaction_by_category"].items():
573
+ response += f"| {category} | {score:.1f}/5.0 |\n"
574
+ response += "\n"
575
+
576
+ # Trends
577
+ if "satisfaction_trends" in satisfaction:
578
+ response += "### Satisfaction Trends\n\n"
579
+ response += "| Period | Satisfaction Score |\n"
580
+ response += "|--------|-------------------|\n"
581
+ for period, score in satisfaction["satisfaction_trends"].items():
582
+ response += f"| {period} | {score:.1f}/5.0 |\n"
583
+ response += "\n"
584
+
585
+ return response
586
+
587
+ @staticmethod
588
+ def _handle_staff_utilization_task(task: str, analysis_results: Dict[str, Any]) -> str:
589
+ """Handle staff utilization analysis task"""
590
+ response = "## Staff Utilization Analysis\n\n"
591
+
592
+ if "staff_utilization" not in analysis_results:
593
+ return response + "No staff utilization data available"
594
+
595
+ staff = analysis_results["staff_utilization"]
596
+
597
+ # Overall utilization
598
+ if "overall_utilization" in staff:
599
+ response += f"**Overall Staff Utilization**: {staff['overall_utilization']:.1%}\n\n"
600
+
601
+ # Utilization by role
602
+ if "utilization_by_role" in staff:
603
+ response += "### Utilization by Role\n\n"
604
+ response += "| Role | Utilization Rate |\n"
605
+ response += "|------|------------------|\n"
606
+ for role, rate in staff["utilization_by_role"].items():
607
+ response += f"| {role} | {rate:.1%} |\n"
608
+ response += "\n"
609
+
610
+ # Staffing levels
611
+ if "staffing_levels" in staff:
612
+ response += "### Staffing Levels\n\n"
613
+ response += "| Role | Current Staff | Recommended Staff | Gap |\n"
614
+ response += "|------|---------------|-------------------|-----|\n"
615
+ for role, data in staff["staffing_levels"].items():
616
+ current = data.get("current", 0)
617
+ recommended = data.get("recommended", 0)
618
+ gap = current - recommended
619
+ response += f"| {role} | {current} | {recommended} | {gap:+} |\n"
620
+ response += "\n"
621
+
622
+ return response
623
+
624
+ @staticmethod
625
+ def _handle_equipment_task(task: str, analysis_results: Dict[str, Any]) -> str:
626
+ """Handle equipment inventory assessment task"""
627
+ response = "## Equipment Inventory Assessment\n\n"
628
+
629
+ if "equipment_inventory" not in analysis_results:
630
+ return response + "No equipment inventory data available"
631
+
632
+ equipment = analysis_results["equipment_inventory"]
633
+
634
+ # Total equipment value
635
+ if "total_value" in equipment:
636
+ response += f"**Total Equipment Value**: ${equipment['total_value']:,.2f}\n\n"
637
+
638
+ # Equipment by category
639
+ if "equipment_by_category" in equipment:
640
+ response += "### Equipment by Category\n\n"
641
+ response += "| Category | Count | Total Value |\n"
642
+ response += "|----------|-------|-------------|\n"
643
+ for category, data in equipment["equipment_by_category"].items():
644
+ count = data.get("count", 0)
645
+ value = data.get("value", 0)
646
+ response += f"| {category} | {count} | ${value:,.2f} |\n"
647
+ response += "\n"
648
+
649
+ # Utilization rates
650
+ if "utilization_rates" in equipment:
651
+ response += "### Equipment Utilization Rates\n\n"
652
+ response += "| Equipment Type | Utilization Rate |\n"
653
+ response += "|----------------|------------------|\n"
654
+ for eq_type, rate in equipment["utilization_rates"].items():
655
+ response += f"| {eq_type} | {rate:.1%} |\n"
656
+ response += "\n"
657
+
658
+ return response
659
+
660
+ @staticmethod
661
+ def _handle_financial_task(task: str, analysis_results: Dict[str, Any]) -> str:
662
+ """Handle financial analysis task"""
663
+ response = "## Financial Analysis\n\n"
664
+
665
+ if "financial_analysis" not in analysis_results:
666
+ return response + "No financial analysis data available"
667
+
668
+ financial = analysis_results["financial_analysis"]
669
+
670
+ # Total budget
671
+ if "total_budget" in financial:
672
+ response += f"**Total Budget**: ${financial['total_budget']:,.2f}\n\n"
673
+
674
+ # Expenditure by category
675
+ if "expenditure_by_category" in financial:
676
+ response += "### Expenditure by Category\n\n"
677
+ response += "| Category | Amount | Percentage |\n"
678
+ response += "|----------|--------|------------|\n"
679
+ for category, data in financial["expenditure_by_category"].items():
680
+ amount = data.get("amount", 0)
681
+ percentage = data.get("percentage", 0)
682
+ response += f"| {category} | ${amount:,.2f} | {percentage:.1f}% |\n"
683
+ response += "\n"
684
+
685
+ # Cost per patient
686
+ if "cost_per_patient" in financial:
687
+ response += f"**Average Cost per Patient**: ${financial['cost_per_patient']:,.2f}\n\n"
688
+
689
+ # Financial trends
690
+ if "financial_trends" in financial:
691
+ response += "### Financial Trends\n\n"
692
+ response += "| Period | Revenue | Expenditure | Surplus/Deficit |\n"
693
+ response += "|--------|---------|-------------|-----------------|\n"
694
+ for period, data in financial["financial_trends"].items():
695
+ revenue = data.get("revenue", 0)
696
+ expenditure = data.get("expenditure", 0)
697
+ surplus = revenue - expenditure
698
+ response += f"| {period} | ${revenue:,.2f} | ${expenditure:,.2f} | ${surplus:+,.2f} |\n"
699
+ response += "\n"
700
+
701
+ return response
702
+
703
+ @staticmethod
704
+ def _handle_quality_metrics_task(task: str, analysis_results: Dict[str, Any]) -> str:
705
+ """Handle quality metrics analysis task"""
706
+ response = "## Quality Metrics Analysis\n\n"
707
+
708
+ if "quality_metrics" not in analysis_results:
709
+ return response + "No quality metrics data available"
710
+
711
+ quality = analysis_results["quality_metrics"]
712
+
713
+ # Overall quality score
714
+ if "overall_quality_score" in quality:
715
+ response += f"**Overall Quality Score**: {quality['overall_quality_score']:.1f}/100\n\n"
716
+
717
+ # Quality indicators
718
+ if "quality_indicators" in quality:
719
+ response += "### Quality Indicators\n\n"
720
+ response += "| Indicator | Current Value | Target | Status |\n"
721
+ response += "|-----------|---------------|--------|--------|\n"
722
+ for indicator, data in quality["quality_indicators"].items():
723
+ current = data.get("current", 0)
724
+ target = data.get("target", 0)
725
+ status = "✅ Met" if current >= target else "❌ Not Met"
726
+ response += f"| {indicator} | {current:.1f} | {target:.1f} | {status} |\n"
727
+ response += "\n"
728
+
729
+ # Trends
730
+ if "quality_trends" in quality:
731
+ response += "### Quality Trends\n\n"
732
+ response += "| Period | Quality Score |\n"
733
+ response += "|--------|---------------|\n"
734
+ for period, score in quality["quality_trends"].items():
735
+ response += f"| {period} | {score:.1f}/100 |\n"
736
+ response += "\n"
737
+
738
+ return response
739
+
740
+ @staticmethod
741
+ def _handle_geographic_distribution_task(task: str, analysis_results: Dict[str, Any]) -> str:
742
+ """Handle geographic distribution analysis task"""
743
+ response = "## Geographic Distribution Analysis\n\n"
744
+
745
+ if "geographic_distribution" not in analysis_results:
746
+ return response + "No geographic distribution data available"
747
+
748
+ geo = analysis_results["geographic_distribution"]
749
+
750
+ # Total facilities
751
+ if "total_facilities" in geo:
752
+ response += f"**Total Facilities**: {geo['total_facilities']:,}\n\n"
753
+
754
+ # Distribution by region
755
+ if "distribution_by_region" in geo:
756
+ response += "### Distribution by Region\n\n"
757
+ response += "| Region | Facility Count | Population Served | Facilities per 100K |\n"
758
+ response += "|--------|----------------|-------------------|-------------------|\n"
759
+ for region, data in geo["distribution_by_region"].items():
760
+ count = data.get("facility_count", 0)
761
+ population = data.get("population_served", 0)
762
+ per_100k = (count / population * 100000) if population > 0 else 0
763
+ response += f"| {region} | {count:,} | {population:,} | {per_100k:.1f} |\n"
764
+ response += "\n"
765
+
766
+ # Access inequality
767
+ if "gini_coefficient" in geo:
768
+ gini = geo["gini_coefficient"]
769
+ level = "High" if gini > 0.4 else "Moderate" if gini > 0.2 else "Low"
770
+ response += f"**Access Inequality**: {level} (Gini coefficient: {gini:.2f})\n\n"
771
+
772
+ return response
773
+
774
+ @staticmethod
775
+ def _handle_access_task(task: str, analysis_results: Dict[str, Any]) -> str:
776
+ """Handle healthcare access analysis task"""
777
+ response = "## Healthcare Access Analysis\n\n"
778
+
779
+ if "healthcare_access" not in analysis_results:
780
+ return response + "No healthcare access data available"
781
+
782
+ access = analysis_results["healthcare_access"]
783
+
784
+ # Overall access score
785
+ if "overall_access_score" in access:
786
+ response += f"**Overall Access Score**: {access['overall_access_score']:.1f}/100\n\n"
787
+
788
+ # Access by service type
789
+ if "access_by_service" in access:
790
+ response += "### Access by Service Type\n\n"
791
+ response += "| Service Type | Access Score | Wait Time (Days) | Availability |\n"
792
+ response += "|--------------|-------------|-----------------|-------------|\n"
793
+ for service, data in access["access_by_service"].items():
794
+ score = data.get("access_score", 0)
795
+ wait_time = data.get("wait_time_days", 0)
796
+ availability = data.get("availability", "N/A")
797
+ response += f"| {service} | {score:.1f}/100 | {wait_time:.1f} | {availability} |\n"
798
+ response += "\n"
799
+
800
+ # Barriers to care
801
+ if "barriers_to_care" in access:
802
+ response += "### Top Barriers to Care\n\n"
803
+ for i, barrier in enumerate(access["barriers_to_care"][:5], 1):
804
+ response += f"{i}. {barrier}\n"
805
+ response += "\n"
806
+
807
+ return response
808
+
809
+ @staticmethod
810
+ def _handle_wait_time_task(task: str, analysis_results: Dict[str, Any]) -> str:
811
+ """Handle wait time analysis task"""
812
+ response = "## Wait Time Analysis\n\n"
813
+
814
+ if "wait_time_analysis" not in analysis_results:
815
+ return response + "No wait time data available"
816
+
817
+ wait_time = analysis_results["wait_time_analysis"]
818
+
819
+ # Average wait time
820
+ if "average_wait_time" in wait_time:
821
+ response += f"**Average Wait Time**: {wait_time['average_wait_time']:.1f} days\n\n"
822
+
823
+ # Wait time by service
824
+ if "wait_time_by_service" in wait_time:
825
+ response += "### Wait Time by Service\n\n"
826
+ response += "| Service | Average Wait (Days) | Target Wait (Days) | Status |\n"
827
+ response += "|---------|-------------------|-------------------|--------|\n"
828
+ for service, data in wait_time["wait_time_by_service"].items():
829
+ current = data.get("current_wait", 0)
830
+ target = data.get("target_wait", 0)
831
+ status = "✅ Met" if current <= target else "❌ Exceeded"
832
+ response += f"| {service} | {current:.1f} | {target:.1f} | {status} |\n"
833
+ response += "\n"
834
+
835
+ # Trends
836
+ if "wait_time_trends" in wait_time:
837
+ response += "### Wait Time Trends\n\n"
838
+ response += "| Period | Average Wait (Days) |\n"
839
+ response += "|--------|-------------------|\n"
840
+ for period, wait in wait_time["wait_time_trends"].items():
841
+ response += f"| {period} | {wait:.1f} |\n"
842
+ response += "\n"
843
+
844
+ return response
845
+
846
+ @staticmethod
847
+ def _handle_population_health_task(task: str, analysis_results: Dict[str, Any]) -> str:
848
+ """Handle population health analysis task"""
849
+ response = "## Population Health Analysis\n\n"
850
+
851
+ if "population_health" not in analysis_results:
852
+ return response + "No population health data available"
853
+
854
+ health = analysis_results["population_health"]
855
+
856
+ # Total population
857
+ if "total_population" in health:
858
+ response += f"**Total Population**: {health['total_population']:,}\n\n"
859
+
860
+ # Health indicators
861
+ if "health_indicators" in health:
862
+ response += "### Key Health Indicators\n\n"
863
+ response += "| Indicator | Value | Target |\n"
864
+ response += "|-----------|-------|--------|\n"
865
+ for indicator, data in health["health_indicators"].items():
866
+ value = data.get("value", 0)
867
+ target = data.get("target", 0)
868
+ response += f"| {indicator} | {value:.1f} | {target:.1f} |\n"
869
+ response += "\n"
870
 
871
+ # Disease burden
872
+ if "disease_burden" in health:
873
+ response += "### Top Causes of Disease Burden\n\n"
874
+ response += "| Disease | DALYs | Percentage |\n"
875
+ response += "|---------|-------|------------|\n"
876
+ for disease, data in health["disease_burden"].items():
877
+ dalys = data.get("dalys", 0)
878
+ percentage = data.get("percentage", 0)
879
+ response += f"| {disease} | {dalys:,} | {percentage:.1f}% |\n"
880
+ response += "\n"
881
 
882
+ return response
883
+
884
+ @staticmethod
885
+ def _handle_emergency_services_task(task: str, analysis_results: Dict[str, Any]) -> str:
886
+ """Handle emergency services analysis task"""
887
+ response = "## Emergency Services Analysis\n\n"
888
+
889
+ if "emergency_services" not in analysis_results:
890
+ return response + "No emergency services data available"
891
+
892
+ emergency = analysis_results["emergency_services"]
893
+
894
+ # Total ER visits
895
+ if "total_er_visits" in emergency:
896
+ response += f"**Total ER Visits**: {emergency['total_er_visits']:,}\n\n"
897
+
898
+ # ER utilization
899
+ if "er_utilization" in emergency:
900
+ response += "### ER Utilization Metrics\n\n"
901
+ response += "| Metric | Value |\n"
902
+ response += "|--------|-------|\n"
903
+ for metric, value in emergency["er_utilization"].items():
904
+ if isinstance(value, float):
905
+ response += f"| {metric.replace('_', ' ').title()} | {value:.1f} |\n"
906
+ else:
907
+ response += f"| {metric.replace('_', ' ').title()} | {value} |\n"
908
+ response += "\n"
909
 
910
+ # Wait times
911
+ if "er_wait_times" in emergency:
912
+ response += "### ER Wait Times\n\n"
913
+ response += "| Triage Level | Average Wait (Hours) | Target Wait (Hours) |\n"
914
+ response += "|--------------|---------------------|---------------------|\n"
915
+ for level, data in emergency["er_wait_times"].items():
916
+ current = data.get("current_wait", 0)
917
+ target = data.get("target_wait", 0)
918
+ response += f"| {level} | {current:.1f} | {target:.1f} |\n"
919
+ response += "\n"
920
 
921
+ return response
922
+
923
+ @staticmethod
924
+ def _handle_specialized_care_task(task: str, analysis_results: Dict[str, Any]) -> str:
925
+ """Handle specialized care analysis task"""
926
+ response = "## Specialized Care Analysis\n\n"
927
+
928
+ if "specialized_care" not in analysis_results:
929
+ return response + "No specialized care data available"
930
+
931
+ specialized = analysis_results["specialized_care"]
932
+
933
+ # Total specialized facilities
934
+ if "total_specialized_facilities" in specialized:
935
+ response += f"**Total Specialized Facilities**: {specialized['total_specialized_facilities']:,}\n\n"
936
+
937
+ # Services by specialty
938
+ if "services_by_specialty" in specialized:
939
+ response += "### Services by Specialty\n\n"
940
+ response += "| Specialty | Facility Count | Patient Volume | Wait Time (Days) |\n"
941
+ response += "|-----------|----------------|----------------|-----------------|\n"
942
+ for specialty, data in specialized["services_by_specialty"].items():
943
+ count = data.get("facility_count", 0)
944
+ volume = data.get("patient_volume", 0)
945
+ wait_time = data.get("wait_time_days", 0)
946
+ response += f"| {specialty} | {count} | {volume:,} | {wait_time:.1f} |\n"
947
+ response += "\n"
948
+
949
+ # Access metrics
950
+ if "access_metrics" in specialized:
951
+ response += "### Access Metrics\n\n"
952
+ response += "| Metric | Value |\n"
953
+ response += "|--------|-------|\n"
954
+ for metric, value in specialized["access_metrics"].items():
955
+ if isinstance(value, float):
956
+ response += f"| {metric.replace('_', ' ').title()} | {value:.1f} |\n"
957
+ else:
958
+ response += f"| {metric.replace('_', ' ').title()} | {value} |\n"
959
+ response += "\n"
960
+
961
+ return response
962
+
963
+ @staticmethod
964
+ def _handle_preventive_care_task(task: str, analysis_results: Dict[str, Any]) -> str:
965
+ """Handle preventive care analysis task"""
966
+ response = "## Preventive Care Analysis\n\n"
967
+
968
+ if "preventive_care" not in analysis_results:
969
+ return response + "No preventive care data available"
970
+
971
+ preventive = analysis_results["preventive_care"]
972
+
973
+ # Screening coverage
974
+ if "screening_coverage" in preventive:
975
+ response += "### Screening Coverage Rates\n\n"
976
+ response += "| Screening Type | Coverage Rate | Target |\n"
977
+ response += "|----------------|---------------|--------|\n"
978
+ for screening, data in preventive["screening_coverage"].items():
979
+ current = data.get("current_rate", 0)
980
+ target = data.get("target_rate", 0)
981
+ response += f"| {screening} | {current:.1%} | {target:.1%} |\n"
982
+ response += "\n"
983
+
984
+ # Vaccination rates
985
+ if "vaccination_rates" in preventive:
986
+ response += "### Vaccination Rates\n\n"
987
+ response += "| Vaccine | Coverage Rate | Herd Immunity Threshold |\n"
988
+ response += "|---------|---------------|------------------------|\n"
989
+ for vaccine, data in preventive["vaccination_rates"].items():
990
+ coverage = data.get("coverage_rate", 0)
991
+ threshold = data.get("herd_immunity_threshold", 0)
992
+ status = "✅ Achieved" if coverage >= threshold else "❌ Not Achieved"
993
+ response += f"| {vaccine} | {coverage:.1%} | {threshold:.1%} | {status} |\n"
994
+ response += "\n"
995
+
996
+ # Wellness programs
997
+ if "wellness_programs" in preventive:
998
+ response += "### Wellness Program Participation\n\n"
999
+ response += "| Program | Participants | Completion Rate |\n"
1000
+ response += "|---------|-------------|-----------------|\n"
1001
+ for program, data in preventive["wellness_programs"].items():
1002
+ participants = data.get("participants", 0)
1003
+ completion = data.get("completion_rate", 0)
1004
+ response += f"| {program} | {participants:,} | {completion:.1%} |\n"
1005
+ response += "\n"
1006
+
1007
+ return response
1008
+
1009
+ @staticmethod
1010
+ def _handle_telehealth_task(task: str, analysis_results: Dict[str, Any]) -> str:
1011
+ """Handle telehealth analysis task"""
1012
+ response = "## Telehealth Analysis\n\n"
1013
+
1014
+ if "telehealth" not in analysis_results:
1015
+ return response + "No telehealth data available"
1016
+
1017
+ telehealth = analysis_results["telehealth"]
1018
+
1019
+ # Total virtual visits
1020
+ if "total_virtual_visits" in telehealth:
1021
+ response += f"**Total Virtual Visits**: {telehealth['total_virtual_visits']:,}\n\n"
1022
+
1023
+ # Adoption metrics
1024
+ if "adoption_metrics" in telehealth:
1025
+ response += "### Telehealth Adoption Metrics\n\n"
1026
+ response += "| Metric | Value |\n"
1027
+ response += "|--------|-------|\n"
1028
+ for metric, value in telehealth["adoption_metrics"].items():
1029
+ if isinstance(value, float):
1030
+ response += f"| {metric.replace('_', ' ').title()} | {value:.1f} |\n"
1031
+ else:
1032
+ response += f"| {metric.replace('_', ' ').title()} | {value} |\n"
1033
+ response += "\n"
1034
+
1035
+ # Satisfaction
1036
+ if "patient_satisfaction" in telehealth:
1037
+ response += "### Patient Satisfaction with Telehealth\n\n"
1038
+ response += "| Aspect | Satisfaction Score |\n"
1039
+ response += "|--------|-------------------|\n"
1040
+ for aspect, score in telehealth["patient_satisfaction"].items():
1041
+ response += f"| {aspect} | {score:.1f}/5.0 |\n"
1042
+ response += "\n"
1043
+
1044
+ return response
1045
+
1046
+ @staticmethod
1047
+ def _handle_research_task(task: str, analysis_results: Dict[str, Any]) -> str:
1048
+ """Handle research and innovation analysis task"""
1049
+ response = "## Research and Innovation Analysis\n\n"
1050
+
1051
+ if "research_innovation" not in analysis_results:
1052
+ return response + "No research and innovation data available"
1053
+
1054
+ research = analysis_results["research_innovation"]
1055
+
1056
+ # Active trials
1057
+ if "active_clinical_trials" in research:
1058
+ response += f"**Active Clinical Trials**: {research['active_clinical_trials']:,}\n\n"
1059
+
1060
+ # Research areas
1061
+ if "research_areas" in research:
1062
+ response += "### Research Focus Areas\n\n"
1063
+ response += "| Area | Number of Projects | Funding |\n"
1064
+ response += "|------|-------------------|---------|\n"
1065
+ for area, data in research["research_areas"].items():
1066
+ projects = data.get("projects", 0)
1067
+ funding = data.get("funding", 0)
1068
+ response += f"| {area} | {projects} | ${funding:,.2f} |\n"
1069
+ response += "\n"
1070
+
1071
+ # Innovation metrics
1072
+ if "innovation_metrics" in research:
1073
+ response += "### Innovation Metrics\n\n"
1074
+ response += "| Metric | Value |\n"
1075
+ response += "|--------|-------|\n"
1076
+ for metric, value in research["innovation_metrics"].items():
1077
+ if isinstance(value, float):
1078
+ response += f"| {metric.replace('_', ' ').title()} | {value:.1f} |\n"
1079
+ else:
1080
+ response += f"| {metric.replace('_', ' ').title()} | {value} |\n"
1081
+ response += "\n"
1082
+
1083
+ return response
1084
 
1085
  @staticmethod
1086
  def _generate_executive_summary(results: Dict[str, Any]) -> str:
 
1125
  response += f"- {task}\n"
1126
  response += "\n"
1127
 
1128
+ return response