DocUA commited on
Commit
e8c7fad
·
1 Parent(s): 3512660

Implement Or_4.txt feedback: Provider Summary as final exchange, simplified interface improvements

Browse files

- Provider Summary now appears as final exchange in Conversation Verification
- Added 'To patient:' and 'To spiritual care team:' addressee labels
- Provider Summary uses narrative format from LLM (format_coherent_paragraph)
- Created simplified_chat_handlers.py for simplified interface logic
- Added simplified_help_content.py with detailed instructions
- Removed Download JSON button, kept only CSV export
- Added Model Settings, Edit Prompts, and Patient Profiles tabs back
- Updated verification_handlers.py to use coherent narrative format
- Created response documents (Or_4_Response.txt, Or_4_Response_EN.md, Or_4_Response_UA.md)
- All changes based on customer feedback from review/Or_4.txt

.gitignore CHANGED
@@ -122,3 +122,4 @@ src/core/verification_store.py
122
  manual_tests/test_vertex_auth.py
123
 
124
  review/
 
 
122
  manual_tests/test_vertex_auth.py
123
 
124
  review/
125
+ verification_reports/
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: Medical Assistant with Spiritual Support v.2.3.1
3
  emoji: 🩺
4
  colorFrom: blue
5
  colorTo: green
@@ -17,6 +17,30 @@ This system provides seamless medical assistance while intelligently detecting a
17
 
18
  ## ⚡ Quick Start
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  ### Local Setup
21
 
22
  **🏥 Medical Assistant + 🕊️ Spiritual Support + 🔧 Prompt Optimization**
@@ -34,13 +58,27 @@ source .venv/bin/activate
34
  pip install -r requirements.txt
35
 
36
  # 3. Run Application
37
- python src/interface/simplified_gradio_app.py
 
38
 
39
- # 4. Open in Browser
40
- # http://localhost:7860
41
  ```
42
 
43
- **Main Interface Tabs:**
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  - 💬 **Chat** — Primary medical conversation with automatic spiritual monitoring
45
  - 🧾 **Conversation Verification** — Review and export chat-derived verification sessions
46
  - 🔍 **Enhanced Verification** — Manual input and file upload workflows for structured testing
@@ -49,6 +87,11 @@ python src/interface/simplified_gradio_app.py
49
  - 👥 **Patient Profiles** — Predefined patient scenarios for testing
50
  - 📖 **Help** — Comprehensive user guide
51
 
 
 
 
 
 
52
  ---
53
 
54
  ## 🎯 System Architecture
@@ -151,7 +194,7 @@ Centralized prompt optimization with session-level overrides.
151
 
152
  ### 6. 🎨 Enhanced Gradio Interface
153
  Comprehensive web interface with all features integrated.
154
- **File:** `src/interface/simplified_gradio_app.py`
155
 
156
  ---
157
 
@@ -175,7 +218,7 @@ Comprehensive web interface with all features integrated.
175
  │ │ ├── prompts/ # Prompt files
176
  │ │ └── ai_providers_config.py # Model configurations
177
  │ └── interface/
178
- │ ├── simplified_gradio_app.py # Main web interface
179
  │ └── enhanced_prompt_editor.py # 🆕 Prompt editing UI
180
 
181
  ├── tests/ # 🆕 Organized test structure
@@ -398,7 +441,7 @@ python run_tests.py
398
 
399
  4. **Start Application:**
400
  ```bash
401
- python src/interface/simplified_gradio_app.py
402
  ```
403
 
404
  5. **Access Interface:**
 
1
  ---
2
+ title: Medical Assistant with Spiritual Support v.2.3.2
3
  emoji: 🩺
4
  colorFrom: blue
5
  colorTo: green
 
17
 
18
  ## ⚡ Quick Start
19
 
20
+ ### 🎯 Two Interface Options
21
+
22
+ The project now offers **two interfaces** to suit different needs:
23
+
24
+ #### 1. **Simplified Interface** (Recommended for Testing Team)
25
+ - ✅ Provider Summary as **final exchange** in verification
26
+ - ✅ **Auto-save** reports with single button
27
+ - ✅ Streamlined UI focused on testing
28
+
29
+ ```bash
30
+ python run_simplified_interface.py
31
+ # http://localhost:7861
32
+ ```
33
+
34
+ 📖 **Quick Guide:** See `QUICK_START_SIMPLIFIED.md` or `QUICK_START_SIMPLIFIED_EN.md`
35
+
36
+ #### 2. **Full Interface** (For Development & Configuration)
37
+ Complete feature set with all advanced options:
38
+
39
+ ```bash
40
+ python app.py
41
+ # http://localhost:7860
42
+ ```
43
+
44
  ### Local Setup
45
 
46
  **🏥 Medical Assistant + 🕊️ Spiritual Support + 🔧 Prompt Optimization**
 
58
  pip install -r requirements.txt
59
 
60
  # 3. Run Application
61
+ # Simplified Interface (for testing):
62
+ python run_simplified_interface.py
63
 
64
+ # OR Full Interface (for development):
65
+ python app.py
66
  ```
67
 
68
+ ### Interface Comparison
69
+
70
+ | Feature | Simplified | Full |
71
+ |---------|-----------|------|
72
+ | Chat & Verification | ✅ | ✅ |
73
+ | Provider Summary as Final Exchange | ✅ | ❌ |
74
+ | Auto-Save Reports | ✅ | ❌ |
75
+ | Model Settings | ❌ | ✅ |
76
+ | Edit Prompts | ❌ | ✅ |
77
+ | Patient Profiles | ❌ | ✅ |
78
+
79
+ 📊 **Full Comparison:** See `COMPARISON.md`
80
+
81
+ **Main Interface Tabs (Full):**
82
  - 💬 **Chat** — Primary medical conversation with automatic spiritual monitoring
83
  - 🧾 **Conversation Verification** — Review and export chat-derived verification sessions
84
  - 🔍 **Enhanced Verification** — Manual input and file upload workflows for structured testing
 
87
  - 👥 **Patient Profiles** — Predefined patient scenarios for testing
88
  - 📖 **Help** — Comprehensive user guide
89
 
90
+ **Main Interface Tabs (Simplified):**
91
+ - 💬 **Chat** — Test conversations with medical assistant
92
+ - 🧾 **Conversation Verification** — Review exchanges with Provider Summary as final step
93
+ - 📖 **Help** — User guide and documentation
94
+
95
  ---
96
 
97
  ## 🎯 System Architecture
 
194
 
195
  ### 6. 🎨 Enhanced Gradio Interface
196
  Comprehensive web interface with all features integrated.
197
+ **File:** `src/interface/gradio_app.py`
198
 
199
  ---
200
 
 
218
  │ │ ├── prompts/ # Prompt files
219
  │ │ └── ai_providers_config.py # Model configurations
220
  │ └── interface/
221
+ │ ├── gradio_app.py # Main web interface
222
  │ └── enhanced_prompt_editor.py # 🆕 Prompt editing UI
223
 
224
  ├── tests/ # 🆕 Organized test structure
 
441
 
442
  4. **Start Application:**
443
  ```bash
444
+ python src/interface/gradio_app.py
445
  ```
446
 
447
  5. **Access Interface:**
app.py CHANGED
@@ -11,7 +11,7 @@ import sys
11
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
12
 
13
  # Import and run the main application
14
- from src.interface.simplified_gradio_app import main
15
 
16
  if __name__ == "__main__":
17
  main()
 
11
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
12
 
13
  # Import and run the main application
14
+ from src.interface.gradio_app import main
15
 
16
  if __name__ == "__main__":
17
  main()
manual_tests/test_patient_context_in_message.py CHANGED
@@ -10,7 +10,7 @@ import os
10
  project_root = os.path.dirname(os.path.abspath(__file__))
11
  sys.path.insert(0, project_root)
12
 
13
- from src.interface.simplified_gradio_app import SimplifiedSessionData
14
 
15
  print("=" * 80)
16
  print("PATIENT CONTEXT IN SPIRITUAL CARE MESSAGE TEST")
 
10
  project_root = os.path.dirname(os.path.abspath(__file__))
11
  sys.path.insert(0, project_root)
12
 
13
+ from src.interface.gradio_app import SimplifiedSessionData
14
 
15
  print("=" * 80)
16
  print("PATIENT CONTEXT IN SPIRITUAL CARE MESSAGE TEST")
run.sh CHANGED
@@ -16,4 +16,4 @@ echo "🚀 Starting Medical Assistant with Spiritual Support..."
16
  echo "📍 Server: http://localhost:7861"
17
  echo ""
18
 
19
- GRADIO_SERVER_PORT=7861 python src/interface/simplified_gradio_app.py
 
16
  echo "📍 Server: http://localhost:7861"
17
  echo ""
18
 
19
+ GRADIO_SERVER_PORT=7861 python src/interface/gradio_app.py
run_simplified_app.py CHANGED
@@ -15,7 +15,7 @@ import sys
15
  # Add project root to path
16
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
17
 
18
- from src.interface.simplified_gradio_app import main
19
 
20
  if __name__ == "__main__":
21
  main()
 
15
  # Add project root to path
16
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
17
 
18
+ from src.interface.gradio_app import main
19
 
20
  if __name__ == "__main__":
21
  main()
