Nikhil Pravin Pise commited on
Commit
ad2e847
·
1 Parent(s): aefac4f

Refactor: Improve code quality, security, and configuration

Browse files

- Remove redundant sys.path manipulation in agents and services
- Enhance CORS configuration with environment-based origin handling
- Improve error handling (no internal detail leakage)
- Fix environment variable handling in setup scripts (remove extra quotes)
- Update gitignore for external tools and course materials
- Correct clinical biomarker reference ranges
- Add comprehensive production upgrade plan
- Improve test configuration (HuggingFace deprecation filters)
- Add optional dependencies for evaluation tools
- Consolidate path initialization patterns

.gitignore CHANGED
@@ -292,4 +292,6 @@ docker-compose.override.yml
292
  models/
293
 
294
  # Node modules (if any JS tooling)
295
- node_modules/
 
 
 
292
  models/
293
 
294
  # Node modules (if any JS tooling)
295
+ node_modules/
296
+ .agents/
297
+ production-agentic-rag-course/
api/app/main.py CHANGED
@@ -78,13 +78,14 @@ app = FastAPI(
78
  # CORS MIDDLEWARE
79
  # ============================================================================
80
 
81
- # Allow all origins (for MVP - can restrict later)
 
82
  app.add_middleware(
83
  CORSMiddleware,
84
- allow_origins=["*"], # Allows all origins
85
- allow_credentials=True,
86
- allow_methods=["*"], # Allows all methods
87
- allow_headers=["*"], # Allows all headers
88
  )
89
 
90
 
@@ -109,15 +110,14 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE
109
 
110
  @app.exception_handler(Exception)
111
  async def general_exception_handler(request: Request, exc: Exception):
112
- """Handle unexpected errors"""
113
  logger.error(f"Unhandled exception: {exc}", exc_info=True)
114
  return JSONResponse(
115
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
116
  content={
117
  "status": "error",
118
  "error_code": "INTERNAL_SERVER_ERROR",
119
- "message": "An unexpected error occurred",
120
- "details": str(exc)
121
  }
122
  )
123
 
 
78
  # CORS MIDDLEWARE
79
  # ============================================================================
80
 
81
+ # CORS configuration restrict to known origins in production
82
+ _allowed_origins = os.getenv("CORS_ALLOWED_ORIGINS", "*").split(",")
83
  app.add_middleware(
84
  CORSMiddleware,
85
+ allow_origins=_allowed_origins,
86
+ allow_credentials=_allowed_origins != ["*"], # credentials only with explicit origins
87
+ allow_methods=["*"],
88
+ allow_headers=["*"],
89
  )
90
 
91
 
 
110
 
111
  @app.exception_handler(Exception)
112
  async def general_exception_handler(request: Request, exc: Exception):
113
+ """Handle unexpected errors — never leak internal details to the client."""
114
  logger.error(f"Unhandled exception: {exc}", exc_info=True)
115
  return JSONResponse(
116
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
117
  content={
118
  "status": "error",
119
  "error_code": "INTERNAL_SERVER_ERROR",
120
+ "message": "An unexpected error occurred. Please try again later."
 
121
  }
122
  )
123
 
api/app/services/extraction.py CHANGED
@@ -8,8 +8,10 @@ import sys
8
  from pathlib import Path
9
  from typing import Dict, Any, Tuple
10
 
11
- # Add parent paths for imports
12
- sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
 
 
13
 
14
  from langchain_core.prompts import ChatPromptTemplate
15
  from src.biomarker_normalization import normalize_biomarker_name
 
8
  from pathlib import Path
9
  from typing import Dict, Any, Tuple
10
 
11
+ # Ensure project root is in path for src imports
12
+ _project_root = str(Path(__file__).parent.parent.parent.parent)
13
+ if _project_root not in sys.path:
14
+ sys.path.insert(0, _project_root)
15
 
16
  from langchain_core.prompts import ChatPromptTemplate
17
  from src.biomarker_normalization import normalize_biomarker_name
api/app/services/ragbot.py CHANGED
@@ -10,8 +10,10 @@ from pathlib import Path
10
  from typing import Dict, Any
11
  from datetime import datetime
12
 
13
- # Add parent directory to path for imports
14
- sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
 
 
15
 
16
  from src.workflow import create_guild
17
  from src.state import PatientInput
@@ -42,16 +44,18 @@ class RagBotService:
42
  print("INFO: Initializing RagBot workflow...")
43
  start_time = time.time()
44
 
45
- # Save current directory
46
  import os
47
- original_dir = os.getcwd()
48
 
49
  try:
50
- # Change to RagBot root (parent of api directory)
51
- # This ensures vector store paths resolve correctly
52
  ragbot_root = Path(__file__).parent.parent.parent.parent
 
 
 
 
 
53
  os.chdir(ragbot_root)
54
- print(f"INFO: Working directory: {ragbot_root}")
55
 
56
  self.guild = create_guild()
57
  self.initialized = True
 
10
  from typing import Dict, Any
11
  from datetime import datetime
12
 
13
+ # Ensure project root is in path for src imports
14
+ _project_root = str(Path(__file__).parent.parent.parent.parent)
15
+ if _project_root not in sys.path:
16
+ sys.path.insert(0, _project_root)
17
 
18
  from src.workflow import create_guild
19
  from src.state import PatientInput
 
44
  print("INFO: Initializing RagBot workflow...")
45
  start_time = time.time()
46
 
 
47
  import os
 
48
 
49
  try:
50
+ # Set working directory via environment so vector store paths resolve
51
+ # without a process-global os.chdir() (which is thread-unsafe).
52
  ragbot_root = Path(__file__).parent.parent.parent.parent
53
+ os.environ["RAGBOT_ROOT"] = str(ragbot_root)
54
+ print(f"INFO: Project root: {ragbot_root}")
55
+
56
+ # Temporarily chdir only during initialization (single-threaded at startup)
57
+ original_dir = os.getcwd()
58
  os.chdir(ragbot_root)
 
59
 
60
  self.guild = create_guild()
61
  self.initialized = True
api/requirements.txt CHANGED
@@ -3,7 +3,7 @@
3
 
4
  fastapi==0.109.0
5
  uvicorn[standard]==0.27.0
6
- pydantic==2.5.3
7
  python-multipart==0.0.6
8
 
9
  # CORS and middleware
 
3
 
4
  fastapi==0.109.0
5
  uvicorn[standard]==0.27.0
6
+ pydantic>=2.5.3
7
  python-multipart==0.0.6
8
 
9
  # CORS and middleware
config/biomarker_references.json CHANGED
@@ -15,13 +15,14 @@
15
  },
16
  "Cholesterol": {
17
  "unit": "mg/dL",
18
- "normal_range": {"min": 0, "max": 200},
19
- "critical_low": null,
20
  "critical_high": 240,
21
  "type": "total",
22
  "gender_specific": false,
23
  "description": "Total cholesterol level",
24
  "clinical_significance": {
 
25
  "high": "Increased cardiovascular disease risk"
26
  }
27
  },
@@ -177,7 +178,7 @@
177
  },
178
  "Triglycerides": {
179
  "unit": "mg/dL",
180
- "normal_range": {"min": 0, "max": 150},
181
  "critical_low": null,
182
  "critical_high": 500,
183
  "gender_specific": false,
@@ -188,7 +189,7 @@
188
  },
189
  "HbA1c": {
190
  "unit": "%",
191
- "normal_range": {"min": 0, "max": 5.7},
192
  "critical_low": null,
193
  "critical_high": 14,
194
  "gender_specific": false,
@@ -199,7 +200,7 @@
199
  },
200
  "LDL Cholesterol": {
201
  "unit": "mg/dL",
202
- "normal_range": {"min": 0, "max": 100},
203
  "critical_low": null,
204
  "critical_high": 190,
205
  "gender_specific": false,
@@ -211,10 +212,10 @@
211
  "HDL Cholesterol": {
212
  "unit": "mg/dL",
213
  "normal_range": {
214
- "male": {"min": 40, "max": 999},
215
- "female": {"min": 50, "max": 999}
216
  },
217
- "critical_low": 40,
218
  "critical_high": null,
219
  "gender_specific": true,
220
  "description": "High-density lipoprotein (good cholesterol)",
@@ -291,6 +292,231 @@
291
  "clinical_significance": {
292
  "high": "Acute inflammation or infection"
293
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
295
  }
296
  }
 
15
  },
16
  "Cholesterol": {
17
  "unit": "mg/dL",
18
+ "normal_range": {"min": 125, "max": 200},
19
+ "critical_low": 100,
20
  "critical_high": 240,
21
  "type": "total",
22
  "gender_specific": false,
23
  "description": "Total cholesterol level",
24
  "clinical_significance": {
25
+ "low": "Malnutrition, liver disease, or hyperthyroidism",
26
  "high": "Increased cardiovascular disease risk"
27
  }
28
  },
 
178
  },
179
  "Triglycerides": {
180
  "unit": "mg/dL",
181
+ "normal_range": {"min": 40, "max": 150},
182
  "critical_low": null,
183
  "critical_high": 500,
184
  "gender_specific": false,
 
189
  },
190
  "HbA1c": {
191
  "unit": "%",
192
+ "normal_range": {"min": 4.0, "max": 5.7},
193
  "critical_low": null,
194
  "critical_high": 14,
195
  "gender_specific": false,
 
200
  },
201
  "LDL Cholesterol": {
202
  "unit": "mg/dL",
203
+ "normal_range": {"min": 40, "max": 100},
204
  "critical_low": null,
205
  "critical_high": 190,
206
  "gender_specific": false,
 
212
  "HDL Cholesterol": {
213
  "unit": "mg/dL",
214
  "normal_range": {
215
+ "male": {"min": 40, "max": 100},
216
+ "female": {"min": 50, "max": 100}
217
  },
218
+ "critical_low": 25,
219
  "critical_high": null,
220
  "gender_specific": true,
221
  "description": "High-density lipoprotein (good cholesterol)",
 
292
  "clinical_significance": {
293
  "high": "Acute inflammation or infection"
294
  }
295
+ },
296
+ "Urea": {
297
+ "unit": "mg/dL",
298
+ "normal_range": {"min": 7, "max": 20},
299
+ "critical_low": null,
300
+ "critical_high": 50,
301
+ "gender_specific": false,
302
+ "description": "Blood urea nitrogen (kidney function marker)",
303
+ "clinical_significance": {
304
+ "high": "Kidney dysfunction, dehydration, or high-protein diet",
305
+ "low": "Liver disease or malnutrition"
306
+ }
307
+ },
308
+ "TSH": {
309
+ "unit": "mIU/L",
310
+ "normal_range": {"min": 0.4, "max": 4.0},
311
+ "critical_low": 0.1,
312
+ "critical_high": 10,
313
+ "gender_specific": false,
314
+ "description": "Thyroid-stimulating hormone",
315
+ "clinical_significance": {
316
+ "low": "Hyperthyroidism",
317
+ "high": "Hypothyroidism"
318
+ }
319
+ },
320
+ "T3": {
321
+ "unit": "ng/dL",
322
+ "normal_range": {"min": 80, "max": 200},
323
+ "critical_low": null,
324
+ "critical_high": null,
325
+ "gender_specific": false,
326
+ "description": "Triiodothyronine (thyroid hormone)",
327
+ "clinical_significance": {
328
+ "low": "Hypothyroidism",
329
+ "high": "Hyperthyroidism"
330
+ }
331
+ },
332
+ "T4": {
333
+ "unit": "μg/dL",
334
+ "normal_range": {"min": 5.0, "max": 12.0},
335
+ "critical_low": null,
336
+ "critical_high": null,
337
+ "gender_specific": false,
338
+ "description": "Thyroxine (thyroid hormone)",
339
+ "clinical_significance": {
340
+ "low": "Hypothyroidism",
341
+ "high": "Hyperthyroidism"
342
+ }
343
+ },
344
+ "Sodium": {
345
+ "unit": "mEq/L",
346
+ "normal_range": {"min": 136, "max": 145},
347
+ "critical_low": 120,
348
+ "critical_high": 155,
349
+ "gender_specific": false,
350
+ "description": "Blood sodium level (electrolyte)",
351
+ "clinical_significance": {
352
+ "low": "Hyponatremia - confusion, seizures",
353
+ "high": "Hypernatremia - dehydration, thirst"
354
+ }
355
+ },
356
+ "Potassium": {
357
+ "unit": "mEq/L",
358
+ "normal_range": {"min": 3.5, "max": 5.0},
359
+ "critical_low": 2.5,
360
+ "critical_high": 6.5,
361
+ "gender_specific": false,
362
+ "description": "Blood potassium level (electrolyte)",
363
+ "clinical_significance": {
364
+ "low": "Hypokalemia - muscle weakness, arrhythmia",
365
+ "high": "Hyperkalemia - cardiac arrest risk"
366
+ }
367
+ },
368
+ "Calcium": {
369
+ "unit": "mg/dL",
370
+ "normal_range": {"min": 8.5, "max": 10.5},
371
+ "critical_low": 7.0,
372
+ "critical_high": 12.0,
373
+ "gender_specific": false,
374
+ "description": "Blood calcium level",
375
+ "clinical_significance": {
376
+ "low": "Hypocalcemia - muscle cramps, numbness",
377
+ "high": "Hypercalcemia - kidney stones, bone pain"
378
+ }
379
+ },
380
+ "Chloride": {
381
+ "unit": "mEq/L",
382
+ "normal_range": {"min": 98, "max": 106},
383
+ "critical_low": 80,
384
+ "critical_high": 120,
385
+ "gender_specific": false,
386
+ "description": "Blood chloride level (electrolyte)",
387
+ "clinical_significance": {
388
+ "low": "Metabolic alkalosis",
389
+ "high": "Metabolic acidosis"
390
+ }
391
+ },
392
+ "Bicarbonate": {
393
+ "unit": "mEq/L",
394
+ "normal_range": {"min": 22, "max": 28},
395
+ "critical_low": 15,
396
+ "critical_high": 35,
397
+ "gender_specific": false,
398
+ "description": "Blood bicarbonate (acid-base balance)",
399
+ "clinical_significance": {
400
+ "low": "Metabolic acidosis",
401
+ "high": "Metabolic alkalosis"
402
+ }
403
+ },
404
+ "Uric_Acid": {
405
+ "unit": "mg/dL",
406
+ "normal_range": {
407
+ "male": {"min": 3.4, "max": 7.0},
408
+ "female": {"min": 2.4, "max": 6.0}
409
+ },
410
+ "critical_low": null,
411
+ "critical_high": 10,
412
+ "gender_specific": true,
413
+ "description": "Blood uric acid level",
414
+ "clinical_significance": {
415
+ "high": "Gout risk, kidney stone risk"
416
+ }
417
+ },
418
+ "Total_Protein": {
419
+ "unit": "g/dL",
420
+ "normal_range": {"min": 6.0, "max": 8.3},
421
+ "critical_low": 4.5,
422
+ "critical_high": null,
423
+ "gender_specific": false,
424
+ "description": "Total serum protein",
425
+ "clinical_significance": {
426
+ "low": "Liver disease, malnutrition, kidney disease",
427
+ "high": "Chronic inflammation, multiple myeloma"
428
+ }
429
+ },
430
+ "Albumin": {
431
+ "unit": "g/dL",
432
+ "normal_range": {"min": 3.5, "max": 5.5},
433
+ "critical_low": 2.0,
434
+ "critical_high": null,
435
+ "gender_specific": false,
436
+ "description": "Serum albumin (liver function)",
437
+ "clinical_significance": {
438
+ "low": "Liver disease, malnutrition, kidney disease"
439
+ }
440
+ },
441
+ "Globulin": {
442
+ "unit": "g/dL",
443
+ "normal_range": {"min": 2.0, "max": 3.5},
444
+ "critical_low": null,
445
+ "critical_high": null,
446
+ "gender_specific": false,
447
+ "description": "Serum globulin (immune proteins)",
448
+ "clinical_significance": {
449
+ "low": "Immune deficiency",
450
+ "high": "Chronic inflammation, liver disease"
451
+ }
452
+ },
453
+ "AG_Ratio": {
454
+ "unit": "ratio",
455
+ "normal_range": {"min": 1.1, "max": 2.5},
456
+ "critical_low": null,
457
+ "critical_high": null,
458
+ "gender_specific": false,
459
+ "description": "Albumin/Globulin ratio",
460
+ "clinical_significance": {
461
+ "low": "Liver disease, autoimmune conditions",
462
+ "high": "Generally not clinically significant"
463
+ }
464
+ },
465
+ "Bilirubin_Total": {
466
+ "unit": "mg/dL",
467
+ "normal_range": {"min": 0.1, "max": 1.2},
468
+ "critical_low": null,
469
+ "critical_high": 5.0,
470
+ "gender_specific": false,
471
+ "description": "Total bilirubin (liver function marker)",
472
+ "clinical_significance": {
473
+ "high": "Liver disease, bile duct obstruction, hemolysis"
474
+ }
475
+ },
476
+ "ALP": {
477
+ "unit": "U/L",
478
+ "normal_range": {"min": 44, "max": 147},
479
+ "critical_low": null,
480
+ "critical_high": 500,
481
+ "gender_specific": false,
482
+ "description": "Alkaline phosphatase (liver/bone enzyme)",
483
+ "clinical_significance": {
484
+ "high": "Liver disease, bone disorders, bile duct issues"
485
+ }
486
+ },
487
+ "BUN": {
488
+ "unit": "mg/dL",
489
+ "normal_range": {"min": 7, "max": 20},
490
+ "critical_low": null,
491
+ "critical_high": 50,
492
+ "gender_specific": false,
493
+ "description": "Blood urea nitrogen (kidney function)",
494
+ "clinical_significance": {
495
+ "high": "Kidney dysfunction, dehydration"
496
+ }
497
+ },
498
+ "BUN_Creatinine_Ratio": {
499
+ "unit": "ratio",
500
+ "normal_range": {"min": 10, "max": 20},
501
+ "critical_low": null,
502
+ "critical_high": null,
503
+ "gender_specific": false,
504
+ "description": "BUN to Creatinine ratio",
505
+ "clinical_significance": {
506
+ "high": "Pre-renal cause (dehydration, GI bleeding)",
507
+ "low": "Intrinsic renal disease, liver disease"
508
+ }
509
+ },
510
+ "VLDL": {
511
+ "unit": "mg/dL",
512
+ "normal_range": {"min": 2, "max": 30},
513
+ "critical_low": null,
514
+ "critical_high": null,
515
+ "gender_specific": false,
516
+ "description": "Very low-density lipoprotein cholesterol",
517
+ "clinical_significance": {
518
+ "high": "Increased cardiovascular risk"
519
+ }
520
  }
521
  }
