Spaces:
Sleeping
Sleeping
feat: Add XML-style tags to prompts for better structure
Browse filesPrompts updated with XML-like tags:
- <system_role> - defines the AI's role
- <classification_categories> - defines categories
- <category> - individual category definitions
- <critical_rules> - important rules
- <guidelines> - behavioral guidelines
- <examples> - example outputs
- <output_format> - expected format
- <scratchpad> - thinking process
- <outcome_categories> - possible outcomes
- <evaluation_process> - step-by-step process
HTML formatter updated to:
- Highlight XML tags in blue/purple
- Highlight attributes in green/orange
- Preserve code-like appearance with monospace font
- Better visual hierarchy
- src/core/soft_triage_manager.py +86 -28
- src/core/spiritual_monitor.py +62 -15
- src/interface/simplified_gradio_app.py +28 -16
src/core/soft_triage_manager.py
CHANGED
|
@@ -25,49 +25,107 @@ logger = logging.getLogger(__name__)
|
|
| 25 |
|
| 26 |
|
| 27 |
# System prompt for generating triage questions
|
| 28 |
-
SYSTEM_PROMPT_TRIAGE_QUESTION = """
|
|
|
|
|
|
|
| 29 |
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
4. Keep the question natural, like a caring conversation
|
| 38 |
-
5. CRITICAL: Respond in the SAME LANGUAGE as the patient's message
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
- "Thank you for sharing that with me. How have you been coping with these feelings?"
|
| 44 |
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
|
| 48 |
# System prompt for evaluating triage responses
|
| 49 |
-
SYSTEM_PROMPT_TRIAGE_EVALUATE = """
|
|
|
|
|
|
|
| 50 |
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
-
|
|
|
|
| 66 |
{
|
| 67 |
"outcome": "resolved_green" | "escalate_red" | "continue",
|
| 68 |
-
"reasoning": "Brief explanation",
|
| 69 |
"confidence": 0.0-1.0
|
| 70 |
-
}
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
|
| 73 |
class SoftTriageManager:
|
|
|
|
| 25 |
|
| 26 |
|
| 27 |
# System prompt for generating triage questions
|
| 28 |
+
SYSTEM_PROMPT_TRIAGE_QUESTION = """<system_role>
|
| 29 |
+
You are a compassionate healthcare assistant conducting a gentle wellness check. The patient may be experiencing some emotional or spiritual distress. Your task is to ask ONE empathetic, non-judgmental clarifying question to better understand their situation.
|
| 30 |
+
</system_role>
|
| 31 |
|
| 32 |
+
<guidelines>
|
| 33 |
+
<guideline priority="high">Be warm and supportive, not clinical or interrogating</guideline>
|
| 34 |
+
<guideline priority="high">Ask open-ended questions that invite sharing</guideline>
|
| 35 |
+
<guideline priority="medium">Acknowledge their feelings without making assumptions</guideline>
|
| 36 |
+
<guideline priority="medium">Keep the question natural, like a caring conversation</guideline>
|
| 37 |
+
<guideline priority="critical">CRITICAL: Respond in the SAME LANGUAGE as the patient's message</guideline>
|
| 38 |
+
</guidelines>
|
| 39 |
|
| 40 |
+
<examples>
|
| 41 |
+
<example language="english">
|
| 42 |
+
"It sounds like you're going through a difficult time. Would you like to tell me more about what's on your mind?"
|
| 43 |
+
</example>
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
<example language="english">
|
| 46 |
+
"I hear that things feel heavy right now. What would be most helpful for you to talk about?"
|
| 47 |
+
</example>
|
|
|
|
| 48 |
|
| 49 |
+
<example language="english">
|
| 50 |
+
"Thank you for sharing that with me. How have you been coping with these feelings?"
|
| 51 |
+
</example>
|
| 52 |
+
|
| 53 |
+
<example language="ukrainian">
|
| 54 |
+
"Здається, ви переживаєте важкий час. Чи хотіли б ви розповісти більше про те, що вас турбує?"
|
| 55 |
+
</example>
|
| 56 |
+
|
| 57 |
+
<example language="ukrainian">
|
| 58 |
+
"Я розумію, що зараз вам важко. Про що б вам найбільше хотілося поговорити?"
|
| 59 |
+
</example>
|
| 60 |
+
</examples>
|
| 61 |
+
|
| 62 |
+
<output_format>
|
| 63 |
+
Respond with ONLY the question text, no JSON or formatting. Match the patient's language.
|
| 64 |
+
</output_format>"""
|
| 65 |
|
| 66 |
|
| 67 |
# System prompt for evaluating triage responses
|
| 68 |
+
SYSTEM_PROMPT_TRIAGE_EVALUATE = """<system_role>
|
| 69 |
+
You are evaluating a patient's response during a gentle wellness check. Based on the patient's response, determine the appropriate outcome to guide next steps.
|
| 70 |
+
</system_role>
|
| 71 |
|
| 72 |
+
<outcome_categories>
|
| 73 |
+
<outcome name="RESOLVED_GREEN" action="return_to_medical">
|
| 74 |
+
<description>Patient is coping well, has support systems, or the concern was minor</description>
|
| 75 |
+
<indicators>
|
| 76 |
+
- Mentions coping strategies or support from others
|
| 77 |
+
- Describes temporary stress that is manageable
|
| 78 |
+
- Reports feeling better or having resources
|
| 79 |
+
- Shows resilience or positive outlook
|
| 80 |
+
</indicators>
|
| 81 |
+
<example>"I'm just having a bad day, but I have my family to talk to"</example>
|
| 82 |
+
<example>"It's been tough, but I'm managing with my therapist's help"</example>
|
| 83 |
+
</outcome>
|
| 84 |
|
| 85 |
+
<outcome name="ESCALATE_RED" action="generate_referral">
|
| 86 |
+
<description>Patient shows significant distress that needs professional support</description>
|
| 87 |
+
<indicators>
|
| 88 |
+
- Persistent hopelessness without relief
|
| 89 |
+
- Complete isolation with no support system
|
| 90 |
+
- Inability to cope or function
|
| 91 |
+
- Worsening symptoms or deterioration
|
| 92 |
+
- Continued crisis language
|
| 93 |
+
</indicators>
|
| 94 |
+
<example>"I feel completely alone and nothing helps anymore"</example>
|
| 95 |
+
<example>"Every day is worse, I can't see a way forward"</example>
|
| 96 |
+
</outcome>
|
| 97 |
|
| 98 |
+
<outcome name="CONTINUE" action="ask_another_question">
|
| 99 |
+
<description>Need more information to make a determination</description>
|
| 100 |
+
<indicators>
|
| 101 |
+
- Vague or unclear response
|
| 102 |
+
- Patient deflecting or avoiding
|
| 103 |
+
- Ambiguous situation requiring clarification
|
| 104 |
+
- Mixed signals that need exploration
|
| 105 |
+
</indicators>
|
| 106 |
+
<example>"I don't know, it's complicated"</example>
|
| 107 |
+
<example>"Maybe, I'm not sure"</example>
|
| 108 |
+
</outcome>
|
| 109 |
+
</outcome_categories>
|
| 110 |
|
| 111 |
+
<evaluation_process>
|
| 112 |
+
<step>Review the patient's response carefully</step>
|
| 113 |
+
<step>Identify specific indicators present in their words</step>
|
| 114 |
+
<step>Match indicators to outcome categories</step>
|
| 115 |
+
<step>Consider the overall tone and context</step>
|
| 116 |
+
<step>Assess confidence in your determination</step>
|
| 117 |
+
</evaluation_process>
|
| 118 |
|
| 119 |
+
<output_format>
|
| 120 |
+
Respond ONLY with valid JSON in this exact format:
|
| 121 |
{
|
| 122 |
"outcome": "resolved_green" | "escalate_red" | "continue",
|
| 123 |
+
"reasoning": "Brief explanation of why you chose this outcome",
|
| 124 |
"confidence": 0.0-1.0
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
Do not include any text before or after the JSON object.
|
| 128 |
+
</output_format>"""
|
| 129 |
|
| 130 |
|
| 131 |
class SoftTriageManager:
|
src/core/spiritual_monitor.py
CHANGED
|
@@ -62,30 +62,77 @@ YELLOW_FLAG_INDICATORS = [
|
|
| 62 |
|
| 63 |
|
| 64 |
# System prompt for spiritual classification
|
| 65 |
-
SYSTEM_PROMPT_SPIRITUAL_MONITOR = """
|
|
|
|
|
|
|
| 66 |
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
- YELLOW: Potential distress indicators present. May need gentle follow-up.
|
| 70 |
-
- RED: Severe distress indicators. Immediate support needed.
|
| 71 |
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
3. GREEN (none): Medical symptoms only, routine questions, no emotional content
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
-
|
| 80 |
-
- Spiritual questions (about God, faith, meaning)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
{
|
| 84 |
"state": "green" | "yellow" | "red",
|
| 85 |
"indicators": ["indicator1", "indicator2"],
|
| 86 |
"confidence": 0.0-1.0,
|
| 87 |
"reasoning": "Brief explanation"
|
| 88 |
-
}
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
|
| 91 |
class SpiritualMonitor:
|
|
|
|
| 62 |
|
| 63 |
|
| 64 |
# System prompt for spiritual classification
|
| 65 |
+
SYSTEM_PROMPT_SPIRITUAL_MONITOR = """<system_role>
|
| 66 |
+
You are a background spiritual distress classifier for a medical chatbot. Your task is to analyze patient messages and classify their level of spiritual or emotional distress to help route them to appropriate support.
|
| 67 |
+
</system_role>
|
| 68 |
|
| 69 |
+
<classification_categories>
|
| 70 |
+
You must classify this message into exactly ONE of the following three categories:
|
|
|
|
|
|
|
| 71 |
|
| 72 |
+
<category name="GREEN" severity="no_distress">
|
| 73 |
+
The message contains only medical symptoms, routine questions, appointment scheduling, medication inquiries, or other standard healthcare topics. There are no indicators of emotional or spiritual distress.
|
| 74 |
+
</category>
|
|
|
|
| 75 |
|
| 76 |
+
<category name="YELLOW" severity="potential_distress">
|
| 77 |
+
The message contains indicators of mild to moderate distress, including:
|
| 78 |
+
- Expressions of sadness, worry, or anxiety
|
| 79 |
+
- Spiritual or existential questions (about God, faith, life's meaning, purpose)
|
| 80 |
+
- Grief or loss (not acute crisis)
|
| 81 |
+
- Loneliness or isolation
|
| 82 |
+
- Feeling overwhelmed or stressed
|
| 83 |
+
- Questions about suffering or "why me"
|
| 84 |
+
- Mild hopelessness that doesn't involve crisis language
|
| 85 |
+
</category>
|
| 86 |
|
| 87 |
+
<category name="RED" severity="severe_distress">
|
| 88 |
+
The message contains indicators of severe distress or crisis, including:
|
| 89 |
+
- ANY mention of suicide, suicidal thoughts, or suicidal ideation
|
| 90 |
+
- Self-harm thoughts or behaviors
|
| 91 |
+
- Explicit wishes to die or not wake up
|
| 92 |
+
- Severe hopelessness combined with crisis language
|
| 93 |
+
- Statements like "I can't go on," "I want to end it," "no reason to live"
|
| 94 |
+
- Active crisis or emergency language
|
| 95 |
+
</category>
|
| 96 |
+
</classification_categories>
|
| 97 |
+
|
| 98 |
+
<critical_rules>
|
| 99 |
+
1. ANY mention of suicide, self-harm, death wishes, or wanting to die is ALWAYS classified as RED, regardless of other content
|
| 100 |
+
2. When uncertain between GREEN and YELLOW, always choose YELLOW (err on the side of caution)
|
| 101 |
+
3. When uncertain between YELLOW and RED, carefully evaluate for active crisis language - if present, choose RED
|
| 102 |
+
4. Spiritual questions alone (without crisis indicators) are YELLOW, not RED
|
| 103 |
+
5. Multiple YELLOW indicators together still remain YELLOW unless crisis language is present
|
| 104 |
+
6. Physical pain or medical symptoms alone are GREEN unless accompanied by emotional/spiritual distress language
|
| 105 |
+
</critical_rules>
|
| 106 |
+
|
| 107 |
+
<analysis_process>
|
| 108 |
+
Before providing your classification, use the scratchpad to think through your analysis:
|
| 109 |
+
|
| 110 |
+
<scratchpad>
|
| 111 |
+
- Identify any distress indicators present in the message
|
| 112 |
+
- Note the severity level of each indicator
|
| 113 |
+
- Consider whether crisis language is present
|
| 114 |
+
- Determine which category best fits
|
| 115 |
+
- Assess your confidence level
|
| 116 |
+
</scratchpad>
|
| 117 |
+
</analysis_process>
|
| 118 |
+
|
| 119 |
+
<output_format>
|
| 120 |
+
After your analysis, provide your classification in valid JSON format with the following structure:
|
| 121 |
+
- "state": Must be exactly "green", "yellow", or "red" (lowercase)
|
| 122 |
+
- "indicators": An array of specific distress indicators found (empty array [] if none)
|
| 123 |
+
- "confidence": A number between 0.0 and 1.0 representing your confidence in the classification
|
| 124 |
+
- "reasoning": A brief 1-2 sentence explanation of why you chose this classification
|
| 125 |
+
|
| 126 |
+
Your response must be ONLY valid JSON in this exact format:
|
| 127 |
{
|
| 128 |
"state": "green" | "yellow" | "red",
|
| 129 |
"indicators": ["indicator1", "indicator2"],
|
| 130 |
"confidence": 0.0-1.0,
|
| 131 |
"reasoning": "Brief explanation"
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
Do not include any text before or after the JSON object.
|
| 135 |
+
</output_format>"""
|
| 136 |
|
| 137 |
|
| 138 |
class SpiritualMonitor:
|
src/interface/simplified_gradio_app.py
CHANGED
|
@@ -261,30 +261,39 @@ For emergencies, please call emergency services immediately.
|
|
| 261 |
def format_prompt_with_html(prompt_text: str) -> str:
|
| 262 |
"""Format prompt with HTML tags for better visualization."""
|
| 263 |
import re
|
|
|
|
| 264 |
|
| 265 |
-
#
|
| 266 |
-
formatted = prompt_text
|
| 267 |
|
| 268 |
-
# Highlight
|
| 269 |
formatted = re.sub(
|
| 270 |
-
r'
|
| 271 |
-
r'<
|
| 272 |
formatted,
|
| 273 |
-
flags=re.
|
| 274 |
)
|
| 275 |
|
| 276 |
-
# Highlight
|
| 277 |
formatted = re.sub(
|
| 278 |
-
r'
|
| 279 |
-
r'<
|
| 280 |
formatted,
|
| 281 |
-
flags=re.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
)
|
| 283 |
|
| 284 |
# Highlight bullet points
|
| 285 |
formatted = re.sub(
|
| 286 |
r'^([-•]\s+.+)$',
|
| 287 |
-
r'<
|
| 288 |
formatted,
|
| 289 |
flags=re.MULTILINE
|
| 290 |
)
|
|
@@ -292,7 +301,7 @@ For emergencies, please call emergency services immediately.
|
|
| 292 |
# Highlight numbered lists
|
| 293 |
formatted = re.sub(
|
| 294 |
r'^(\d+\.\s+.+)$',
|
| 295 |
-
r'<
|
| 296 |
formatted,
|
| 297 |
flags=re.MULTILINE
|
| 298 |
)
|
|
@@ -300,7 +309,7 @@ For emergencies, please call emergency services immediately.
|
|
| 300 |
# Highlight important keywords
|
| 301 |
keywords = [
|
| 302 |
'IMPORTANT', 'CRITICAL', 'REQUIRED', 'MUST', 'SHALL',
|
| 303 |
-
'WARNING', 'NOTE', 'TASK', 'GOAL', 'OUTPUT'
|
| 304 |
]
|
| 305 |
for keyword in keywords:
|
| 306 |
formatted = re.sub(
|
|
@@ -313,12 +322,15 @@ For emergencies, please call emergency services immediately.
|
|
| 313 |
# Highlight JSON/code blocks
|
| 314 |
formatted = re.sub(
|
| 315 |
r'(\{[^}]+\})',
|
| 316 |
-
r'<code style="background-color: #f3f4f6; padding: 2px 6px; border-radius: 3px; font-family: monospace;">\1</code>',
|
| 317 |
formatted
|
| 318 |
)
|
| 319 |
|
| 320 |
-
#
|
| 321 |
-
formatted =
|
|
|
|
|
|
|
|
|
|
| 322 |
|
| 323 |
return formatted
|
| 324 |
|
|
|
|
| 261 |
def format_prompt_with_html(prompt_text: str) -> str:
|
| 262 |
"""Format prompt with HTML tags for better visualization."""
|
| 263 |
import re
|
| 264 |
+
import html
|
| 265 |
|
| 266 |
+
# Escape HTML first to prevent injection
|
| 267 |
+
formatted = html.escape(prompt_text)
|
| 268 |
|
| 269 |
+
# Highlight XML-like opening tags
|
| 270 |
formatted = re.sub(
|
| 271 |
+
r'<([a-z_]+)(?:\s+[^>]*)?>',
|
| 272 |
+
r'<span style="color: #2563eb; font-weight: 600;"><\1></span>',
|
| 273 |
formatted,
|
| 274 |
+
flags=re.IGNORECASE
|
| 275 |
)
|
| 276 |
|
| 277 |
+
# Highlight XML-like closing tags
|
| 278 |
formatted = re.sub(
|
| 279 |
+
r'</([a-z_]+)>',
|
| 280 |
+
r'<span style="color: #7c3aed; font-weight: 600;"></\1></span>',
|
| 281 |
formatted,
|
| 282 |
+
flags=re.IGNORECASE
|
| 283 |
+
)
|
| 284 |
+
|
| 285 |
+
# Highlight XML attributes
|
| 286 |
+
formatted = re.sub(
|
| 287 |
+
r'([a-z_]+)="([^"]+)"',
|
| 288 |
+
r'<span style="color: #059669;">\1</span>=<span style="color: #d97706;">"\2"</span>',
|
| 289 |
+
formatted,
|
| 290 |
+
flags=re.IGNORECASE
|
| 291 |
)
|
| 292 |
|
| 293 |
# Highlight bullet points
|
| 294 |
formatted = re.sub(
|
| 295 |
r'^([-•]\s+.+)$',
|
| 296 |
+
r'<div style="margin-left: 1.5em; color: #059669;">\1</div>',
|
| 297 |
formatted,
|
| 298 |
flags=re.MULTILINE
|
| 299 |
)
|
|
|
|
| 301 |
# Highlight numbered lists
|
| 302 |
formatted = re.sub(
|
| 303 |
r'^(\d+\.\s+.+)$',
|
| 304 |
+
r'<div style="margin-left: 1.5em; color: #dc2626;">\1</div>',
|
| 305 |
formatted,
|
| 306 |
flags=re.MULTILINE
|
| 307 |
)
|
|
|
|
| 309 |
# Highlight important keywords
|
| 310 |
keywords = [
|
| 311 |
'IMPORTANT', 'CRITICAL', 'REQUIRED', 'MUST', 'SHALL',
|
| 312 |
+
'WARNING', 'NOTE', 'TASK', 'GOAL', 'OUTPUT', 'ANY'
|
| 313 |
]
|
| 314 |
for keyword in keywords:
|
| 315 |
formatted = re.sub(
|
|
|
|
| 322 |
# Highlight JSON/code blocks
|
| 323 |
formatted = re.sub(
|
| 324 |
r'(\{[^}]+\})',
|
| 325 |
+
r'<code style="background-color: #f3f4f6; padding: 2px 6px; border-radius: 3px; font-family: monospace; font-size: 0.9em;">\1</code>',
|
| 326 |
formatted
|
| 327 |
)
|
| 328 |
|
| 329 |
+
# Convert newlines to <br> for proper display
|
| 330 |
+
formatted = formatted.replace('\n', '<br>')
|
| 331 |
+
|
| 332 |
+
# Wrap in container with monospace font for code-like appearance
|
| 333 |
+
formatted = f'<div style="font-family: \'Courier New\', monospace; line-height: 1.8; padding: 1em; background-color: #f9fafb; border-radius: 8px; overflow-x: auto;">{formatted}</div>'
|
| 334 |
|
| 335 |
return formatted
|
| 336 |
|