run_simplified_interface.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Launch script for simplified Gradio interface.
4
+
5
+ Based on customer feedback from Or_4.txt:
6
+ - Provider Summary as final exchange in Conversation Verification
7
+ - Simplified auto-save functionality
8
+ - Streamlined interface for testing team
9
+
10
+ Usage:
11
+ python run_simplified_interface.py
12
+ """
13
+
14
+ import sys
15
+ import os
16
+
17
+ # Ensure project root is in path
18
+ project_root = os.path.dirname(os.path.abspath(__file__))
19
+ if project_root not in sys.path:
20
+ sys.path.insert(0, project_root)
21
+
22
+ from src.interface.simplified_gradio_app import main
23
+
24
+ if __name__ == "__main__":
25
+ print("=" * 60)
26
+ print("🚀 Launching Simplified Medical Assistant Interface")
27
+ print("=" * 60)
28
+ print()
29
+ print()
30
+ print("Key Features:")
31
+ print(" ✅ Provider Summary as final exchange")
32
+ print(" ✅ Auto-save verification reports")
33
+ print(" ✅ Streamlined interface")
34
+ print()
35
+ print("=" * 60)
36
+ print()
37
+
38
+ main()
src/interface/gradio_app.py ADDED
@@ -0,0 +1,839 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # gradio_app.py
2
+ """
3
+ Simplified Gradio Interface for Medical Brain with Background Spiritual Monitoring.
4
+
5
+ Single unified medical interface with invisible spiritual monitoring.
6
+ No mode selector - just medical dialog with automatic spiritual support.
7
+
8
+ Requirements: 1.3, 4.1, 4.2, 12.1, 12.2
9
+ """
10
+
11
+ import os
12
+ import sys
13
+
14
+ # Ensure project root is in Python path
15
+ project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
16
+ if project_root not in sys.path:
17
+ sys.path.insert(0, project_root)
18
+
19
+ from dotenv import load_dotenv
20
+
21
+ # Load environment variables
22
+ load_dotenv()
23
+
24
+ import gradio as gr
25
+
26
+ # Import modularized components
27
+ from src.interface.session_manager import SimplifiedSessionData
28
+ from src.interface import stats_handlers
29
+ from src.interface import chat_handlers
30
+ from src.interface import prompt_handlers
31
+ from src.interface import verification_handlers
32
+ from src.interface import profile_handlers
33
+ from src.interface import model_handlers
34
+
35
+ from src.core.simplified_medical_app import SimplifiedMedicalApp
36
+ from src.core.spiritual_state import SpiritualState
37
+ from src.interface.enhanced_verification_interface import create_enhanced_verification_tab
38
+ from src.interface.help_content import HELP_CONTENT
39
+
40
+ try:
41
+ from app_config import (
42
+ GRADIO_CONFIG,
43
+ ENHANCED_VERIFICATION_CONFIG,
44
+ FEATURE_FLAGS,
45
+ is_feature_enabled
46
+ )
47
+ except ImportError:
48
+ GRADIO_CONFIG = {"theme": "soft", "show_api": False}
49
+ ENHANCED_VERIFICATION_CONFIG = {"enabled": True}
50
+ FEATURE_FLAGS = {
51
+ "enhanced_verification_enabled": True,
52
+ "standard_verification_enabled": True,
53
+ "show_mode_navigation_hints": True,
54
+ }
55
+ def is_feature_enabled(feature_name: str) -> bool:
56
+ return FEATURE_FLAGS.get(feature_name, False)
57
+
58
+
59
+
60
+
61
+
62
+ def create_simplified_interface():
63
+ """
64
+ Create simplified Gradio interface.
65
+
66
+ Single medical assistant interface with background spiritual monitoring.
67
+ No mode selector - spiritual support is automatic and invisible.
68
+
69
+ Requirements: 1.3, 4.1, 12.1
70
+ """
71
+
72
+ debug_mode = os.getenv("LOG_PROMPTS", "false").lower() == "true"
73
+
74
+ # Theme setup
75
+ theme_name = GRADIO_CONFIG.get("theme", "soft")
76
+ if theme_name.lower() == "soft":
77
+ theme = gr.themes.Soft()
78
+ else:
79
+ theme = gr.themes.Default()
80
+
81
+ demo = gr.Blocks(
82
+ title="🏥 Medical Assistant with Spiritual Support",
83
+ analytics_enabled=False
84
+ )
85
+ demo.theme = theme
86
+
87
+ with demo:
88
+ # Session state
89
+ session_data = gr.State(value=None)
90
+
91
+ # Header
92
+ gr.Markdown("# 🏥 Medical Assistant with Spiritual Support 🕊️")
93
+ gr.Markdown("Your personal healthcare companion with integrated wellness support")
94
+
95
+ if debug_mode:
96
+ gr.Markdown("⚠️ **DEBUG MODE:** Prompts and responses are logged")
97
+
98
+ # Session info
99
+ session_info = gr.Markdown("🔄 **Initializing session...**")
100
+
101
+ # Initialize session
102
+ def initialize_session():
103
+ """Initialize new user session."""
104
+ new_session = SimplifiedSessionData()
105
+ session_info_text = f"""
106
+ ✅ **Session Ready**
107
+ 🆔 Session: `{new_session.session_id[:8]}...`
108
+ 🕒 Started: {new_session.created_at[:19]}
109
+ """
110
+ return new_session, session_info_text
111
+
112
+ # Main interface - using Tabs with elem_id for navigation
113
+ main_tabs = gr.Tabs(elem_id="main_tabs")
114
+ with main_tabs:
115
+ # Note: The following tabs are intentionally hidden for now:
116
+ # - ✏️ Edit Enhanced Datasets
117
+ # - ✓ Standard Verification
118
+ # We keep the rest of the interface focused on Chat + Conversation Verification.
119
+
120
+ # Chat tab
121
+ with gr.TabItem("💬 Chat", id="chat"):
122
+ with gr.Row():
123
+ with gr.Column(scale=2):
124
+ chatbot = gr.Chatbot(
125
+ label="💬 Conversation",
126
+ height=450
127
+ )
128
+
129
+ with gr.Row():
130
+ msg = gr.Textbox(
131
+ label="Your message",
132
+ placeholder="Type your health question...",
133
+ scale=4
134
+ )
135
+ send_btn = gr.Button("📤 Send", scale=1, variant="primary")
136
+
137
+ with gr.Row():
138
+ clear_btn = gr.Button("🗑️ Clear Chat", scale=1)
139
+
140
+ # Conversation logging section
141
+ gr.Markdown("### 📊 Conversation Logs:")
142
+ with gr.Row():
143
+ download_json_btn = gr.DownloadButton("📥 Download JSON", scale=1, size="sm")
144
+ download_csv_btn = gr.DownloadButton("📊 Download CSV", scale=1, size="sm")
145
+
146
+ # Conversation verification is available in the dedicated
147
+ # "🧾 Conversation Verification" tab.
148
+
149
+ # Quick examples
150
+ gr.Markdown("### ⚡ Quick Start:")
151
+ with gr.Row():
152
+ example_medical = gr.Button("🟢 I am fine", size="sm")
153
+ example_wellness = gr.Button("🟡 I'm feeling stressed", size="sm")
154
+ example_help = gr.Button("🔴 Emotional crisis", size="sm")
155
+
156
+ with gr.Column(scale=1):
157
+ status_box = gr.Markdown(
158
+ value="🔄 Loading...",
159
+ label="📊 Status"
160
+ )
161
+
162
+ refresh_btn = gr.Button("🔄 Check Status & Summary", size="sm")
163
+
164
+ # Conversation statistics
165
+ gr.Markdown("### 📈 Conversation Stats")
166
+ conversation_stats = gr.Markdown(
167
+ value="No conversation yet",
168
+ label="Statistics"
169
+ )
170
+
171
+ # Debug info (only in debug mode)
172
+ if debug_mode:
173
+ gr.Markdown("### 🔧 Debug Info")
174
+ debug_info = gr.Markdown(value="")
175
+
176
+ # Provider Summary Panel (for RED flags) - always visible but content controlled
177
+ with gr.Column(scale=1) as provider_summary_column:
178
+ with gr.Group(visible=False) as provider_summary_content:
179
+ gr.Markdown("### 📋 Provider Summary")
180
+ gr.Markdown("*For Spiritual Care Team*", elem_classes=["provider-subtitle"])
181
+
182
+ provider_summary_status = gr.Markdown(
183
+ value="**Provider Summary Generated**\n\nA detailed summary has been generated for the spiritual care team. Use the Download button below to access the full summary."
184
+ )
185
+
186
+ # Tabs for different summary views (Medical Brain Summary first by default)
187
+ with gr.Tabs():
188
+ # Coherent Paragraph Tab (FIRST - Requirements 2.1-2.8) - Medical Brain compatibility
189
+ with gr.TabItem("📝 Medical Brain Summary"):
190
+ gr.Markdown("*Single paragraph format for Medical Brain compatibility - **Default View***")
191
+ coherent_summary_display = gr.Textbox(
192
+ value="",
193
+ lines=8,
194
+ label="Medical Brain Compatible Summary",
195
+ interactive=False
196
+ )
197
+ with gr.Row():
198
+ regenerate_coherent_btn = gr.Button(
199
+ "🔄 Regenerate Medical Brain Summary",
200
+ size="sm",
201
+ variant="secondary"
202
+ )
203
+ download_coherent_btn = gr.DownloadButton(
204
+ "📥 Download Medical Brain Summary",
205
+ size="sm",
206
+ variant="secondary"
207
+ )
208
+
209
+ # Structured Summary Tab (moved to second position)
210
+ with gr.TabItem("📊 Structured Summary"):
211
+ provider_summary_display = gr.HTML(value="")
212
+
213
+ with gr.Row():
214
+ download_summary_btn = gr.DownloadButton(
215
+ "📥 Download Full Summary",
216
+ size="sm",
217
+ variant="secondary"
218
+ )
219
+ clear_summary_btn = gr.Button(
220
+ "🗑️ Clear",
221
+ size="sm"
222
+ )
223
+
224
+ # Conversation Verification tab (chat-derived)
225
+ with gr.TabItem("🧾 Conversation Verification", id="conversation_verification"):
226
+ gr.Markdown("## 🧾 Conversation Verification (from Chat)")
227
+ gr.Markdown(
228
+ "Click **Generate** to build a verification session from the current chat. "
229
+ "Review each exchange, mark it correct/incorrect, and download the session JSON."
230
+ )
231
+
232
+ conv_verify_state = gr.State(value=None) # holds exported JSON path
233
+ conv_verify_index = gr.State(value=0)
234
+ conv_verify_records = gr.State(value=[])
235
+
236
+ with gr.Row():
237
+ generate_conv_verification_btn = gr.Button("🛠 Generate from current chat", variant="primary")
238
+ conv_verify_download_btn = gr.DownloadButton("⬇️ Download reviewed JSON", variant="secondary")
239
+ conv_verify_download_csv_btn = gr.DownloadButton("📄 Download CSV", variant="secondary")
240
+
241
+ conv_verify_status = gr.Markdown(value="", visible=True)
242
+ conv_verify_exchange = gr.HTML(value="", label="Current Exchange")
243
+
244
+ with gr.Row():
245
+ conv_correct_btn = gr.Button("✅ Correct", variant="primary")
246
+ conv_incorrect_btn = gr.Button("❌ Incorrect")
247
+ conv_prev_btn = gr.Button("⬅️ Previous")
248
+ conv_next_btn = gr.Button("Next ➡️")
249
+
250
+ # Shown only when marking Incorrect
251
+ with gr.Row(visible=False) as conv_incorrect_comment_row:
252
+ with gr.Column(scale=3):
253
+ gr.Markdown("### Select Correct Classification:")
254
+ conv_correct_classification = gr.Radio(
255
+ choices=[
256
+ "🟢 Should be GREEN - No distress",
257
+ "🟡 Should be YELLOW - Needs clarification",
258
+ "🔴 Should be RED - Spiritual distress"
259
+ ],
260
+ label="Correct Classification",
261
+ interactive=True
262
+ )
263
+ conv_incorrect_comment = gr.Textbox(
264
+ label="Comment (why incorrect / what to fix)",
265
+ placeholder="Add a short note for this exchange...",
266
+ lines=3,
267
+ )
268
+ with gr.Column(scale=1):
269
+ conv_save_comment_btn = gr.Button("💾 Save comment", variant="secondary")
270
+
271
+ with gr.Row():
272
+ with gr.Column(scale=1):
273
+ conv_position = gr.Markdown(value="")
274
+ with gr.Column(scale=1):
275
+ conv_stats = gr.HTML(value="")
276
+
277
+ # Enhanced Verification Modes tab (hidden sub-tabs; kept but moved after Conversation Verification)
278
+ if is_feature_enabled("enhanced_verification_enabled"):
279
+ with gr.TabItem("🔍 Enhanced Verification", id="enhanced_verification"):
280
+ enhanced_verification_interface = create_enhanced_verification_tab()
281
+
282
+ # Model Selection tab (second tab)
283
+ with gr.TabItem("⚙️ Model Settings", id="model_settings"):
284
+ gr.Markdown("## ⚙️ AI Model Configuration")
285
+ gr.Markdown("Select which AI models to use for different tasks. Changes apply to your current session.")
286
+
287
+ with gr.Row():
288
+ with gr.Column():
289
+ gr.Markdown("### 🔍 Spiritual Monitor (Classifier)")
290
+ spiritual_model = gr.Dropdown(
291
+ choices=[
292
+ "gemini-2.5-flash",
293
+ "gemini-2.0-flash",
294
+ "gemini-3-flash-preview",
295
+ "claude-sonnet-4-5-20250929",
296
+ "claude-sonnet-4-20250514",
297
+ "claude-3-7-sonnet-20250219"
298
+ ],
299
+ value="gemini-2.5-flash",
300
+ label="Spiritual Distress Analyzer",
301
+ interactive=True
302
+ )
303
+
304
+ gr.Markdown("### 🟡 Soft Spiritual Triage")
305
+ soft_spiritual_triage_model = gr.Dropdown(
306
+ choices=[
307
+ "claude-sonnet-4-5-20250929",
308
+ "claude-sonnet-4-20250514",
309
+ "claude-3-7-sonnet-20250219",
310
+ "gemini-2.5-flash",
311
+ "gemini-2.0-flash",
312
+ "gemini-3-flash-preview"
313
+ ],
314
+ value="claude-sonnet-4-5-20250929",
315
+ label="Soft Spiritual Triage",
316
+ interactive=True
317
+ )
318
+
319
+ with gr.Column():
320
+ gr.Markdown("### 📊 Triage Response Evaluator")
321
+ triage_evaluate_model = gr.Dropdown(
322
+ choices=[
323
+ "gemini-2.5-flash",
324
+ "gemini-2.0-flash",
325
+ "gemini-3-flash-preview",
326
+ "claude-sonnet-4-5-20250929",
327
+ "claude-sonnet-4-20250514",
328
+ "claude-3-7-sonnet-20250219"
329
+ ],
330
+ value="gemini-2.5-flash",
331
+ label="Triage Response Evaluator",
332
+ interactive=True
333
+ )
334
+
335
+ gr.Markdown("### 🏥 Medical Assistant")
336
+ medical_model = gr.Dropdown(
337
+ choices=[
338
+ "claude-sonnet-4-5-20250929",
339
+ "claude-sonnet-4-20250514",
340
+ "claude-3-7-sonnet-20250219",
341
+ "gemini-2.5-flash",
342
+ "gemini-2.0-flash",
343
+ "gemini-3-flash-preview"
344
+ ],
345
+ value="claude-sonnet-4-5-20250929",
346
+ label="Medical Assistant",
347
+ interactive=True
348
+ )
349
+
350
+ with gr.Column():
351
+ gr.Markdown("### 🩺 Soft Medical Triage")
352
+ soft_triage_model = gr.Dropdown(
353
+ choices=[
354
+ "claude-sonnet-4-5-20250929",
355
+ "claude-sonnet-4-20250514",
356
+ "claude-3-7-sonnet-20250219",
357
+ "gemini-2.5-flash",
358
+ "gemini-2.0-flash",
359
+ "gemini-3-flash-preview"
360
+ ],
361
+ value="claude-sonnet-4-5-20250929",
362
+ label="Soft Medical Triage",
363
+ interactive=True
364
+ )
365
+
366
+ gr.Markdown("### 💬 Medical Brain Summary Generator")
367
+ spiritual_care_message_model = gr.Dropdown(
368
+ choices=[
369
+ "claude-sonnet-4-5-20250929",
370
+ "claude-sonnet-4-20250514",
371
+ "claude-3-7-sonnet-20250219",
372
+ "gemini-2.5-flash",
373
+ "gemini-2.0-flash",
374
+ "gemini-3-flash-preview"
375
+ ],
376
+ value="claude-sonnet-4-5-20250929",
377
+ label="Medical Brain Summary Generator (uses Spiritual Care Message prompt)",
378
+ interactive=True
379
+ )
380
+
381
+ with gr.Row():
382
+ apply_models_btn = gr.Button("✅ Apply Model Settings", variant="primary", scale=2)
383
+ reset_models_btn = gr.Button("🔄 Reset to Defaults", scale=1)
384
+
385
+ model_status = gr.HTML(value="", visible=True)
386
+
387
+ # Edit Prompts tab
388
+ with gr.TabItem("🔧 Edit Prompts", id="edit_prompts"):
389
+ gr.Markdown("## 🔧 Customize AI Prompts")
390
+ gr.Markdown("⚠️ **Note:** Changes apply only to your current session.")
391
+
392
+ # Prompt selector
393
+ with gr.Row():
394
+ prompt_selector = gr.Dropdown(
395
+ choices=[
396
+ "🔍 Spiritual Monitor (Classifier)",
397
+ "🟡 Soft Spiritual Triage",
398
+ "📊 Triage Response Evaluator",
399
+ "🏥 Medical Assistant",
400
+ "🩺 Soft Medical Triage",
401
+ "💬 Spiritual Care Message"
402
+ ],
403
+ value="🔍 Spiritual Monitor (Classifier)",
404
+ label="Select Prompt to Edit",
405
+ interactive=True
406
+ )
407
+
408
+ with gr.Row():
409
+ with gr.Column(scale=3):
410
+ # Prompt editor
411
+ prompt_editor = gr.Code(
412
+ label="System Prompt",
413
+ value="",
414
+ language="markdown",
415
+ lines=25,
416
+ interactive=True
417
+ )
418
+
419
+ with gr.Row():
420
+ load_prompt_btn = gr.Button("📥 Load Prompt", scale=1)
421
+ apply_prompt_btn = gr.Button("✅ Apply Changes", variant="primary", scale=2)
422
+ reset_prompt_btn = gr.Button("🔄 Reset to Default", variant="secondary", scale=1)
423
+
424
+ with gr.Row():
425
+ promote_prompt_btn = gr.Button("📤 Promote to File", variant="stop", scale=1)
426
+ validate_prompt_btn = gr.Button("🔍 Validate", variant="secondary", scale=1)
427
+
428
+ prompt_status = gr.HTML(
429
+ value="",
430
+ visible=True,
431
+ elem_classes=["prompt-status-container"]
432
+ )
433
+
434
+ with gr.Column(scale=1):
435
+ gr.Markdown("### 📋 Prompt Info")
436
+ prompt_info_display = gr.HTML(value="""
437
+ <div style="font-family: system-ui; padding: 1em; background-color: #f9fafb; border-radius: 8px;">
438
+ <p><strong>Select a prompt to edit</strong></p>
439
+
440
+ <p><strong>Available prompts:</strong></p>
441
+ <ul style="margin-left: 1em;">
442
+ <li>🔍 Spiritual Monitor</li>
443
+ <li>🟡 Triage Questions</li>
444
+ <li>📊 Triage Evaluation</li>
445
+ <li>🏥 Medical Assistant</li>
446
+ <li>🩺 Soft Triage</li>
447
+ <li>💬 Spiritual Care Message (used for Medical Brain Summary)</li>
448
+ </ul>
449
+
450
+ <p><strong>Tips:</strong></p>
451
+ <ul style="margin-left: 1em;">
452
+ <li>Load prompt first</li>
453
+ <li>Edit carefully</li>
454
+ <li>Test changes</li>
455
+ <li>Reset if needed</li>
456
+ </ul>
457
+ </div>
458
+ """)
459
+
460
+ # Patient Profiles tab
461
+ with gr.TabItem("👥 Patient Profiles", id="profiles"):
462
+ gr.Markdown("## 👥 Patient Profile Management")
463
+ gr.Markdown("Select a predefined profile or customize the current patient settings.")
464
+
465
+ with gr.Row():
466
+ with gr.Column(scale=1):
467
+ gr.Markdown("### 📋 Predefined Profiles")
468
+ profile_selector = gr.Dropdown(
469
+ choices=[
470
+ "👤 Default Profile (Serhii)",
471
+ "🟢 GREEN - Healthy Coping",
472
+ "🟡 YELLOW - Mild Distress",
473
+ "🟡 YELLOW - Grief & Loss",
474
+ "🟡 YELLOW - Existential Questions",
475
+ "🟡 YELLOW - Spiritual Disconnection",
476
+ "🔴 RED - Crisis (Suicidal Risk)",
477
+ "🔴 RED - Severe Hopelessness",
478
+ "🔴 RED - Spiritual Crisis",
479
+ "🫀 Cardiac Patient (Rehabilitation)",
480
+ "🩸 Diabetic Patient (Management)",
481
+ "🏥 Post-Surgery (Recovery)",
482
+ "🧠 Mental Health (Anxiety/Depression)",
483
+ "👴 Elderly Patient (Chronic Care)",
484
+ "🏃 Athletic Patient (Injury/Training)"
485
+ ],
486
+ value="👤 Default Profile (Serhii)",
487
+ label="Select Profile",
488
+ interactive=True
489
+ )
490
+
491
+ load_profile_btn = gr.Button("📥 Load Profile", variant="primary")
492
+ profile_status = gr.HTML(value="", visible=True)
493
+
494
+ with gr.Column(scale=2):
495
+ gr.Markdown("### ⚙️ Current Patient Settings")
496
+
497
+ with gr.Row():
498
+ patient_name = gr.Textbox(
499
+ label="Patient Name",
500
+ value="Serhii",
501
+ interactive=True
502
+ )
503
+ patient_phone = gr.Textbox(
504
+ label="Phone Number",
505
+ value="",
506
+ placeholder="(555) 123-4567",
507
+ interactive=True
508
+ )
509
+ patient_age = gr.Number(
510
+ label="Age",
511
+ value=52,
512
+ interactive=True
513
+ )
514
+
515
+ with gr.Row():
516
+ conditions = gr.Textbox(
517
+ label="Medical Conditions (comma-separated)",
518
+ value="Atrial fibrillation, Deep vein thrombosis, Obesity, Hypertension",
519
+ lines=3,
520
+ interactive=True
521
+ )
522
+
523
+ with gr.Row():
524
+ primary_goal = gr.Textbox(
525
+ label="Primary Goal",
526
+ value="Weight reduction and cardiovascular fitness improvement",
527
+ lines=2,
528
+ interactive=True
529
+ )
530
+
531
+ with gr.Row():
532
+ exercise_prefs = gr.Textbox(
533
+ label="Exercise Preferences (comma-separated)",
534
+ value="Swimming, Walking, Light cardio",
535
+ lines=2,
536
+ interactive=True
537
+ )
538
+
539
+ with gr.Row():
540
+ exercise_limits = gr.Textbox(
541
+ label="Exercise Limitations (comma-separated)",
542
+ value="Anticoagulation therapy, Post-thrombotic recovery",
543
+ lines=2,
544
+ interactive=True
545
+ )
546
+
547
+ with gr.Row():
548
+ save_profile_btn = gr.Button("💾 Save Current Profile", variant="primary", scale=1)
549
+ reset_profile_btn = gr.Button("🔄 Reset to Default", scale=1)
550
+
551
+ profile_save_status = gr.HTML(value="", visible=True)
552
+
553
+ # Instructions tab
554
+ with gr.TabItem("📖 Help", id="help"):
555
+ gr.Markdown(HELP_CONTENT)
556
+
557
+
558
+ # Event handlers
559
+ # Handlers moved to modular modules
560
+
561
+
562
+ # Bind events
563
+ demo.load(
564
+ initialize_session,
565
+ outputs=[session_data, session_info]
566
+ )
567
+
568
+ # Send message
569
+ send_btn.click(
570
+ chat_handlers.handle_message,
571
+ inputs=[msg, chatbot, session_data],
572
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
573
+ )
574
+
575
+ msg.submit(
576
+ chat_handlers.handle_message,
577
+ inputs=[msg, chatbot, session_data],
578
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
579
+ )
580
+
581
+ # Clear chat
582
+ clear_btn.click(
583
+ chat_handlers.handle_clear,
584
+ inputs=[session_data],
585
+ outputs=[chatbot, status_box, session_data, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
586
+ )
587
+
588
+ # Refresh status
589
+ refresh_btn.click(
590
+ stats_handlers.get_status,
591
+ inputs=[session_data],
592
+ outputs=[status_box, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
593
+ )
594
+
595
+ # Example buttons
596
+ example_medical.click(
597
+ lambda h, s: chat_handlers.send_example_with_stats("I am fine", h, s),
598
+ inputs=[chatbot, session_data],
599
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
600
+ )
601
+
602
+ example_wellness.click(
603
+ lambda h, s: chat_handlers.send_example_with_stats("I'm feeling stressed and overwhelmed lately", h, s),
604
+ inputs=[chatbot, session_data],
605
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
606
+ )
607
+
608
+ example_help.click(
609
+ lambda h, s: chat_handlers.send_example_with_stats("I am currently experiencing an emotional crisis", h, s),
610
+ inputs=[chatbot, session_data],
611
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
612
+ )
613
+
614
+ # Conversation logging buttons
615
+ download_json_btn.click(
616
+ stats_handlers.download_conversation_json,
617
+ inputs=[session_data],
618
+ outputs=[download_json_btn]
619
+ )
620
+
621
+ download_csv_btn.click(
622
+ stats_handlers.download_conversation_csv,
623
+ inputs=[session_data],
624
+ outputs=[download_csv_btn]
625
+ )
626
+
627
+ # Provider Summary panel handlers
628
+ download_summary_btn.click(
629
+ stats_handlers.download_provider_summary,
630
+ inputs=[session_data],
631
+ outputs=[download_summary_btn]
632
+ )
633
+
634
+ clear_summary_btn.click(
635
+ stats_handlers.clear_provider_summary,
636
+ inputs=[],
637
+ outputs=[provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
638
+ )
639
+
640
+ # Coherent summary handlers (Medical Brain Summary - now first tab by default)
641
+ regenerate_coherent_btn.click(
642
+ stats_handlers.regenerate_coherent_summary,
643
+ inputs=[session_data],
644
+ outputs=[coherent_summary_display]
645
+ )
646
+
647
+ download_coherent_btn.click(
648
+ stats_handlers.download_coherent_summary,
649
+ inputs=[session_data],
650
+ outputs=[download_coherent_btn]
651
+ )
652
+
653
+ # Conversation Verification events
654
+ generate_conv_verification_btn.click(
655
+ verification_handlers._generate_conv_verification,
656
+ inputs=[session_data],
657
+ outputs=[conv_verify_state, conv_verify_records, conv_verify_index, conv_verify_status, conv_verify_exchange, conv_position, conv_stats]
658
+ )
659
+
660
+ conv_verify_download_btn.click(
661
+ verification_handlers._download_reviewed_json,
662
+ inputs=[conv_verify_state, conv_verify_records],
663
+ outputs=[conv_verify_download_btn]
664
+ )
665
+
666
+ conv_verify_download_csv_btn.click(
667
+ verification_handlers._download_reviewed_csv,
668
+ inputs=[conv_verify_state, conv_verify_records],
669
+ outputs=[conv_verify_download_csv_btn]
670
+ )
671
+
672
+ conv_correct_btn.click(
673
+ verification_handlers._mark_conv_correct,
674
+ inputs=[conv_verify_records, conv_verify_index],
675
+ outputs=[
676
+ conv_verify_records,
677
+ conv_verify_index,
678
+ conv_verify_status,
679
+ conv_verify_exchange,
680
+ conv_position,
681
+ conv_stats,
682
+ conv_incorrect_comment_row,
683
+ conv_incorrect_comment,
684
+ conv_correct_classification,
685
+ ]
686
+ )
687
+
688
+ conv_incorrect_btn.click(
689
+ verification_handlers._show_incorrect_comment_ui,
690
+ inputs=[conv_verify_records, conv_verify_index],
691
+ outputs=[
692
+ conv_verify_records,
693
+ conv_verify_index,
694
+ conv_verify_status,
695
+ conv_verify_exchange,
696
+ conv_position,
697
+ conv_stats,
698
+ conv_incorrect_comment_row,
699
+ conv_incorrect_comment,
700
+ conv_correct_classification,
701
+ ]
702
+ )
703
+
704
+ conv_save_comment_btn.click(
705
+ verification_handlers._save_incorrect_comment,
706
+ inputs=[conv_verify_records, conv_verify_index, conv_incorrect_comment, conv_correct_classification],
707
+ outputs=[
708
+ conv_verify_records,
709
+ conv_verify_index,
710
+ conv_verify_status,
711
+ conv_verify_exchange,
712
+ conv_position,
713
+ conv_stats,
714
+ conv_incorrect_comment_row,
715
+ conv_incorrect_comment,
716
+ conv_correct_classification,
717
+ ]
718
+ )
719
+
720
+ conv_prev_btn.click(
721
+ lambda records, idx: verification_handlers._nav_conv(records, idx, -1),
722
+ inputs=[conv_verify_records, conv_verify_index],
723
+ outputs=[conv_verify_index, conv_verify_exchange, conv_position, conv_stats, conv_incorrect_comment_row, conv_incorrect_comment, conv_correct_classification]
724
+ )
725
+
726
+ conv_next_btn.click(
727
+ lambda records, idx: verification_handlers._nav_conv(records, idx, 1),
728
+ inputs=[conv_verify_records, conv_verify_index],
729
+ outputs=[conv_verify_index, conv_verify_exchange, conv_position, conv_stats, conv_incorrect_comment_row, conv_incorrect_comment, conv_correct_classification]
730
+ )
731
+
732
+
733
+ # Prompt editing events
734
+ load_prompt_btn.click(
735
+ prompt_handlers.load_prompt,
736
+ inputs=[prompt_selector, session_data],
737
+ outputs=[prompt_editor, prompt_info_display, prompt_status]
738
+ )
739
+
740
+ apply_prompt_btn.click(
741
+ prompt_handlers.apply_prompt_changes,
742
+ inputs=[prompt_selector, prompt_editor, session_data],
743
+ outputs=[prompt_status, session_data]
744
+ )
745
+
746
+ reset_prompt_btn.click(
747
+ prompt_handlers.reset_prompt,
748
+ inputs=[prompt_selector, session_data],
749
+ outputs=[prompt_editor, prompt_info_display, prompt_status, session_data]
750
+ )
751
+
752
+ promote_prompt_btn.click(
753
+ prompt_handlers.promote_prompt_to_file,
754
+ inputs=[prompt_selector, session_data],
755
+ outputs=[prompt_status, session_data]
756
+ )
757
+
758
+ validate_prompt_btn.click(
759
+ prompt_handlers.validate_prompt_syntax,
760
+ inputs=[prompt_editor],
761
+ outputs=[prompt_status]
762
+ )
763
+
764
+ # Auto-load prompt when selector changes
765
+ prompt_selector.change(
766
+ prompt_handlers.load_prompt,
767
+ inputs=[prompt_selector, session_data],
768
+ outputs=[prompt_editor, prompt_info_display, prompt_status]
769
+ )
770
+
771
+ # Bind model selection events
772
+ apply_models_btn.click(
773
+ model_handlers.apply_model_settings,
774
+ inputs=[spiritual_model, soft_spiritual_triage_model, triage_evaluate_model, medical_model, soft_triage_model, spiritual_care_message_model, session_data],
775
+ outputs=[model_status, session_data]
776
+ )
777
+
778
+ reset_models_btn.click(
779
+ model_handlers.reset_model_settings,
780
+ inputs=[session_data],
781
+ outputs=[model_status, session_data]
782
+ )
783
+
784
+ # Bind profile events
785
+ load_profile_btn.click(
786
+ profile_handlers.load_profile,
787
+ inputs=[profile_selector, session_data],
788
+ outputs=[patient_name, patient_phone, patient_age, conditions, primary_goal, exercise_prefs, exercise_limits, profile_status]
789
+ )
790
+
791
+ save_profile_btn.click(
792
+ profile_handlers.save_profile,
793
+ inputs=[patient_name, patient_phone, patient_age, conditions, primary_goal, exercise_prefs, exercise_limits, session_data],
794
+ outputs=[profile_save_status]
795
+ )
796
+
797
+ reset_profile_btn.click(
798
+ profile_handlers.reset_profile,
799
+ inputs=[session_data],
800
+ outputs=[patient_name, patient_phone, patient_age, conditions, primary_goal, exercise_prefs, exercise_limits, profile_save_status]
801
+ )
802
+
803
+ # Add CSS for prompt status container
804
+ demo.css = """
805
+ .prompt-status-container {
806
+ max-height: 300px !important;
807
+ overflow-y: auto !important;
808
+ margin: 0.5em 0 !important;
809
+ }
810
+ .prompt-status-container > div {
811
+ max-height: 280px !important;
812
+ overflow-y: auto !important;
813
+ }
814
+ """
815
+
816
+ return demo
817
+
818
+
819
+ def main():
820
+ """Launch the simplified Gradio interface."""
821
+ demo = create_simplified_interface()
822
+
823
+ # Get configuration
824
+ server_name = os.getenv("GRADIO_SERVER_NAME", "0.0.0.0")
825
+ server_port = int(os.getenv("GRADIO_SERVER_PORT", "7860"))
826
+ share = os.getenv("GRADIO_SHARE", "false").lower() == "true"
827
+
828
+ print(f"🚀 Starting Simplified Medical Assistant...")
829
+ print(f"📍 Server: http://{server_name}:{server_port}")
830
+
831
+ demo.launch(
832
+ server_name=server_name,
833
+ server_port=server_port,
834
+ share=share
835
+ )
836
+
837
+
838
+ if __name__ == "__main__":
839
+ main()
src/interface/simplified_chat_handlers.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # simplified_chat_handlers.py
2
+ """
3
+ Chat handlers for simplified interface with Provider Summary replacement.
4
+
5
+ Based on Or_4.txt requirement:
6
+ "Instead of showing the final user message (consent confirmation),
7
+ show the Provider Summary message for the spiritual care team."
8
+ """
9
+
10
+ import gradio as gr
11
+ import html
12
+ from src.interface.session_manager import SimplifiedSessionData
13
+ from src.interface.stats_handlers import get_conversation_stats
14
+
15
+
16
+ def handle_message_simplified(message: str, history, session: SimplifiedSessionData):
17
+ """
18
+ Handle user message with Provider Summary replacement for simplified interface.
19
+
20
+ Key difference from standard handler:
21
+ - When RED flag is triggered and consent is given, the last assistant message
22
+ is replaced with the Provider Summary (message for spiritual care team)
23
+ instead of the confirmation message to the user.
24
+ - All assistant messages are prefixed with "To patient:" or "To spiritual care team:"
25
+ """
26
+ if session is None:
27
+ session = SimplifiedSessionData()
28
+
29
+ session.update_activity()
30
+
31
+ # Apply per-session model overrides (if configured)
32
+ custom_models = getattr(session, 'custom_models', None)
33
+ if custom_models:
34
+ session.app_instance.set_model_overrides(custom_models)
35
+ else:
36
+ session.app_instance.set_model_overrides({})
37
+
38
+ # Apply per-session prompt overrides (if configured)
39
+ custom_prompts = getattr(session, 'custom_prompts', None)
40
+ if custom_prompts:
41
+ session.app_instance.set_prompt_overrides(custom_prompts)
42
+ else:
43
+ session.app_instance.set_prompt_overrides({})
44
+
45
+ # Store previous spiritual state to detect transitions
46
+ previous_state = session.app_instance.spiritual_state.spiritual_state
47
+
48
+ # Process message
49
+ new_history, status = session.app_instance.process_message(message, history)
50
+
51
+ # Check if we just transitioned to RED state (consent was given)
52
+ current_state = session.app_instance.spiritual_state.spiritual_state
53
+ consent_just_given = (previous_state.value == "awaiting_consent" and
54
+ current_state.value == "red")
55
+
56
+ # SIMPLIFIED INTERFACE MODIFICATION:
57
+ # Replace last assistant message with Provider Summary if consent was just given
58
+ if consent_just_given:
59
+ last_summary = session.app_instance.get_last_provider_summary()
60
+ if last_summary and new_history:
61
+ # Get the COHERENT NARRATIVE summary (LLM-generated from spiritual_care_message.txt)
62
+ # This is the Medical Brain compatible format, not the structured format
63
+ try:
64
+ provider_summary_text = session.app_instance.provider_summary_generator.format_coherent_paragraph(last_summary)
65
+
66
+ if not provider_summary_text:
67
+ # Fallback to structured format if coherent generation fails
68
+ provider_summary_text = session.app_instance.provider_summary_generator.format_for_export(last_summary)
69
+
70
+ except Exception as e:
71
+ print(f"ERROR: Failed to generate coherent summary: {e}")
72
+ # Fallback to structured format
73
+ provider_summary_text = session.app_instance.provider_summary_generator.format_for_export(last_summary)
74
+
75
+ # Format with clear addressee label after classification
76
+ # Provider Summary should also have classification info, then "**To spiritual care team:**"
77
+ summary_display = f"""**To spiritual care team:**
78
+
79
+ {provider_summary_text}"""
80
+
81
+ # Replace the last assistant message with the provider summary
82
+ # History format: list of dicts with 'role' and 'content'
83
+ if len(new_history) > 0:
84
+ last_item = new_history[-1]
85
+ if isinstance(last_item, dict) and last_item.get('role') == 'assistant':
86
+ # Replace the content
87
+ new_history[-1] = {
88
+ 'role': 'assistant',
89
+ 'content': summary_display
90
+ }
91
+ elif isinstance(last_item, (list, tuple)) and len(last_item) > 1:
92
+ # Old format: (user_msg, assistant_msg)
93
+ new_history[-1] = (last_item[0], summary_display)
94
+
95
+ print(f"DEBUG: Replaced last message with Provider Summary (coherent narrative)")
96
+ print(f"DEBUG: Summary length: {len(provider_summary_text)} chars")
97
+ else:
98
+ # Add "To patient:" after classification status for all other assistant messages
99
+ if new_history and len(new_history) > 0:
100
+ last_item = new_history[-1]
101
+ if isinstance(last_item, dict) and last_item.get('role') == 'assistant':
102
+ content = last_item.get('content', '')
103
+ # Only add prefix if not already present
104
+ if 'To patient:' not in content and 'To spiritual care team:' not in content:
105
+ # Insert "To patient:" after the classification line
106
+ # Format: "🟢 GREEN (95%)\n*Indicators...*\n*Reasoning...*\n\nActual message"
107
+ # We need to insert "To patient:\n" after the classification block
108
+ lines = content.split('\n')
109
+
110
+ # Find where classification ends (after reasoning line or after first empty line)
111
+ insert_index = 0
112
+ for i, line in enumerate(lines):
113
+ if line.strip().startswith('*') or line.strip().startswith('🟢') or line.strip().startswith('🟡') or line.strip().startswith('🔴') or line.strip().startswith('⚪'):
114
+ insert_index = i + 1
115
+ elif insert_index > 0 and line.strip() == '':
116
+ # Found empty line after classification
117
+ insert_index = i
118
+ break
119
+
120
+ # Insert "**To patient:**" at the right position (after the empty line)
121
+ if insert_index > 0 and insert_index < len(lines):
122
+ lines.insert(insert_index, '**To patient:**')
123
+ lines.insert(insert_index + 1, '') # Add empty line after "**To patient:**"
124
+ new_content = '\n'.join(lines)
125
+ else:
126
+ # Fallback: add at the beginning
127
+ new_content = f"**To patient:**\n\n{content}"
128
+
129
+ new_history[-1] = {
130
+ 'role': 'assistant',
131
+ 'content': new_content
132
+ }
133
+ elif isinstance(last_item, (list, tuple)) and len(last_item) > 1:
134
+ content = last_item[1]
135
+ if 'To patient:' not in content and 'To spiritual care team:' not in content:
136
+ # Same logic for tuple format
137
+ lines = content.split('\n')
138
+ insert_index = 0
139
+ for i, line in enumerate(lines):
140
+ if line.strip().startswith('*') or line.strip().startswith('🟢') or line.strip().startswith('🟡') or line.strip().startswith('🔴') or line.strip().startswith('⚪'):
141
+ insert_index = i + 1
142
+ elif insert_index > 0 and line.strip() == '':
143
+ insert_index = i + 1
144
+ break
145
+
146
+ if insert_index > 0 and insert_index < len(lines):
147
+ lines.insert(insert_index, '**To patient:**')
148
+ lines.insert(insert_index + 1, '') # Add empty line after "**To patient:**"
149
+ new_content = '\n'.join(lines)
150
+ else:
151
+ new_content = f"**To patient:**\n\n{content}"
152
+
153
+ new_history[-1] = (last_item[0], new_content)
154
+
155
+ # Get updated conversation stats
156
+ stats = get_conversation_stats(session)
157
+
158
+ return (
159
+ new_history,
160
+ status,
161
+ session,
162
+ "", # Clear input
163
+ stats
164
+ )
165
+
166
+
167
+ def handle_clear_simplified(session: SimplifiedSessionData):
168
+ """
169
+ Handle clear chat button for simplified interface.
170
+
171
+ Resets entire session including:
172
+ - Chat history
173
+ - Spiritual monitoring state
174
+ - Conversation statistics
175
+ """
176
+ if session is None:
177
+ session = SimplifiedSessionData()
178
+
179
+ session.update_activity()
180
+ new_history, status = session.app_instance.reset_session()
181
+
182
+ return (
183
+ new_history, # Clear chat history
184
+ status, # Reset status
185
+ session # Updated session
186
+ )
187
+
188
+
189
+ def send_example_simplified(example_text: str, history, session: SimplifiedSessionData):
190
+ """Send example message in simplified interface."""
191
+ return handle_message_simplified(example_text, history, session)
src/interface/simplified_gradio_app.py CHANGED
@@ -1,11 +1,13 @@
1
  # simplified_gradio_app.py
2
  """