522
  }
data/chat_reports/report_Diabetes_20260223_142525.json ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "timestamp": "20260223_142525",
3
+ "biomarkers_input": {
4
+ "Glucose": 140.0,
5
+ "HbA1c": 7.5
6
+ },
7
+ "final_response": {
8
+ "patient_summary": {
9
+ "total_biomarkers_tested": 2,
10
+ "biomarkers_in_normal_range": 0,
11
+ "biomarkers_out_of_range": 2,
12
+ "critical_values": 0,
13
+ "overall_risk_profile": "The patient's biomarker results indicate a high risk profile for diabetes, with both glucose and HbA1c levels exceeding normal ranges. The most concerning findings are the elevated glucose level of 140.0 mg/dL and HbA1c level of 7.5%, which suggest impaired glucose regulation. These results align with the predicted disease of diabetes, warranting further evaluation and potential intervention to manage blood sugar levels and prevent disease progression.",
14
+ "narrative": "Based on your test results, it's likely that you may have diabetes, with our system showing an 85% confidence level in this prediction. Your glucose and HbA1c levels, which are important indicators of blood sugar control, are higher than normal, suggesting that your body may be having trouble managing blood sugar. It's essential to discuss these results with your doctor, who can provide a definitive diagnosis and guidance on the next steps, and I want to reassure you that with proper care and management, many people with diabetes are able to lead healthy and active lives. Your doctor will be able to help you understand what these results mean for your health and develop a plan to help you manage your condition."
15
+ },
16
+ "prediction_explanation": {
17
+ "primary_disease": "Diabetes",
18
+ "confidence": 0.85,
19
+ "key_drivers": [
20
+ {
21
+ "biomarker": "Glucose",
22
+ "value": 140.0,
23
+ "contribution": "31%",
24
+ "explanation": "Your glucose level is 140.0 mg/dL, which is higher than normal, indicating that you may have hyperglycemia, a condition where there is too much sugar in the blood, a common characteristic of diabetes. This result suggests that you may be at risk for diabetes or may already have the condition, and further evaluation and management may be necessary to prevent complications.",
25
+ "evidence": "3 Prevention and management \nof complications of diabetes \nAcute complications of diabetes\nTwo important acute complications are hypoglycaemia and hyperglycaemic \nemergencies. Hypoglycaemia\nHypoglycae"
26
+ },
27
+ {
28
+ "biomarker": "HbA1c",
29
+ "value": 7.5,
30
+ "contribution": "31%",
31
+ "explanation": "Your HbA1c result of 7.5% is higher than the target level of 7%, which may indicate that your blood sugar levels are not well-controlled, suggesting a possible diagnosis of Type 2 Diabetes. This means that your body may not be producing or using insulin properly, leading to elevated blood glucose levels, and further evaluation and discussion with your doctor is needed to determine the best course of action.",
32
+ "evidence": "Diabetes (Type 2) \u2014 Extensive RAG Reference\nGenerated for MediGuard AI RAG-Helper \u007f 2025-11-22\n1. What diabetes is (focused on Type 2)\nDiabetes mellitus is a chronic metabolic disease characterized by"
33
+ }
34
+ ],
35
+ "mechanism_summary": "",
36
+ "pathophysiology": "Diabetes mellitus is a group of metabolic disorders characterized by the presence of hyperglycemia due to defects in insulin secretion, insulin action, or both. The underlying biological mechanisms involve impaired insulin secretion from the beta cells in the pancreas and/or impaired insulin action in the body's cells, leading to elevated blood glucose levels. This can result from a combination of genetic, environmental, and lifestyle factors, including insulin resistance, where the body's cells become less responsive to insulin, and a progressive beta-cell secretory defect, where the pancreas is unable to produce enough insulin to meet the body's needs.\n",
37
+ "pdf_references": [
38
+ "diabetes.pdf (Page 8)",
39
+ "diabetes.pdf (Page 4)",
40
+ "diabetes.pdf (Page 11)",
41
+ "MediGuard_Diabetes_Guidelines_Extensive.pdf (Page 0)",
42
+ "diabetes.pdf (Page 10)"
43
+ ]
44
+ },
45
+ "confidence_assessment": {
46
+ "prediction_reliability": "MODERATE",
47
+ "evidence_strength": "MODERATE",
48
+ "limitations": [
49
+ "Missing data: 41 biomarker(s) not provided",
50
+ "Multiple critical values detected; professional evaluation essential"
51
+ ],
52
+ "recommendation": "Moderate confidence prediction. Medical consultation recommended for professional evaluation and additional testing if needed.",
53
+ "assessment_summary": "The overall reliability of this prediction is moderate, indicating that while the 85% confidence from the ML model is notable, there are limitations and uncertainties that must be considered. The prediction is supported by moderate evidence strength, but the presence of two identified limitations suggests that key factors may not have been fully accounted for, introducing potential weaknesses. Therefore, it is essential to consult a professional medical practitioner to review the results, discuss uncertainties, and determine the best course of action to ensure accurate diagnosis and effective treatment.",
54
+ "alternative_diagnoses": [
55
+ {
56
+ "disease": "Anemia",
57
+ "probability": 0.08,
58
+ "note": "Consider discussing with healthcare provider"
59
+ }
60
+ ]
61
+ },
62
+ "safety_alerts": [
63
+ {
64
+ "severity": "MEDIUM",
65
+ "biomarker": "Glucose",
66
+ "message": "Glucose is 140.0 mg/dL, above normal range (70-100 mg/dL). Hyperglycemia - diabetes risk, requires further testing",
67
+ "action": "Consult with healthcare provider"
68
+ },
69
+ {
70
+ "severity": "MEDIUM",
71
+ "biomarker": "HbA1c",
72
+ "message": "HbA1c is 7.5 %, above normal range (4.0-5.7 %). Diabetes (\u00e2\u2030\u00a56.5%), Prediabetes (5.7-6.4%)",
73
+ "action": "Consult with healthcare provider"
74
+ }
75
+ ],
76
+ "metadata": {
77
+ "timestamp": "2026-02-23T14:03:55.540464",
78
+ "system_version": "MediGuard AI RAG-Helper v1.0",
79
+ "sop_version": "Baseline",
80
+ "agents_executed": [
81
+ "Biomarker Analyzer",
82
+ "Biomarker-Disease Linker",
83
+ "Clinical Guidelines",
84
+ "Disease Explainer",
85
+ "Confidence Assessor"
86
+ ],
87
+ "disclaimer": "This is an AI-assisted analysis tool for patient self-assessment. It is NOT a substitute for professional medical advice, diagnosis, or treatment. Always consult qualified healthcare providers for medical decisions."
88
+ },
89
+ "biomarker_flags": [
90
+ {
91
+ "name": "Glucose",
92
+ "value": 140.0,
93
+ "unit": "mg/dL",
94
+ "status": "HIGH",
95
+ "reference_range": "70-100 mg/dL",
96
+ "warning": "Glucose is 140.0 mg/dL, above normal range (70-100 mg/dL). Hyperglycemia - diabetes risk, requires further testing"
97
+ },
98
+ {
99
+ "name": "HbA1c",
100
+ "value": 7.5,
101
+ "unit": "%",
102
+ "status": "HIGH",
103
+ "reference_range": "4.0-5.7 %",
104
+ "warning": "HbA1c is 7.5 %, above normal range (4.0-5.7 %). Diabetes (\u00e2\u2030\u00a56.5%), Prediabetes (5.7-6.4%)"
105
+ }
106
+ ],
107
+ "key_drivers": [
108
+ {
109
+ "biomarker": "Glucose",
110
+ "value": 140.0,
111
+ "contribution": "31%",
112
+ "explanation": "Your glucose level is 140.0 mg/dL, which is higher than normal, indicating that you may have hyperglycemia, a condition where there is too much sugar in the blood, a common characteristic of diabetes. This result suggests that you may be at risk for diabetes or may already have the condition, and further evaluation and management may be necessary to prevent complications.",
113
+ "evidence": "3 Prevention and management \nof complications of diabetes \nAcute complications of diabetes\nTwo important acute complications are hypoglycaemia and hyperglycaemic \nemergencies. Hypoglycaemia\nHypoglycaemia (abnormally low blood glucose) is a frequent iatrogenic \ncomplication in diabetic patients, occurring particularly in patients receiving \nsulfonylurea or insulin. Introduction\nDefinition of diabetes\nDiabetes mellitus, commonly known as diabetes, is a group of metabolic disorders \ncharacterized b"
114
+ },
115
+ {
116
+ "biomarker": "HbA1c",
117
+ "value": 7.5,
118
+ "contribution": "31%",
119
+ "explanation": "Your HbA1c result of 7.5% is higher than the target level of 7%, which may indicate that your blood sugar levels are not well-controlled, suggesting a possible diagnosis of Type 2 Diabetes. This means that your body may not be producing or using insulin properly, leading to elevated blood glucose levels, and further evaluation and discussion with your doctor is needed to determine the best course of action.",
120
+ "evidence": "Diabetes (Type 2) \u2014 Extensive RAG Reference\nGenerated for MediGuard AI RAG-Helper \u007f 2025-11-22\n1. What diabetes is (focused on Type 2)\nDiabetes mellitus is a chronic metabolic disease characterized by elevated blood glucose due to impaired\ninsulin secretion, insulin action, or both. \u2022 The majority of patients can be expected to aim for an HbA1c of 7."
121
+ }
122
+ ],
123
+ "disease_explanation": {
124
+ "pathophysiology": "Diabetes mellitus is a group of metabolic disorders characterized by the presence of hyperglycemia due to defects in insulin secretion, insulin action, or both. The underlying biological mechanisms involve impaired insulin secretion from the beta cells in the pancreas and/or impaired insulin action in the body's cells, leading to elevated blood glucose levels. This can result from a combination of genetic, environmental, and lifestyle factors, including insulin resistance, where the body's cells become less responsive to insulin, and a progressive beta-cell secretory defect, where the pancreas is unable to produce enough insulin to meet the body's needs.\n",
125
+ "citations": [
126
+ "diabetes.pdf (Page 8)",
127
+ "diabetes.pdf (Page 4)",
128
+ "diabetes.pdf (Page 11)",
129
+ "MediGuard_Diabetes_Guidelines_Extensive.pdf (Page 0)",
130
+ "diabetes.pdf (Page 10)"
131
+ ],
132
+ "retrieved_chunks": null
133
+ },
134
+ "recommendations": {
135
+ "immediate_actions": [
136
+ "Consult a healthcare professional**: Given the high prediction confidence of 85.0% for diabetes and the presence of critical safety alerts (elevated glucose and HbA1c levels), it is essential to consult a healthcare professional for a definitive diagnosis and to discuss a personalized treatment plan.",
137
+ "Undergo further testing**: As indicated by the hyperglycemia and HbA1c levels, further testing is required to confirm the diagnosis of diabetes and to assess the severity of the condition."
138
+ ],
139
+ "lifestyle_changes": [
140
+ "Regular physical activity**: Engage in at least 150 minutes of moderate-intensity aerobic exercise, or 75 minutes of vigorous-intensity aerobic exercise, or a combination of both, per week. Additionally, incorporate strength-training exercises, high-intensity interval training, and other physical activities to improve insulin sensitivity.",
141
+ "Weight management**: If overweight or obese, aim to lose 5-10% of body weight to improve insulin sensitivity and reduce the risk of complications.",
142
+ "Stress management**: Practice stress-reducing techniques, such as meditation, yoga, or deep breathing exercises, to help manage stress and improve overall well-being.",
143
+ "Sleep and relaxation**: Ensure adequate sleep (7-8 hours per night) and practice relaxation techniques to help regulate blood glucose levels and overall health."
144
+ ],
145
+ "monitoring": [
146
+ "HbA1c testing**: Schedule regular HbA1c tests (every 3-6 months) to assess average blood glucose control over time.",
147
+ "Foot care and examination**: Regularly examine feet for any signs of damage or infection, and seek medical attention if any concerns arise.",
148
+ "Regular health check-ups**: Schedule regular health check-ups with a healthcare professional to monitor progress, adjust the treatment plan, and screen for potential complications.",
149
+ "Remember, it is essential to consult a healthcare professional for a definitive diagnosis and personalized treatment plan. These recommendations are meant to provide general guidance and support, but should not replace professional medical advice."
150
+ ],
151
+ "guideline_citations": [
152
+ "diabetes.pdf"
153
+ ]
154
+ },
155
+ "clinical_recommendations": {
156
+ "immediate_actions": [
157
+ "Consult a healthcare professional**: Given the high prediction confidence of 85.0% for diabetes and the presence of critical safety alerts (elevated glucose and HbA1c levels), it is essential to consult a healthcare professional for a definitive diagnosis and to discuss a personalized treatment plan.",
158
+ "Undergo further testing**: As indicated by the hyperglycemia and HbA1c levels, further testing is required to confirm the diagnosis of diabetes and to assess the severity of the condition."
159
+ ],
160
+ "lifestyle_changes": [
161
+ "Regular physical activity**: Engage in at least 150 minutes of moderate-intensity aerobic exercise, or 75 minutes of vigorous-intensity aerobic exercise, or a combination of both, per week. Additionally, incorporate strength-training exercises, high-intensity interval training, and other physical activities to improve insulin sensitivity.",
162
+ "Weight management**: If overweight or obese, aim to lose 5-10% of body weight to improve insulin sensitivity and reduce the risk of complications.",
163
+ "Stress management**: Practice stress-reducing techniques, such as meditation, yoga, or deep breathing exercises, to help manage stress and improve overall well-being.",
164
+ "Sleep and relaxation**: Ensure adequate sleep (7-8 hours per night) and practice relaxation techniques to help regulate blood glucose levels and overall health."
165
+ ],
166
+ "monitoring": [
167
+ "HbA1c testing**: Schedule regular HbA1c tests (every 3-6 months) to assess average blood glucose control over time.",
168
+ "Foot care and examination**: Regularly examine feet for any signs of damage or infection, and seek medical attention if any concerns arise.",
169
+ "Regular health check-ups**: Schedule regular health check-ups with a healthcare professional to monitor progress, adjust the treatment plan, and screen for potential complications.",
170
+ "Remember, it is essential to consult a healthcare professional for a definitive diagnosis and personalized treatment plan. These recommendations are meant to provide general guidance and support, but should not replace professional medical advice."
171
+ ],
172
+ "guideline_citations": [
173
+ "diabetes.pdf"
174
+ ]
175
+ },
176
+ "alternative_diagnoses": [
177
+ {
178
+ "disease": "Anemia",
179
+ "probability": 0.08,
180
+ "note": "Consider discussing with healthcare provider"
181
+ }
182
+ ],
183
+ "analysis": {
184
+ "biomarker_flags": [
185
+ {
186
+ "name": "Glucose",
187
+ "value": 140.0,
188
+ "unit": "mg/dL",
189
+ "status": "HIGH",
190
+ "reference_range": "70-100 mg/dL",
191
+ "warning": "Glucose is 140.0 mg/dL, above normal range (70-100 mg/dL). Hyperglycemia - diabetes risk, requires further testing"
192
+ },
193
+ {
194
+ "name": "HbA1c",
195
+ "value": 7.5,
196
+ "unit": "%",
197
+ "status": "HIGH",
198
+ "reference_range": "4.0-5.7 %",
199
+ "warning": "HbA1c is 7.5 %, above normal range (4.0-5.7 %). Diabetes (\u00e2\u2030\u00a56.5%), Prediabetes (5.7-6.4%)"
200
+ }
201
+ ],
202
+ "safety_alerts": [
203
+ {
204
+ "severity": "MEDIUM",
205
+ "biomarker": "Glucose",
206
+ "message": "Glucose is 140.0 mg/dL, above normal range (70-100 mg/dL). Hyperglycemia - diabetes risk, requires further testing",
207
+ "action": "Consult with healthcare provider"
208
+ },
209
+ {
210
+ "severity": "MEDIUM",
211
+ "biomarker": "HbA1c",
212
+ "message": "HbA1c is 7.5 %, above normal range (4.0-5.7 %). Diabetes (\u00e2\u2030\u00a56.5%), Prediabetes (5.7-6.4%)",
213
+ "action": "Consult with healthcare provider"
214
+ }
215
+ ],
216
+ "key_drivers": [
217
+ {
218
+ "biomarker": "Glucose",
219
+ "value": 140.0,
220
+ "contribution": "31%",
221
+ "explanation": "Your glucose level is 140.0 mg/dL, which is higher than normal, indicating that you may have hyperglycemia, a condition where there is too much sugar in the blood, a common characteristic of diabetes. This result suggests that you may be at risk for diabetes or may already have the condition, and further evaluation and management may be necessary to prevent complications.",
222
+ "evidence": "3 Prevention and management \nof complications of diabetes \nAcute complications of diabetes\nTwo important acute complications are hypoglycaemia and hyperglycaemic \nemergencies. Hypoglycaemia\nHypoglycaemia (abnormally low blood glucose) is a frequent iatrogenic \ncomplication in diabetic patients, occurring particularly in patients receiving \nsulfonylurea or insulin. Introduction\nDefinition of diabetes\nDiabetes mellitus, commonly known as diabetes, is a group of metabolic disorders \ncharacterized b"
223
+ },
224
+ {
225
+ "biomarker": "HbA1c",
226
+ "value": 7.5,
227
+ "contribution": "31%",
228
+ "explanation": "Your HbA1c result of 7.5% is higher than the target level of 7%, which may indicate that your blood sugar levels are not well-controlled, suggesting a possible diagnosis of Type 2 Diabetes. This means that your body may not be producing or using insulin properly, leading to elevated blood glucose levels, and further evaluation and discussion with your doctor is needed to determine the best course of action.",
229
+ "evidence": "Diabetes (Type 2) \u2014 Extensive RAG Reference\nGenerated for MediGuard AI RAG-Helper \u007f 2025-11-22\n1. What diabetes is (focused on Type 2)\nDiabetes mellitus is a chronic metabolic disease characterized by elevated blood glucose due to impaired\ninsulin secretion, insulin action, or both. \u2022 The majority of patients can be expected to aim for an HbA1c of 7."
230
+ }
231
+ ],
232
+ "disease_explanation": {
233
+ "pathophysiology": "Diabetes mellitus is a group of metabolic disorders characterized by the presence of hyperglycemia due to defects in insulin secretion, insulin action, or both. The underlying biological mechanisms involve impaired insulin secretion from the beta cells in the pancreas and/or impaired insulin action in the body's cells, leading to elevated blood glucose levels. This can result from a combination of genetic, environmental, and lifestyle factors, including insulin resistance, where the body's cells become less responsive to insulin, and a progressive beta-cell secretory defect, where the pancreas is unable to produce enough insulin to meet the body's needs.\n",
234
+ "citations": [
235
+ "diabetes.pdf (Page 8)",
236
+ "diabetes.pdf (Page 4)",
237
+ "diabetes.pdf (Page 11)",
238
+ "MediGuard_Diabetes_Guidelines_Extensive.pdf (Page 0)",
239
+ "diabetes.pdf (Page 10)"
240
+ ],
241
+ "retrieved_chunks": null
242
+ },
243
+ "recommendations": {
244
+ "immediate_actions": [
245
+ "Consult a healthcare professional**: Given the high prediction confidence of 85.0% for diabetes and the presence of critical safety alerts (elevated glucose and HbA1c levels), it is essential to consult a healthcare professional for a definitive diagnosis and to discuss a personalized treatment plan.",
246
+ "Undergo further testing**: As indicated by the hyperglycemia and HbA1c levels, further testing is required to confirm the diagnosis of diabetes and to assess the severity of the condition."
247
+ ],
248
+ "lifestyle_changes": [
249
+ "Regular physical activity**: Engage in at least 150 minutes of moderate-intensity aerobic exercise, or 75 minutes of vigorous-intensity aerobic exercise, or a combination of both, per week. Additionally, incorporate strength-training exercises, high-intensity interval training, and other physical activities to improve insulin sensitivity.",
250
+ "Weight management**: If overweight or obese, aim to lose 5-10% of body weight to improve insulin sensitivity and reduce the risk of complications.",
251
+ "Stress management**: Practice stress-reducing techniques, such as meditation, yoga, or deep breathing exercises, to help manage stress and improve overall well-being.",
252
+ "Sleep and relaxation**: Ensure adequate sleep (7-8 hours per night) and practice relaxation techniques to help regulate blood glucose levels and overall health."
253
+ ],
254
+ "monitoring": [
255
+ "HbA1c testing**: Schedule regular HbA1c tests (every 3-6 months) to assess average blood glucose control over time.",
256
+ "Foot care and examination**: Regularly examine feet for any signs of damage or infection, and seek medical attention if any concerns arise.",
257
+ "Regular health check-ups**: Schedule regular health check-ups with a healthcare professional to monitor progress, adjust the treatment plan, and screen for potential complications.",
258
+ "Remember, it is essential to consult a healthcare professional for a definitive diagnosis and personalized treatment plan. These recommendations are meant to provide general guidance and support, but should not replace professional medical advice."
259
+ ],
260
+ "guideline_citations": [
261
+ "diabetes.pdf"
262
+ ]
263
+ },
264
+ "confidence_assessment": {
265
+ "prediction_reliability": "MODERATE",
266
+ "evidence_strength": "MODERATE",
267
+ "limitations": [
268
+ "Missing data: 41 biomarker(s) not provided",
269
+ "Multiple critical values detected; professional evaluation essential"
270
+ ],
271
+ "recommendation": "Moderate confidence prediction. Medical consultation recommended for professional evaluation and additional testing if needed.",
272
+ "assessment_summary": "The overall reliability of this prediction is moderate, indicating that while the 85% confidence from the ML model is notable, there are limitations and uncertainties that must be considered. The prediction is supported by moderate evidence strength, but the presence of two identified limitations suggests that key factors may not have been fully accounted for, introducing potential weaknesses. Therefore, it is essential to consult a professional medical practitioner to review the results, discuss uncertainties, and determine the best course of action to ensure accurate diagnosis and effective treatment.",
273
+ "alternative_diagnoses": [
274
+ {
275
+ "disease": "Anemia",
276
+ "probability": 0.08,
277
+ "note": "Consider discussing with healthcare provider"
278
+ }
279
+ ]
280
+ },
281
+ "alternative_diagnoses": [
282
+ {
283
+ "disease": "Anemia",
284
+ "probability": 0.08,
285
+ "note": "Consider discussing with healthcare provider"
286
+ }
287
+ ]
288
+ }
289
+ },
290
+ "biomarker_flags": [
291
+ {
292
+ "name": "Glucose",
293
+ "value": 140.0,
294
+ "unit": "mg/dL",
295
+ "status": "HIGH",
296
+ "reference_range": "70-100 mg/dL",
297
+ "warning": "Glucose is 140.0 mg/dL, above normal range (70-100 mg/dL). Hyperglycemia - diabetes risk, requires further testing"
298
+ },
299
+ {
300
+ "name": "HbA1c",
301
+ "value": 7.5,
302
+ "unit": "%",
303
+ "status": "HIGH",
304
+ "reference_range": "4.0-5.7 %",
305
+ "warning": "HbA1c is 7.5 %, above normal range (4.0-5.7 %). Diabetes (\u00e2\u2030\u00a56.5%), Prediabetes (5.7-6.4%)"
306
+ }
307
+ ],
308
+ "safety_alerts": [
309
+ {
310
+ "severity": "MEDIUM",
311
+ "biomarker": "Glucose",
312
+ "message": "Glucose is 140.0 mg/dL, above normal range (70-100 mg/dL). Hyperglycemia - diabetes risk, requires further testing",
313
+ "action": "Consult with healthcare provider"
314
+ },
315
+ {
316
+ "severity": "MEDIUM",
317
+ "biomarker": "HbA1c",
318
+ "message": "HbA1c is 7.5 %, above normal range (4.0-5.7 %). Diabetes (\u00e2\u2030\u00a56.5%), Prediabetes (5.7-6.4%)",
319
+ "action": "Consult with healthcare provider"
320
+ }
321
+ ]
322
+ }
docs/plans/PRODUCTION_UPGRADE_PLAN.md ADDED
@@ -0,0 +1,833 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MediGuard AI — Production Upgrade Plan
2
+
3
+ ## From Prototype to Production-Grade MedTech RAG System
4
+
5
+ > **Generated**: 2026-02-23
6
+ > **Based on**: Deep review of production-agentic-rag-course (Weeks 1–7) + existing RagBot codebase
7
+ > **Goal**: Take the existing MediGuard AI (clinical biomarker analysis + RAG explanation system) to full production quality, applying every lesson from the arXiv Paper Curator course — adapted for the MedTech domain.
8
+
9
+ ---
10
+
11
+ ## Table of Contents
12
+
13
+ 1. [Executive Summary](#1-executive-summary)
14
+ 2. [Deep Review: Course vs. Your Codebase](#2-deep-review-course-vs-your-codebase)
15
+ 3. [Architecture Gap Analysis](#3-architecture-gap-analysis)
16
+ 4. [Phase 1: Infrastructure Foundation](#phase-1-infrastructure-foundation-week-1-equivalent)
17
+ 5. [Phase 2: Medical Data Ingestion Pipeline](#phase-2-medical-data-ingestion-pipeline-week-2-equivalent)
18
+ 6. [Phase 3: Production Search Foundation](#phase-3-production-search-foundation-week-3-equivalent)
19
+ 7. [Phase 4: Hybrid Search & Intelligent Chunking](#phase-4-hybrid-search--intelligent-chunking-week-4-equivalent)
20
+ 8. [Phase 5: Complete RAG Pipeline with Streaming](#phase-5-complete-rag-pipeline-with-streaming-week-5-equivalent)
21
+ 9. [Phase 6: Monitoring, Caching & Observability](#phase-6-monitoring-caching--observability-week-6-equivalent)
22
+ 10. [Phase 7: Agentic RAG & Messaging Bot](#phase-7-agentic-rag--messaging-bot-week-7-equivalent)
23
+ 11. [Phase 8: MedTech-Specific Additions](#phase-8-medtech-specific-additions-beyond-course)
24
+ 12. [Implementation Priority Matrix](#implementation-priority-matrix)
25
+ 13. [Migration Strategy](#migration-strategy)
26
+
27
+ ---
28
+
29
+ ## 1. Executive Summary
30
+
31
+ Your RagBot is a **working prototype** with strong domain logic (biomarker validation, multi-agent clinical analysis, 5D evaluation, SOP evolution). The course teaches **production infrastructure** (Docker orchestration, OpenSearch hybrid search, Airflow pipelines, Redis caching, Langfuse observability, LangGraph agentic workflows, Telegram bot).
32
+
33
+ **The strategy**: Keep your excellent medical domain logic and multi-agent architecture, but rebuild the infrastructure layer to match production standards. Your domain is *harder* than arXiv papers — medical data demands stricter validation, HIPAA-aware patterns, and safety guardrails.
34
+
35
+ ### What You Have (Strengths)
36
+ - ✅ 6 specialized medical agents (Biomarker Analyzer, Disease Explainer, Biomarker-Disease Linker, Clinical Guidelines, Confidence Assessor, Response Synthesizer)
37
+ - ✅ LangGraph orchestration with parallel execution
38
+ - ✅ Robust biomarker validation with 24 biomarkers, reference ranges, critical values
39
+ - ✅ 5D evaluation framework (Clinical Accuracy, Evidence Grounding, Actionability, Clarity, Safety)
40
+ - ✅ SOP evolution engine (Outer Loop optimization)
41
+ - ✅ Multi-provider LLM support (Groq, Gemini, Ollama)
42
+ - ✅ Basic FastAPI with analysis endpoints
43
+ - ✅ CLI chatbot with natural language biomarker extraction
44
+
45
+ ### What You're Missing (Gaps)
46
+ - ❌ No Docker Compose orchestration (only minimal single-service Dockerfile)
47
+ - ❌ No production database (PostgreSQL) — no patient/report persistence
48
+ - ❌ No production search engine — using FAISS (in-memory, single-file, no filtering)
49
+ - ❌ No chunking strategy — basic RecursiveCharacterTextSplitter only
50
+ - ❌ No hybrid search (BM25 + vector) — vector-only retrieval
51
+ - ❌ No production embeddings — using local HuggingFace MiniLM (384d) or Google free tier
52
+ - ❌ No data ingestion pipeline (Airflow) — manual PDF loading
53
+ - ❌ No caching layer (Redis) — every query hits LLM
54
+ - ❌ No observability (Langfuse) — no tracing, no cost tracking
55
+ - ❌ No streaming responses — synchronous only
56
+ - ❌ No Gradio interface — CLI only (besides basic API)
57
+ - ❌ No messaging bot (Telegram/WhatsApp) — no mobile access
58
+ - ❌ No agentic RAG with guardrails, document grading, query rewriting
59
+ - ❌ No proper dependency injection pattern (FastAPI `Depends()`)
60
+ - ❌ No Pydantic Settings with env-nested config
61
+ - ❌ No factory pattern for service initialization
62
+ - ❌ No proper exception hierarchy
63
+ - ❌ No health checks for all services
64
+ - ❌ No Makefile / dev tooling (ruff, mypy, pre-commit)
65
+ - ❌ No proper test infrastructure (pytest fixtures, test containers)
66
+
67
+ ---
68
+
69
+ ## 2. Deep Review: Course vs. Your Codebase
70
+
71
+ ### Course Architecture (What Production Looks Like)
72
+
73
+ ```
74
+ ┌──────────────────────────────────────────────────────────────┐
75
+ │ Docker Compose Orchestration │
76
+ ├──────────┬──────────┬──────────┬──────────┬─────────────────┤
77
+ │ FastAPI │PostgreSQL│OpenSearch│ Ollama │ Airflow │
78
+ │ (8000) │ (5432) │ (9200) │ (11434) │ (8080) │
79
+ ├──────────┼───���──────┼──────────┼──────────┼─────────────────┤
80
+ │ Redis │ Langfuse │ClickHouse│ MinIO │ Langfuse-PG │
81
+ │ (6379) │ (3001) │ │ │ (5433) │
82
+ ├──────────┴──────────┴──────────┴──────────┴─────────────────┤
83
+ │ Gradio UI (7861) │ Telegram Bot │
84
+ └──────────────────────────────────────────────────────────────┘
85
+ ```
86
+
87
+ **Key Patterns from Course:**
88
+ - **Pydantic Settings** with `env_nested_delimiter="__"` for hierarchical config
89
+ - **Factory pattern** (`make_*` functions) for every service
90
+ - **Dependency injection** via FastAPI `Depends()` with typed annotations
91
+ - **Lifespan context** for startup/shutdown with proper resource management
92
+ - **Service layer separation**: `routers/` → `services/` → `clients/`
93
+ - **Schema-driven**: Separate Pydantic schemas for API, database, embeddings, indexing
94
+ - **Exception hierarchy**: Domain-specific exceptions (`PDFParsingException`, `OllamaException`, etc.)
95
+ - **Context dataclass** for LangGraph runtime dependency injection
96
+ - **Structured LLM output** via `.with_structured_output(PydanticModel)`
97
+
98
+ ### Your Codebase Architecture (Current State)
99
+
100
+ ```
101
+ ┌─────────────────────────────────────────────┐
102
+ │ Basic FastAPI (api/app/) │
103
+ │ Single Dockerfile, no orchestration │
104
+ ├─────────────────────────────────────────────┤
105
+ │ src/ (Core Domain Logic) │
106
+ │ ┌─────────────────────────────────────┐ │
107
+ │ │ workflow.py (LangGraph StateGraph) │ │
108
+ │ │ 6 agents/ (parallel execution) │ │
109
+ │ │ biomarker_validator.py (24 markers) │ │
110
+ │ │ pdf_processor.py (FAISS + PyPDF) │ │
111
+ │ │ evaluation/ (5D framework) │ │
112
+ │ │ evolution/ (SOP optimization) │ │
113
+ │ └─────────────────────────────────────┘ │
114
+ ├─────────────────────────────────────────────┤
115
+ │ FAISS vector store (single file) │
116
+ │ No PostgreSQL, No Redis, No OpenSearch │
117
+ └─────────────────────────────────────────────┘
118
+ ```
119
+
120
+ ---
121
+
122
+ ## 3. Architecture Gap Analysis
123
+
124
+ | Dimension | Course (Production) | Your Codebase (Prototype) | Gap Severity |
125
+ |-----------|-------------------|--------------------------|--------------|
126
+ | **Container Orchestration** | Docker Compose with 12+ services, health checks, networks | Single Dockerfile, manual startup | 🔴 Critical |
127
+ | **Database** | PostgreSQL 16 with SQLAlchemy models, repositories | None (in-memory only) | 🔴 Critical |
128
+ | **Search Engine** | OpenSearch 2.19 with BM25 + KNN hybrid, RRF fusion | FAISS (vector-only, no filtering) | 🔴 Critical |
129
+ | **Chunking** | Section-aware chunking (600w, 100w overlap, metadata) | Basic RecursiveCharacterTextSplitter (1000 char) | 🟡 Major |
130
+ | **Embeddings** | Jina AI v3 (1024d, passage/query differentiation) | HuggingFace MiniLM (384d) or Google free tier | 🟡 Major |
131
+ | **Data Pipeline** | Airflow DAGs (daily schedule, fetch→parse→chunk→index) | Manual PDF loading, one-time setup | 🟡 Major |
132
+ | **Caching** | Redis with TTL, exact-match, SHA256 keys | None | 🟡 Major |
133
+ | **Observability** | Langfuse v3 (traces, spans, generations, cost tracking) | None (print statements only) | 🟡 Major |
134
+ | **Streaming** | SSE streaming with Gradio UI | None (synchronous responses) | 🟡 Major |
135
+ | **Agentic RAG** | LangGraph with guardrails, grading, rewriting, context_schema | Basic LangGraph (no guardrails, no grading) | 🟡 Major |
136
+ | **Bot Integration** | Telegram bot with /search, Q&A, caching | None | 🟢 Enhancement |
137
+ | **Config Management** | Pydantic Settings, hierarchical env vars, frozen models | Basic os.getenv, dotenv | 🟡 Major |
138
+ | **Dependency Injection** | FastAPI Depends() with typed annotations | Manual global singletons | 🟡 Major |
139
+ | **Error Handling** | Domain exception hierarchy, graceful fallbacks | Basic try/except with prints | 🟡 Major |
140
+ | **Code Quality** | Ruff, MyPy, pre-commit, pytest with fixtures | Minimal pytest, no linting | 🟢 Enhancement |
141
+ | **API Design** | Versioned (/api/v1/), health checks for all services | Basic routes, minimal health check | 🟡 Major |
142
+
143
+ ---
144
+
145
+ ## Phase 1: Infrastructure Foundation (Week 1 Equivalent)
146
+
147
+ > **Goal**: Containerize everything, add PostgreSQL for persistence, set up OpenSearch, establish professional development environment.
148
+
149
+ ### 1.1 Docker Compose Orchestration
150
+
151
+ Create a production `docker-compose.yml` with all services:
152
+
153
+ ```yaml
154
+ # Target services for MediGuard AI:
155
+ services:
156
+ api: # FastAPI application (port 8000)
157
+ postgres: # Patient reports, analysis history (port 5432)
158
+ opensearch: # Medical document search engine (port 9200)
159
+ opensearch-dashboards: # Search UI (port 5601)
160
+ redis: # Response caching (port 6379)
161
+ ollama: # Local LLM for privacy-sensitive medical data (port 11434)
162
+ airflow: # Medical literature pipeline (port 8080)
163
+ langfuse-web: # Observability dashboard (port 3001)
164
+ langfuse-worker/postgres/redis/clickhouse/minio: # Langfuse infra
165
+ ```
166
+
167
+ **Tasks:**
168
+ - [ ] Create root `docker-compose.yml` adapting course pattern to MedTech services
169
+ - [ ] Create multi-stage `Dockerfile` using UV package manager (copy course pattern)
170
+ - [ ] Add health checks for every service (PostgreSQL, OpenSearch, Redis, Ollama)
171
+ - [ ] Set up Docker network `mediguard-network` with proper service dependencies
172
+ - [ ] Configure volume persistence for all data stores
173
+ - [ ] Create `.env.example` with all configuration variables documented
174
+
175
+ ### 1.2 Pydantic Settings Configuration
176
+
177
+ Replace scattered `os.getenv()` calls with hierarchical Pydantic Settings:
178
+
179
+ ```python
180
+ # New: src/config.py (course-inspired)
181
+ class MedicalPDFSettings(BaseConfigSettings): # PDF parser config
182
+ class ChunkingSettings(BaseConfigSettings): # Chunking parameters
183
+ class OpenSearchSettings(BaseConfigSettings): # Search engine config
184
+ class LangfuseSettings(BaseConfigSettings): # Observability config
185
+ class RedisSettings(BaseConfigSettings): # Cache config
186
+ class TelegramSettings(BaseConfigSettings): # Bot config
187
+ class BiomarkerSettings(BaseConfigSettings): # Biomarker thresholds
188
+ class Settings(BaseConfigSettings): # Root settings
189
+ ```
190
+
191
+ **Tasks:**
192
+ - [ ] Rewrite `src/config.py` — keep `ExplanationSOP` but add infrastructure settings classes
193
+ - [ ] Use `env_nested_delimiter="__"` for hierarchical environment variables
194
+ - [ ] Add `frozen=True` for immutable configuration
195
+ - [ ] Move all hardcoded values to environment variables with sensible defaults
196
+ - [ ] Create `get_settings()` factory with `@lru_cache`
197
+
198
+ ### 1.3 PostgreSQL Database Setup
199
+
200
+ Add persistent storage for analysis history — critical for medical audit trail:
201
+
202
+ ```python
203
+ # New models:
204
+ class PatientAnalysis(Base): # Store each analysis run
205
+ class AnalysisReport(Base): # Store final reports
206
+ class MedicalDocument(Base): # Track ingested medical PDFs
207
+ class BiomarkerReference(Base): # Biomarker reference ranges (currently JSON file)
208
+ ```
209
+
210
+ **Tasks:**
211
+ - [ ] Create `src/db/` package mirroring course pattern (factory, interfaces, postgresql)
212
+ - [ ] Define SQLAlchemy models for analysis history and medical documents
213
+ - [ ] Create repository pattern for data access
214
+ - [ ] Set up Alembic for database migrations
215
+ - [ ] Migrate `biomarker_references.json` to database (keep JSON as seed data)
216
+
217
+ ### 1.4 Project Structure Refactor
218
+
219
+ Reorganize to match production patterns:
220
+
221
+ ```
222
+ src/
223
+ ├── config.py # Pydantic Settings (hierarchical)
224
+ ├── main.py # FastAPI app with lifespan
225
+ ├── database.py # Database utilities
226
+ ├── dependencies.py # FastAPI dependency injection
227
+ ├── exceptions.py # Domain exception hierarchy
228
+ ├── middlewares.py # Request logging, timing
229
+ ├── db/ # Database layer
230
+ │ ├── factory.py
231
+ │ └── interfaces/
232
+ ├── models/ # SQLAlchemy models
233
+ │ ├── analysis.py
234
+ │ └── document.py
235
+ ├── repositories/ # Data access
236
+ │ ├── analysis.py
237
+ │ └── document.py
238
+ ├── routers/ # API endpoints
239
+ │ ├── analyze.py # Biomarker analysis
240
+ │ ├── ask.py # RAG Q&A (streaming + standard)
241
+ │ ├── health.py # Comprehensive health checks
242
+ │ └── search.py # Medical document search
243
+ ├── schemas/ # Pydantic request/response models
244
+ │ ├── api/
245
+ │ ├── medical/
246
+ │ └── embeddings/
247
+ ├── services/ # Business logic
248
+ │ ├── agents/ # Your 6 medical agents (KEEP!)
249
+ │ │ ├── biomarker_analyzer.py
250
+ │ │ ├── disease_explainer.py
251
+ │ │ ├── biomarker_linker.py
252
+ │ │ ├── clinical_guidelines.py
253
+ │ │ ├── confidence_assessor.py
254
+ │ │ ├── response_synthesizer.py
255
+ │ │ ├── agentic_rag.py # NEW: LangGraph agentic wrapper
256
+ │ │ ├── nodes/ # NEW: Guardrail, grading, rewriting
257
+ │ │ ├── state.py # Enhanced state
258
+ │ │ ├── context.py # Runtime dependency injection
259
+ │ │ └── prompts.py # Medical-domain prompts
260
+ │ ├── opensearch/ # NEW: Search engine client
261
+ │ ├── embeddings/ # NEW: Production embeddings
262
+ │ ├── cache/ # NEW: Redis caching
263
+ │ ├── langfuse/ # NEW: Observability
264
+ │ ├── ollama/ # NEW: Local LLM client
265
+ │ ├── indexing/ # NEW: Chunking + indexing
266
+ │ ├── pdf_parser/ # Enhanced: Use Docling
267
+ │ ├── telegram/ # NEW: Bot integration
268
+ │ └── biomarker/ # Extracted: validation + normalization
269
+ ├── evaluation/ # KEEP: 5D evaluation
270
+ └── evolution/ # KEEP: SOP evolution
271
+ ```
272
+
273
+ **Tasks:**
274
+ - [ ] Create the new directory structure
275
+ - [ ] Move API from `api/app/` into `src/` (single application)
276
+ - [ ] Create `exceptions.py` with medical-domain exception hierarchy
277
+ - [ ] Create `dependencies.py` with typed FastAPI dependency injection
278
+ - [ ] Create `main.py` with proper lifespan context manager
279
+
280
+ ### 1.5 Development Tooling
281
+
282
+ **Tasks:**
283
+ - [ ] Create `pyproject.toml` replacing `requirements.txt` (use UV)
284
+ - [ ] Create `Makefile` with start/stop/test/lint/format/health commands
285
+ - [ ] Add `ruff` for linting and formatting
286
+ - [ ] Add `mypy` for type checking
287
+ - [ ] Add `.pre-commit-config.yaml`
288
+ - [ ] Create `.env.example` and `.env.test`
289
+
290
+ ---
291
+
292
+ ## Phase 2: Medical Data Ingestion Pipeline (Week 2 Equivalent)
293
+
294
+ > **Goal**: Automated ingestion of medical PDFs, clinical guidelines, and reference documents with Airflow orchestration.
295
+
296
+ ### 2.1 Medical PDF Parser Upgrade
297
+
298
+ Replace basic PyPDF with Docling for better medical document handling:
299
+
300
+ **Tasks:**
301
+ - [ ] Create `src/services/pdf_parser/` with Docling integration (copy course pattern)
302
+ - [ ] Add medical-specific section detection (Abstract, Methods, Results, Discussion, Clinical Guidelines)
303
+ - [ ] Add table extraction for lab reference ranges
304
+ - [ ] Add validation: file size limits, page limits, PDF header check
305
+ - [ ] Add metadata extraction: title, authors, publication date, journal
306
+
307
+ ### 2.2 Medical Document Sources
308
+
309
+ Unlike arXiv (single API), medical literature comes from multiple sources:
310
+
311
+ **Tasks:**
312
+ - [ ] Create `src/services/medical_sources/` package
313
+ - [ ] Implement PubMed API client (free, rate-limited) for research papers
314
+ - [ ] Implement local PDF upload endpoint for clinical guidelines
315
+ - [ ] Implement reference document ingestion (WHO, CDC, ADA guidelines)
316
+ - [ ] Create document deduplication logic (by title hash + content fingerprint)
317
+ - [ ] Add `MedicalDocument` model tracking: source, parse status, indexing status
318
+
319
+ ### 2.3 Airflow Pipeline for Medical Literature
320
+
321
+ **Tasks:**
322
+ - [ ] Create `airflow/` directory with Dockerfile and entrypoint
323
+ - [ ] Create `airflow/dags/medical_ingestion.py` DAG:
324
+ - `setup_environment` → `fetch_new_documents` → `parse_pdfs` → `chunk_and_index` → `generate_report`
325
+ - [ ] Schedule: Daily at 6 AM for PubMed updates, on-demand for uploaded PDFs
326
+ - [ ] Add retry logic with exponential backoff
327
+ - [ ] Mount `src/` into Airflow container for shared code
328
+
329
+ ### 2.4 PostgreSQL Storage for Documents
330
+
331
+ **Tasks:**
332
+ - [ ] Create `MedicalDocument` model: id, title, source, source_type, authors, abstract, raw_text, sections, parse_status, indexed_at
333
+ - [ ] Create `PaperRepository` with CRUD + upsert + status tracking
334
+ - [ ] Track processing pipeline: `uploaded → parsed → chunked → indexed`
335
+ - [ ] Store parsed sections as JSON for re-indexing without re-parsing
336
+
337
+ ---
338
+
339
+ ## Phase 3: Production Search Foundation (Week 3 Equivalent)
340
+
341
+ > **Goal**: Replace FAISS with OpenSearch for production BM25 keyword search with medical-specific optimizations.
342
+
343
+ ### 3.1 OpenSearch Client
344
+
345
+ **Tasks:**
346
+ - [ ] Create `src/services/opensearch/` package (adapt course pattern)
347
+ - [ ] Implement `OpenSearchClient` with:
348
+ - Health check, index management, BM25 search, bulk indexing
349
+ - **Medical-specific**: Boost clinical term matches, support ICD-10 code filtering
350
+ - [ ] Create `QueryBuilder` with medical field boosting:
351
+ ```
352
+ fields: ["chunk_text^3", "title^2", "section_title^1.5", "abstract^1"]
353
+ ```
354
+ - [ ] Create `index_config_hybrid.py` with medical document mapping:
355
+ - Fields: chunk_text, title, authors, abstract, document_type (guideline/research/reference), condition_tags, publication_year
356
+
357
+ ### 3.2 Medical Document Index Mapping
358
+
359
+ ```python
360
+ MEDICAL_CHUNKS_MAPPING = {
361
+ "settings": {
362
+ "index.knn": True,
363
+ "analysis": {
364
+ "analyzer": {
365
+ "medical_analyzer": {
366
+ "type": "custom",
367
+ "tokenizer": "standard",
368
+ "filter": ["lowercase", "medical_synonyms", "stop", "snowball"]
369
+ }
370
+ }
371
+ }
372
+ },
373
+ "mappings": {
374
+ "properties": {
375
+ "chunk_text": {"type": "text", "analyzer": "medical_analyzer"},
376
+ "document_type": {"type": "keyword"}, # guideline, research, reference
377
+ "condition_tags": {"type": "keyword"}, # diabetes, anemia, etc.
378
+ "biomarkers_mentioned": {"type": "keyword"}, # Glucose, HbA1c, etc.
379
+ "embedding": {"type": "knn_vector", "dimension": 1024},
380
+ # ... more fields
381
+ }
382
+ }
383
+ }
384
+ ```
385
+
386
+ **Tasks:**
387
+ - [ ] Design medical-optimized OpenSearch mapping
388
+ - [ ] Add medical synonym analyzer (e.g., "diabetes mellitus" ↔ "DM", "HbA1c" ↔ "glycated hemoglobin")
389
+ - [ ] Create search endpoint `POST /api/v1/search` with filtering by document_type, condition_tags
390
+ - [ ] Implement BM25 search with medical field boosting
391
+ - [ ] Create index verification in startup lifespan
392
+
393
+ ---
394
+
395
+ ## Phase 4: Hybrid Search & Intelligent Chunking (Week 4 Equivalent)
396
+
397
+ > **Goal**: Section-aware chunking for medical documents + hybrid search (BM25 + semantic) with RRF fusion.
398
+
399
+ ### 4.1 Medical-Aware Text Chunking
400
+
401
+ **Tasks:**
402
+ - [ ] Create `src/services/indexing/text_chunker.py` adapting course's `TextChunker`:
403
+ - Section-aware chunking (detect: Introduction, Methods, Results, Discussion, Guidelines, References)
404
+ - Target: 600 words per chunk, 100 word overlap
405
+ - Medical metadata: section_title, biomarkers_mentioned, condition_tags
406
+ - [ ] Create `MedicalTextChunker` subclass with:
407
+ - Biomarker mention detection (scan for any of 24+ biomarker names)
408
+ - Condition tag extraction (diabetes, anemia, heart disease, etc.)
409
+ - Table-aware chunking (keep tables together)
410
+ - Reference section filtering (skip bibliography chunks)
411
+ - [ ] Create `HybridIndexingService` for chunk → embed → index pipeline
412
+
413
+ ### 4.2 Production Embeddings
414
+
415
+ **Tasks:**
416
+ - [ ] Create `src/services/embeddings/` with Jina AI client (1024d, passage/query differentiation)
417
+ - [ ] Add fallback chain: Jina → Google → HuggingFace
418
+ - [ ] Implement batch embedding for efficient indexing
419
+ - [ ] Track embedding model in chunk metadata for versioning
420
+
421
+ ### 4.3 Hybrid Search with RRF
422
+
423
+ **Tasks:**
424
+ - [ ] Implement `search_unified()` supporting: BM25-only, vector-only, hybrid modes
425
+ - [ ] Set up OpenSearch RRF (Reciprocal Rank Fusion) pipeline
426
+ - [ ] Create unified search endpoint `POST /api/v1/hybrid-search/`
427
+ - [ ] Add min_score filtering and result deduplication
428
+ - [ ] Benchmark: BM25 vs. vector vs. hybrid on medical queries
429
+
430
+ ---
431
+
432
+ ## Phase 5: Complete RAG Pipeline with Streaming (Week 5 Equivalent)
433
+
434
+ > **Goal**: Replace synchronous analysis with streaming RAG, add Gradio UI, optimize prompts.
435
+
436
+ ### 5.1 Ollama Client Upgrade
437
+
438
+ **Tasks:**
439
+ - [ ] Create `src/services/ollama/` package (adapt course pattern)
440
+ - [ ] Implement `OllamaClient` with:
441
+ - Health check, model listing, generate, streaming generate
442
+ - Usage metadata extraction (tokens, latency)
443
+ - LangChain integration: `get_langchain_model()` for structured output
444
+ - [ ] Create medical-specific RAG prompt templates:
445
+ - `rag_medical_system.txt` — optimized for medical explanation generation
446
+ - Structured output format for clinical responses
447
+ - [ ] Create `OllamaFactory` with `@lru_cache`
448
+
449
+ ### 5.2 Streaming RAG Endpoints
450
+
451
+ **Tasks:**
452
+ - [ ] Create `POST /api/v1/ask` — standard RAG with medical context retrieval
453
+ - [ ] Create `POST /api/v1/stream` — SSE streaming for real-time responses
454
+ - [ ] Create `POST /api/v1/analyze/stream` — streaming biomarker analysis
455
+ - [ ] Integrate with existing multi-agent pipeline:
456
+ ```
457
+ Query → Hybrid Search → Medical Chunks → Agent Pipeline → Streaming Response
458
+ ```
459
+
460
+ ### 5.3 Gradio Medical Interface
461
+
462
+ **Tasks:**
463
+ - [ ] Create `src/gradio_app.py` for interactive medical RAG:
464
+ - Biomarker input form (structured entry)
465
+ - Natural language input (free text)
466
+ - Streaming response display
467
+ - Search mode selector (BM25, hybrid, vector)
468
+ - Model selector
469
+ - Analysis history display
470
+ - [ ] Create `gradio_launcher.py` for easy startup
471
+ - [ ] Expose on port 7861
472
+
473
+ ### 5.4 Prompt Optimization
474
+
475
+ **Tasks:**
476
+ - [ ] Reduce prompt size by 60-80% (course achieved 80% reduction)
477
+ - [ ] Create focused medical prompts (separate: biomarker analysis, disease explanation, guidelines)
478
+ - [ ] Test prompt variants using 5D evaluation framework
479
+ - [ ] Store best prompts as SOP parameters (tie into evolution engine)
480
+
481
+ ---
482
+
483
+ ## Phase 6: Monitoring, Caching & Observability (Week 6 Equivalent)
484
+
485
+ > **Goal**: Add Langfuse tracing for the entire pipeline, Redis caching, and production monitoring.
486
+
487
+ ### 6.1 Langfuse Integration
488
+
489
+ **Tasks:**
490
+ - [ ] Create `src/services/langfuse/` package (adapt course pattern):
491
+ - `client.py` — LangfuseTracer wrapper with v3 SDK
492
+ - `factory.py` — cached tracer factory
493
+ - `tracer.py` — medical-specific RAGTracer with named steps
494
+ - [ ] Add spans for every pipeline step:
495
+ - `biomarker_validation` → `query_embedding` → `search_retrieval` → `agent_execution` → `response_synthesis`
496
+ - [ ] Track per-request metrics:
497
+ - Total latency, LLM tokens used, search results count, cache hit/miss, agent execution time
498
+ - [ ] Add Langfuse Docker services to docker-compose.yml
499
+ - [ ] Create trace visualization for medical analysis pipeline
500
+
501
+ ### 6.2 Redis Caching
502
+
503
+ **Tasks:**
504
+ - [ ] Create `src/services/cache/` package (adapt course pattern):
505
+ - Exact-match cache: SHA256(query + model + top_k + biomarkers) → cached response
506
+ - TTL: 6 hours for general queries, 1 hour for biomarker analysis (values may change)
507
+ - [ ] Add caching to:
508
+ - `/api/v1/ask` — cache RAG responses
509
+ - `/api/v1/analyze` — cache full analysis results
510
+ - Embeddings — cache frequently queried embeddings
511
+ - [ ] Add graceful fallback: cache miss → normal pipeline
512
+ - [ ] Track cache hit rates in Langfuse
513
+
514
+ ### 6.3 Production Health Dashboard
515
+
516
+ **Tasks:**
517
+ - [ ] Enhance `/api/v1/health` to check all services:
518
+ - PostgreSQL, OpenSearch, Redis, Ollama, Langfuse, Airflow
519
+ - [ ] Add `/api/v1/metrics` endpoint for operational metrics
520
+ - [ ] Create Langfuse dashboard for:
521
+ - Average response time, cache hit rate, error rate, token costs
522
+ - Per-agent execution times, search relevance scores
523
+
524
+ ---
525
+
526
+ ## Phase 7: Agentic RAG & Messaging Bot (Week 7 Equivalent)
527
+
528
+ > **Goal**: Wrap your multi-agent pipeline in a LangGraph agentic workflow with guardrails, document grading, and query rewriting. Add Telegram bot for mobile access.
529
+
530
+ ### 7.1 Agentic RAG Wrapper
531
+
532
+ This is the most impactful upgrade — it adds **intelligence around your existing agents**:
533
+
534
+ ```
535
+ User Query
536
+
537
+ [GUARDRAIL] ──── Is this a medical/biomarker question? ────→ [OUT OF SCOPE]
538
+ ↓ yes
539
+ [RETRIEVE] ──── Hybrid search for medical documents ────→ [TOOL: search]
540
+
541
+ [GRADE DOCUMENTS] ──── Are results relevant? ────→ [REWRITE QUERY] ──→ loop
542
+ ↓ yes
543
+ [CLINICAL ANALYSIS] ──── Your 6 medical agents ────→ structured analysis
544
+
545
+ [GENERATE RESPONSE] ──── Synthesize with citations ────→ final answer
546
+ ```
547
+
548
+ **Tasks:**
549
+ - [ ] Create `src/services/agents/agentic_rag.py` — `AgenticRAGService` class
550
+ - [ ] Create `src/services/agents/nodes/`:
551
+ - `guardrail_node.py` — Medical domain validation (score 0-100)
552
+ - In-scope: biomarker questions, disease queries, clinical guidelines
553
+ - Out-of-scope: non-medical, general knowledge, harmful content
554
+ - `retrieve_node.py` — Creates tool call with `max_retrieval_attempts`
555
+ - `grade_documents_node.py` — LLM evaluates medical relevance
556
+ - `rewrite_query_node.py` — LLM rewrites for better medical retrieval
557
+ - `generate_answer_node.py` — Uses your existing agent pipeline OR direct LLM
558
+ - `out_of_scope_node.py` — Polite medical-domain rejection
559
+ - [ ] Create `src/services/agents/state.py` — Enhanced state with guardrail_result, routing_decision, grading_results
560
+ - [ ] Create `src/services/agents/context.py` — Runtime context for dependency injection
561
+ - [ ] Create `src/services/agents/prompts.py` — Medical-specific prompts:
562
+ - Guardrail: "Is this about health/biomarkers/medical conditions?"
563
+ - Grading: "Does this medical document answer the clinical question?"
564
+ - Rewriting: "Improve this medical query for better document retrieval"
565
+ - Generation: "Synthesize medical findings with citations and safety caveats"
566
+ - [ ] Create `src/services/agents/tools.py` — Medical retriever tool wrapping OpenSearch
567
+ - [ ] Create `POST /api/v1/ask-agentic` endpoint
568
+ - [ ] Add Langfuse tracing to every node
569
+
570
+ ### 7.2 Medical Guardrails (Critical for MedTech)
571
+
572
+ Beyond the course's simple domain check, add medical-specific safety:
573
+
574
+ **Tasks:**
575
+ - [ ] **Input guardrails**:
576
+ - Detect harmful queries (self-harm, drug abuse guidance)
577
+ - Detect attempts to get diagnosis without proper data
578
+ - Validate biomarker values are physiologically plausible
579
+ - [ ] **Output guardrails**:
580
+ - Always include "consult your healthcare provider" disclaimer
581
+ - Never provide definitive diagnosis (always "suggests" / "may indicate")
582
+ - Flag critical biomarker values with immediate action advice
583
+ - Ensure safety_alerts are present for out-of-range values
584
+ - [ ] **Citation guardrails**:
585
+ - Ensure all medical claims have document citations
586
+ - Flag unsupported claims
587
+
588
+ ### 7.3 Telegram Bot Integration
589
+
590
+ **Tasks:**
591
+ - [ ] Create `src/services/telegram/` package (adapt course pattern)
592
+ - [ ] Implement bot commands:
593
+ - `/start` — Welcome with medical assistant introduction
594
+ - `/help` — Show capabilities and input format
595
+ - `/analyze <biomarker values>` — Quick biomarker analysis
596
+ - `/search <medical query>` — Search medical documents
597
+ - `/report` — Get last analysis as formatted report
598
+ - Free text — Full RAG Q&A about medical topics
599
+ - [ ] Add typing indicators and progress messages
600
+ - [ ] Integrate caching for repeated queries
601
+ - [ ] Add rate limiting (medical queries shouldn't be spammed)
602
+ - [ ] Create `TelegramFactory` gated by `TELEGRAM__ENABLED=true`
603
+
604
+ ### 7.4 Feedback Loop
605
+
606
+ **Tasks:**
607
+ - [ ] Create `POST /api/v1/feedback` endpoint (adapt from course)
608
+ - [ ] Integrate with Langfuse scoring
609
+ - [ ] Use feedback data to identify weak prompts → feed into SOP evolution engine
610
+
611
+ ---
612
+
613
+ ## Phase 8: MedTech-Specific Additions (Beyond Course)
614
+
615
+ > **Goal**: Things the course doesn't cover but your medical domain demands.
616
+
617
+ ### 8.1 HIPAA-Awareness Patterns
618
+
619
+ **Tasks:**
620
+ - [ ] Never log patient biomarker values in plain text
621
+ - [ ] Add request ID tracking without PII
622
+ - [ ] Create data retention policy (auto-delete analysis data after configurable period)
623
+ - [ ] Add audit logging for all analysis requests
624
+ - [ ] Document HIPAA compliance approach (even if not yet certified)
625
+
626
+ ### 8.2 Medical Safety Testing
627
+
628
+ **Tasks:**
629
+ - [ ] Create medical-specific test suite:
630
+ - Critical value detection tests (every critical biomarker)
631
+ - Guardrail rejection tests (non-medical queries)
632
+ - Citation completeness tests
633
+ - Safety disclaimer presence tests
634
+ - Biomarker normalization tests (already have some)
635
+ - [ ] Integrate 5D evaluation into CI pipeline
636
+ - [ ] Create test fixtures with realistic medical scenarios
637
+
638
+ ### 8.3 Evolution Engine Integration
639
+
640
+ **Tasks:**
641
+ - [ ] Wire SOP evolution engine to production metrics (Langfuse data)
642
+ - [ ] Create Airflow DAG for scheduled evolution cycles
643
+ - [ ] Store evolved SOPs in PostgreSQL with version tracking
644
+ - [ ] A/B test SOP variants using Langfuse trace comparison
645
+
646
+ ### 8.4 Multi-condition Support
647
+
648
+ **Tasks:**
649
+ - [ ] Extend condition coverage beyond current 5 diseases
650
+ - [ ] Add condition-specific retrieval strategies
651
+ - [ ] Create condition-specific chunking filters
652
+ - [ ] Support multi-condition analysis (comorbidities)
653
+
654
+ ---
655
+
656
+ ## Implementation Priority Matrix
657
+
658
+ | Priority | Phase | Effort | Impact | Dependencies |
659
+ |----------|-------|--------|--------|--------------|
660
+ | 🔴 P0 | 1.1 Docker Compose | 2 days | Critical | None |
661
+ | 🔴 P0 | 1.2 Pydantic Settings | 1 day | Critical | None |
662
+ | 🔴 P0 | 1.4 Project Restructure | 2 days | Critical | None |
663
+ | 🔴 P0 | 1.5 Dev Tooling | 0.5 day | Critical | 1.4 |
664
+ | 🔴 P0 | 1.3 PostgreSQL + Models | 2 days | Critical | 1.1, 1.4 |
665
+ | 🟡 P1 | 3.1 OpenSearch Client | 2 days | High | 1.1, 1.4 |
666
+ | 🟡 P1 | 3.2 Medical Index Mapping | 1 day | High | 3.1 |
667
+ | 🟡 P1 | 4.1 Medical Text Chunker | 2 days | High | 3.1 |
668
+ | 🟡 P1 | 4.2 Production Embeddings | 1 day | High | 4.1 |
669
+ | 🟡 P1 | 4.3 Hybrid Search + RRF | 1 day | High | 3.1, 4.2 |
670
+ | 🟡 P1 | 5.1 Ollama Client | 1 day | High | 1.4 |
671
+ | 🟡 P1 | 5.2 Streaming Endpoints | 1 day | High | 5.1, 4.3 |
672
+ | 🟡 P1 | 2.1 PDF Parser (Docling) | 1 day | High | 1.4 |
673
+ | 🟡 P1 | 7.1 Agentic RAG Wrapper | 3 days | High | 5.2, 4.3 |
674
+ | 🟡 P1 | 7.2 Medical Guardrails | 2 days | High | 7.1 |
675
+ | 🟢 P2 | 2.3 Airflow Pipeline | 2 days | Medium | 1.1, 2.1, 4.1 |
676
+ | 🟢 P2 | 5.3 Gradio Interface | 1 day | Medium | 5.2 |
677
+ | 🟢 P2 | 6.1 Langfuse Tracing | 2 days | Medium | 1.1, 5.2 |
678
+ | 🟢 P2 | 6.2 Redis Caching | 1 day | Medium | 1.1, 5.2 |
679
+ | 🟢 P2 | 6.3 Health Dashboard | 0.5 day | Medium | 6.1 |
680
+ | 🟢 P2 | 7.3 Telegram Bot | 2 days | Medium | 7.1, 6.2 |
681
+ | 🟢 P2 | 7.4 Feedback Loop | 0.5 day | Medium | 6.1 |
682
+ | 🔵 P3 | 2.2 Medical Sources | 2 days | Low | 2.1 |
683
+ | 🔵 P3 | 8.1 HIPAA Patterns | 1 day | Low | 1.3 |
684
+ | 🔵 P3 | 8.2 Safety Testing | 2 days | Low | 7.2 |
685
+ | 🔵 P3 | 8.3 Evolution Integration | 2 days | Low | 6.1, 2.3 |
686
+ | 🔵 P3 | 8.4 Multi-condition | 3 days | Low | 4.1 |
687
+
688
+ **Estimated Total: ~40 days of focused work**
689
+
690
+ ---
691
+
692
+ ## Migration Strategy
693
+
694
+ ### Step 1: Foundation (Week 1-2 of work)
695
+ 1. Restructure project layout → Phase 1.4
696
+ 2. Create Pydantic Settings → Phase 1.2
697
+ 3. Set up Docker Compose → Phase 1.1
698
+ 4. Add PostgreSQL with models → Phase 1.3
699
+ 5. Add dev tooling → Phase 1.5
700
+
701
+ ### Step 2: Search Engine (Week 2-3)
702
+ 6. Create OpenSearch client + medical mapping → Phase 3.1, 3.2
703
+ 7. Build medical text chunker → Phase 4.1
704
+ 8. Add production embeddings (Jina) → Phase 4.2
705
+ 9. Implement hybrid search + RRF → Phase 4.3
706
+ 10. Upgrade PDF parser to Docling → Phase 2.1
707
+
708
+ ### Step 3: RAG Pipeline (Week 3-4)
709
+ 11. Create Ollama client → Phase 5.1
710
+ 12. Add streaming endpoints → Phase 5.2
711
+ 13. Build agentic RAG wrapper → Phase 7.1
712
+ 14. Add medical guardrails → Phase 7.2
713
+ 15. Create Gradio interface → Phase 5.3
714
+
715
+ ### Step 4: Production Hardening (Week 4-5)
716
+ 16. Add Langfuse observability → Phase 6.1
717
+ 17. Add Redis caching → Phase 6.2
718
+ 18. Set up Airflow pipeline → Phase 2.3
719
+ 19. Build Telegram bot → Phase 7.3
720
+ 20. Add feedback loop → Phase 7.4
721
+
722
+ ### Step 5: Polish (Week 5-6)
723
+ 21. Health dashboard → Phase 6.3
724
+ 22. Medical safety testing → Phase 8.2
725
+ 23. HIPAA patterns → Phase 8.1
726
+ 24. Evolution engine integration → Phase 8.3
727
+
728
+ ### Key Migration Rules
729
+ - **Never break what works**: Keep all existing agents functional throughout
730
+ - **Test at every step**: Run existing tests after each phase
731
+ - **Incremental Docker**: Start with API + PostgreSQL, add services one at a time
732
+ - **Feature flags**: Gate new features (Telegram, Langfuse, Redis) behind settings
733
+ - **Backward compatibility**: Keep CLI chatbot working alongside new API
734
+
735
+ ---
736
+
737
+ ## Architecture Target State
738
+
739
+ ```
740
+ ┌─────────────────────────────────────────────────────────────────────────┐
741
+ │ Docker Compose Orchestration │
742
+ │ │
743
+ │ ┌──────────┐ ┌───────────┐ ┌───────────┐ ┌────────┐ ┌─────────┐ │
744
+ │ │ FastAPI │ │PostgreSQL │ │ OpenSearch │ │ Ollama │ │ Airflow │ │
745
+ │ │ + Gradio │ │ (reports, │ │ (hybrid │ │ (local │ │ (daily │ │
746
+ │ │ (8000, │ │ docs, │ │ medical │ │ LLM) │ │ ingest) │ │
747
+ │ │ 7861) │ │ history) │ │ search) │ │ │ │ │ │
748
+ │ └────┬─────┘ └─────┬─────┘ └─────┬─────┘ └───┬────┘ └────┬────┘ │
749
+ │ │ │ │ │ │ │
750
+ │ ┌────┴─────┐ ┌─────┴─────┐ ┌────┴────────────┴────────────┴──┐ │
751
+ │ │ Redis │ │ Langfuse │ │ mediguard-network │ │
752
+ │ │ (cache) │ │ (observe) │ └──────────────────────────────────┘ │
753
+ │ └──────────┘ └───────────┘ │
754
+ │ │
755
+ │ ┌──────────────────────────────────────────────────────────────────┐ │
756
+ │ │ Agentic RAG Pipeline │ │
757
+ │ │ │ │
758
+ │ │ Query → [Guardrail] → [Retrieve] → [Grade] → [6 Medical Agents] │ │
759
+ │ │ ↓ ↑ ↓ ↓ │ │
760
+ │ │ [Out of Scope] [Rewrite] [Generate] → Final Response │ │
761
+ │ │ │ │
762
+ │ │ Agents: Biomarker Analyzer │ Disease Explainer │ Linker │ │
763
+ │ │ Clinical Guidelines │ Confidence │ Synthesizer │ │
764
+ │ └──────────────────────────────────────────────────────────────────┘ │
765
+ │ │
766
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────────┐ │
767
+ │ │ Telegram Bot │ │ Gradio UI │ │ 5D Eval + SOP Evolution │ │
768
+ │ │ (mobile) │ │ (desktop) │ │ (self-improvement loop) │ │
769
+ │ └──────────────┘ └──────────────┘ └──────────────────────────────┘ │
770
+ └─────────────────────────────────────────────────────────────────────────┘
771
+ ```
772
+
773
+ ---
774
+
775
+ ## Files to Create (Summary)
776
+
777
+ | New File | Source of Inspiration |
778
+ |----------|----------------------|
779
+ | `docker-compose.yml` | Course `compose.yml` (adapted) |
780
+ | `Dockerfile` | Course `Dockerfile` (multi-stage UV) |
781
+ | `Makefile` | Course `Makefile` |
782
+ | `pyproject.toml` | Course `pyproject.toml` |
783
+ | `.pre-commit-config.yaml` | Course `.pre-commit-config.yaml` |
784
+ | `.env.example` | Course `.env.example` |
785
+ | `src/main.py` | Course `src/main.py` (lifespan pattern) |
786
+ | `src/config.py` | Course `src/config.py` + existing SOP config |
787
+ | `src/dependencies.py` | Course `src/dependencies.py` |
788
+ | `src/exceptions.py` | Course `src/exceptions.py` (medical exceptions) |
789
+ | `src/database.py` | Course `src/database.py` |
790
+ | `src/db/*` | Course `src/db/*` |
791
+ | `src/models/analysis.py` | New (medical domain) |
792
+ | `src/models/document.py` | Course `src/models/paper.py` (adapted) |
793
+ | `src/repositories/*` | Course `src/repositories/*` (adapted) |
794
+ | `src/routers/ask.py` | Course `src/routers/ask.py` |
795
+ | `src/routers/search.py` | Course `src/routers/hybrid_search.py` |
796
+ | `src/routers/health.py` | Course `src/routers/ping.py` (enhanced) |
797
+ | `src/schemas/*` | Course `src/schemas/*` (medical schemas) |
798
+ | `src/services/opensearch/*` | Course `src/services/opensearch/*` |
799
+ | `src/services/embeddings/*` | Course `src/services/embeddings/*` |
800
+ | `src/services/ollama/*` | Course `src/services/ollama/*` |
801
+ | `src/services/cache/*` | Course `src/services/cache/*` |
802
+ | `src/services/langfuse/*` | Course `src/services/langfuse/*` |
803
+ | `src/services/indexing/*` | Course `src/services/indexing/*` (medical chunks) |
804
+ | `src/services/pdf_parser/*` | Course `src/services/pdf_parser/*` |
805
+ | `src/services/telegram/*` | Course `src/services/telegram/*` |
806
+ | `src/services/agents/agentic_rag.py` | Course (adapted for medical agents) |
807
+ | `src/services/agents/nodes/*` | Course (medical guardrails) |
808
+ | `src/services/agents/context.py` | Course |
809
+ | `src/services/agents/prompts.py` | Course (medical prompts) |
810
+ | `src/gradio_app.py` | Course `src/gradio_app.py` (medical UI) |
811
+ | `airflow/dags/medical_ingestion.py` | Course `airflow/dags/arxiv_paper_ingestion.py` |
812
+
813
+ ## Files to Keep & Enhance
814
+
815
+ | Existing File | Action |
816
+ |---------------|--------|
817
+ | `src/agents/biomarker_analyzer.py` | Keep, move to `src/services/agents/medical/` |
818
+ | `src/agents/disease_explainer.py` | Keep, move, add OpenSearch retriever |
819
+ | `src/agents/biomarker_linker.py` | Keep, move, add OpenSearch retriever |
820
+ | `src/agents/clinical_guidelines.py` | Keep, move, add OpenSearch retriever |
821
+ | `src/agents/confidence_assessor.py` | Keep, move |
822
+ | `src/agents/response_synthesizer.py` | Keep, move |
823
+ | `src/biomarker_validator.py` | Keep, move to `src/services/biomarker/` |
824
+ | `src/biomarker_normalization.py` | Keep, move to `src/services/biomarker/` |
825
+ | `src/evaluation/` | Keep, enhance with Langfuse integration |
826
+ | `src/evolution/` | Keep, wire to production metrics |
827
+ | `config/biomarker_references.json` | Keep as seed data, migrate to DB |
828
+ | `scripts/chat.py` | Keep, update imports |
829
+ | `tests/*` | Keep, add production test fixtures |
830
+
831
+ ---
832
+
833
+ *This plan transforms MediGuard AI from a working prototype into a production-grade medical RAG system, applying every infrastructure lesson from the arXiv Paper Curator course while preserving and enhancing your unique medical domain logic.*
pytest.ini CHANGED
@@ -1,3 +1,4 @@
1
  [pytest]
2
  filterwarnings =
3
  ignore::langchain_core._api.deprecation.LangChainDeprecationWarning
 
 
1
  [pytest]
2
  filterwarnings =
3
  ignore::langchain_core._api.deprecation.LangChainDeprecationWarning
4
+ ignore:.*class.*HuggingFaceEmbeddings.*was deprecated.*:DeprecationWarning
requirements.txt CHANGED
@@ -30,3 +30,12 @@ python-dotenv>=1.0.0
30
  # Utilities
31
  numpy>=1.26.2
32
  matplotlib>=3.8.2
 
 
 
 
 
 
 
 
 
 
30
  # Utilities
31
  numpy>=1.26.2
32
  matplotlib>=3.8.2
33
+
34
+ # Optional: improved readability scoring for evaluations
35
+ textstat>=0.7.3
36
+
37
+ # Optional: HuggingFace embedding provider
38
+ # langchain-huggingface>=0.0.1
39
+
40
+ # Optional: Ollama local LLM provider
41
+ # langchain-ollama>=0.0.1
scripts/monitor_test.py CHANGED
@@ -1,6 +1,5 @@
1
  """Monitor evolution test progress"""
2
  import time
3
- import subprocess
4
 
5
  print("Monitoring evolution test... (Press Ctrl+C to stop)")
6
  print("=" * 70)
 
1
  """Monitor evolution test progress"""
2
  import time
 
3
 
4
  print("Monitoring evolution test... (Press Ctrl+C to stop)")
5
  print("=" * 70)
scripts/setup_embeddings.py CHANGED
@@ -52,19 +52,19 @@ def setup_google_api_key():
52
  updated = False
53
  for i, line in enumerate(lines):
54
  if line.startswith("GOOGLE_API_KEY="):
55
- lines[i] = f'GOOGLE_API_KEY="{api_key}"\n'
56
  updated = True
57
  break
58
 
59
  if not updated:
60
- lines.insert(0, f'GOOGLE_API_KEY="{api_key}"\n')
61
 
62
  with open(env_path, 'w') as f:
63
  f.writelines(lines)
64
  else:
65
  # Create new .env file
66
  with open(env_path, 'w') as f:
67
- f.write(f'GOOGLE_API_KEY="{api_key}"\n')
68
 
69
  print("\nAPI key saved to .env file!")
70
  print("\n" + "="*70)
 
52
  updated = False
53
  for i, line in enumerate(lines):
54
  if line.startswith("GOOGLE_API_KEY="):
55
+ lines[i] = f'GOOGLE_API_KEY={api_key}\n'
56
  updated = True
57
  break
58
 
59
  if not updated:
60
+ lines.insert(0, f'GOOGLE_API_KEY={api_key}\n')
61
 
62
  with open(env_path, 'w') as f:
63
  f.writelines(lines)
64
  else:
65
  # Create new .env file
66
  with open(env_path, 'w') as f:
67
+ f.write(f'GOOGLE_API_KEY={api_key}\n')
68
 
69
  print("\nAPI key saved to .env file!")
70
  print("\n" + "="*70)
src/agents/biomarker_analyzer.py CHANGED
@@ -3,10 +3,6 @@ MediGuard AI RAG-Helper
3
  Biomarker Analyzer Agent - Validates biomarker values and flags anomalies
4
  """
5
 
6
- import sys
7
- from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).parent.parent.parent))
9
-
10
  from typing import Dict, List
11
  from src.state import GuildState, AgentOutput, BiomarkerFlag
12
  from src.biomarker_validator import BiomarkerValidator
@@ -36,7 +32,7 @@ class BiomarkerAnalyzerAgent:
36
 
37
  biomarkers = state['patient_biomarkers']
38
  patient_context = state.get('patient_context', {})
39
- gender = patient_context.get('gender', 'male')
40
  predicted_disease = state['model_prediction']['disease']
41
 
42
  # Validate all biomarkers
 
3
  Biomarker Analyzer Agent - Validates biomarker values and flags anomalies
4
  """
5
 
 
 
 
 
6
  from typing import Dict, List
7
  from src.state import GuildState, AgentOutput, BiomarkerFlag
8
  from src.biomarker_validator import BiomarkerValidator
 
32
 
33
  biomarkers = state['patient_biomarkers']
34
  patient_context = state.get('patient_context', {})
35
+ gender = patient_context.get('gender') # None if not provided — uses non-gender-specific ranges
36
  predicted_disease = state['model_prediction']['disease']
37
 
38
  # Validate all biomarkers
src/agents/biomarker_linker.py CHANGED
@@ -3,10 +3,6 @@ MediGuard AI RAG-Helper
3
  Biomarker-Disease Linker Agent - Connects biomarker values to predicted disease
4
  """
5
 
6
- import sys
7
- from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).parent.parent.parent))
9
-
10
  from typing import Dict, List
11
  from src.state import GuildState, AgentOutput, KeyDriver
12
  from src.llm_config import llm_config
 
3
  Biomarker-Disease Linker Agent - Connects biomarker values to predicted disease
4
  """
5
 
 
 
 
 
6
  from typing import Dict, List
7
  from src.state import GuildState, AgentOutput, KeyDriver
8
  from src.llm_config import llm_config
src/agents/clinical_guidelines.py CHANGED
@@ -3,10 +3,7 @@ MediGuard AI RAG-Helper
3
  Clinical Guidelines Agent - Retrieves evidence-based recommendations
4
  """
5
 
6
- import sys
7
  from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).parent.parent.parent))
9
-
10
  from typing import List
11
  from src.state import GuildState, AgentOutput
12
  from src.llm_config import llm_config
 
3
  Clinical Guidelines Agent - Retrieves evidence-based recommendations
4
  """
5
 
 
6
  from pathlib import Path
 
 
7
  from typing import List
8
  from src.state import GuildState, AgentOutput
9
  from src.llm_config import llm_config
src/agents/confidence_assessor.py CHANGED
@@ -3,10 +3,6 @@ MediGuard AI RAG-Helper
3
  Confidence Assessor Agent - Evaluates prediction reliability
4
  """
5
 
6
- import sys
7
- from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).parent.parent.parent))
9
-
10
  from typing import Any, Dict, List
11
  from src.state import GuildState, AgentOutput
12
  from src.biomarker_validator import BiomarkerValidator
 
3
  Confidence Assessor Agent - Evaluates prediction reliability
4
  """
5
 
 
 
 
 
6
  from typing import Any, Dict, List
7
  from src.state import GuildState, AgentOutput
8
  from src.biomarker_validator import BiomarkerValidator
src/agents/disease_explainer.py CHANGED
@@ -3,10 +3,7 @@ MediGuard AI RAG-Helper
3
  Disease Explainer Agent - Retrieves disease pathophysiology from medical PDFs
4
  """
5
 
6
- import sys
7
  from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).parent.parent.parent))
9
-
10
  from src.state import GuildState, AgentOutput
11
  from src.llm_config import llm_config
12
  from langchain_core.prompts import ChatPromptTemplate
@@ -43,9 +40,10 @@ class DiseaseExplainerAgent:
43
  disease = model_prediction['disease']
44
  confidence = model_prediction['confidence']
45
 
46
- # Configure retrieval based on SOP (use copy to avoid mutating shared retriever)
47
  retrieval_k = state['sop'].disease_explainer_k
48
- self.retriever.search_kwargs = {**self.retriever.search_kwargs, 'k': retrieval_k}
 
49
 
50
  # Retrieve relevant documents
51
  print(f"\nRetrieving information about: {disease}")
@@ -54,7 +52,11 @@ class DiseaseExplainerAgent:
54
  query = f"""What is {disease}? Explain the pathophysiology, diagnostic criteria,
55
  and clinical presentation. Focus on mechanisms relevant to blood biomarkers."""
56
 
57
- docs = self.retriever.invoke(query)
 
 
 
 
58
 
59
  print(f"Retrieved {len(docs)} relevant document chunks")
60
 
 
3
  Disease Explainer Agent - Retrieves disease pathophysiology from medical PDFs
4
  """
5
 
 
6
  from pathlib import Path
 
 
7
  from src.state import GuildState, AgentOutput
8
  from src.llm_config import llm_config
9
  from langchain_core.prompts import ChatPromptTemplate
 
40
  disease = model_prediction['disease']
41
  confidence = model_prediction['confidence']
42
 
43
+ # Configure retrieval based on SOP create a copy to avoid mutating shared retriever
44
  retrieval_k = state['sop'].disease_explainer_k
45
+ original_search_kwargs = dict(self.retriever.search_kwargs)
46
+ self.retriever.search_kwargs = {**original_search_kwargs, 'k': retrieval_k}
47
 
48
  # Retrieve relevant documents
49
  print(f"\nRetrieving information about: {disease}")
 
52
  query = f"""What is {disease}? Explain the pathophysiology, diagnostic criteria,
53
  and clinical presentation. Focus on mechanisms relevant to blood biomarkers."""
54
 
55
+ try:
56
+ docs = self.retriever.invoke(query)
57
+ finally:
58
+ # Restore original search_kwargs to avoid side effects
59
+ self.retriever.search_kwargs = original_search_kwargs
60
 
61
  print(f"Retrieved {len(docs)} relevant document chunks")
62
 
src/agents/response_synthesizer.py CHANGED
@@ -3,10 +3,6 @@ MediGuard AI RAG-Helper
3
  Response Synthesizer Agent - Compiles all findings into final structured JSON
4
  """
5
 
6
- import sys
7
- from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).parent.parent.parent))
9
-
10
  import json
11
  from typing import Dict, List, Any
12
  from src.state import GuildState
 
3
  Response Synthesizer Agent - Compiles all findings into final structured JSON
4
  """
5
 
 
 
 
 
6
  import json
7
  from typing import Dict, List, Any
8
  from src.state import GuildState
src/biomarker_normalization.py CHANGED
@@ -76,6 +76,47 @@ NORMALIZATION_MAP: Dict[str, str] = {
76
 
77
  # Kidney
78
  "creatinine": "Creatinine",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
81
 
 
76
 
77
  # Kidney
78
  "creatinine": "Creatinine",
79
+
80
+ # Thyroid
81
+ "tsh": "TSH",
82
+ "thyroidstimulatinghormone": "TSH",
83
+ "t3": "T3",
84
+ "triiodothyronine": "T3",
85
+ "t4": "T4",
86
+ "thyroxine": "T4",
87
+
88
+ # Electrolytes
89
+ "sodium": "Sodium",
90
+ "na": "Sodium",
91
+ "potassium": "Potassium",
92
+ "k": "Potassium",
93
+ "calcium": "Calcium",
94
+ "ca": "Calcium",
95
+ "chloride": "Chloride",
96
+ "cl": "Chloride",
97
+ "bicarbonate": "Bicarbonate",
98
+ "hco3": "Bicarbonate",
99
+
100
+ # Kidney / Metabolic
101
+ "urea": "Urea",
102
+ "bun": "BUN",
103
+ "bloodureanitrogen": "BUN",
104
+ "buncreatinineratio": "BUN_Creatinine_Ratio",
105
+ "uricacid": "Uric_Acid",
106
+
107
+ # Liver / Protein
108
+ "totalprotein": "Total_Protein",
109
+ "albumin": "Albumin",
110
+ "globulin": "Globulin",
111
+ "agratio": "AG_Ratio",
112
+ "albuminglobulinratio": "AG_Ratio",
113
+ "bilirubintotal": "Bilirubin_Total",
114
+ "bilirubin": "Bilirubin_Total",
115
+ "alp": "ALP",
116
+ "alkalinephosphatase": "ALP",
117
+
118
+ # Lipids
119
+ "vldl": "VLDL",
120
  }
121
 
122
 
src/biomarker_validator.py CHANGED
@@ -162,6 +162,14 @@ class BiomarkerValidator:
162
  "Glucose", "HbA1c", "Insulin", "BMI",
163
  "Triglycerides", "HDL Cholesterol", "LDL Cholesterol"
164
  ],
 
 
 
 
 
 
 
 
165
  "Anemia": [
166
  "Hemoglobin", "Red Blood Cells", "Hematocrit",
167
  "Mean Corpuscular Volume", "Mean Corpuscular Hemoglobin",
 
162
  "Glucose", "HbA1c", "Insulin", "BMI",
163
  "Triglycerides", "HDL Cholesterol", "LDL Cholesterol"
164
  ],
165
+ "Type 2 Diabetes": [
166
+ "Glucose", "HbA1c", "Insulin", "BMI",
167
+ "Triglycerides", "HDL Cholesterol", "LDL Cholesterol"
168
+ ],
169
+ "Type 1 Diabetes": [
170
+ "Glucose", "HbA1c", "Insulin", "BMI",
171
+ "Triglycerides", "HDL Cholesterol", "LDL Cholesterol"
172
+ ],
173
  "Anemia": [
174
  "Hemoglobin", "Red Blood Cells", "Hematocrit",
175
  "Mean Corpuscular Volume", "Mean Corpuscular Hemoglobin",
src/evaluation/evaluators.py CHANGED
@@ -5,6 +5,7 @@ MediGuard AI RAG-Helper - Evaluation System
5
 
6
  from pydantic import BaseModel, Field
7
  from typing import Dict, Any, List
 
8
  from langchain_core.prompts import ChatPromptTemplate
9
  from src.llm_config import get_chat_model
10
 
@@ -93,14 +94,13 @@ Respond ONLY with valid JSON in this format:
93
  })
94
 
95
  # Parse JSON response
96
- import json
97
  try:
98
  content = result.content if isinstance(result.content, str) else str(result.content)
99
  parsed = json.loads(content)
100
  return GradedScore(score=parsed['score'], reasoning=parsed['reasoning'])
101
  except (json.JSONDecodeError, KeyError, TypeError):
102
- # Fallback if JSON parsing fails
103
- return GradedScore(score=0.85, reasoning="Medical interpretations appear accurate and evidence-based.")
104
 
105
 
106
  # Evaluator 2: Evidence Grounding (Programmatic + LLM)
@@ -192,13 +192,12 @@ Respond ONLY with valid JSON in this format:
192
  })
193
 
194
  # Parse JSON response
195
- import json
196
  try:
197
  parsed = json.loads(result.content if isinstance(result.content, str) else str(result.content))
198
  return GradedScore(score=parsed['score'], reasoning=parsed['reasoning'])
199
  except (json.JSONDecodeError, KeyError, TypeError):
200
- # Fallback if JSON parsing fails
201
- return GradedScore(score=0.90, reasoning="Recommendations are clear, actionable, and appropriately prioritized.")
202
 
203
 
204
  # Evaluator 4: Explainability Clarity (Programmatic)
 
5
 
6
  from pydantic import BaseModel, Field
7
  from typing import Dict, Any, List
8
+ import json
9
  from langchain_core.prompts import ChatPromptTemplate
10
  from src.llm_config import get_chat_model
11
 
 
94
  })
95
 
96
  # Parse JSON response
 
97
  try:
98
  content = result.content if isinstance(result.content, str) else str(result.content)
99
  parsed = json.loads(content)
100
  return GradedScore(score=parsed['score'], reasoning=parsed['reasoning'])
101
  except (json.JSONDecodeError, KeyError, TypeError):
102
+ # Fallback if JSON parsing fails — use a conservative score to avoid inflating metrics
103
+ return GradedScore(score=0.5, reasoning="Unable to parse LLM evaluation response; defaulting to neutral score.")
104
 
105
 
106
  # Evaluator 2: Evidence Grounding (Programmatic + LLM)
 
192
  })
193
 
194
  # Parse JSON response
 
195
  try:
196
  parsed = json.loads(result.content if isinstance(result.content, str) else str(result.content))
197
  return GradedScore(score=parsed['score'], reasoning=parsed['reasoning'])
198
  except (json.JSONDecodeError, KeyError, TypeError):
199
+ # Fallback if JSON parsing fails — use a conservative score to avoid inflating metrics
200
+ return GradedScore(score=0.5, reasoning="Unable to parse LLM evaluation response; defaulting to neutral score.")
201
 
202
 
203
  # Evaluator 4: Explainability Clarity (Programmatic)
src/evolution/director.py CHANGED
@@ -399,11 +399,20 @@ def run_evolution_cycle(
399
 
400
  # Run workflow with mutated SOP
401
  from src.state import PatientInput
 
402
  graph_input = {
403
  "patient_biomarkers": patient_input.biomarkers,
404
  "model_prediction": patient_input.model_prediction,
405
  "patient_context": patient_input.patient_context,
406
- "sop": mutant_sop
 
 
 
 
 
 
 
 
407
  }
408
 
409
  try:
 
399
 
400
  # Run workflow with mutated SOP
401
  from src.state import PatientInput
402
+ from datetime import datetime
403
  graph_input = {
404
  "patient_biomarkers": patient_input.biomarkers,
405
  "model_prediction": patient_input.model_prediction,
406
  "patient_context": patient_input.patient_context,
407
+ "plan": None,
408
+ "sop": mutant_sop,
409
+ "agent_outputs": [],
410
+ "biomarker_flags": [],
411
+ "safety_alerts": [],
412
+ "biomarker_analysis": None,
413
+ "final_response": None,
414
+ "processing_timestamp": datetime.now().isoformat(),
415
+ "sop_version": description
416
  }
417
 
418
  try:
src/llm_config.py CHANGED
@@ -9,6 +9,7 @@ Supports multiple providers:
9
  """
10
 
11
  import os
 
12
  from typing import Literal, Optional
13
  from dotenv import load_dotenv
14
 
@@ -23,8 +24,8 @@ DEFAULT_LLM_PROVIDER = os.getenv("LLM_PROVIDER", "groq")
23
 
24
 
25
  def get_chat_model(
26
- provider: Literal["groq", "gemini", "ollama"] = None,
27
- model: str = None,
28
  temperature: float = 0.0,
29
  json_mode: bool = False
30
  ):
@@ -100,7 +101,7 @@ def get_chat_model(
100
  raise ValueError(f"Unknown provider: {provider}. Use 'groq', 'gemini', or 'ollama'")
101
 
102
 
103
- def get_embedding_model(provider: Literal["google", "huggingface", "ollama"] = None):
104
  """
105
  Get embedding model for vector search.
106
 
@@ -155,7 +156,7 @@ def get_embedding_model(provider: Literal["google", "huggingface", "ollama"] = N
155
  class LLMConfig:
156
  """Central configuration for all LLM models"""
157
 
158
- def __init__(self, provider: str = None, lazy: bool = True):
159
  """
160
  Initialize all model clients.
161
 
@@ -166,6 +167,7 @@ class LLMConfig:
166
  self.provider = provider or DEFAULT_LLM_PROVIDER
167
  self._lazy = lazy
168
  self._initialized = False
 
169
 
170
  # Lazy-initialized model instances
171
  self._planner = None
@@ -184,7 +186,12 @@ class LLMConfig:
184
  if self._initialized:
185
  return
186
 
187
- print(f"Initializing LLM models with provider: {self.provider.upper()}")
 
 
 
 
 
188
 
189
  # Fast model for structured tasks (planning, analysis)
190
  self._planner = get_chat_model(
@@ -263,7 +270,7 @@ class LLMConfig:
263
  self._initialize_models()
264
  return self._embedding_model
265
 
266
- def get_synthesizer(self, model_name: str = None):
267
  """Get synthesizer model (for backward compatibility)"""
268
  if model_name:
269
  return get_chat_model(provider=self.provider, model=model_name, temperature=0.2)
 
9
  """
10
 
11
  import os
12
+ import threading
13
  from typing import Literal, Optional
14
  from dotenv import load_dotenv
15
 
 
24
 
25
 
26
  def get_chat_model(
27
+ provider: Optional[Literal["groq", "gemini", "ollama"]] = None,
28
+ model: Optional[str] = None,
29
  temperature: float = 0.0,
30
  json_mode: bool = False
31
  ):
 
101
  raise ValueError(f"Unknown provider: {provider}. Use 'groq', 'gemini', or 'ollama'")
102
 
103
 
104
+ def get_embedding_model(provider: Optional[Literal["google", "huggingface", "ollama"]] = None):
105
  """
106
  Get embedding model for vector search.
107
 
 
156
  class LLMConfig:
157
  """Central configuration for all LLM models"""
158
 
159
+ def __init__(self, provider: Optional[str] = None, lazy: bool = True):
160
  """
161
  Initialize all model clients.
162
 
 
167
  self.provider = provider or DEFAULT_LLM_PROVIDER
168
  self._lazy = lazy
169
  self._initialized = False
170
+ self._lock = threading.Lock()
171
 
172
  # Lazy-initialized model instances
173
  self._planner = None
 
186
  if self._initialized:
187
  return
188
 
189
+ with self._lock:
190
+ # Double-checked locking
191
+ if self._initialized:
192
+ return
193
+
194
+ print(f"Initializing LLM models with provider: {self.provider.upper()}")
195
 
196
  # Fast model for structured tasks (planning, analysis)
197
  self._planner = get_chat_model(
 
270
  self._initialize_models()
271
  return self._embedding_model
272
 
273
+ def get_synthesizer(self, model_name: Optional[str] = None):
274
  """Get synthesizer model (for backward compatibility)"""
275
  if model_name:
276
  return get_chat_model(provider=self.provider, model=model_name, temperature=0.2)
src/pdf_processor.py CHANGED
@@ -6,7 +6,7 @@ PDF document processing and vector store creation
6
  import os
7
  import warnings
8
  from pathlib import Path
9
- from typing import List, Optional, Literal
10
  from langchain_community.document_loaders import PyPDFLoader, DirectoryLoader
11
  from langchain_text_splitters import RecursiveCharacterTextSplitter
12
  from langchain_community.vectorstores import FAISS
@@ -21,62 +21,8 @@ os.environ.setdefault("HF_HUB_DISABLE_IMPLICIT_TOKEN", "1")
21
  # Load environment variables
22
  load_dotenv()
23
 
24
-
25
- def get_embedding_model(provider: Literal["google", "huggingface", "ollama"] = None):
26
- """
27
- Get embedding model with automatic fallback.
28
-
29
- Args:
30
- provider: "google" (FREE, recommended), "huggingface" (local), or "ollama" (local)
31
-
32
- Returns:
33
- Embedding model instance
34
- """
35
- provider = provider or os.getenv("EMBEDDING_PROVIDER", "google")
36
-
37
- if provider == "google":
38
- from langchain_google_genai import GoogleGenerativeAIEmbeddings
39
-
40
- api_key = os.getenv("GOOGLE_API_KEY")
41
- if not api_key:
42
- print("WARN: GOOGLE_API_KEY not found in .env file")
43
- print("INFO: Get FREE API key: https://aistudio.google.com/app/apikey")
44
- print("INFO: Falling back to HuggingFace local embeddings...\n")
45
- return get_embedding_model("huggingface")
46
-
47
- try:
48
- print("INFO: Using Google Gemini embeddings (FREE, fast)")
49
- return GoogleGenerativeAIEmbeddings(
50
- model="models/text-embedding-004",
51
- google_api_key=api_key
52
- )
53
- except Exception as e:
54
- print(f"WARN: Google embeddings failed: {e}")
55
- print("INFO: Falling back to HuggingFace local embeddings...\n")
56
- return get_embedding_model("huggingface")
57
-
58
- elif provider == "huggingface":
59
- try:
60
- from langchain_huggingface import HuggingFaceEmbeddings
61
- except ImportError:
62
- from langchain_community.embeddings import HuggingFaceEmbeddings
63
-
64
- print("INFO: Using HuggingFace local embeddings (free, offline)")
65
- return HuggingFaceEmbeddings(
66
- model_name="sentence-transformers/all-MiniLM-L6-v2"
67
- )
68
-
69
- elif provider == "ollama":
70
- try:
71
- from langchain_ollama import OllamaEmbeddings
72
- except ImportError:
73
- from langchain_community.embeddings import OllamaEmbeddings
74
-
75
- print("INFO: Using local Ollama embeddings (requires Ollama running)")
76
- return OllamaEmbeddings(model="nomic-embed-text")
77
-
78
- else:
79
- raise ValueError(f"Unknown provider: {provider}. Use 'google', 'huggingface', or 'ollama'")
80
 
81
 
82
  class PDFProcessor:
@@ -170,6 +116,10 @@ class PDFProcessor:
170
 
171
  chunks = self.text_splitter.split_documents(documents)
172
 
 
 
 
 
173
  # Add chunk index to metadata
174
  for i, chunk in enumerate(chunks):
175
  chunk.metadata['chunk_id'] = i
@@ -236,6 +186,9 @@ class PDFProcessor:
236
  return None
237
 
238
  try:
 
 
 
239
  vector_store = FAISS.load_local(
240
  str(self.vector_store_path),
241
  embedding_model,
 
6
  import os
7
  import warnings
8
  from pathlib import Path
9
+ from typing import List, Optional
10
  from langchain_community.document_loaders import PyPDFLoader, DirectoryLoader
11
  from langchain_text_splitters import RecursiveCharacterTextSplitter
12
  from langchain_community.vectorstores import FAISS
 
21
  # Load environment variables
22
  load_dotenv()
23
 
24
+ # Re-export for backward compatibility
25
+ from src.llm_config import get_embedding_model # noqa: F401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
 
28
  class PDFProcessor:
 
116
 
117
  chunks = self.text_splitter.split_documents(documents)
118
 
119
+ if not chunks:
120
+ print("WARN: No chunks generated from documents")
121
+ return chunks
122
+
123
  # Add chunk index to metadata
124
  for i, chunk in enumerate(chunks):
125
  chunk.metadata['chunk_id'] = i
 
186
  return None
187
 
188
  try:
189
+ # SECURITY NOTE: allow_dangerous_deserialization=True uses pickle.
190
+ # Only load vector stores from trusted, locally-built sources.
191
+ # Never load .faiss/.pkl files from untrusted origins.
192
  vector_store = FAISS.load_local(
193
  str(self.vector_store_path),
194
  embedding_model,
src/workflow.py CHANGED
@@ -3,10 +3,6 @@ MediGuard AI RAG-Helper
3
  Main LangGraph Workflow - Clinical Insight Guild Orchestration
4
  """
5
 
6
- import sys
7
- from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).parent.parent))
9
-
10
  from langgraph.graph import StateGraph, END
11
  from src.state import GuildState
12
  from src.pdf_processor import get_all_retrievers
 
3
  Main LangGraph Workflow - Clinical Insight Guild Orchestration
4
  """
5
 
 
 
 
 
6
  from langgraph.graph import StateGraph, END
7
  from src.state import GuildState
8
  from src.pdf_processor import get_all_retrievers
tests/test_evaluation_system.py CHANGED
@@ -89,27 +89,27 @@ def test_evaluation_system():
89
  AgentOutput(
90
  agent_name="Disease Explainer",
91
  findings=disease_explainer_context,
92
- citations=["diabetes.pdf", "MediGuard_Diabetes_Guidelines_Extensive.pdf"]
93
  ),
94
  AgentOutput(
95
  agent_name="Biomarker Analyzer",
96
  findings="Analyzed 25 biomarkers. Found 19 out of range, 3 critical values.",
97
- citations=[]
98
  ),
99
  AgentOutput(
100
  agent_name="Biomarker-Disease Linker",
101
  findings="Glucose and HbA1c are primary drivers for Type 2 Diabetes prediction.",
102
- citations=["diabetes.pdf"]
103
  ),
104
  AgentOutput(
105
  agent_name="Clinical Guidelines",
106
  findings="Recommend immediate medical consultation, lifestyle modifications.",
107
- citations=["diabetes.pdf"]
108
  ),
109
  AgentOutput(
110
  agent_name="Confidence Assessor",
111
  findings="High confidence prediction (87%) based on strong biomarker evidence.",
112
- citations=[]
113
  )
114
  ]
115
 
 
89
  AgentOutput(
90
  agent_name="Disease Explainer",
91
  findings=disease_explainer_context,
92
+ metadata={"citations": ["diabetes.pdf", "MediGuard_Diabetes_Guidelines_Extensive.pdf"]}
93
  ),
94
  AgentOutput(
95
  agent_name="Biomarker Analyzer",
96
  findings="Analyzed 25 biomarkers. Found 19 out of range, 3 critical values.",
97
+ metadata={"citations": []}
98
  ),
99
  AgentOutput(
100
  agent_name="Biomarker-Disease Linker",
101
  findings="Glucose and HbA1c are primary drivers for Type 2 Diabetes prediction.",
102
+ metadata={"citations": ["diabetes.pdf"]}
103
  ),
104
  AgentOutput(
105
  agent_name="Clinical Guidelines",
106
  findings="Recommend immediate medical consultation, lifestyle modifications.",
107
+ metadata={"citations": ["diabetes.pdf"]}
108
  ),
109
  AgentOutput(
110
  agent_name="Confidence Assessor",
111
  findings="High confidence prediction (87%) based on strong biomarker evidence.",
112
+ metadata={"citations": []}
113
  )
114
  ]
115