Spaces:
Running
Running
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 +3 -1
- api/app/main.py +8 -8
- api/app/services/extraction.py +4 -2
- api/app/services/ragbot.py +11 -7
- api/requirements.txt +1 -1
- config/biomarker_references.json +234 -8
- data/chat_reports/report_Diabetes_20260223_142525.json +322 -0
- docs/plans/PRODUCTION_UPGRADE_PLAN.md +833 -0
- pytest.ini +1 -0
- requirements.txt +9 -0
- scripts/monitor_test.py +0 -1
- scripts/setup_embeddings.py +3 -3
- src/agents/biomarker_analyzer.py +1 -5
- src/agents/biomarker_linker.py +0 -4
- src/agents/clinical_guidelines.py +0 -3
- src/agents/confidence_assessor.py +0 -4
- src/agents/disease_explainer.py +8 -6
- src/agents/response_synthesizer.py +0 -4
- src/biomarker_normalization.py +41 -0
- src/biomarker_validator.py +8 -0
- src/evaluation/evaluators.py +5 -6
- src/evolution/director.py +10 -1
- src/llm_config.py +13 -6
- src/pdf_processor.py +10 -57
- src/workflow.py +0 -4
- tests/test_evaluation_system.py +5 -5
.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 |
-
#
|
|
|
|
| 82 |
app.add_middleware(
|
| 83 |
CORSMiddleware,
|
| 84 |
-
allow_origins=
|
| 85 |
-
allow_credentials=
|
| 86 |
-
allow_methods=["*"],
|
| 87 |
-
allow_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 |
-
#
|
| 12 |
-
|
|
|
|
|
|
|
| 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 |
-
#
|
| 14 |
-
|
|
|
|
|
|
|
| 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 |
-
#
|
| 51 |
-
#
|
| 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=
|
| 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":
|
| 19 |
-
"critical_low":
|
| 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":
|
| 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":
|
| 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":
|
| 215 |
-
"female": {"min": 50, "max":
|
| 216 |
},
|
| 217 |
-
"critical_low":
|
| 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=
|
| 56 |
updated = True
|
| 57 |
break
|
| 58 |
|
| 59 |
if not updated:
|
| 60 |
-
lines.insert(0, f'GOOGLE_API_KEY=
|
| 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=
|
| 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'
|
| 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
|
| 47 |
retrieval_k = state['sop'].disease_explainer_k
|
| 48 |
-
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.
|
| 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.
|
| 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 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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 |
-
|
| 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 |
-
|
| 93 |
),
|
| 94 |
AgentOutput(
|
| 95 |
agent_name="Biomarker Analyzer",
|
| 96 |
findings="Analyzed 25 biomarkers. Found 19 out of range, 3 critical values.",
|
| 97 |
-
|
| 98 |
),
|
| 99 |
AgentOutput(
|
| 100 |
agent_name="Biomarker-Disease Linker",
|
| 101 |
findings="Glucose and HbA1c are primary drivers for Type 2 Diabetes prediction.",
|
| 102 |
-
|
| 103 |
),
|
| 104 |
AgentOutput(
|
| 105 |
agent_name="Clinical Guidelines",
|
| 106 |
findings="Recommend immediate medical consultation, lifestyle modifications.",
|
| 107 |
-
|
| 108 |
),
|
| 109 |
AgentOutput(
|
| 110 |
agent_name="Confidence Assessor",
|
| 111 |
findings="High confidence prediction (87%) based on strong biomarker evidence.",
|
| 112 |
-
|
| 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 |
|