3
- Simplified Gradio Interface for Medical Brain with Background Spiritual Monitoring.
4
 
5
- Single unified medical interface with invisible spiritual monitoring.
6
- No mode selector - just medical dialog with automatic spiritual support.
 
 
7
 
8
- Requirements: 1.3, 4.1, 4.2, 12.1, 12.2
9
  """
10
 
11
  import os
@@ -26,47 +28,27 @@ import gradio as gr
26
  # Import modularized components
27
  from src.interface.session_manager import SimplifiedSessionData
28
  from src.interface import stats_handlers
29
- from src.interface import chat_handlers
30
- from src.interface import prompt_handlers
31
  from src.interface import verification_handlers
32
- from src.interface import profile_handlers
33
  from src.interface import model_handlers
34
-
35
- from src.core.simplified_medical_app import SimplifiedMedicalApp
36
- from src.core.spiritual_state import SpiritualState
37
- from src.interface.enhanced_verification_interface import create_enhanced_verification_tab
38
- from src.interface.help_content import HELP_CONTENT
39
 
40
  try:
41
- from app_config import (
42
- GRADIO_CONFIG,
43
- ENHANCED_VERIFICATION_CONFIG,
44
- FEATURE_FLAGS,
45
- is_feature_enabled
46
- )
47
  except ImportError:
48
  GRADIO_CONFIG = {"theme": "soft", "show_api": False}
49
- ENHANCED_VERIFICATION_CONFIG = {"enabled": True}
50
- FEATURE_FLAGS = {
51
- "enhanced_verification_enabled": True,
52
- "standard_verification_enabled": True,
53
- "show_mode_navigation_hints": True,
54
- }
55
- def is_feature_enabled(feature_name: str) -> bool:
56
- return FEATURE_FLAGS.get(feature_name, False)
57
-
58
-
59
-
60
 
61
 
62
  def create_simplified_interface():
63
  """
