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/soap_note_wizard.py
DELETED
|
@@ -1,679 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
SOAP Note Wizard Router - AI Nurse Florence
|
|
3
|
-
Following Wizard Pattern Implementation from SBAR and Shift Handoff wizards
|
|
4
|
-
|
|
5
|
-
SOAP (Subjective, Objective, Assessment, Plan) note documentation wizard
|
|
6
|
-
for comprehensive clinical progress notes. Evidence-based format for
|
|
7
|
-
interprofessional communication and continuity of care.
|
|
8
|
-
|
|
9
|
-
Version: 2.0 - 5-step wizard with review/approval (Jan 2025)
|
|
10
|
-
Users must preview and explicitly approve documents before finalization.
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
import logging
|
|
14
|
-
from datetime import datetime
|
|
15
|
-
from typing import Any
|
|
16
|
-
from uuid import uuid4
|
|
17
|
-
|
|
18
|
-
from fastapi import APIRouter, HTTPException, status
|
|
19
|
-
from src.services import get_service
|
|
20
|
-
from src.utils.api_responses import create_success_response
|
|
21
|
-
from src.utils.config import get_settings
|
|
22
|
-
|
|
23
|
-
logger = logging.getLogger(__name__)
|
|
24
|
-
|
|
25
|
-
# Conditional translation import
|
|
26
|
-
try:
|
|
27
|
-
from src.services.translation_service import translate_text
|
|
28
|
-
|
|
29
|
-
_has_translation = True
|
|
30
|
-
except ImportError:
|
|
31
|
-
_has_translation = False
|
|
32
|
-
|
|
33
|
-
async def translate_text(
|
|
34
|
-
text: str,
|
|
35
|
-
target_language: str,
|
|
36
|
-
source_language: str = "en",
|
|
37
|
-
context: str = "medical",
|
|
38
|
-
):
|
|
39
|
-
return {"translated_text": text, "success": False}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# Settings following coding instructions
|
|
43
|
-
settings = get_settings()
|
|
44
|
-
|
|
45
|
-
router = APIRouter(
|
|
46
|
-
prefix="/wizards/soap-note",
|
|
47
|
-
tags=["clinical-wizards"],
|
|
48
|
-
responses={
|
|
49
|
-
404: {"description": "Wizard session not found"},
|
|
50
|
-
422: {"description": "Invalid wizard step data"},
|
|
51
|
-
500: {"description": "Wizard processing error"},
|
|
52
|
-
},
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
# Session storage (Redis in production, memory for development)
|
|
56
|
-
try:
|
|
57
|
-
from src.utils.redis_cache import get_redis_client
|
|
58
|
-
|
|
59
|
-
_has_redis = True
|
|
60
|
-
except ImportError:
|
|
61
|
-
_has_redis = False
|
|
62
|
-
|
|
63
|
-
_wizard_sessions: dict[str, dict[str, Any]] = {}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# SOAP note wizard steps
|
|
67
|
-
SOAP_NOTE_STEPS = {
|
|
68
|
-
1: {
|
|
69
|
-
"step": 1,
|
|
70
|
-
"title": "Subjective - Patient's Experience",
|
|
71
|
-
"prompt": "Document the patient's subjective experience and reported symptoms",
|
|
72
|
-
"fields": [
|
|
73
|
-
"chief_complaint",
|
|
74
|
-
"history_present_illness",
|
|
75
|
-
"patient_reported_symptoms",
|
|
76
|
-
"pain_description",
|
|
77
|
-
"functional_status",
|
|
78
|
-
"patient_concerns",
|
|
79
|
-
],
|
|
80
|
-
"help_text": "Record what the patient tells you in their own words. Include chief complaint, symptoms, pain, and any concerns they express.",
|
|
81
|
-
},
|
|
82
|
-
2: {
|
|
83
|
-
"step": 2,
|
|
84
|
-
"title": "Objective - Clinical Observations",
|
|
85
|
-
"prompt": "Record objective clinical findings and measurements",
|
|
86
|
-
"fields": [
|
|
87
|
-
"vital_signs",
|
|
88
|
-
"physical_exam_findings",
|
|
89
|
-
"lab_results",
|
|
90
|
-
"imaging_results",
|
|
91
|
-
"medication_administration",
|
|
92
|
-
"procedures_performed",
|
|
93
|
-
],
|
|
94
|
-
"help_text": "Document measurable data: vital signs, physical exam findings, lab/imaging results, medications given, procedures done.",
|
|
95
|
-
},
|
|
96
|
-
3: {
|
|
97
|
-
"step": 3,
|
|
98
|
-
"title": "Assessment - Clinical Analysis",
|
|
99
|
-
"prompt": "Provide your clinical assessment and interpretation",
|
|
100
|
-
"fields": [
|
|
101
|
-
"primary_diagnosis",
|
|
102
|
-
"differential_diagnoses",
|
|
103
|
-
"problem_list",
|
|
104
|
-
"progress_evaluation",
|
|
105
|
-
"response_to_treatment",
|
|
106
|
-
"complications_concerns",
|
|
107
|
-
],
|
|
108
|
-
"help_text": "Analyze the data: primary diagnosis, other possibilities, current problems, patient's progress, treatment response, any concerns.",
|
|
109
|
-
},
|
|
110
|
-
4: {
|
|
111
|
-
"step": 4,
|
|
112
|
-
"title": "Plan - Care Plan and Next Steps",
|
|
113
|
-
"prompt": "Outline the care plan and next steps",
|
|
114
|
-
"fields": [
|
|
115
|
-
"diagnostic_plan",
|
|
116
|
-
"therapeutic_plan",
|
|
117
|
-
"patient_education",
|
|
118
|
-
"monitoring_plan",
|
|
119
|
-
"follow_up",
|
|
120
|
-
"consultations_needed",
|
|
121
|
-
],
|
|
122
|
-
"help_text": "Detail the plan: further diagnostics needed, treatment changes, patient education, monitoring requirements, follow-up, consultations.",
|
|
123
|
-
},
|
|
124
|
-
5: {
|
|
125
|
-
"step": 5,
|
|
126
|
-
"title": "Review & Finalize",
|
|
127
|
-
"prompt": "Review your SOAP note and finalize the document",
|
|
128
|
-
"fields": ["review_complete", "user_approved"],
|
|
129
|
-
"help_text": "Review all sections of your SOAP note. Click 'Generate Preview' to see the formatted note. You can go back to edit any section before finalizing.",
|
|
130
|
-
"is_review_step": True,
|
|
131
|
-
},
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
# Educational banner for all SOAP note outputs
|
|
136
|
-
EDU_BANNER = """
|
|
137
|
-
⚕️ EDUCATIONAL TOOL NOTICE ⚕️
|
|
138
|
-
This SOAP note wizard is an educational tool for healthcare professionals.
|
|
139
|
-
All clinical documentation should be reviewed and validated by qualified providers.
|
|
140
|
-
Never rely solely on automated tools for clinical decision-making or documentation.
|
|
141
|
-
"""
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
async def _store_wizard_session(wizard_id: str, session_data: dict[str, Any]) -> bool:
|
|
145
|
-
"""Store wizard session in Redis (preferred) or memory (fallback)"""
|
|
146
|
-
try:
|
|
147
|
-
if _has_redis:
|
|
148
|
-
redis_client = await get_redis_client()
|
|
149
|
-
if redis_client:
|
|
150
|
-
import json
|
|
151
|
-
|
|
152
|
-
cache_key = f"wizard:soap_note:{wizard_id}"
|
|
153
|
-
await redis_client.setex(
|
|
154
|
-
cache_key, 7200, json.dumps(session_data) # 2 hour TTL - FIXED: use JSON
|
|
155
|
-
)
|
|
156
|
-
logger.info(f"Stored SOAP note wizard session {wizard_id} in Redis")
|
|
157
|
-
return True
|
|
158
|
-
except Exception as e:
|
|
159
|
-
logger.warning(f"Failed to store session in Redis: {e}, using memory fallback")
|
|
160
|
-
|
|
161
|
-
# Memory fallback
|
|
162
|
-
_wizard_sessions[wizard_id] = session_data
|
|
163
|
-
logger.info(f"Stored SOAP note wizard session {wizard_id} in memory")
|
|
164
|
-
return True
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
async def _get_wizard_session(wizard_id: str) -> dict[str, Any] | None:
|
|
168
|
-
"""Retrieve wizard session from Redis (preferred) or memory (fallback)"""
|
|
169
|
-
try:
|
|
170
|
-
if _has_redis:
|
|
171
|
-
redis_client = await get_redis_client()
|
|
172
|
-
if redis_client:
|
|
173
|
-
import json
|
|
174
|
-
|
|
175
|
-
cache_key = f"wizard:soap_note:{wizard_id}"
|
|
176
|
-
session_str = await redis_client.get(cache_key)
|
|
177
|
-
if session_str:
|
|
178
|
-
# SECURITY FIX: Use json.loads() instead of ast.literal_eval()
|
|
179
|
-
return json.loads(session_str)
|
|
180
|
-
except Exception as e:
|
|
181
|
-
logger.warning(f"Failed to retrieve session from Redis: {e}, checking memory")
|
|
182
|
-
|
|
183
|
-
# Memory fallback
|
|
184
|
-
return _wizard_sessions.get(wizard_id)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def _get_step_data(step: int) -> dict[str, Any]:
|
|
188
|
-
"""Get step configuration data"""
|
|
189
|
-
if step not in SOAP_NOTE_STEPS:
|
|
190
|
-
raise HTTPException(
|
|
191
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
192
|
-
detail=f"Invalid step number: {step}",
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
step_config = SOAP_NOTE_STEPS[step]
|
|
196
|
-
return {
|
|
197
|
-
"step": step,
|
|
198
|
-
"title": step_config["title"],
|
|
199
|
-
"prompt": step_config["prompt"],
|
|
200
|
-
"fields": step_config["fields"],
|
|
201
|
-
"help_text": step_config["help_text"],
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
def _generate_soap_note_report(collected_data: dict[str, Any]) -> dict[str, Any]:
|
|
206
|
-
"""Generate final SOAP note report from collected data"""
|
|
207
|
-
|
|
208
|
-
# Extract data by section
|
|
209
|
-
subjective = {
|
|
210
|
-
"chief_complaint": collected_data.get("chief_complaint", "Not documented"),
|
|
211
|
-
"history_present_illness": collected_data.get("history_present_illness", "Not documented"),
|
|
212
|
-
"patient_reported_symptoms": collected_data.get(
|
|
213
|
-
"patient_reported_symptoms", "Not documented"
|
|
214
|
-
),
|
|
215
|
-
"pain_description": collected_data.get("pain_description", "Not documented"),
|
|
216
|
-
"functional_status": collected_data.get("functional_status", "Not documented"),
|
|
217
|
-
"patient_concerns": collected_data.get("patient_concerns", "None reported"),
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
objective = {
|
|
221
|
-
"vital_signs": collected_data.get("vital_signs", "Not documented"),
|
|
222
|
-
"physical_exam_findings": collected_data.get("physical_exam_findings", "Not documented"),
|
|
223
|
-
"lab_results": collected_data.get("lab_results", "Pending or not available"),
|
|
224
|
-
"imaging_results": collected_data.get("imaging_results", "Pending or not available"),
|
|
225
|
-
"medication_administration": collected_data.get(
|
|
226
|
-
"medication_administration", "None documented"
|
|
227
|
-
),
|
|
228
|
-
"procedures_performed": collected_data.get("procedures_performed", "None documented"),
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
assessment = {
|
|
232
|
-
"primary_diagnosis": collected_data.get("primary_diagnosis", "Not documented"),
|
|
233
|
-
"differential_diagnoses": collected_data.get("differential_diagnoses", "Not documented"),
|
|
234
|
-
"problem_list": collected_data.get("problem_list", "Not documented"),
|
|
235
|
-
"progress_evaluation": collected_data.get("progress_evaluation", "Not documented"),
|
|
236
|
-
"response_to_treatment": collected_data.get("response_to_treatment", "Not documented"),
|
|
237
|
-
"complications_concerns": collected_data.get("complications_concerns", "None identified"),
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
plan = {
|
|
241
|
-
"diagnostic_plan": collected_data.get("diagnostic_plan", "Not documented"),
|
|
242
|
-
"therapeutic_plan": collected_data.get("therapeutic_plan", "Not documented"),
|
|
243
|
-
"patient_education": collected_data.get("patient_education", "Not documented"),
|
|
244
|
-
"monitoring_plan": collected_data.get("monitoring_plan", "Not documented"),
|
|
245
|
-
"follow_up": collected_data.get("follow_up", "Not documented"),
|
|
246
|
-
"consultations_needed": collected_data.get("consultations_needed", "None at this time"),
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
# Generate formatted narrative
|
|
250
|
-
narrative = f"""
|
|
251
|
-
SOAP NOTE
|
|
252
|
-
Date: {collected_data.get('note_date', datetime.now().strftime('%Y-%m-%d %H:%M'))}
|
|
253
|
-
|
|
254
|
-
SUBJECTIVE:
|
|
255
|
-
Chief Complaint: {subjective['chief_complaint']}
|
|
256
|
-
|
|
257
|
-
History of Present Illness: {subjective['history_present_illness']}
|
|
258
|
-
|
|
259
|
-
Patient-Reported Symptoms: {subjective['patient_reported_symptoms']}
|
|
260
|
-
|
|
261
|
-
Pain: {subjective['pain_description']}
|
|
262
|
-
|
|
263
|
-
Functional Status: {subjective['functional_status']}
|
|
264
|
-
|
|
265
|
-
Patient Concerns: {subjective['patient_concerns']}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
OBJECTIVE:
|
|
269
|
-
Vital Signs: {objective['vital_signs']}
|
|
270
|
-
|
|
271
|
-
Physical Examination: {objective['physical_exam_findings']}
|
|
272
|
-
|
|
273
|
-
Laboratory Results: {objective['lab_results']}
|
|
274
|
-
|
|
275
|
-
Imaging Results: {objective['imaging_results']}
|
|
276
|
-
|
|
277
|
-
Medications Administered: {objective['medication_administration']}
|
|
278
|
-
|
|
279
|
-
Procedures Performed: {objective['procedures_performed']}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
ASSESSMENT:
|
|
283
|
-
Primary Diagnosis: {assessment['primary_diagnosis']}
|
|
284
|
-
|
|
285
|
-
Differential Diagnoses: {assessment['differential_diagnoses']}
|
|
286
|
-
|
|
287
|
-
Problem List: {assessment['problem_list']}
|
|
288
|
-
|
|
289
|
-
Progress Evaluation: {assessment['progress_evaluation']}
|
|
290
|
-
|
|
291
|
-
Response to Treatment: {assessment['response_to_treatment']}
|
|
292
|
-
|
|
293
|
-
Complications/Concerns: {assessment['complications_concerns']}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
PLAN:
|
|
297
|
-
Diagnostic Plan: {plan['diagnostic_plan']}
|
|
298
|
-
|
|
299
|
-
Therapeutic Plan: {plan['therapeutic_plan']}
|
|
300
|
-
|
|
301
|
-
Patient Education: {plan['patient_education']}
|
|
302
|
-
|
|
303
|
-
Monitoring Plan: {plan['monitoring_plan']}
|
|
304
|
-
|
|
305
|
-
Follow-up: {plan['follow_up']}
|
|
306
|
-
|
|
307
|
-
Consultations Needed: {plan['consultations_needed']}
|
|
308
|
-
"""
|
|
309
|
-
|
|
310
|
-
return {
|
|
311
|
-
"soap_note": {
|
|
312
|
-
"subjective": subjective,
|
|
313
|
-
"objective": objective,
|
|
314
|
-
"assessment": assessment,
|
|
315
|
-
"plan": plan,
|
|
316
|
-
},
|
|
317
|
-
"narrative": narrative.strip(),
|
|
318
|
-
"metadata": {
|
|
319
|
-
"generated_at": datetime.now().isoformat(),
|
|
320
|
-
"note_date": collected_data.get("note_date", datetime.now().strftime("%Y-%m-%d %H:%M")),
|
|
321
|
-
"wizard_type": "soap_note",
|
|
322
|
-
},
|
|
323
|
-
"banner": EDU_BANNER,
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
@router.post("/start", summary="Start SOAP Note Wizard")
|
|
328
|
-
async def start_soap_note_wizard():
|
|
329
|
-
"""
|
|
330
|
-
Initialize a new SOAP note documentation wizard session.
|
|
331
|
-
|
|
332
|
-
SOAP (Subjective, Objective, Assessment, Plan) is the standard format
|
|
333
|
-
for clinical progress notes used across healthcare settings.
|
|
334
|
-
|
|
335
|
-
Returns a wizard session ID and first step configuration.
|
|
336
|
-
"""
|
|
337
|
-
try:
|
|
338
|
-
wizard_id = str(uuid4())
|
|
339
|
-
|
|
340
|
-
session_data = {
|
|
341
|
-
"wizard_id": wizard_id,
|
|
342
|
-
"wizard_type": "soap_note",
|
|
343
|
-
"current_step": 1,
|
|
344
|
-
"total_steps": 5,
|
|
345
|
-
"collected_data": {},
|
|
346
|
-
"created_at": datetime.now().isoformat(),
|
|
347
|
-
"updated_at": datetime.now().isoformat(),
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
# Store session
|
|
351
|
-
await _store_wizard_session(wizard_id, session_data)
|
|
352
|
-
|
|
353
|
-
# Get first step data
|
|
354
|
-
step_data = _get_step_data(1)
|
|
355
|
-
|
|
356
|
-
response_data = {
|
|
357
|
-
"wizard_session": session_data,
|
|
358
|
-
"current_step": step_data,
|
|
359
|
-
"progress": {"current": 1, "total": 4, "percentage": 25},
|
|
360
|
-
"banner": EDU_BANNER,
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return create_success_response(
|
|
364
|
-
data=response_data, message="SOAP note wizard started successfully"
|
|
365
|
-
)
|
|
366
|
-
|
|
367
|
-
except Exception as e:
|
|
368
|
-
logger.error(f"Failed to start SOAP note wizard: {e}")
|
|
369
|
-
raise HTTPException(
|
|
370
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
371
|
-
detail=f"Failed to start SOAP note wizard: {str(e)}",
|
|
372
|
-
)
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
@router.post("/{wizard_id}/step", summary="Submit SOAP note wizard step")
|
|
376
|
-
async def submit_soap_note_step(wizard_id: str, step_data: dict[str, Any]):
|
|
377
|
-
"""
|
|
378
|
-
Submit data for current step and advance to next step.
|
|
379
|
-
|
|
380
|
-
The wizard will validate the data, store it, and either:
|
|
381
|
-
- Return the next step configuration (if more steps remain)
|
|
382
|
-
- Return the complete SOAP note report (if all steps completed)
|
|
383
|
-
"""
|
|
384
|
-
try:
|
|
385
|
-
# Retrieve session
|
|
386
|
-
session = await _get_wizard_session(wizard_id)
|
|
387
|
-
if not session:
|
|
388
|
-
raise HTTPException(
|
|
389
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
390
|
-
detail=f"Wizard session {wizard_id} not found",
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
current_step = session["current_step"]
|
|
394
|
-
total_steps = session["total_steps"]
|
|
395
|
-
|
|
396
|
-
# Validate step number
|
|
397
|
-
submitted_step = step_data.get("step", current_step)
|
|
398
|
-
if submitted_step != current_step:
|
|
399
|
-
raise HTTPException(
|
|
400
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
401
|
-
detail=f"Expected step {current_step}, got step {submitted_step}",
|
|
402
|
-
)
|
|
403
|
-
|
|
404
|
-
# Store submitted data
|
|
405
|
-
session["collected_data"].update(step_data.get("data", {}))
|
|
406
|
-
session["updated_at"] = datetime.now().isoformat()
|
|
407
|
-
|
|
408
|
-
# Advance to next step (but don't auto-complete, even on final step)
|
|
409
|
-
if current_step < total_steps:
|
|
410
|
-
next_step = current_step + 1
|
|
411
|
-
session["current_step"] = next_step
|
|
412
|
-
else:
|
|
413
|
-
# On review step - stay on same step, don't auto-complete
|
|
414
|
-
next_step = current_step
|
|
415
|
-
|
|
416
|
-
await _store_wizard_session(wizard_id, session)
|
|
417
|
-
|
|
418
|
-
# Get next step configuration
|
|
419
|
-
next_step_data = _get_step_data(next_step)
|
|
420
|
-
|
|
421
|
-
response_data = {
|
|
422
|
-
"wizard_session": session,
|
|
423
|
-
"current_step": next_step_data,
|
|
424
|
-
"progress": {
|
|
425
|
-
"current": next_step,
|
|
426
|
-
"total": total_steps,
|
|
427
|
-
"percentage": int((next_step / total_steps) * 100),
|
|
428
|
-
},
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
return create_success_response(
|
|
432
|
-
data=response_data,
|
|
433
|
-
message=f"Step {current_step} completed, moved to step {next_step}",
|
|
434
|
-
)
|
|
435
|
-
|
|
436
|
-
except HTTPException:
|
|
437
|
-
raise
|
|
438
|
-
except Exception as e:
|
|
439
|
-
logger.error(f"Failed to process SOAP note wizard step: {e}")
|
|
440
|
-
raise HTTPException(
|
|
441
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
442
|
-
detail=f"Failed to process wizard step: {str(e)}",
|
|
443
|
-
)
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
@router.post("/{wizard_id}/enhance", summary="Enhance SOAP note text with AI")
|
|
447
|
-
async def enhance_soap_note_text(wizard_id: str, text_data: dict[str, Any]):
|
|
448
|
-
"""
|
|
449
|
-
Enhance user-provided text with AI to improve clinical documentation quality.
|
|
450
|
-
|
|
451
|
-
Uses the chat service to refine language, add clinical terminology,
|
|
452
|
-
and improve clarity while preserving the original meaning.
|
|
453
|
-
"""
|
|
454
|
-
try:
|
|
455
|
-
# Verify wizard session exists
|
|
456
|
-
session = await _get_wizard_session(wizard_id)
|
|
457
|
-
if not session:
|
|
458
|
-
raise HTTPException(
|
|
459
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
460
|
-
detail=f"Wizard session {wizard_id} not found",
|
|
461
|
-
)
|
|
462
|
-
|
|
463
|
-
original_text = text_data.get("text", "")
|
|
464
|
-
field_name = text_data.get("field", "text")
|
|
465
|
-
|
|
466
|
-
if not original_text:
|
|
467
|
-
raise HTTPException(
|
|
468
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
469
|
-
detail="No text provided for enhancement",
|
|
470
|
-
)
|
|
471
|
-
|
|
472
|
-
# Get chat service
|
|
473
|
-
chat_service = get_service("chat")
|
|
474
|
-
|
|
475
|
-
# Create enhancement prompt
|
|
476
|
-
enhancement_prompt = f"""
|
|
477
|
-
You are assisting with SOAP note documentation. Please enhance the following text
|
|
478
|
-
to be more professional and clinically appropriate while preserving the original meaning:
|
|
479
|
-
|
|
480
|
-
Field: {field_name}
|
|
481
|
-
Original text: {original_text}
|
|
482
|
-
|
|
483
|
-
Please provide an enhanced version that:
|
|
484
|
-
- Uses appropriate clinical terminology
|
|
485
|
-
- Is clear and concise
|
|
486
|
-
- Maintains professional tone
|
|
487
|
-
- Preserves all key information
|
|
488
|
-
- Follows SOAP note documentation standards
|
|
489
|
-
|
|
490
|
-
Enhanced text:"""
|
|
491
|
-
|
|
492
|
-
# Call chat service for enhancement
|
|
493
|
-
chat_response = await chat_service.chat(
|
|
494
|
-
message=enhancement_prompt,
|
|
495
|
-
conversation_id=f"soap_enhance_{wizard_id}",
|
|
496
|
-
context={"wizard_id": wizard_id, "field": field_name},
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
enhanced_text = chat_response.get("response", original_text)
|
|
500
|
-
|
|
501
|
-
response_data = {
|
|
502
|
-
"original_text": original_text,
|
|
503
|
-
"enhanced_text": enhanced_text,
|
|
504
|
-
"field": field_name,
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
return create_success_response(data=response_data, message="Text enhanced successfully")
|
|
508
|
-
|
|
509
|
-
except HTTPException:
|
|
510
|
-
raise
|
|
511
|
-
except Exception as e:
|
|
512
|
-
logger.error(f"Failed to enhance SOAP note text: {e}")
|
|
513
|
-
raise HTTPException(
|
|
514
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
515
|
-
detail=f"Failed to enhance text: {str(e)}",
|
|
516
|
-
)
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
@router.post("/{wizard_id}/preview", summary="Preview SOAP note report")
|
|
520
|
-
async def preview_soap_note_report(wizard_id: str):
|
|
521
|
-
"""
|
|
522
|
-
Generate preview of SOAP note report without finalizing.
|
|
523
|
-
|
|
524
|
-
This endpoint allows users to see the formatted SOAP note before
|
|
525
|
-
finalizing it. The report is NOT marked as complete. Users can
|
|
526
|
-
still go back and edit data after previewing.
|
|
527
|
-
"""
|
|
528
|
-
try:
|
|
529
|
-
# Retrieve session
|
|
530
|
-
session = await _get_wizard_session(wizard_id)
|
|
531
|
-
if not session:
|
|
532
|
-
raise HTTPException(
|
|
533
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
534
|
-
detail=f"Wizard session {wizard_id} not found",
|
|
535
|
-
)
|
|
536
|
-
|
|
537
|
-
# Verify user is on review step
|
|
538
|
-
if session["current_step"] != session["total_steps"]:
|
|
539
|
-
raise HTTPException(
|
|
540
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
541
|
-
detail=f"Not on review step. Complete steps 1-{session['total_steps']-1} first.",
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
# Generate preview report (does NOT mark as complete)
|
|
545
|
-
preview_report = _generate_soap_note_report(session["collected_data"])
|
|
546
|
-
|
|
547
|
-
# Store preview in session
|
|
548
|
-
session["preview_report"] = preview_report
|
|
549
|
-
session["preview_generated_at"] = datetime.now().isoformat()
|
|
550
|
-
await _store_wizard_session(wizard_id, session)
|
|
551
|
-
|
|
552
|
-
response_data = {
|
|
553
|
-
"preview": preview_report,
|
|
554
|
-
"wizard_session": session,
|
|
555
|
-
"message": "Review the SOAP note above. Click 'Finalize Report' to save, or go back to edit any section.",
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return create_success_response(data=response_data, message="Preview generated successfully")
|
|
559
|
-
|
|
560
|
-
except HTTPException:
|
|
561
|
-
raise
|
|
562
|
-
except Exception as e:
|
|
563
|
-
logger.error(f"Failed to generate SOAP note preview: {e}")
|
|
564
|
-
raise HTTPException(
|
|
565
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
566
|
-
detail=f"Failed to generate preview: {str(e)}",
|
|
567
|
-
)
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
@router.post("/{wizard_id}/save", summary="Finalize SOAP note report")
|
|
571
|
-
async def save_soap_note_report(wizard_id: str, approval_data: dict[str, Any]):
|
|
572
|
-
"""
|
|
573
|
-
Finalize and save the SOAP note report after user review and approval.
|
|
574
|
-
|
|
575
|
-
Requires that the user has:
|
|
576
|
-
1. Generated a preview first (/preview endpoint)
|
|
577
|
-
2. Explicitly approved the report (user_approved: true)
|
|
578
|
-
|
|
579
|
-
Only after calling this endpoint is the report marked as complete.
|
|
580
|
-
"""
|
|
581
|
-
try:
|
|
582
|
-
# Retrieve session
|
|
583
|
-
session = await _get_wizard_session(wizard_id)
|
|
584
|
-
if not session:
|
|
585
|
-
raise HTTPException(
|
|
586
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
587
|
-
detail=f"Wizard session {wizard_id} not found",
|
|
588
|
-
)
|
|
589
|
-
|
|
590
|
-
# Verify preview was generated
|
|
591
|
-
if "preview_report" not in session:
|
|
592
|
-
raise HTTPException(
|
|
593
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
594
|
-
detail="Must generate preview before saving. Call /preview endpoint first.",
|
|
595
|
-
)
|
|
596
|
-
|
|
597
|
-
# Verify user explicitly approved
|
|
598
|
-
if not approval_data.get("user_approved", False):
|
|
599
|
-
raise HTTPException(
|
|
600
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
601
|
-
detail="User approval required. Set 'user_approved': true in request body.",
|
|
602
|
-
)
|
|
603
|
-
|
|
604
|
-
# NOW we mark as complete
|
|
605
|
-
session["completed"] = True
|
|
606
|
-
session["completed_at"] = datetime.now().isoformat()
|
|
607
|
-
session["final_report"] = session["preview_report"]
|
|
608
|
-
session["user_approved"] = True
|
|
609
|
-
|
|
610
|
-
await _store_wizard_session(wizard_id, session)
|
|
611
|
-
|
|
612
|
-
response_data = {
|
|
613
|
-
"wizard_session": session,
|
|
614
|
-
"report": session["final_report"],
|
|
615
|
-
"completed": True,
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
return create_success_response(
|
|
619
|
-
data=response_data, message="SOAP note finalized successfully"
|
|
620
|
-
)
|
|
621
|
-
|
|
622
|
-
except HTTPException:
|
|
623
|
-
raise
|
|
624
|
-
except Exception as e:
|
|
625
|
-
logger.error(f"Failed to save SOAP note: {e}")
|
|
626
|
-
raise HTTPException(
|
|
627
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
628
|
-
detail=f"Failed to finalize SOAP note: {str(e)}",
|
|
629
|
-
)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
@router.get("/{wizard_id}/report", summary="Get SOAP note report")
|
|
633
|
-
async def get_soap_note_report(wizard_id: str):
|
|
634
|
-
"""
|
|
635
|
-
Retrieve the completed SOAP note report.
|
|
636
|
-
|
|
637
|
-
Only available after all wizard steps have been completed.
|
|
638
|
-
Returns the structured SOAP note data and formatted narrative.
|
|
639
|
-
"""
|
|
640
|
-
try:
|
|
641
|
-
# Retrieve session
|
|
642
|
-
session = await _get_wizard_session(wizard_id)
|
|
643
|
-
if not session:
|
|
644
|
-
raise HTTPException(
|
|
645
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
646
|
-
detail=f"Wizard session {wizard_id} not found",
|
|
647
|
-
)
|
|
648
|
-
|
|
649
|
-
# Check if completed
|
|
650
|
-
if not session.get("completed", False):
|
|
651
|
-
raise HTTPException(
|
|
652
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
653
|
-
detail="SOAP note wizard not yet completed. Complete all steps first.",
|
|
654
|
-
)
|
|
655
|
-
|
|
656
|
-
# Generate report
|
|
657
|
-
report = _generate_soap_note_report(session["collected_data"])
|
|
658
|
-
|
|
659
|
-
response_data = {
|
|
660
|
-
"wizard_session": session,
|
|
661
|
-
"report": report,
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
return create_success_response(
|
|
665
|
-
data=response_data, message="SOAP note report retrieved successfully"
|
|
666
|
-
)
|
|
667
|
-
|
|
668
|
-
except HTTPException:
|
|
669
|
-
raise
|
|
670
|
-
except Exception as e:
|
|
671
|
-
logger.error(f"Failed to retrieve SOAP note report: {e}")
|
|
672
|
-
raise HTTPException(
|
|
673
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
674
|
-
detail=f"Failed to retrieve report: {str(e)}",
|
|
675
|
-
)
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
# Export router
|
|
679
|
-
__all__ = ["router"]
|
wizards/treatment_plan.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Shim module to expose the existing treatment_plan router under the `src` package.
|
|
3
|
-
Some routers live at `routers.wizards.*` (top-level); tests and src loader expect `src.routers.wizards.*`.
|
|
4
|
-
This shim imports the real router and exposes it for the src-based loader.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
try:
|
|
8
|
-
from routers.wizards.treatment_plan import router # type: ignore
|
|
9
|
-
except Exception:
|
|
10
|
-
# Fallback: expose an empty APIRouter so imports don't fail
|
|
11
|
-
from fastapi import APIRouter
|
|
12
|
-
|
|
13
|
-
router = APIRouter()
|
|
14
|
-
|
|
15
|
-
__all__ = ["router"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|