empathy-framework 4.6.6__py3-none-any.whl → 4.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/METADATA +7 -6
- empathy_framework-4.7.0.dist-info/RECORD +354 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/top_level.txt +0 -2
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
- empathy_llm_toolkit/agent_factory/__init__.py +6 -6
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
- empathy_llm_toolkit/agents_md/__init__.py +22 -0
- empathy_llm_toolkit/agents_md/loader.py +218 -0
- empathy_llm_toolkit/agents_md/parser.py +271 -0
- empathy_llm_toolkit/agents_md/registry.py +307 -0
- empathy_llm_toolkit/commands/__init__.py +51 -0
- empathy_llm_toolkit/commands/context.py +375 -0
- empathy_llm_toolkit/commands/loader.py +301 -0
- empathy_llm_toolkit/commands/models.py +231 -0
- empathy_llm_toolkit/commands/parser.py +371 -0
- empathy_llm_toolkit/commands/registry.py +429 -0
- empathy_llm_toolkit/config/__init__.py +8 -8
- empathy_llm_toolkit/config/unified.py +3 -7
- empathy_llm_toolkit/context/__init__.py +22 -0
- empathy_llm_toolkit/context/compaction.py +455 -0
- empathy_llm_toolkit/context/manager.py +434 -0
- empathy_llm_toolkit/hooks/__init__.py +24 -0
- empathy_llm_toolkit/hooks/config.py +306 -0
- empathy_llm_toolkit/hooks/executor.py +289 -0
- empathy_llm_toolkit/hooks/registry.py +302 -0
- empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
- empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
- empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
- empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
- empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
- empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
- empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
- empathy_llm_toolkit/learning/__init__.py +30 -0
- empathy_llm_toolkit/learning/evaluator.py +438 -0
- empathy_llm_toolkit/learning/extractor.py +514 -0
- empathy_llm_toolkit/learning/storage.py +560 -0
- empathy_llm_toolkit/providers.py +4 -11
- empathy_llm_toolkit/security/__init__.py +17 -17
- empathy_llm_toolkit/utils/tokens.py +2 -5
- empathy_os/__init__.py +202 -70
- empathy_os/cache_monitor.py +5 -3
- empathy_os/cli/__init__.py +11 -55
- empathy_os/cli/__main__.py +29 -15
- empathy_os/cli/commands/inspection.py +21 -12
- empathy_os/cli/commands/memory.py +4 -12
- empathy_os/cli/commands/profiling.py +198 -0
- empathy_os/cli/commands/utilities.py +27 -7
- empathy_os/cli.py +28 -57
- empathy_os/cli_unified.py +525 -1164
- empathy_os/cost_tracker.py +9 -3
- empathy_os/dashboard/server.py +200 -2
- empathy_os/hot_reload/__init__.py +7 -7
- empathy_os/hot_reload/config.py +6 -7
- empathy_os/hot_reload/integration.py +35 -35
- empathy_os/hot_reload/reloader.py +57 -57
- empathy_os/hot_reload/watcher.py +28 -28
- empathy_os/hot_reload/websocket.py +2 -2
- empathy_os/memory/__init__.py +11 -4
- empathy_os/memory/claude_memory.py +1 -1
- empathy_os/memory/cross_session.py +8 -12
- empathy_os/memory/edges.py +6 -6
- empathy_os/memory/file_session.py +770 -0
- empathy_os/memory/graph.py +30 -30
- empathy_os/memory/nodes.py +6 -6
- empathy_os/memory/short_term.py +15 -9
- empathy_os/memory/unified.py +606 -140
- empathy_os/meta_workflows/agent_creator.py +3 -9
- empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
- empathy_os/meta_workflows/form_engine.py +6 -18
- empathy_os/meta_workflows/intent_detector.py +64 -24
- empathy_os/meta_workflows/models.py +3 -1
- empathy_os/meta_workflows/pattern_learner.py +13 -31
- empathy_os/meta_workflows/plan_generator.py +55 -47
- empathy_os/meta_workflows/session_context.py +2 -3
- empathy_os/meta_workflows/workflow.py +20 -51
- empathy_os/models/cli.py +2 -2
- empathy_os/models/tasks.py +1 -2
- empathy_os/models/telemetry.py +4 -1
- empathy_os/models/token_estimator.py +3 -1
- empathy_os/monitoring/alerts.py +938 -9
- empathy_os/monitoring/alerts_cli.py +346 -183
- empathy_os/orchestration/execution_strategies.py +12 -29
- empathy_os/orchestration/pattern_learner.py +20 -26
- empathy_os/orchestration/real_tools.py +6 -15
- empathy_os/platform_utils.py +2 -1
- empathy_os/plugins/__init__.py +2 -2
- empathy_os/plugins/base.py +64 -64
- empathy_os/plugins/registry.py +32 -32
- empathy_os/project_index/index.py +49 -15
- empathy_os/project_index/models.py +1 -2
- empathy_os/project_index/reports.py +1 -1
- empathy_os/project_index/scanner.py +1 -0
- empathy_os/redis_memory.py +10 -7
- empathy_os/resilience/__init__.py +1 -1
- empathy_os/resilience/health.py +10 -10
- empathy_os/routing/__init__.py +7 -7
- empathy_os/routing/chain_executor.py +37 -37
- empathy_os/routing/classifier.py +36 -36
- empathy_os/routing/smart_router.py +40 -40
- empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
- empathy_os/scaffolding/__init__.py +8 -8
- empathy_os/scaffolding/__main__.py +1 -1
- empathy_os/scaffolding/cli.py +28 -28
- empathy_os/socratic/__init__.py +3 -19
- empathy_os/socratic/ab_testing.py +25 -36
- empathy_os/socratic/blueprint.py +38 -38
- empathy_os/socratic/cli.py +34 -20
- empathy_os/socratic/collaboration.py +30 -28
- empathy_os/socratic/domain_templates.py +9 -1
- empathy_os/socratic/embeddings.py +17 -13
- empathy_os/socratic/engine.py +135 -70
- empathy_os/socratic/explainer.py +70 -60
- empathy_os/socratic/feedback.py +24 -19
- empathy_os/socratic/forms.py +15 -10
- empathy_os/socratic/generator.py +51 -35
- empathy_os/socratic/llm_analyzer.py +25 -23
- empathy_os/socratic/mcp_server.py +99 -159
- empathy_os/socratic/session.py +19 -13
- empathy_os/socratic/storage.py +98 -67
- empathy_os/socratic/success.py +38 -27
- empathy_os/socratic/visual_editor.py +51 -39
- empathy_os/socratic/web_ui.py +99 -66
- empathy_os/telemetry/cli.py +3 -1
- empathy_os/telemetry/usage_tracker.py +1 -3
- empathy_os/test_generator/__init__.py +3 -3
- empathy_os/test_generator/cli.py +28 -28
- empathy_os/test_generator/generator.py +64 -66
- empathy_os/test_generator/risk_analyzer.py +11 -11
- empathy_os/vscode_bridge.py +173 -0
- empathy_os/workflows/__init__.py +212 -120
- empathy_os/workflows/batch_processing.py +8 -24
- empathy_os/workflows/bug_predict.py +1 -1
- empathy_os/workflows/code_review.py +20 -5
- empathy_os/workflows/code_review_pipeline.py +13 -8
- empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
- empathy_os/workflows/manage_documentation.py +1 -0
- empathy_os/workflows/orchestrated_health_check.py +6 -11
- empathy_os/workflows/orchestrated_release_prep.py +3 -3
- empathy_os/workflows/pr_review.py +18 -10
- empathy_os/workflows/progressive/__init__.py +2 -12
- empathy_os/workflows/progressive/cli.py +14 -37
- empathy_os/workflows/progressive/core.py +12 -12
- empathy_os/workflows/progressive/orchestrator.py +166 -144
- empathy_os/workflows/progressive/reports.py +22 -31
- empathy_os/workflows/progressive/telemetry.py +8 -14
- empathy_os/workflows/progressive/test_gen.py +29 -48
- empathy_os/workflows/progressive/workflow.py +31 -70
- empathy_os/workflows/release_prep.py +21 -6
- empathy_os/workflows/release_prep_crew.py +1 -0
- empathy_os/workflows/secure_release.py +13 -6
- empathy_os/workflows/security_audit.py +8 -3
- empathy_os/workflows/test_coverage_boost_crew.py +3 -2
- empathy_os/workflows/test_maintenance_crew.py +1 -0
- empathy_os/workflows/test_runner.py +16 -12
- empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
- empathy_software_plugin/cli.py +0 -122
- coach_wizards/__init__.py +0 -45
- coach_wizards/accessibility_wizard.py +0 -91
- coach_wizards/api_wizard.py +0 -91
- coach_wizards/base_wizard.py +0 -209
- coach_wizards/cicd_wizard.py +0 -91
- coach_wizards/code_reviewer_README.md +0 -60
- coach_wizards/code_reviewer_wizard.py +0 -180
- coach_wizards/compliance_wizard.py +0 -91
- coach_wizards/database_wizard.py +0 -91
- coach_wizards/debugging_wizard.py +0 -91
- coach_wizards/documentation_wizard.py +0 -91
- coach_wizards/generate_wizards.py +0 -347
- coach_wizards/localization_wizard.py +0 -173
- coach_wizards/migration_wizard.py +0 -91
- coach_wizards/monitoring_wizard.py +0 -91
- coach_wizards/observability_wizard.py +0 -91
- coach_wizards/performance_wizard.py +0 -91
- coach_wizards/prompt_engineering_wizard.py +0 -661
- coach_wizards/refactoring_wizard.py +0 -91
- coach_wizards/scaling_wizard.py +0 -90
- coach_wizards/security_wizard.py +0 -92
- coach_wizards/testing_wizard.py +0 -91
- empathy_framework-4.6.6.dist-info/RECORD +0 -410
- empathy_llm_toolkit/wizards/__init__.py +0 -43
- empathy_llm_toolkit/wizards/base_wizard.py +0 -364
- empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
- empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
- empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
- empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
- empathy_os/wizard_factory_cli.py +0 -170
- empathy_software_plugin/wizards/__init__.py +0 -42
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
- empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
- empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
- empathy_software_plugin/wizards/base_wizard.py +0 -288
- empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
- empathy_software_plugin/wizards/code_review_wizard.py +0 -604
- empathy_software_plugin/wizards/debugging/__init__.py +0 -50
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
- empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
- empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
- empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
- empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
- empathy_software_plugin/wizards/debugging/verification.py +0 -369
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
- empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
- empathy_software_plugin/wizards/performance/__init__.py +0 -9
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
- empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
- empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
- empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
- empathy_software_plugin/wizards/security/__init__.py +0 -32
- empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
- empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
- empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
- empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
- empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
- empathy_software_plugin/wizards/testing/__init__.py +0 -27
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
- empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
- empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
- empathy_software_plugin/wizards/testing_wizard.py +0 -274
- wizards/__init__.py +0 -82
- wizards/admission_assessment_wizard.py +0 -644
- wizards/care_plan.py +0 -321
- wizards/clinical_assessment.py +0 -769
- wizards/discharge_planning.py +0 -77
- wizards/discharge_summary_wizard.py +0 -468
- wizards/dosage_calculation.py +0 -497
- wizards/incident_report_wizard.py +0 -454
- wizards/medication_reconciliation.py +0 -85
- wizards/nursing_assessment.py +0 -171
- wizards/patient_education.py +0 -654
- wizards/quality_improvement.py +0 -705
- wizards/sbar_report.py +0 -324
- wizards/sbar_wizard.py +0 -608
- wizards/shift_handoff_wizard.py +0 -535
- wizards/soap_note_wizard.py +0 -679
- wizards/treatment_plan.py +0 -15
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/WHEEL +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/entry_points.txt +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/licenses/LICENSE +0 -0
wizards/discharge_planning.py
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Discharge Planning Wizard - AI Nurse Florence
|
|
3
|
-
Following Wizard Pattern Implementation from coding instructions
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from datetime import datetime
|
|
7
|
-
from typing import Any
|
|
8
|
-
from uuid import uuid4
|
|
9
|
-
|
|
10
|
-
from fastapi import APIRouter, HTTPException
|
|
11
|
-
|
|
12
|
-
from ...utils.config import get_educational_banner
|
|
13
|
-
|
|
14
|
-
router = APIRouter(
|
|
15
|
-
prefix="/wizard/discharge-planning",
|
|
16
|
-
tags=["wizards", "discharge-planning"],
|
|
17
|
-
responses={
|
|
18
|
-
404: {"description": "Wizard session not found"},
|
|
19
|
-
422: {"description": "Invalid step data"},
|
|
20
|
-
},
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
# Wizard session storage (Redis in production)
|
|
24
|
-
_wizard_sessions: dict[str, dict[str, Any]] = {}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@router.post("/start")
|
|
28
|
-
async def start_discharge_planning():
|
|
29
|
-
"""Start discharge planning wizard following Wizard Pattern Implementation."""
|
|
30
|
-
wizard_id = str(uuid4())
|
|
31
|
-
|
|
32
|
-
session_data = {
|
|
33
|
-
"wizard_id": wizard_id,
|
|
34
|
-
"wizard_type": "discharge_planning",
|
|
35
|
-
"created_at": datetime.now().isoformat(),
|
|
36
|
-
"current_step": 1,
|
|
37
|
-
"total_steps": 4,
|
|
38
|
-
"completed_steps": [],
|
|
39
|
-
"data": {},
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
_wizard_sessions[wizard_id] = session_data
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
"banner": get_educational_banner(),
|
|
46
|
-
"wizard_id": wizard_id,
|
|
47
|
-
"wizard_type": "discharge_planning",
|
|
48
|
-
"current_step": 1,
|
|
49
|
-
"total_steps": 4,
|
|
50
|
-
"step_title": "Discharge Assessment",
|
|
51
|
-
"educational_note": "Effective discharge planning begins at admission and involves multidisciplinary collaboration.",
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@router.get("/{wizard_id}/status")
|
|
56
|
-
async def get_discharge_planning_status(wizard_id: str):
|
|
57
|
-
"""Get discharge planning wizard status following Wizard Pattern Implementation."""
|
|
58
|
-
|
|
59
|
-
if wizard_id not in _wizard_sessions:
|
|
60
|
-
raise HTTPException(status_code=404, detail="Wizard session not found")
|
|
61
|
-
|
|
62
|
-
session = _wizard_sessions[wizard_id]
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
"banner": get_educational_banner(),
|
|
66
|
-
"wizard_id": wizard_id,
|
|
67
|
-
"wizard_type": session["wizard_type"],
|
|
68
|
-
"current_step": session["current_step"],
|
|
69
|
-
"total_steps": session["total_steps"],
|
|
70
|
-
"completed_steps": session["completed_steps"],
|
|
71
|
-
"progress": len(session["completed_steps"]) / session["total_steps"] * 100,
|
|
72
|
-
"status": (
|
|
73
|
-
"completed"
|
|
74
|
-
if len(session["completed_steps"]) == session["total_steps"]
|
|
75
|
-
else "in_progress"
|
|
76
|
-
),
|
|
77
|
-
}
|
|
@@ -1,468 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Discharge Summary Wizard Router - AI Nurse Florence
|
|
3
|
-
Following Wizard Pattern Implementation
|
|
4
|
-
|
|
5
|
-
Guided discharge documentation for comprehensive discharge summaries.
|
|
6
|
-
Based on evidence-based discharge planning and continuity of care standards.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import logging
|
|
10
|
-
from datetime import datetime
|
|
11
|
-
from typing import Any
|
|
12
|
-
from uuid import uuid4
|
|
13
|
-
|
|
14
|
-
from fastapi import APIRouter, HTTPException, status
|
|
15
|
-
from src.services import get_service
|
|
16
|
-
from src.utils.api_responses import create_success_response
|
|
17
|
-
from src.utils.config import get_settings
|
|
18
|
-
|
|
19
|
-
logger = logging.getLogger(__name__)
|
|
20
|
-
|
|
21
|
-
# Conditional imports
|
|
22
|
-
try:
|
|
23
|
-
from src.services.translation_service import translate_text
|
|
24
|
-
|
|
25
|
-
_has_translation = True
|
|
26
|
-
except ImportError:
|
|
27
|
-
_has_translation = False
|
|
28
|
-
|
|
29
|
-
async def translate_text(
|
|
30
|
-
text: str,
|
|
31
|
-
target_language: str,
|
|
32
|
-
source_language: str = "en",
|
|
33
|
-
context: str = "medical",
|
|
34
|
-
):
|
|
35
|
-
return {"translated_text": text, "success": False}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
settings = get_settings()
|
|
39
|
-
|
|
40
|
-
router = APIRouter(
|
|
41
|
-
prefix="/wizards/discharge-summary",
|
|
42
|
-
tags=["clinical-wizards"],
|
|
43
|
-
responses={
|
|
44
|
-
404: {"description": "Wizard session not found"},
|
|
45
|
-
422: {"description": "Invalid wizard step data"},
|
|
46
|
-
500: {"description": "Wizard processing error"},
|
|
47
|
-
},
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
try:
|
|
51
|
-
from src.utils.redis_cache import get_redis_client
|
|
52
|
-
|
|
53
|
-
_has_redis = True
|
|
54
|
-
except ImportError:
|
|
55
|
-
_has_redis = False
|
|
56
|
-
|
|
57
|
-
_wizard_sessions: dict[str, dict[str, Any]] = {}
|
|
58
|
-
|
|
59
|
-
DISCHARGE_SUMMARY_STEPS = {
|
|
60
|
-
1: {
|
|
61
|
-
"step": 1,
|
|
62
|
-
"title": "Patient & Admission Information",
|
|
63
|
-
"prompt": "Document patient demographics and admission details",
|
|
64
|
-
"fields": [
|
|
65
|
-
"patient_name",
|
|
66
|
-
"admission_date",
|
|
67
|
-
"discharge_date",
|
|
68
|
-
"length_of_stay",
|
|
69
|
-
"attending_physician",
|
|
70
|
-
"discharge_disposition",
|
|
71
|
-
],
|
|
72
|
-
"help_text": "Start with basic patient info, admission/discharge dates, and discharge destination",
|
|
73
|
-
},
|
|
74
|
-
2: {
|
|
75
|
-
"step": 2,
|
|
76
|
-
"title": "Hospital Course",
|
|
77
|
-
"prompt": "Summarize the patient's hospital course and treatment",
|
|
78
|
-
"fields": [
|
|
79
|
-
"admission_diagnosis",
|
|
80
|
-
"hospital_course",
|
|
81
|
-
"procedures_performed",
|
|
82
|
-
"complications",
|
|
83
|
-
"consults_obtained",
|
|
84
|
-
"significant_events",
|
|
85
|
-
],
|
|
86
|
-
"help_text": "Describe what happened during hospitalization, including treatments, procedures, and any complications",
|
|
87
|
-
},
|
|
88
|
-
3: {
|
|
89
|
-
"step": 3,
|
|
90
|
-
"title": "Discharge Status & Findings",
|
|
91
|
-
"prompt": "Document patient's condition at discharge",
|
|
92
|
-
"fields": [
|
|
93
|
-
"discharge_diagnosis",
|
|
94
|
-
"discharge_condition",
|
|
95
|
-
"discharge_vital_signs",
|
|
96
|
-
"pending_results",
|
|
97
|
-
"discharge_labs",
|
|
98
|
-
"functional_status",
|
|
99
|
-
],
|
|
100
|
-
"help_text": "Record patient's final diagnoses, clinical status, and any pending tests or results",
|
|
101
|
-
},
|
|
102
|
-
4: {
|
|
103
|
-
"step": 4,
|
|
104
|
-
"title": "Discharge Medications & Instructions",
|
|
105
|
-
"prompt": "List discharge medications and patient instructions",
|
|
106
|
-
"fields": [
|
|
107
|
-
"discharge_medications",
|
|
108
|
-
"medication_changes",
|
|
109
|
-
"diet_instructions",
|
|
110
|
-
"activity_restrictions",
|
|
111
|
-
"wound_care",
|
|
112
|
-
"equipment_needs",
|
|
113
|
-
],
|
|
114
|
-
"help_text": "Include all discharge meds, changes from admission, diet/activity restrictions, and special care instructions",
|
|
115
|
-
},
|
|
116
|
-
5: {
|
|
117
|
-
"step": 5,
|
|
118
|
-
"title": "Follow-up & Patient Education",
|
|
119
|
-
"prompt": "Document follow-up plans and education provided",
|
|
120
|
-
"fields": [
|
|
121
|
-
"follow_up_appointments",
|
|
122
|
-
"warning_signs",
|
|
123
|
-
"patient_education_provided",
|
|
124
|
-
"discharge_instructions_given",
|
|
125
|
-
"patient_understanding",
|
|
126
|
-
"caregiver_education",
|
|
127
|
-
],
|
|
128
|
-
"help_text": "Note follow-up appointments, warning signs to watch for, education provided, and patient/caregiver understanding",
|
|
129
|
-
},
|
|
130
|
-
6: {
|
|
131
|
-
"step": 6,
|
|
132
|
-
"title": "Review & Finalize",
|
|
133
|
-
"prompt": "Review your discharge summary and finalize the document",
|
|
134
|
-
"fields": ["review_complete", "user_approved"],
|
|
135
|
-
"help_text": "Review all sections of the discharge summary. Click 'Generate Preview' to see the formatted document. You can go back to edit any section before finalizing.",
|
|
136
|
-
"is_review_step": True,
|
|
137
|
-
},
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
EDU_BANNER = """
|
|
141
|
-
⚕️ EDUCATIONAL TOOL NOTICE ⚕️
|
|
142
|
-
This discharge summary wizard is an educational tool for healthcare professionals.
|
|
143
|
-
All discharge documentation should be reviewed and validated by qualified providers.
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
async def _store_wizard_session(wizard_id: str, session_data: dict[str, Any]) -> bool:
|
|
148
|
-
try:
|
|
149
|
-
if _has_redis:
|
|
150
|
-
import json
|
|
151
|
-
|
|
152
|
-
redis_client = await get_redis_client()
|
|
153
|
-
if redis_client:
|
|
154
|
-
await redis_client.setex(
|
|
155
|
-
f"wizard:discharge_summary:{wizard_id}",
|
|
156
|
-
7200,
|
|
157
|
-
json.dumps(session_data), # FIXED: use JSON
|
|
158
|
-
)
|
|
159
|
-
return True
|
|
160
|
-
except Exception: # noqa: BLE001
|
|
161
|
-
# INTENTIONAL: Graceful degradation - fall back to in-memory storage if Redis fails
|
|
162
|
-
pass
|
|
163
|
-
_wizard_sessions[wizard_id] = session_data
|
|
164
|
-
return True
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
async def _get_wizard_session(wizard_id: str) -> dict[str, Any] | None:
|
|
168
|
-
try:
|
|
169
|
-
if _has_redis:
|
|
170
|
-
import json
|
|
171
|
-
|
|
172
|
-
redis_client = await get_redis_client()
|
|
173
|
-
if redis_client:
|
|
174
|
-
session_str = await redis_client.get(f"wizard:discharge_summary:{wizard_id}")
|
|
175
|
-
if session_str:
|
|
176
|
-
# SECURITY FIX: Use json.loads() instead of ast.literal_eval()
|
|
177
|
-
return json.loads(session_str)
|
|
178
|
-
except Exception: # noqa: BLE001
|
|
179
|
-
# INTENTIONAL: Graceful degradation - fall back to in-memory storage if Redis fails
|
|
180
|
-
pass
|
|
181
|
-
return _wizard_sessions.get(wizard_id)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
def _get_step_data(step: int) -> dict[str, Any]:
|
|
185
|
-
if step not in DISCHARGE_SUMMARY_STEPS:
|
|
186
|
-
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Invalid step: {step}")
|
|
187
|
-
step_config = DISCHARGE_SUMMARY_STEPS[step]
|
|
188
|
-
return {
|
|
189
|
-
"step": step,
|
|
190
|
-
"title": step_config["title"],
|
|
191
|
-
"prompt": step_config["prompt"],
|
|
192
|
-
"fields": step_config["fields"],
|
|
193
|
-
"help_text": step_config["help_text"],
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def _generate_discharge_summary_report(collected_data: dict[str, Any]) -> dict[str, Any]:
|
|
198
|
-
narrative = f"""
|
|
199
|
-
DISCHARGE SUMMARY
|
|
200
|
-
|
|
201
|
-
PATIENT INFORMATION
|
|
202
|
-
Name: {collected_data.get('patient_name', 'Not documented')}
|
|
203
|
-
Admission Date: {collected_data.get('admission_date', 'Not documented')}
|
|
204
|
-
Discharge Date: {collected_data.get('discharge_date', datetime.now().strftime('%Y-%m-%d'))}
|
|
205
|
-
Length of Stay: {collected_data.get('length_of_stay', 'Not documented')}
|
|
206
|
-
Attending Physician: {collected_data.get('attending_physician', 'Not documented')}
|
|
207
|
-
Discharge Disposition: {collected_data.get('discharge_disposition', 'Not documented')}
|
|
208
|
-
|
|
209
|
-
HOSPITAL COURSE
|
|
210
|
-
Admission Diagnosis: {collected_data.get('admission_diagnosis', 'Not documented')}
|
|
211
|
-
Hospital Course: {collected_data.get('hospital_course', 'Not documented')}
|
|
212
|
-
Procedures Performed: {collected_data.get('procedures_performed', 'None')}
|
|
213
|
-
Complications: {collected_data.get('complications', 'None')}
|
|
214
|
-
Consultations: {collected_data.get('consults_obtained', 'None')}
|
|
215
|
-
Significant Events: {collected_data.get('significant_events', 'None')}
|
|
216
|
-
|
|
217
|
-
DISCHARGE STATUS
|
|
218
|
-
Discharge Diagnosis: {collected_data.get('discharge_diagnosis', 'Not documented')}
|
|
219
|
-
Discharge Condition: {collected_data.get('discharge_condition', 'Not documented')}
|
|
220
|
-
Discharge Vital Signs: {collected_data.get('discharge_vital_signs', 'Not documented')}
|
|
221
|
-
Pending Results: {collected_data.get('pending_results', 'None')}
|
|
222
|
-
Discharge Labs: {collected_data.get('discharge_labs', 'Not documented')}
|
|
223
|
-
Functional Status: {collected_data.get('functional_status', 'Not documented')}
|
|
224
|
-
|
|
225
|
-
DISCHARGE MEDICATIONS & INSTRUCTIONS
|
|
226
|
-
Discharge Medications: {collected_data.get('discharge_medications', 'Not documented')}
|
|
227
|
-
Medication Changes: {collected_data.get('medication_changes', 'None')}
|
|
228
|
-
Diet: {collected_data.get('diet_instructions', 'Not documented')}
|
|
229
|
-
Activity: {collected_data.get('activity_restrictions', 'Not documented')}
|
|
230
|
-
Wound Care: {collected_data.get('wound_care', 'Not applicable')}
|
|
231
|
-
Equipment Needs: {collected_data.get('equipment_needs', 'None')}
|
|
232
|
-
|
|
233
|
-
FOLLOW-UP & EDUCATION
|
|
234
|
-
Follow-up Appointments: {collected_data.get('follow_up_appointments', 'Not documented')}
|
|
235
|
-
Warning Signs: {collected_data.get('warning_signs', 'Not documented')}
|
|
236
|
-
Patient Education: {collected_data.get('patient_education_provided', 'Not documented')}
|
|
237
|
-
Discharge Instructions: {collected_data.get('discharge_instructions_given', 'Provided')}
|
|
238
|
-
Patient Understanding: {collected_data.get('patient_understanding', 'Verbalized')}
|
|
239
|
-
Caregiver Education: {collected_data.get('caregiver_education', 'Not applicable')}
|
|
240
|
-
|
|
241
|
-
Completed by: [Provider Name]
|
|
242
|
-
Date/Time: {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
|
243
|
-
"""
|
|
244
|
-
return {
|
|
245
|
-
"discharge_summary": collected_data,
|
|
246
|
-
"narrative": narrative.strip(),
|
|
247
|
-
"metadata": {
|
|
248
|
-
"generated_at": datetime.now().isoformat(),
|
|
249
|
-
"wizard_type": "discharge_summary",
|
|
250
|
-
},
|
|
251
|
-
"banner": EDU_BANNER,
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
@router.post("/start", summary="Start Discharge Summary Wizard")
|
|
256
|
-
async def start_discharge_summary_wizard():
|
|
257
|
-
try:
|
|
258
|
-
wizard_id = str(uuid4())
|
|
259
|
-
session_data = {
|
|
260
|
-
"wizard_id": wizard_id,
|
|
261
|
-
"wizard_type": "discharge_summary",
|
|
262
|
-
"current_step": 1,
|
|
263
|
-
"total_steps": 6,
|
|
264
|
-
"collected_data": {},
|
|
265
|
-
"created_at": datetime.now().isoformat(),
|
|
266
|
-
"updated_at": datetime.now().isoformat(),
|
|
267
|
-
}
|
|
268
|
-
await _store_wizard_session(wizard_id, session_data)
|
|
269
|
-
step_data = _get_step_data(1)
|
|
270
|
-
response_data = {
|
|
271
|
-
"wizard_session": session_data,
|
|
272
|
-
"current_step": step_data,
|
|
273
|
-
"progress": {"current": 1, "total": 5, "percentage": 20},
|
|
274
|
-
"banner": EDU_BANNER,
|
|
275
|
-
}
|
|
276
|
-
return create_success_response(
|
|
277
|
-
data=response_data, message="Discharge summary wizard started successfully"
|
|
278
|
-
)
|
|
279
|
-
except Exception as e:
|
|
280
|
-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
@router.post("/{wizard_id}/step", summary="Submit discharge summary step")
|
|
284
|
-
async def submit_discharge_summary_step(wizard_id: str, step_data: dict[str, Any]):
|
|
285
|
-
try:
|
|
286
|
-
session = await _get_wizard_session(wizard_id)
|
|
287
|
-
if not session:
|
|
288
|
-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
|
|
289
|
-
current_step = session["current_step"]
|
|
290
|
-
session["collected_data"].update(step_data.get("data", {}))
|
|
291
|
-
session["updated_at"] = datetime.now().isoformat()
|
|
292
|
-
|
|
293
|
-
# Advance to next step (but don't auto-complete, even on final step)
|
|
294
|
-
if current_step < session["total_steps"]:
|
|
295
|
-
next_step = current_step + 1
|
|
296
|
-
session["current_step"] = next_step
|
|
297
|
-
else:
|
|
298
|
-
# On review step - stay on same step, don't auto-complete
|
|
299
|
-
next_step = current_step
|
|
300
|
-
|
|
301
|
-
await _store_wizard_session(wizard_id, session)
|
|
302
|
-
return create_success_response(
|
|
303
|
-
data={
|
|
304
|
-
"wizard_session": session,
|
|
305
|
-
"current_step": _get_step_data(next_step),
|
|
306
|
-
"progress": {
|
|
307
|
-
"current": next_step,
|
|
308
|
-
"total": session["total_steps"],
|
|
309
|
-
"percentage": int((next_step / session["total_steps"]) * 100),
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
message=f"Step {current_step} completed",
|
|
313
|
-
)
|
|
314
|
-
except Exception as e:
|
|
315
|
-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
@router.post("/{wizard_id}/enhance", summary="Enhance discharge summary text")
|
|
319
|
-
async def enhance_discharge_summary_text(wizard_id: str, text_data: dict[str, Any]):
|
|
320
|
-
try:
|
|
321
|
-
session = await _get_wizard_session(wizard_id)
|
|
322
|
-
if not session:
|
|
323
|
-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
|
|
324
|
-
original_text = text_data.get("text", "")
|
|
325
|
-
field_name = text_data.get("field", "text")
|
|
326
|
-
if not original_text:
|
|
327
|
-
raise HTTPException(
|
|
328
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
329
|
-
detail="No text provided",
|
|
330
|
-
)
|
|
331
|
-
chat_service = get_service("chat")
|
|
332
|
-
enhancement_prompt = f"Enhance this discharge summary field ({field_name}) to be professional and complete: {original_text}"
|
|
333
|
-
chat_response = await chat_service.chat(
|
|
334
|
-
message=enhancement_prompt,
|
|
335
|
-
conversation_id=f"discharge_enhance_{wizard_id}",
|
|
336
|
-
context={"wizard_id": wizard_id, "field": field_name},
|
|
337
|
-
)
|
|
338
|
-
enhanced_text = chat_response.get("response", original_text)
|
|
339
|
-
return create_success_response(
|
|
340
|
-
data={
|
|
341
|
-
"original_text": original_text,
|
|
342
|
-
"enhanced_text": enhanced_text,
|
|
343
|
-
"field": field_name,
|
|
344
|
-
},
|
|
345
|
-
message="Text enhanced successfully",
|
|
346
|
-
)
|
|
347
|
-
except Exception as e:
|
|
348
|
-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
@router.post("/{wizard_id}/preview", summary="Preview discharge summary report")
|
|
352
|
-
async def preview_discharge_summary_report(wizard_id: str):
|
|
353
|
-
"""
|
|
354
|
-
Generate preview of discharge summary report without finalizing.
|
|
355
|
-
|
|
356
|
-
This endpoint allows users to see the formatted discharge summary before
|
|
357
|
-
finalizing it. The report is NOT marked as complete. Users can
|
|
358
|
-
still go back and edit data after previewing.
|
|
359
|
-
"""
|
|
360
|
-
try:
|
|
361
|
-
session = await _get_wizard_session(wizard_id)
|
|
362
|
-
if not session:
|
|
363
|
-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
|
|
364
|
-
|
|
365
|
-
# Verify user is on review step
|
|
366
|
-
if session["current_step"] != session["total_steps"]:
|
|
367
|
-
raise HTTPException(
|
|
368
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
369
|
-
detail=f"Not on review step. Complete steps 1-{session['total_steps']-1} first.",
|
|
370
|
-
)
|
|
371
|
-
|
|
372
|
-
# Generate preview report (does NOT mark as complete)
|
|
373
|
-
preview_report = _generate_discharge_summary_report(session["collected_data"])
|
|
374
|
-
|
|
375
|
-
# Store preview in session
|
|
376
|
-
session["preview_report"] = preview_report
|
|
377
|
-
session["preview_generated_at"] = datetime.now().isoformat()
|
|
378
|
-
await _store_wizard_session(wizard_id, session)
|
|
379
|
-
|
|
380
|
-
response_data = {
|
|
381
|
-
"preview": preview_report,
|
|
382
|
-
"wizard_session": session,
|
|
383
|
-
"message": "Review the discharge summary above. Click 'Finalize Report' to save, or go back to edit any section.",
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return create_success_response(data=response_data, message="Preview generated successfully")
|
|
387
|
-
|
|
388
|
-
except HTTPException:
|
|
389
|
-
raise
|
|
390
|
-
except Exception as e:
|
|
391
|
-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
@router.post("/{wizard_id}/save", summary="Finalize discharge summary report")
|
|
395
|
-
async def save_discharge_summary_report(wizard_id: str, approval_data: dict[str, Any]):
|
|
396
|
-
"""
|
|
397
|
-
Finalize and save the discharge summary report after user review and approval.
|
|
398
|
-
|
|
399
|
-
Requires that the user has:
|
|
400
|
-
1. Generated a preview first (/preview endpoint)
|
|
401
|
-
2. Explicitly approved the report (user_approved: true)
|
|
402
|
-
|
|
403
|
-
Only after calling this endpoint is the report marked as complete.
|
|
404
|
-
"""
|
|
405
|
-
try:
|
|
406
|
-
session = await _get_wizard_session(wizard_id)
|
|
407
|
-
if not session:
|
|
408
|
-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
|
|
409
|
-
|
|
410
|
-
# Verify preview was generated
|
|
411
|
-
if "preview_report" not in session:
|
|
412
|
-
raise HTTPException(
|
|
413
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
414
|
-
detail="Must generate preview before saving. Call /preview endpoint first.",
|
|
415
|
-
)
|
|
416
|
-
|
|
417
|
-
# Verify user explicitly approved
|
|
418
|
-
if not approval_data.get("user_approved", False):
|
|
419
|
-
raise HTTPException(
|
|
420
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
421
|
-
detail="User approval required. Set 'user_approved': true in request body.",
|
|
422
|
-
)
|
|
423
|
-
|
|
424
|
-
# NOW we mark as complete
|
|
425
|
-
session["completed"] = True
|
|
426
|
-
session["completed_at"] = datetime.now().isoformat()
|
|
427
|
-
session["final_report"] = session["preview_report"]
|
|
428
|
-
session["user_approved"] = True
|
|
429
|
-
|
|
430
|
-
await _store_wizard_session(wizard_id, session)
|
|
431
|
-
|
|
432
|
-
response_data = {
|
|
433
|
-
"wizard_session": session,
|
|
434
|
-
"report": session["final_report"],
|
|
435
|
-
"completed": True,
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return create_success_response(
|
|
439
|
-
data=response_data, message="Discharge summary finalized successfully"
|
|
440
|
-
)
|
|
441
|
-
|
|
442
|
-
except HTTPException:
|
|
443
|
-
raise
|
|
444
|
-
except Exception as e:
|
|
445
|
-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
@router.get("/{wizard_id}/report", summary="Get discharge summary report")
|
|
449
|
-
async def get_discharge_summary_report(wizard_id: str):
|
|
450
|
-
try:
|
|
451
|
-
session = await _get_wizard_session(wizard_id)
|
|
452
|
-
if not session:
|
|
453
|
-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
|
|
454
|
-
if not session.get("completed", False):
|
|
455
|
-
raise HTTPException(
|
|
456
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
457
|
-
detail="Wizard not completed",
|
|
458
|
-
)
|
|
459
|
-
report = _generate_discharge_summary_report(session["collected_data"])
|
|
460
|
-
return create_success_response(
|
|
461
|
-
data={"wizard_session": session, "report": report},
|
|
462
|
-
message="Report retrieved successfully",
|
|
463
|
-
)
|
|
464
|
-
except Exception as e:
|
|
465
|
-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
__all__ = ["router"]
|