64
- Create simplified Gradio interface.
65
 
66
- Single medical assistant interface with background spiritual monitoring.
67
- No mode selector - spiritual support is automatic and invisible.
68
-
69
- Requirements: 1.3, 4.1, 12.1
70
  """
71
 
72
  debug_mode = os.getenv("LOG_PROMPTS", "false").lower() == "true"
@@ -79,7 +61,7 @@ def create_simplified_interface():
79
  theme = gr.themes.Default()
80
 
81
  demo = gr.Blocks(
82
- title="🏥 Medical Assistant with Spiritual Support",
83
  analytics_enabled=False
84
  )
85
  demo.theme = theme
@@ -89,8 +71,8 @@ def create_simplified_interface():
89
  session_data = gr.State(value=None)
90
 
91
  # Header
92
- gr.Markdown("# 🏥 Medical Assistant with Spiritual Support 🕊️")
93
- gr.Markdown("Your personal healthcare companion with integrated wellness support")
94
 
95
  if debug_mode:
96
  gr.Markdown("⚠️ **DEBUG MODE:** Prompts and responses are logged")
@@ -109,13 +91,9 @@ def create_simplified_interface():
109
  """
110
  return new_session, session_info_text
111
 
112
- # Main interface - using Tabs with elem_id for navigation
113
  main_tabs = gr.Tabs(elem_id="main_tabs")
114
  with main_tabs:
115
- # Note: The following tabs are intentionally hidden for now:
116
- # - ✏️ Edit Enhanced Datasets
117
- # - ✓ Standard Verification
118
- # We keep the rest of the interface focused on Chat + Conversation Verification.
119
 
120
  # Chat tab
121
  with gr.TabItem("💬 Chat", id="chat"):
@@ -137,15 +115,6 @@ def create_simplified_interface():
137
  with gr.Row():
138
  clear_btn = gr.Button("🗑️ Clear Chat", scale=1)
139
 
140
- # Conversation logging section
141
- gr.Markdown("### 📊 Conversation Logs:")
142
- with gr.Row():
143
- download_json_btn = gr.DownloadButton("📥 Download JSON", scale=1, size="sm")
144
- download_csv_btn = gr.DownloadButton("📊 Download CSV", scale=1, size="sm")
145
-
146
- # Conversation verification is available in the dedicated
147
- # "🧾 Conversation Verification" tab.
148
-
149
  # Quick examples
150
  gr.Markdown("### ⚡ Quick Start:")
151
  with gr.Row():
@@ -159,7 +128,7 @@ def create_simplified_interface():
159
  label="📊 Status"
160
  )
161
 
162
- refresh_btn = gr.Button("🔄 Check Status & Summary", size="sm")
163
 
164
  # Conversation statistics
165
  gr.Markdown("### 📈 Conversation Stats")
@@ -167,76 +136,24 @@ def create_simplified_interface():
167
  value="No conversation yet",
168
  label="Statistics"
169
  )
170
-
171
- # Debug info (only in debug mode)
172
- if debug_mode:
173
- gr.Markdown("### 🔧 Debug Info")
174
- debug_info = gr.Markdown(value="")
175
-
176
- # Provider Summary Panel (for RED flags) - always visible but content controlled
177
- with gr.Column(scale=1) as provider_summary_column:
178
- with gr.Group(visible=False) as provider_summary_content:
179
- gr.Markdown("### 📋 Provider Summary")
180
- gr.Markdown("*For Spiritual Care Team*", elem_classes=["provider-subtitle"])
181
-
182
- provider_summary_status = gr.Markdown(
183
- value="**Provider Summary Generated**\n\nA detailed summary has been generated for the spiritual care team. Use the Download button below to access the full summary."
184
- )
185
-
186
- # Tabs for different summary views (Medical Brain Summary first by default)
187
- with gr.Tabs():
188
- # Coherent Paragraph Tab (FIRST - Requirements 2.1-2.8) - Medical Brain compatibility
189
- with gr.TabItem("📝 Medical Brain Summary"):
190
- gr.Markdown("*Single paragraph format for Medical Brain compatibility - **Default View***")
191
- coherent_summary_display = gr.Textbox(
192
- value="",
193
- lines=8,
194
- label="Medical Brain Compatible Summary",
195
- interactive=False
196
- )
197
- with gr.Row():
198
- regenerate_coherent_btn = gr.Button(
199
- "🔄 Regenerate Medical Brain Summary",
200
- size="sm",
201
- variant="secondary"
202
- )
203
- download_coherent_btn = gr.DownloadButton(
204
- "📥 Download Medical Brain Summary",
205
- size="sm",
206
- variant="secondary"
207
- )
208
-
209
- # Structured Summary Tab (moved to second position)
210
- with gr.TabItem("📊 Structured Summary"):
211
- provider_summary_display = gr.HTML(value="")
212
-
213
- with gr.Row():
214
- download_summary_btn = gr.DownloadButton(
215
- "📥 Download Full Summary",
216
- size="sm",
217
- variant="secondary"
218
- )
219
- clear_summary_btn = gr.Button(
220
- "🗑️ Clear",
221
- size="sm"
222
- )
223
-
224
- # Conversation Verification tab (chat-derived)
225
  with gr.TabItem("🧾 Conversation Verification", id="conversation_verification"):
226
- gr.Markdown("## 🧾 Conversation Verification (from Chat)")
227
  gr.Markdown(
228
- "Click **Generate** to build a verification session from the current chat. "
229
- "Review each exchange, mark it correct/incorrect, and download the session JSON."
230
  )
231
 
232
- conv_verify_state = gr.State(value=None) # holds exported JSON path
233
  conv_verify_index = gr.State(value=0)
234
  conv_verify_records = gr.State(value=[])
235
 
236
  with gr.Row():
237
- generate_conv_verification_btn = gr.Button("🛠 Generate from current chat", variant="primary")
238
- conv_verify_download_btn = gr.DownloadButton("⬇️ Download reviewed JSON", variant="secondary")
239
- conv_verify_download_csv_btn = gr.DownloadButton("📄 Download CSV", variant="secondary")
 
240
 
241
  conv_verify_status = gr.Markdown(value="", visible=True)
242
  conv_verify_exchange = gr.HTML(value="", label="Current Exchange")
@@ -262,7 +179,7 @@ def create_simplified_interface():
262
  )
263
  conv_incorrect_comment = gr.Textbox(
264
  label="Comment (why incorrect / what to fix)",
265
- placeholder="Add a short note for this exchange...",
266
  lines=3,
267
  )
268
  with gr.Column(scale=1):
@@ -273,13 +190,13 @@ def create_simplified_interface():
273
  conv_position = gr.Markdown(value="")
274
  with gr.Column(scale=1):
275
  conv_stats = gr.HTML(value="")
 
 
 
 
 
276
 
277
- # Enhanced Verification Modes tab (hidden sub-tabs; kept but moved after Conversation Verification)
278
- if is_feature_enabled("enhanced_verification_enabled"):
279
- with gr.TabItem("🔍 Enhanced Verification", id="enhanced_verification"):
280
- enhanced_verification_interface = create_enhanced_verification_tab()
281
-
282
- # Model Selection tab (second tab)
283
  with gr.TabItem("⚙️ Model Settings", id="model_settings"):
284
  gr.Markdown("## ⚙️ AI Model Configuration")
285
  gr.Markdown("Select which AI models to use for different tasks. Changes apply to your current session.")
@@ -549,17 +466,15 @@ def create_simplified_interface():
549
  reset_profile_btn = gr.Button("🔄 Reset to Default", scale=1)
550
 
551
  profile_save_status = gr.HTML(value="", visible=True)
552
-
553
- # Instructions tab
554
  with gr.TabItem("📖 Help", id="help"):
555
- gr.Markdown(HELP_CONTENT)
556
 
557
 
558
  # Event handlers
559
- # Handlers moved to modular modules
560
-
561
 
562
- # Bind events
563
  demo.load(
564
  initialize_session,
565
  outputs=[session_data, session_info]
@@ -567,102 +482,57 @@ def create_simplified_interface():
567
 
568
  # Send message
569
  send_btn.click(
570
- chat_handlers.handle_message,
571
  inputs=[msg, chatbot, session_data],
572
- outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
573
  )
574
 
575
  msg.submit(
576
- chat_handlers.handle_message,
577
  inputs=[msg, chatbot, session_data],
578
- outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
579
  )
580
 
581
  # Clear chat
582
  clear_btn.click(
583
- chat_handlers.handle_clear,
584
  inputs=[session_data],
585
- outputs=[chatbot, status_box, session_data, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
586
  )
587
 
588
  # Refresh status
589
  refresh_btn.click(
590
  stats_handlers.get_status,
591
  inputs=[session_data],
592
- outputs=[status_box, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
593
  )
594
 
595
  # Example buttons
596
  example_medical.click(
597
- lambda h, s: chat_handlers.send_example_with_stats("I am fine", h, s),
598
  inputs=[chatbot, session_data],
599
- outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
600
  )
601
 
602
  example_wellness.click(
603
- lambda h, s: chat_handlers.send_example_with_stats("I'm feeling stressed and overwhelmed lately", h, s),
604
  inputs=[chatbot, session_data],
605
- outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
606
  )
607
 
608
  example_help.click(
609
- lambda h, s: chat_handlers.send_example_with_stats("I am currently experiencing an emotional crisis", h, s),
610
  inputs=[chatbot, session_data],
611
- outputs=[chatbot, status_box, session_data, msg, conversation_stats, provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
612
- )
613
-
614
- # Conversation logging buttons
615
- download_json_btn.click(
616
- stats_handlers.download_conversation_json,
617
- inputs=[session_data],
618
- outputs=[download_json_btn]
619
- )
620
-
621
- download_csv_btn.click(
622
- stats_handlers.download_conversation_csv,
623
- inputs=[session_data],
624
- outputs=[download_csv_btn]
625
- )
626
-
627
- # Provider Summary panel handlers
628
- download_summary_btn.click(
629
- stats_handlers.download_provider_summary,
630
- inputs=[session_data],
631
- outputs=[download_summary_btn]
632
- )
633
-
634
- clear_summary_btn.click(
635
- stats_handlers.clear_provider_summary,
636
- inputs=[],
637
- outputs=[provider_summary_content, provider_summary_status, provider_summary_display, coherent_summary_display]
638
- )
639
-
640
- # Coherent summary handlers (Medical Brain Summary - now first tab by default)
641
- regenerate_coherent_btn.click(
642
- stats_handlers.regenerate_coherent_summary,
643
- inputs=[session_data],
644
- outputs=[coherent_summary_display]
645
- )
646
-
647
- download_coherent_btn.click(
648
- stats_handlers.download_coherent_summary,
649
- inputs=[session_data],
650
- outputs=[download_coherent_btn]
651
  )
652
 
653
  # Conversation Verification events
654
  generate_conv_verification_btn.click(
655
- verification_handlers._generate_conv_verification,
656
  inputs=[session_data],
657
  outputs=[conv_verify_state, conv_verify_records, conv_verify_index, conv_verify_status, conv_verify_exchange, conv_position, conv_stats]
658
  )
659
 
660
- conv_verify_download_btn.click(
661
- verification_handlers._download_reviewed_json,
662
- inputs=[conv_verify_state, conv_verify_records],
663
- outputs=[conv_verify_download_btn]
664
- )
665
-
666
  conv_verify_download_csv_btn.click(
667
  verification_handlers._download_reviewed_csv,
668
  inputs=[conv_verify_state, conv_verify_records],
@@ -729,7 +599,6 @@ def create_simplified_interface():
729
  outputs=[conv_verify_index, conv_verify_exchange, conv_position, conv_stats, conv_incorrect_comment_row, conv_incorrect_comment, conv_correct_classification]
730
  )
731
 
732
-
733
  # Prompt editing events
734
  load_prompt_btn.click(
735
  prompt_handlers.load_prompt,
@@ -822,10 +691,10 @@ def main():
822
 
823
  # Get configuration
824
  server_name = os.getenv("GRADIO_SERVER_NAME", "0.0.0.0")
825
- server_port = int(os.getenv("GRADIO_SERVER_PORT", "7860"))
826
  share = os.getenv("GRADIO_SHARE", "false").lower() == "true"
827
 
828
- print(f"🚀 Starting Simplified Medical Assistant...")
829
  print(f"📍 Server: http://{server_name}:{server_port}")
830
 
831
  demo.launch(
 
1
  # simplified_gradio_app.py
2
  """
3
+ Simplified Gradio Interface based on customer feedback from Or_4.txt
4
 
5
+ Key changes:
6
+ 1. Provider Summary is the final exchange in Conversation Verification tab
7
+ 2. Streamlined interface focusing on essential features
8
+ 3. CSV export for verification results
9
 
10
+ Requirements: Customer feedback Or_4.txt
11
  """
12
 
13
  import os
 
28
  # Import modularized components
29
  from src.interface.session_manager import SimplifiedSessionData
30
  from src.interface import stats_handlers
31
+ from src.interface import simplified_chat_handlers # Use simplified handlers
 
32
  from src.interface import verification_handlers
33
+ from src.interface import prompt_handlers
34
  from src.interface import model_handlers
35
+ from src.interface import profile_handlers
36
+ from src.interface.simplified_help_content import SIMPLIFIED_HELP_CONTENT
 
 
 
37
 
38
  try:
39
+ from app_config import GRADIO_CONFIG
 
 
 
 
 
40
  except ImportError:
41
  GRADIO_CONFIG = {"theme": "soft", "show_api": False}
 
 
 
 
 
 
 
 
 
 
 
42
 
43
 
44
  def create_simplified_interface():
45
  """
46
+ Create simplified Gradio interface based on customer feedback.
47
 
48
+ Focus on:
49
+ - Chat interface
50
+ - Conversation Verification with Provider Summary as final step
51
+ - Simplified data export
52
  """
53
 
54
  debug_mode = os.getenv("LOG_PROMPTS", "false").lower() == "true"
 
61
  theme = gr.themes.Default()
62
 
63
  demo = gr.Blocks(
64
+ title="🏥 Medical Assistant - Simplified",
65
  analytics_enabled=False
66
  )
67
  demo.theme = theme
 
71
  session_data = gr.State(value=None)
72
 
73
  # Header
74
+ gr.Markdown("# 🏥 Medical Assistant with Spiritual Support")
75
+ gr.Markdown("Simplified interface for conversation verification and testing")
76
 
77
  if debug_mode:
78
  gr.Markdown("⚠️ **DEBUG MODE:** Prompts and responses are logged")
 
91
  """
92
  return new_session, session_info_text
93
 
94
+ # Main interface tabs
95
  main_tabs = gr.Tabs(elem_id="main_tabs")
96
  with main_tabs:
 
 
 
 
97
 
98
  # Chat tab
99
  with gr.TabItem("💬 Chat", id="chat"):
 
115
  with gr.Row():
116
  clear_btn = gr.Button("🗑️ Clear Chat", scale=1)
117
 
 
 
 
 
 
 
 
 
 
118
  # Quick examples
119
  gr.Markdown("### ⚡ Quick Start:")
120
  with gr.Row():
 
128
  label="📊 Status"
129
  )
130
 
131
+ refresh_btn = gr.Button("🔄 Check Status", size="sm")
132
 
133
  # Conversation statistics
134
  gr.Markdown("### 📈 Conversation Stats")
 
136
  value="No conversation yet",
137
  label="Statistics"
138
  )
139
+
140
+ # Conversation Verification tab - MAIN FOCUS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  with gr.TabItem("🧾 Conversation Verification", id="conversation_verification"):
142
+ gr.Markdown("## 🧾 Conversation Verification")
143
  gr.Markdown(
144
+ "Review each exchange from the chat conversation. "
145
+ "**The Provider Summary will be shown as the final step** for your review and feedback."
146
  )
147
 
148
+ conv_verify_state = gr.State(value=None)
149
  conv_verify_index = gr.State(value=0)
150
  conv_verify_records = gr.State(value=[])
151
 
152
  with gr.Row():
153
+ generate_conv_verification_btn = gr.Button(
154
+ "🛠 Generate Verification from Chat",
155
+ variant="primary"
156
+ )
157
 
158
  conv_verify_status = gr.Markdown(value="", visible=True)
159
  conv_verify_exchange = gr.HTML(value="", label="Current Exchange")
 
179
  )
180
  conv_incorrect_comment = gr.Textbox(
181
  label="Comment (why incorrect / what to fix)",
182
+ placeholder="Add your feedback here...",
183
  lines=3,
184
  )
185
  with gr.Column(scale=1):
 
190
  conv_position = gr.Markdown(value="")
191
  with gr.Column(scale=1):
192
  conv_stats = gr.HTML(value="")
193
+
194
+ # Manual download options (backup)
195
+ gr.Markdown("### 📥 Manual Export")
196
+ with gr.Row():
197
+ conv_verify_download_csv_btn = gr.DownloadButton("📄 Download CSV", variant="secondary")
198
 
199
+ # Model Selection tab
 
 
 
 
 
200
  with gr.TabItem("⚙️ Model Settings", id="model_settings"):
201
  gr.Markdown("## ⚙️ AI Model Configuration")
202
  gr.Markdown("Select which AI models to use for different tasks. Changes apply to your current session.")
 
466
  reset_profile_btn = gr.Button("🔄 Reset to Default", scale=1)
467
 
468
  profile_save_status = gr.HTML(value="", visible=True)
469
+
470
+ # Help tab
471
  with gr.TabItem("📖 Help", id="help"):
472
+ gr.Markdown(SIMPLIFIED_HELP_CONTENT)
473
 
474
 
475
  # Event handlers
 
 
476
 
477
+ # Initialize session
478
  demo.load(
479
  initialize_session,
480
  outputs=[session_data, session_info]
 
482
 
483
  # Send message
484
  send_btn.click(
485
+ simplified_chat_handlers.handle_message_simplified,
486
  inputs=[msg, chatbot, session_data],
487
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats]
488
  )
489
 
490
  msg.submit(
491
+ simplified_chat_handlers.handle_message_simplified,
492
  inputs=[msg, chatbot, session_data],
493
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats]
494
  )
495
 
496
  # Clear chat
497
  clear_btn.click(
498
+ simplified_chat_handlers.handle_clear_simplified,
499
  inputs=[session_data],
500
+ outputs=[chatbot, status_box, session_data]
501
  )
502
 
503
  # Refresh status
504
  refresh_btn.click(
505
  stats_handlers.get_status,
506
  inputs=[session_data],
507
+ outputs=[status_box, conversation_stats]
508
  )
509
 
510
  # Example buttons
511
  example_medical.click(
512
+ lambda h, s: simplified_chat_handlers.send_example_simplified("I am fine", h, s),
513
  inputs=[chatbot, session_data],
514
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats]
515
  )
516
 
517
  example_wellness.click(
518
+ lambda h, s: simplified_chat_handlers.send_example_simplified("I'm feeling stressed and overwhelmed lately", h, s),
519
  inputs=[chatbot, session_data],
520
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats]
521
  )
522
 
523
  example_help.click(
524
+ lambda h, s: simplified_chat_handlers.send_example_simplified("I am currently experiencing an emotional crisis", h, s),
525
  inputs=[chatbot, session_data],
526
+ outputs=[chatbot, status_box, session_data, msg, conversation_stats]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  )
528
 
529
  # Conversation Verification events
530
  generate_conv_verification_btn.click(
531
+ verification_handlers._generate_conv_verification_with_summary,
532
  inputs=[session_data],
533
  outputs=[conv_verify_state, conv_verify_records, conv_verify_index, conv_verify_status, conv_verify_exchange, conv_position, conv_stats]
534
  )
535
 
 
 
 
 
 
 
536
  conv_verify_download_csv_btn.click(
537
  verification_handlers._download_reviewed_csv,
538
  inputs=[conv_verify_state, conv_verify_records],
 
599
  outputs=[conv_verify_index, conv_verify_exchange, conv_position, conv_stats, conv_incorrect_comment_row, conv_incorrect_comment, conv_correct_classification]
600
  )
601
 
 
602
  # Prompt editing events
603
  load_prompt_btn.click(
604
  prompt_handlers.load_prompt,
 
691
 
692
  # Get configuration
693
  server_name = os.getenv("GRADIO_SERVER_NAME", "0.0.0.0")
694
+ server_port = int(os.getenv("GRADIO_SERVER_PORT", "7861")) # Different port
695
  share = os.getenv("GRADIO_SHARE", "false").lower() == "true"
696
 
697
+ print(f"🚀 Starting Simplified Medical Assistant Interface...")
698
  print(f"📍 Server: http://{server_name}:{server_port}")
699
 
700
  demo.launch(
src/interface/simplified_help_content.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # simplified_help_content.py
2
+ """
3
+ Help content for simplified Gradio interface.
4
+
5
+ Based on customer feedback from Or_4.txt with focus on:
6
+ - Provider Summary as final exchange
7
+ - Streamlined verification workflow
8
+ - Clear instructions for testing team
9
+ """
10
+
11
+ SIMPLIFIED_HELP_CONTENT = """
12
+ # 🏥 Medical Assistant - Help Guide
13
+
14
+ ## 🎯 Overview
15
+
16
+ This interface helps you test and verify conversations with the Medical Assistant that includes automatic spiritual support monitoring.
17
+
18
+ ---
19
+
20
+ ## 📋 Main Features
21
+
22
+ ### 💬 Chat Tab
23
+ Test conversations with the medical assistant. The system automatically monitors for spiritual distress.
24
+
25
+ **How to use:**
26
+ 1. Type your message in the text box
27
+ 2. Click "📤 Send" or press Enter
28
+ 3. Review the assistant's response
29
+ 4. Notice the classification indicator (🟢 GREEN, 🟡 YELLOW, 🔴 RED)
30
+
31
+ **Message Format:**
32
+ - **Classification line:** Shows distress level and confidence
33
+ - **To patient:** The actual response to the patient
34
+ - **To spiritual care team:** Provider summary (only after consent)
35
+
36
+ **Quick Examples:**
37
+ - 🟢 "I am fine" - Normal conversation
38
+ - 🟡 "I'm feeling stressed" - Potential distress
39
+ - 🔴 "Emotional crisis" - Immediate concern
40
+
41
+ ---
42
+
43
+ ### 🧾 Conversation Verification Tab
44
+
45
+ Review and verify the accuracy of spiritual distress classifications.
46
+
47
+ **Important:** Provider Summary appears as the **final exchange** for your review.
48
+
49
+ **Workflow:**
50
+ 1. Click "🛠 Generate Verification from Chat"
51
+ 2. Review each exchange:
52
+ - Read the user message and assistant response
53
+ - Check the classification (GREEN/YELLOW/RED)
54
+ - Mark as ✅ Correct or ❌ Incorrect
55
+ 3. For incorrect classifications:
56
+ - Select the correct classification
57
+ - Add a comment explaining why it's incorrect
58
+ - Click "💾 Save comment"
59
+ 4. Navigate with ⬅️ Previous / Next ➡️ buttons
60
+ 5. **Final step:** Review the Provider Summary
61
+ - This is the message sent to the spiritual care team
62
+ - Verify it's complete and accurate
63
+ - Add feedback if needed
64
+ 6. Download results: "📄 Download CSV"
65
+
66
+ **Statistics shown:**
67
+ - Reviewed: How many exchanges you've checked
68
+ - ✅ Correct: Accurate classifications
69
+ - ❌ Incorrect: Classifications that need fixing
70
+ - 📝 Incorrect w/ comment: Incorrect with your feedback
71
+
72
+ ---
73
+
74
+ ### ⚙️ Model Settings Tab
75
+
76
+ Configure which AI models to use for different tasks.
77
+
78
+ **Available models:**
79
+ - **Gemini models:** Fast, good for classification
80
+ - **Claude models:** More nuanced, better for conversations
81
+
82
+ **Model roles:**
83
+ - 🔍 Spiritual Monitor: Detects distress indicators
84
+ - 🟡 Soft Spiritual Triage: Asks clarifying questions
85
+ - 📊 Triage Response Evaluator: Analyzes patient responses
86
+ - 🏥 Medical Assistant: Provides medical guidance
87
+ - 🩺 Soft Medical Triage: Medical assessment questions
88
+ - 💬 Medical Brain Summary Generator: Creates provider summaries
89
+
90
+ **How to use:**
91
+ 1. Select models from dropdowns
92
+ 2. Click "✅ Apply Model Settings"
93
+ 3. Changes apply to your current session only
94
+
95
+ ---
96
+
97
+ ### 🔧 Edit Prompts Tab
98
+
99
+ Customize the AI system prompts for testing different behaviors.
100
+
101
+ **Available prompts:**
102
+ - 🔍 Spiritual Monitor (Classifier)
103
+ - 🟡 Soft Spiritual Triage
104
+ - 📊 Triage Response Evaluator
105
+ - 🏥 Medical Assistant
106
+ - 🩺 Soft Medical Triage
107
+ - 💬 Spiritual Care Message (used for Provider Summary)
108
+
109
+ **How to use:**
110
+ 1. Select a prompt from the dropdown
111
+ 2. Click "📥 Load Prompt" to see current version
112
+ 3. Edit the prompt text
113
+ 4. Click "✅ Apply Changes" to test
114
+ 5. Click "🔄 Reset to Default" if needed
115
+
116
+ **Tips:**
117
+ - Changes are session-only (not permanent)
118
+ - Test your changes in the Chat tab
119
+ - Use "🔍 Validate" to check syntax
120
+ - Use "📤 Promote to File" to save permanently
121
+
122
+ ---
123
+
124
+ ### 👥 Patient Profiles Tab
125
+
126
+ Switch between different patient scenarios for testing.
127
+
128
+ **Predefined profiles:**
129
+ - 👤 Default Profile (Serhii)
130
+ - 🟢 GREEN scenarios (healthy coping)
131
+ - 🟡 YELLOW scenarios (mild distress, grief, questions)
132
+ - 🔴 RED scenarios (crisis, hopelessness)
133
+ - Medical conditions (cardiac, diabetic, post-surgery, etc.)
134
+
135
+ **How to use:**
136
+ 1. Select a profile from the dropdown
137
+ 2. Click "📥 Load Profile"
138
+ 3. Profile settings are applied to the session
139
+ 4. Test conversations with this patient context
140
+
141
+ **Custom profiles:**
142
+ - Modify patient name, age, phone
143
+ - Add medical conditions
144
+ - Set primary goals
145
+ - Define exercise preferences and limitations
146
+ - Click "💾 Save Current Profile"
147
+
148
+ ---
149
+
150
+ ## 🎓 For Testing Team
151
+
152
+ ### What to Verify
153
+
154
+ **In Chat:**
155
+ - ✅ Appropriate responses to different distress levels
156
+ - ✅ Correct classification indicators
157
+ - ✅ Clear addressee labels (To patient: / To spiritual care team:)
158
+
159
+ **In Conversation Verification:**
160
+ - ✅ Accurate distress level detection (GREEN/YELLOW/RED)
161
+ - ✅ Provider Summary completeness and accuracy
162
+ - ✅ All important information captured
163
+
164
+ ### Provider Summary Review (Final Exchange)
165
+
166
+ The Provider Summary is the **most important** part to verify:
167
+
168
+ **Check for:**
169
+ - ✅ Patient demographics (name, age, conditions)
170
+ - ✅ Distress indicators clearly stated
171
+ - ✅ Severity and urgency levels
172
+ - ✅ Recommended timeline for contact
173
+ - ✅ Patient quotes (if applicable)
174
+ - ✅ Clear, professional narrative style
175
+
176
+ **If incorrect or incomplete:**
177
+ - Mark as ❌ Incorrect
178
+ - Add detailed comment about what's missing or wrong
179
+ - Specify what should be included
180
+
181
+ ---
182
+
183
+ ## 💡 Tips & Best Practices
184
+
185
+ ### For Effective Testing
186
+
187
+ 1. **Test various scenarios:** Try different distress levels
188
+ 2. **Be specific in comments:** Help us understand what needs fixing
189
+ 3. **Review Provider Summary carefully:** This goes to the spiritual care team
190
+ 4. **Use predefined profiles:** They cover common scenarios
191
+ 5. **Export your results:** Download CSV for reporting
192
+
193
+ ### Common Issues
194
+
195
+ **Classification seems wrong?**
196
+ - Mark as incorrect
197
+ - Select the correct classification
198
+ - Explain your reasoning in the comment
199
+
200
+ **Provider Summary incomplete?**
201
+ - Mark as incorrect
202
+ - List what's missing in the comment
203
+ - Suggest what should be included
204
+
205
+ **Response not appropriate?**
206
+ - Note it in the verification comments
207
+ - Specify what would be better
208
+
209
+ ---
210
+
211
+ ## 📊 Export & Reporting
212
+
213
+ ### CSV Export
214
+
215
+ The CSV file includes:
216
+ - All exchanges with classifications
217
+ - Your verification results (correct/incorrect)
218
+ - Your comments and corrections
219
+ - Provider Summary (in the final row)
220
+ - Session metadata
221
+
222
+ **Use for:**
223
+ - Reporting to development team
224
+ - Tracking accuracy over time
225
+ - Identifying patterns in errors
226
+
227
+ ---
228
+
229
+ ## 🔄 Workflow Summary
230
+
231
+ ```
232
+ 1. Chat Tab
233
+ ↓ Test conversations
234
+
235
+ 2. Conversation Verification Tab
236
+ ↓ Generate verification
237
+ ↓ Review exchanges
238
+ ↓ Mark correct/incorrect
239
+ ↓ Review Provider Summary (final step)
240
+ ↓ Download CSV
241
+
242
+ 3. Report findings to team
243
+ ```
244
+
245
+ ---
246
+
247
+ ## ❓ Frequently Asked Questions
248
+
249
+ **Q: What's the difference between GREEN, YELLOW, and RED?**
250
+ - 🟢 GREEN: No spiritual distress detected
251
+ - 🟡 YELLOW: Potential distress, needs clarification
252
+ - 🔴 RED: Significant distress, requires spiritual care referral
253
+
254
+ **Q: Why is Provider Summary the last exchange?**
255
+ - It allows you to review the final message sent to the spiritual care team
256
+ - You can verify it's complete and accurate
257
+ - Your feedback helps improve summary quality
258
+
259
+ **Q: Do my changes persist between sessions?**
260
+ - No, model and prompt changes are session-only
261
+ - This allows safe testing without affecting others
262
+ - Use "Promote to File" to make permanent changes
263
+
264
+ **Q: What should I focus on when testing?**
265
+ - Accuracy of distress classification
266
+ - Appropriateness of responses
267
+ - Completeness of Provider Summary
268
+ - Overall user experience
269
+
270
+ **Q: How do I report issues?**
271
+ - Use the verification comments
272
+ - Download CSV with your findings
273
+ - Share with the development team
274
+
275
+ ---
276
+
277
+ ## 📞 Support
278
+
279
+ If you encounter issues or have questions:
280
+ 1. Check this help guide
281
+ 2. Review the original requirements: `review/Or_4.txt`
282
+ 3. Contact the development team
283
+
284
+ ---
285
+
286
+ **Thank you for helping improve the Medical Assistant! Your feedback is invaluable! 🙏**
287
+ """
src/interface/verification_handlers.py CHANGED
@@ -756,30 +756,53 @@ def _render_conv_exchange(records: list, index: int):
756
  return "", "", ""
757
  index = max(0, min(index, len(records) - 1))
758
  r = records[index]
759
- # Reuse renderer from conversation_verification_ui to keep style consistent
760
- from src.interface.conversation_verification_ui import VerificationInterface
761
-
762
- vi = VerificationInterface(ConversationVerificationManager())
763
- # If we already have dicts, build a lightweight VerificationRecord
764
- if isinstance(r, dict):
765
- rec = ConvVerificationRecord(
766
- exchange_id=r.get("exchange_id") or r.get("record_id", ""),
767
- exchange_number=r.get("exchange_number", 0),
768
- user_message=r.get("user_message", ""),
769
- assistant_response=r.get("assistant_response", ""),
770
- original_classification=r.get("original_classification", ""),
771
- original_confidence=r.get("original_confidence", 0.0),
772
- original_indicators=r.get("original_indicators", []),
773
- original_reasoning=r.get("original_reasoning", ""),
774
- timestamp=r.get("timestamp"),
775
- is_correct=r.get("is_correct"),
776
- correct_classification=r.get("correct_classification"),
777
- correction_reason=r.get("correction_reason"),
778
- verifier_notes=r.get("verifier_notes"),
779
- )
780
  else:
781
- rec = r
782
- html = vi._render_exchange_review(rec)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
  # status badge
784
  cur_is_correct = (r.get("is_correct") if isinstance(r, dict) else getattr(r, "is_correct", None))
785
  if cur_is_correct is True:
@@ -1065,3 +1088,218 @@ def _nav_conv(records: list, idx: int, delta: int):
1065
  }
1066
  existing_classification = reverse_map.get(correct_class, "")
1067
  return idx, html, pos, stats, row_upd, note_val, existing_classification
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
756
  return "", "", ""
757
  index = max(0, min(index, len(records) - 1))
758
  r = records[index]
759
+
760
+ # Check if this is a Provider Summary exchange (Or_4.txt requirement)
761
+ if isinstance(r, dict) and r.get("original_classification") == "PROVIDER_SUMMARY":
762
+ # Render Provider Summary as final exchange
763
+ provider_summary_html = r.get("provider_summary_html", "")
764
+ if not provider_summary_html:
765
+ # Fallback rendering if HTML not provided
766
+ provider_summary_text = r.get("provider_summary", "")
767
+ provider_summary_html = f"""
768
+ <div style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 1em; margin: 1em 0; border-radius: 4px;">
769
+ <h3 style="margin-top: 0; color: #856404;">📋 Provider Summary (Final Review)</h3>
770
+ <div style="background-color: white; padding: 1em; border-radius: 4px; margin-top: 0.5em;">
771
+ <pre style="white-space: pre-wrap; font-family: system-ui; margin: 0;">{provider_summary_text}</pre>
772
+ </div>
773
+ <p style="margin-bottom: 0; margin-top: 0.5em; font-size: 0.9em; color: #856404;">
774
+ <strong>Please review this summary and provide feedback if incorrect or incomplete.</strong>
775
+ </p>
776
+ </div>
777
+ """
778
+ html = provider_summary_html
 
779
  else:
780
+ # Regular exchange rendering
781
+ # Reuse renderer from conversation_verification_ui to keep style consistent
782
+ from src.interface.conversation_verification_ui import VerificationInterface
783
+
784
+ vi = VerificationInterface(ConversationVerificationManager())
785
+ # If we already have dicts, build a lightweight VerificationRecord
786
+ if isinstance(r, dict):
787
+ rec = ConvVerificationRecord(
788
+ exchange_id=r.get("exchange_id") or r.get("record_id", ""),
789
+ exchange_number=r.get("exchange_number", 0),
790
+ user_message=r.get("user_message", ""),
791
+ assistant_response=r.get("assistant_response", ""),
792
+ original_classification=r.get("original_classification", ""),
793
+ original_confidence=r.get("original_confidence", 0.0),
794
+ original_indicators=r.get("original_indicators", []),
795
+ original_reasoning=r.get("original_reasoning", ""),
796
+ timestamp=r.get("timestamp"),
797
+ is_correct=r.get("is_correct"),
798
+ correct_classification=r.get("correct_classification"),
799
+ correction_reason=r.get("correction_reason"),
800
+ verifier_notes=r.get("verifier_notes"),
801
+ )
802
+ else:
803
+ rec = r
804
+ html = vi._render_exchange_review(rec)
805
+
806
  # status badge
807
  cur_is_correct = (r.get("is_correct") if isinstance(r, dict) else getattr(r, "is_correct", None))
808
  if cur_is_correct is True:
 
1088
  }
1089
  existing_classification = reverse_map.get(correct_class, "")
1090
  return idx, html, pos, stats, row_upd, note_val, existing_classification
1091
+
1092
+
1093
+ # ============================================================================
1094
+ # NEW FUNCTIONS FOR SIMPLIFIED INTERFACE (Or_4.txt requirements)
1095
+ # ============================================================================
1096
+
1097
+ def _generate_conv_verification_with_summary(session: SimplifiedSessionData):
1098
+ """
1099
+ Generate conversation verification with Provider Summary as the FINAL exchange.
1100
+
1101
+ This addresses the customer requirement from Or_4.txt:
1102
+ "Provider Summary to be the final exchange presented in that tab"
1103
+ """
1104
+ if session is None or not hasattr(session.app_instance, "conversation_logger"):
1105
+ return None, [], 0, "❌ No session/conversation found", "", "", ""
1106
+ if not session.app_instance.conversation_logger.entries:
1107
+ return None, [], 0, "⚠️ No exchanges to verify yet", "", "", ""
1108
+
1109
+ manager = ConversationVerificationManager()
1110
+ vs = manager.create_verification_session(session.app_instance.conversation_logger, "Medical Professional")
1111
+
1112
+ # Get patient phone from app if available
1113
+ patient_phone = ""
1114
+ if hasattr(session.app_instance, 'patient_info'):
1115
+ patient_phone = session.app_instance.patient_info.get("phone") or ""
1116
+
1117
+ meta = {
1118
+ "session_id": vs.session_id,
1119
+ "patient_name": vs.patient_name,
1120
+ "patient_phone": patient_phone,
1121
+ "verifier_name": vs.verifier_name,
1122
+ "start_time": vs.start_time.isoformat() if hasattr(vs, "start_time") else None,
1123
+ }
1124
+
1125
+ # Get provider summary if available (for RED cases)
1126
+ provider_summary_text = ""
1127
+ provider_summary_html = ""
1128
+ has_red_flag = False
1129
+
1130
+ if hasattr(session.app_instance, 'get_last_provider_summary'):
1131
+ summary = session.app_instance.get_last_provider_summary()
1132
+ if summary:
1133
+ has_red_flag = True
1134
+ if hasattr(session.app_instance, 'provider_summary_generator'):
1135
+ # Use COHERENT NARRATIVE format (LLM-generated) instead of structured format
1136
+ try:
1137
+ provider_summary_text = session.app_instance.provider_summary_generator.format_coherent_paragraph(summary)
1138
+ if not provider_summary_text:
1139
+ # Fallback to structured format
1140
+ provider_summary_text = session.app_instance.provider_summary_generator.format_for_export(summary)
1141
+ except Exception as e:
1142
+ print(f"ERROR: Failed to generate coherent summary: {e}")
1143
+ provider_summary_text = session.app_instance.provider_summary_generator.format_for_export(summary)
1144
+
1145
+ # Create HTML version for display
1146
+ provider_summary_html = f"""
1147
+ <div style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 1em; margin: 1em 0; border-radius: 4px;">
1148
+ <h3 style="margin-top: 0; color: #856404;">📋 Provider Summary (Final Review)</h3>
1149
+ <div style="background-color: white; padding: 1em; border-radius: 4px; margin-top: 0.5em;">
1150
+ <pre style="white-space: pre-wrap; font-family: system-ui; margin: 0;">{provider_summary_text}</pre>
1151
+ </div>
1152
+ <p style="margin-bottom: 0; margin-top: 0.5em; font-size: 0.9em; color: #856404;">
1153
+ <strong>Please review this summary and provide feedback if incorrect or incomplete.</strong>
1154
+ </p>
1155
+ </div>
1156
+ """
1157
+
1158
+ records_as_dicts = [
1159
+ {
1160
+ "exchange_id": r.exchange_id,
1161
+ "exchange_number": r.exchange_number,
1162
+ "record_id": r.exchange_id,
1163
+ "timestamp": r.timestamp,
1164
+ "user_message": r.user_message,
1165
+ "assistant_response": r.assistant_response,
1166
+ "original_classification": r.original_classification,
1167
+ "original_confidence": r.original_confidence,
1168
+ "original_indicators": r.original_indicators,
1169
+ "original_reasoning": r.original_reasoning,
1170
+ "is_correct": r.is_correct,
1171
+ "correct_classification": r.correct_classification,
1172
+ "correction_reason": r.correction_reason,
1173
+ "verifier_notes": r.verifier_notes,
1174
+ "provider_summary": "", # Not shown in regular exchanges
1175
+ }
1176
+ for r in vs.verification_records
1177
+ ]
1178
+
1179
+ # ADD PROVIDER SUMMARY AS FINAL EXCHANGE (Or_4.txt requirement)
1180
+ if has_red_flag and provider_summary_html:
1181
+ final_exchange = {
1182
+ "exchange_id": f"{vs.session_id}_provider_summary",
1183
+ "exchange_number": len(records_as_dicts) + 1,
1184
+ "record_id": f"{vs.session_id}_provider_summary",
1185
+ "timestamp": datetime.now().isoformat(),
1186
+ "user_message": "",
1187
+ "assistant_response": "",
1188
+ "original_classification": "PROVIDER_SUMMARY",
1189
+ "original_confidence": 1.0,
1190
+ "original_indicators": [],
1191
+ "original_reasoning": "Provider Summary for Spiritual Care Team",
1192
+ "is_correct": None, # Needs review
1193
+ "correct_classification": None,
1194
+ "correction_reason": "",
1195
+ "verifier_notes": "",
1196
+ "provider_summary": provider_summary_text,
1197
+ "provider_summary_html": provider_summary_html,
1198
+ }
1199
+ records_as_dicts.append(final_exchange)
1200
+
1201
+ html, pos, stats = _render_conv_exchange(records_as_dicts, 0)
1202
+ return meta, records_as_dicts, 0, f"✅ Generated session with {len(records_as_dicts)} exchanges (Provider Summary as final step)", html, pos, stats
1203
+
1204
+
1205
+ def _auto_save_verification_report(meta: dict, records: list, session: SimplifiedSessionData):
1206
+ """
1207
+ Auto-save verification report to a predefined location.
1208
+
1209
+ This addresses the customer requirement from Or_4.txt:
1210
+ "I would prefer a single button for automatically saving the report"
1211
+
1212
+ Saves both JSON and CSV formats to a standard location.
1213
+ """
1214
+ try:
1215
+ if not records:
1216
+ return "⚠️ No verification data to save"
1217
+
1218
+ # Create auto-save directory
1219
+ auto_save_dir = os.path.join(os.getcwd(), "verification_reports")
1220
+ os.makedirs(auto_save_dir, exist_ok=True)
1221
+
1222
+ session_id = (meta or {}).get("session_id") or "unknown"
1223
+ timestamp = datetime.utcnow().strftime('%Y%m%d_%H%M%S')
1224
+
1225
+ # Save JSON
1226
+ json_filename = f"report_{timestamp}_{session_id}.json"
1227
+ json_path = os.path.join(auto_save_dir, json_filename)
1228
+
1229
+ payload = {
1230
+ **(meta or {}),
1231
+ "verification_records": records or [],
1232
+ "auto_saved_at": datetime.utcnow().isoformat(),
1233
+ }
1234
+
1235
+ with open(json_path, "w", encoding="utf-8") as f:
1236
+ json.dump(payload, f, ensure_ascii=False, indent=2, default=str)
1237
+
1238
+ # Save CSV
1239
+ csv_filename = f"report_{timestamp}_{session_id}.csv"
1240
+ csv_path = os.path.join(auto_save_dir, csv_filename)
1241
+
1242
+ fieldnames = [
1243
+ "session_id",
1244
+ "patient_name",
1245
+ "patient_phone",
1246
+ "verifier_name",
1247
+ "start_time",
1248
+ "exchange_number",
1249
+ "exchange_id",
1250
+ "original_classification",
1251
+ "original_confidence",
1252
+ "is_correct",
1253
+ "correct_classification",
1254
+ "verifier_notes",
1255
+ "user_message",
1256
+ "assistant_response",
1257
+ "provider_summary",
1258
+ ]
1259
+
1260
+ with open(csv_path, "w", encoding="utf-8", newline="") as f:
1261
+ w = csv.DictWriter(f, fieldnames=fieldnames)
1262
+ w.writeheader()
1263
+ for r in records or []:
1264
+ # Include provider_summary for all records (especially the final one)
1265
+ provider_summary = r.get("provider_summary") or ""
1266
+
1267
+ row = {
1268
+ "session_id": (meta or {}).get("session_id"),
1269
+ "patient_name": (meta or {}).get("patient_name"),
1270
+ "patient_phone": (meta or {}).get("patient_phone") or "",
1271
+ "verifier_name": (meta or {}).get("verifier_name"),
1272
+ "start_time": (meta or {}).get("start_time"),
1273
+ "exchange_number": r.get("exchange_number"),
1274
+ "exchange_id": r.get("exchange_id") or r.get("record_id"),
1275
+ "original_classification": r.get("original_classification"),
1276
+ "original_confidence": r.get("original_confidence"),
1277
+ "is_correct": r.get("is_correct"),
1278
+ "correct_classification": r.get("correct_classification") or "",
1279
+ "verifier_notes": r.get("verifier_notes") or "",
1280
+ "user_message": r.get("user_message"),
1281
+ "assistant_response": r.get("assistant_response"),
1282
+ "provider_summary": provider_summary,
1283
+ }
1284
+ w.writerow(row)
1285
+
1286
+ return f"""✅ **Report Auto-Saved Successfully!**
1287
+
1288
+ 📁 **Location:** `{auto_save_dir}`
1289
+
1290
+ 📄 **Files:**
1291
+ - JSON: `{json_filename}`
1292
+ - CSV: `{csv_filename}`
1293
+
1294
+ 📊 **Summary:**
1295
+ - Total exchanges: {len(records)}
1296
+ - Reviewed: {sum(1 for r in records if r.get('is_correct') is not None)}
1297
+ - Correct: {sum(1 for r in records if r.get('is_correct') is True)}
1298
+ - Incorrect: {sum(1 for r in records if r.get('is_correct') is False)}
1299
+ """
1300
+
1301
+ except Exception as e:
1302
+ import traceback
1303
+ error_details = traceback.format_exc()
1304
+ print(f"❌ Auto-save error: {error_details}")
1305
+ return f"❌ **Auto-save failed:** {str(e)}"
tests/integration/test_integration.py CHANGED
@@ -17,7 +17,7 @@ def test_integration():
17
  print("1. Testing imports...")
18
  from interface.enhanced_prompt_editor import EnhancedPromptEditor
19
  from config.prompt_management.prompt_controller import PromptController
20
- from interface.simplified_gradio_app import main
21
  print(" ✓ All components import successfully")
22
 
23
  # Test 2: Initialize components
 
17
  print("1. Testing imports...")
18
  from interface.enhanced_prompt_editor import EnhancedPromptEditor
19
  from config.prompt_management.prompt_controller import PromptController
20
+ from interface.gradio_app import main
21
  print(" ✓ All components import successfully")
22
 
23
  # Test 2: Initialize components
tests/test_conversation_verification_export.py CHANGED
@@ -33,7 +33,7 @@ def test_conversation_verification_export_serializes_without_record_id(tmp_path,
33
 
34
  vs = _Session()
35
 
36
- # This mirrors the payload schema in simplified_gradio_app.open_verification_window
37
  payload = {
38
  "session_id": vs.session_id,
39
  "patient_name": vs.patient_name,
 
33
 
34
  vs = _Session()
35
 
36
+ # This mirrors the payload schema in gradio_app.open_verification_window
37
  payload = {
38
  "session_id": vs.session_id,
39
  "patient_name": vs.patient_name,
tests/test_ui_smoke.py CHANGED
@@ -1,6 +1,6 @@
1
  import importlib
2
 
3
 
4
- def test_simplified_gradio_app_imports():
5
  """Smoke test: module should import without raising (catches Gradio API breaks)."""
6
- importlib.import_module("src.interface.simplified_gradio_app")
 
1
  import importlib
2
 
3
 
4
+ def test_gradio_app_imports():
5
  """Smoke test: module should import without raising (catches Gradio API breaks)."""
6
+ importlib.import_module("src.interface.gradio_app")
tests/verification_mode/test_final_integration.py CHANGED
@@ -16,7 +16,7 @@ import os
16
  from datetime import datetime
17
  from unittest.mock import Mock, patch, MagicMock
18
 
19
- from src.interface.simplified_gradio_app import create_simplified_interface
20
  from src.interface.verification_ui import VerificationUIComponents
21
  from src.core.verification_models import (
22
  VerificationSession,
 
16
  from datetime import datetime
17
  from unittest.mock import Mock, patch, MagicMock
18
 
19
+ from src.interface.gradio_app import create_simplified_interface
20
  from src.interface.verification_ui import VerificationUIComponents
21
  from src.core.verification_models import (
22
  VerificationSession,