Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -93,116 +93,155 @@ class CICE_Assessment:
|
|
| 93 |
except Exception as e:
|
| 94 |
return f"Error during analysis: {str(e)}", param1, param2, param3, param4, param5
|
| 95 |
|
| 96 |
-
def build_assessment_prompt(self,
|
| 97 |
-
"""Build a dynamic prompt based on user-selected parameters"""
|
| 98 |
|
| 99 |
# Normalize weights
|
| 100 |
-
total_weight =
|
| 101 |
if total_weight == 0:
|
| 102 |
total_weight = 1 # Avoid division by zero
|
| 103 |
|
|
|
|
| 104 |
comm_pct = (communication_weight / total_weight) * 100
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
lead_pct = (leadership_weight / total_weight) * 100
|
| 109 |
|
| 110 |
-
prompt = f"""Analyze this
|
|
|
|
|
|
|
|
|
|
| 111 |
EVALUATION WEIGHTS (Total 100%):
|
| 112 |
-
1.
|
| 113 |
-
2.
|
| 114 |
-
3.
|
| 115 |
-
4.
|
| 116 |
-
5.
|
| 117 |
-
|
|
|
|
| 118 |
"""
|
| 119 |
|
| 120 |
# Add detailed criteria based on weights
|
| 121 |
criteria_sections = []
|
| 122 |
|
| 123 |
-
if
|
| 124 |
criteria_sections.append(f"""
|
| 125 |
-
##
|
| 126 |
Evaluate:
|
| 127 |
-
-
|
| 128 |
-
-
|
| 129 |
-
-
|
| 130 |
-
-
|
| 131 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
""")
|
| 133 |
|
| 134 |
-
if
|
| 135 |
criteria_sections.append(f"""
|
| 136 |
-
##
|
| 137 |
Evaluate:
|
| 138 |
-
-
|
| 139 |
-
-
|
| 140 |
-
-
|
| 141 |
-
-
|
| 142 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
""")
|
| 144 |
|
| 145 |
-
if
|
| 146 |
criteria_sections.append(f"""
|
| 147 |
-
##
|
| 148 |
Evaluate:
|
| 149 |
-
-
|
| 150 |
-
-
|
| 151 |
-
-
|
| 152 |
-
-
|
| 153 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
""")
|
| 155 |
|
| 156 |
-
if
|
| 157 |
criteria_sections.append(f"""
|
| 158 |
-
##
|
| 159 |
Evaluate:
|
| 160 |
-
-
|
| 161 |
-
-
|
| 162 |
-
-
|
| 163 |
-
-
|
| 164 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
""")
|
| 166 |
|
| 167 |
-
if
|
| 168 |
criteria_sections.append(f"""
|
| 169 |
-
##
|
| 170 |
Evaluate:
|
| 171 |
-
-
|
| 172 |
-
-
|
| 173 |
-
-
|
| 174 |
-
-
|
| 175 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
""")
|
| 177 |
|
| 178 |
prompt += "".join(criteria_sections)
|
| 179 |
|
| 180 |
prompt += f"""
|
|
|
|
| 181 |
STRUCTURE YOUR RESPONSE AS FOLLOWS:
|
|
|
|
| 182 |
## OVERALL WEIGHTED ASSESSMENT
|
| 183 |
-
Provide an overall
|
|
|
|
| 184 |
## DETAILED EVALUATION BY PARAMETER
|
| 185 |
For each parameter with weight > 0, provide:
|
| 186 |
- Parameter Name: [Name]
|
| 187 |
- Weight: [X/10]
|
| 188 |
- Score: [X/10]
|
| 189 |
-
- Observations: [
|
| 190 |
-
-
|
|
|
|
|
|
|
| 191 |
## KEY STRENGTHS
|
| 192 |
-
Top 3-5 strengths observed (prioritize based on weighted parameters)
|
|
|
|
| 193 |
## CRITICAL IMPROVEMENTS NEEDED
|
| 194 |
-
Top 3-5 areas needing improvement (prioritize based on weighted parameters)
|
|
|
|
| 195 |
## WEIGHTED FINAL SCORE
|
| 196 |
Calculate the weighted average score:
|
|
|
|
| 197 |
- Communication: {communication_weight}/10 weight × [score]/10
|
| 198 |
-
-
|
| 199 |
-
-
|
| 200 |
-
-
|
| 201 |
-
|
| 202 |
TOTAL WEIGHTED SCORE: [X]/10
|
| 203 |
Performance Level: [Exemplary (8.5-10)/Proficient (7-8.4)/Developing (5-6.9)/Needs Improvement (0-4.9)]
|
|
|
|
|
|
|
| 204 |
## AUDIO SUMMARY
|
| 205 |
-
[Create a 60-second spoken summary focusing on the overall weighted score, top strengths in
|
| 206 |
"""
|
| 207 |
|
| 208 |
return prompt
|
|
@@ -367,8 +406,8 @@ Performance Level: [Exemplary (8.5-10)/Proficient (7-8.4)/Developing (5-6.9)/Nee
|
|
| 367 |
)
|
| 368 |
|
| 369 |
# Add title
|
| 370 |
-
elements.append(Paragraph("
|
| 371 |
-
elements.append(Paragraph("(
|
| 372 |
elements.append(Spacer(1, 12))
|
| 373 |
|
| 374 |
# Add timestamp
|
|
@@ -377,12 +416,12 @@ Performance Level: [Exemplary (8.5-10)/Proficient (7-8.4)/Developing (5-6.9)/Nee
|
|
| 377 |
elements.append(Spacer(1, 20))
|
| 378 |
|
| 379 |
# Add parameter settings
|
| 380 |
-
elements.append(Paragraph("<b>Evaluation Parameters Used:</b>", heading_style))
|
| 381 |
-
elements.append(Paragraph(f"
|
| 382 |
-
elements.append(Paragraph(f"
|
| 383 |
-
elements.append(Paragraph(f"
|
| 384 |
-
elements.append(Paragraph(f"
|
| 385 |
-
elements.append(Paragraph(f"
|
| 386 |
elements.append(Spacer(1, 20))
|
| 387 |
|
| 388 |
# Process the assessment text into PDF-friendly format
|
|
@@ -416,12 +455,12 @@ Performance Level: [Exemplary (8.5-10)/Proficient (7-8.4)/Developing (5-6.9)/Nee
|
|
| 416 |
print(f"PDF generation failed: {str(e)}")
|
| 417 |
# Fallback to text file
|
| 418 |
temp_txt = tempfile.NamedTemporaryFile(delete=False, suffix='.txt', mode='w')
|
| 419 |
-
temp_txt.write("
|
| 420 |
-
temp_txt.write("(
|
| 421 |
temp_txt.write("="*60 + "\n")
|
| 422 |
temp_txt.write(f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
| 423 |
temp_txt.write("="*60 + "\n\n")
|
| 424 |
-
temp_txt.write(f"Parameters:
|
| 425 |
temp_txt.write(assessment_text)
|
| 426 |
temp_txt.close()
|
| 427 |
return temp_txt.name
|
|
@@ -625,8 +664,8 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 625 |
print(f"Resized video: {new_file_size_mb:.1f}MB (saved {file_size_mb - new_file_size_mb:.1f}MB)")
|
| 626 |
|
| 627 |
# Start assessment with parameters
|
| 628 |
-
print(f"Starting
|
| 629 |
-
print(f"Parameters:
|
| 630 |
|
| 631 |
assessment_result, p1, p2, p3, p4, p5 = assessor.analyze_video(video_to_process, param1, param2, param3, param4, param5)
|
| 632 |
|
|
@@ -657,7 +696,7 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 657 |
# Create enhanced visual summary HTML with parameter information
|
| 658 |
summary_html = f"""
|
| 659 |
<div style="max-width:800px; margin:20px auto; padding:30px; border-radius:15px; box-shadow:0 2px 10px rgba(0,0,0,0.08); background:white;">
|
| 660 |
-
<h2 style="text-align:center; color:#111827; margin-bottom:30px; font-weight:600;">
|
| 661 |
|
| 662 |
<div style="background:#F0F9FF; padding:20px; border-radius:10px; margin-bottom:30px; border:1px solid #BAE6FD;">
|
| 663 |
<h3 style="color:#0369A1; margin-top:0; margin-bottom:15px; font-weight:600;">Overall Weighted Assessment</h3>
|
|
@@ -667,7 +706,7 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 667 |
<div style="display:flex; justify-content:space-around; margin:30px 0;">
|
| 668 |
<div style="text-align:center;">
|
| 669 |
<div style="font-size:48px; font-weight:bold; color:{color};">{weighted_score:.1f}/10</div>
|
| 670 |
-
<div style="color:#4B5563; margin-top:10px; font-weight:500;">
|
| 671 |
</div>
|
| 672 |
<div style="text-align:center;">
|
| 673 |
<div style="font-size:48px; font-weight:bold; color:{color};">{percentage:.0f}%</div>
|
|
@@ -678,10 +717,10 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 678 |
<div style="font-size:24px; font-weight:bold; color:{color};">Performance Level: {level}</div>
|
| 679 |
</div>
|
| 680 |
<div style="margin-top:30px;">
|
| 681 |
-
<h3 style="color:#111827; margin-bottom:20px; font-weight:600;">Your Evaluation Parameters:</h3>
|
| 682 |
<div style="background:#F8FAFC; padding:20px; border-radius:10px; border:1px solid #E2E8F0;">
|
| 683 |
<div style="display:flex; justify-content:space-between; margin:10px 0;">
|
| 684 |
-
<span style="color:#374151; font-weight:500;">
|
| 685 |
<span style="color:#111827; font-weight:bold;">{param1}/10</span>
|
| 686 |
</div>
|
| 687 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
@@ -689,7 +728,7 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 689 |
</div>
|
| 690 |
|
| 691 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 692 |
-
<span style="color:#374151; font-weight:500;">
|
| 693 |
<span style="color:#111827; font-weight:bold;">{param2}/10</span>
|
| 694 |
</div>
|
| 695 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
@@ -697,7 +736,7 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 697 |
</div>
|
| 698 |
|
| 699 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 700 |
-
<span style="color:#374151; font-weight:500;">
|
| 701 |
<span style="color:#111827; font-weight:bold;">{param3}/10</span>
|
| 702 |
</div>
|
| 703 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
@@ -705,7 +744,7 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 705 |
</div>
|
| 706 |
|
| 707 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 708 |
-
<span style="color:#374151; font-weight:500;">
|
| 709 |
<span style="color:#111827; font-weight:bold;">{param4}/10</span>
|
| 710 |
</div>
|
| 711 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
@@ -713,18 +752,18 @@ def process_video_core(video, resize_option, assessor, param1, param2, param3, p
|
|
| 713 |
</div>
|
| 714 |
|
| 715 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 716 |
-
<span style="color:#374151; font-weight:500;">
|
| 717 |
<span style="color:#111827; font-weight:bold;">{param5}/10</span>
|
| 718 |
</div>
|
| 719 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
| 720 |
-
<div style="height:100%; background:#
|
| 721 |
</div>
|
| 722 |
</div>
|
| 723 |
</div>
|
| 724 |
<div style="margin-top:30px; padding:20px; background:#FFF7ED; border-radius:10px; border-left:4px solid #EA580C;">
|
| 725 |
<p style="text-align:center; color:#431407; margin:0; font-weight:600;">
|
| 726 |
Listen to the 1-minute audio summary for key findings<br>
|
| 727 |
-
Download the PDF report for complete documentation
|
| 728 |
</p>
|
| 729 |
</div>
|
| 730 |
</div>
|
|
@@ -743,15 +782,19 @@ def process_video(video, resize_option, param1, param2, param3, param4, param5):
|
|
| 743 |
return process_video_with_gpu(video, resize_option, param1, param2, param3, param4, param5)
|
| 744 |
|
| 745 |
# Create and launch the Gradio interface with parameter controls
|
| 746 |
-
print("Launching
|
| 747 |
|
| 748 |
-
with gr.Blocks(title="
|
| 749 |
|
| 750 |
gr.Markdown("""
|
| 751 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 752 |
|
| 753 |
-
**Customize your video evaluation with 5 key parameters to focus on what matters most to your team**
|
| 754 |
-
This tool allows you to adjust the evaluation weights for different aspects of healthcare team performance.
|
| 755 |
Set higher values for areas you want to prioritize in the assessment.
|
| 756 |
---
|
| 757 |
""")
|
|
@@ -798,61 +841,61 @@ with gr.Blocks(title="Healthcare Team Assessment Tool", theme=gr.themes.Soft())
|
|
| 798 |
)
|
| 799 |
|
| 800 |
gr.Markdown("### Evaluation Parameters")
|
| 801 |
-
gr.Markdown("**Set the importance (0-10) for each assessment area:**")
|
| 802 |
|
| 803 |
-
# Add the 5 parameter sliders
|
| 804 |
param1_slider = gr.Slider(
|
| 805 |
minimum=0,
|
| 806 |
maximum=10,
|
| 807 |
value=8,
|
| 808 |
step=1,
|
| 809 |
-
label="
|
| 810 |
-
info="
|
| 811 |
)
|
| 812 |
|
| 813 |
param2_slider = gr.Slider(
|
| 814 |
minimum=0,
|
| 815 |
maximum=10,
|
| 816 |
-
value=
|
| 817 |
step=1,
|
| 818 |
-
label="
|
| 819 |
-
info="
|
| 820 |
)
|
| 821 |
|
| 822 |
param3_slider = gr.Slider(
|
| 823 |
minimum=0,
|
| 824 |
maximum=10,
|
| 825 |
-
value=
|
| 826 |
step=1,
|
| 827 |
-
label="
|
| 828 |
-
info="
|
| 829 |
)
|
| 830 |
|
| 831 |
param4_slider = gr.Slider(
|
| 832 |
minimum=0,
|
| 833 |
maximum=10,
|
| 834 |
-
value=
|
| 835 |
step=1,
|
| 836 |
-
label="
|
| 837 |
-
info="
|
| 838 |
)
|
| 839 |
|
| 840 |
param5_slider = gr.Slider(
|
| 841 |
minimum=0,
|
| 842 |
maximum=10,
|
| 843 |
-
value=
|
| 844 |
step=1,
|
| 845 |
-
label="
|
| 846 |
-
info="
|
| 847 |
)
|
| 848 |
|
| 849 |
gr.Markdown("""
|
| 850 |
### Instructions:
|
| 851 |
-
1. **Set your evaluation parameters** (higher = more important)
|
| 852 |
-
2. **Select video resolution** (lower = faster)
|
| 853 |
-
3. **Upload** or **Record**
|
| 854 |
4. Click **Analyze Video** to start assessment
|
| 855 |
-
5. Review results weighted by your priorities
|
| 856 |
""")
|
| 857 |
|
| 858 |
with gr.Column(scale=2):
|
|
@@ -893,18 +936,23 @@ with gr.Blocks(title="Healthcare Team Assessment Tool", theme=gr.themes.Soft())
|
|
| 893 |
# Footer
|
| 894 |
gr.Markdown("""
|
| 895 |
---
|
| 896 |
-
### About
|
| 897 |
-
This tool uses Google's Gemini AI to evaluate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 898 |
|
| 899 |
-
**
|
| 900 |
-
-
|
| 901 |
-
-
|
| 902 |
-
-
|
| 903 |
-
-
|
| 904 |
|
| 905 |
-
|
| 906 |
-
focuses on what matters most to your training objectives.
|
| 907 |
-
**Powered by Google Gemini 2.0 Flash | ZeroGPU on HuggingFace Spaces**
|
| 908 |
""")
|
| 909 |
|
| 910 |
# Auto-save video when recording stops
|
|
|
|
| 93 |
except Exception as e:
|
| 94 |
return f"Error during analysis: {str(e)}", param1, param2, param3, param4, param5
|
| 95 |
|
| 96 |
+
def build_assessment_prompt(self, history_taking_weight, communication_weight, clinical_reasoning_weight, physical_exam_weight, professionalism_weight):
|
| 97 |
+
"""Build a dynamic prompt based on user-selected parameters for Standardized Patient encounters"""
|
| 98 |
|
| 99 |
# Normalize weights
|
| 100 |
+
total_weight = history_taking_weight + communication_weight + clinical_reasoning_weight + physical_exam_weight + professionalism_weight
|
| 101 |
if total_weight == 0:
|
| 102 |
total_weight = 1 # Avoid division by zero
|
| 103 |
|
| 104 |
+
hist_pct = (history_taking_weight / total_weight) * 100
|
| 105 |
comm_pct = (communication_weight / total_weight) * 100
|
| 106 |
+
clinical_pct = (clinical_reasoning_weight / total_weight) * 100
|
| 107 |
+
physical_pct = (physical_exam_weight / total_weight) * 100
|
| 108 |
+
prof_pct = (professionalism_weight / total_weight) * 100
|
|
|
|
| 109 |
|
| 110 |
+
prompt = f"""Analyze this Standardized Patient (SP) clinical encounter video with the following CUSTOMIZED EVALUATION PARAMETERS:
|
| 111 |
+
|
| 112 |
+
This is an OSCE-style (Objective Structured Clinical Examination) assessment of a healthcare provider/student interacting with a standardized patient in a simulated clinical setting.
|
| 113 |
+
|
| 114 |
EVALUATION WEIGHTS (Total 100%):
|
| 115 |
+
1. HISTORY TAKING & INTERVIEW SKILLS: {hist_pct:.1f}% weight
|
| 116 |
+
2. COMMUNICATION & RAPPORT: {comm_pct:.1f}% weight
|
| 117 |
+
3. CLINICAL REASONING & ASSESSMENT: {clinical_pct:.1f}% weight
|
| 118 |
+
4. PHYSICAL EXAMINATION TECHNIQUE: {physical_pct:.1f}% weight
|
| 119 |
+
5. PROFESSIONALISM & EMPATHY: {prof_pct:.1f}% weight
|
| 120 |
+
|
| 121 |
+
Please evaluate the clinical encounter based on these weighted priorities:
|
| 122 |
"""
|
| 123 |
|
| 124 |
# Add detailed criteria based on weights
|
| 125 |
criteria_sections = []
|
| 126 |
|
| 127 |
+
if history_taking_weight > 0:
|
| 128 |
criteria_sections.append(f"""
|
| 129 |
+
## HISTORY TAKING & INTERVIEW SKILLS (Weight: {history_taking_weight}/10)
|
| 130 |
Evaluate:
|
| 131 |
+
- Chief complaint identification and exploration
|
| 132 |
+
- History of Present Illness (HPI) - OLDCARTS/OPQRST methodology
|
| 133 |
+
- Past Medical History (PMH) inquiry
|
| 134 |
+
- Medication and allergy review
|
| 135 |
+
- Family and social history assessment
|
| 136 |
+
- Review of Systems (ROS) completeness
|
| 137 |
+
- Open-ended vs. closed-ended question balance
|
| 138 |
+
- Logical flow and organization of questioning
|
| 139 |
+
- Avoidance of leading questions
|
| 140 |
+
- Appropriate follow-up questions based on responses
|
| 141 |
""")
|
| 142 |
|
| 143 |
+
if communication_weight > 0:
|
| 144 |
criteria_sections.append(f"""
|
| 145 |
+
## COMMUNICATION & RAPPORT (Weight: {communication_weight}/10)
|
| 146 |
Evaluate:
|
| 147 |
+
- Introduction and identification (name, role, purpose)
|
| 148 |
+
- Active listening behaviors (eye contact, nodding, verbal acknowledgment)
|
| 149 |
+
- Use of patient-friendly language (avoiding medical jargon)
|
| 150 |
+
- Clarification and summarization of patient statements
|
| 151 |
+
- Appropriate pacing and allowing patient to speak
|
| 152 |
+
- Non-verbal communication (body posture, positioning)
|
| 153 |
+
- Addressing patient concerns and questions
|
| 154 |
+
- Clear explanations of procedures or next steps
|
| 155 |
+
- Checking for patient understanding (teach-back)
|
| 156 |
+
- Closure and summary of encounter
|
| 157 |
""")
|
| 158 |
|
| 159 |
+
if clinical_reasoning_weight > 0:
|
| 160 |
criteria_sections.append(f"""
|
| 161 |
+
## CLINICAL REASONING & ASSESSMENT (Weight: {clinical_reasoning_weight}/10)
|
| 162 |
Evaluate:
|
| 163 |
+
- Differential diagnosis consideration
|
| 164 |
+
- Recognition of red flag symptoms
|
| 165 |
+
- Appropriate diagnostic questioning
|
| 166 |
+
- Integration of history findings
|
| 167 |
+
- Clinical decision-making process
|
| 168 |
+
- Prioritization of problems
|
| 169 |
+
- Evidence of systematic thinking
|
| 170 |
+
- Appropriate use of clinical frameworks
|
| 171 |
+
- Recognition of urgent vs. non-urgent conditions
|
| 172 |
+
- Formulation of assessment and plan
|
| 173 |
""")
|
| 174 |
|
| 175 |
+
if physical_exam_weight > 0:
|
| 176 |
criteria_sections.append(f"""
|
| 177 |
+
## PHYSICAL EXAMINATION TECHNIQUE (Weight: {physical_exam_weight}/10)
|
| 178 |
Evaluate:
|
| 179 |
+
- Appropriate hand hygiene and infection control
|
| 180 |
+
- Patient positioning and draping for dignity
|
| 181 |
+
- Systematic examination approach
|
| 182 |
+
- Correct technique for examination maneuvers
|
| 183 |
+
- Appropriate use of equipment (stethoscope, etc.)
|
| 184 |
+
- Explanation of examination steps to patient
|
| 185 |
+
- Patient comfort during examination
|
| 186 |
+
- Vital signs assessment
|
| 187 |
+
- Focused vs. comprehensive exam appropriateness
|
| 188 |
+
- Documentation of findings verbally or noted
|
| 189 |
""")
|
| 190 |
|
| 191 |
+
if professionalism_weight > 0:
|
| 192 |
criteria_sections.append(f"""
|
| 193 |
+
## PROFESSIONALISM & EMPATHY (Weight: {professionalism_weight}/10)
|
| 194 |
Evaluate:
|
| 195 |
+
- Respect for patient dignity and privacy
|
| 196 |
+
- Empathetic responses to patient emotions
|
| 197 |
+
- Cultural sensitivity and awareness
|
| 198 |
+
- Appropriate professional boundaries
|
| 199 |
+
- Honesty and transparency
|
| 200 |
+
- Patient-centered approach
|
| 201 |
+
- Confidentiality awareness
|
| 202 |
+
- Appropriate attire and presentation
|
| 203 |
+
- Time management within encounter
|
| 204 |
+
- Ethical behavior and decision-making
|
| 205 |
""")
|
| 206 |
|
| 207 |
prompt += "".join(criteria_sections)
|
| 208 |
|
| 209 |
prompt += f"""
|
| 210 |
+
|
| 211 |
STRUCTURE YOUR RESPONSE AS FOLLOWS:
|
| 212 |
+
|
| 213 |
## OVERALL WEIGHTED ASSESSMENT
|
| 214 |
+
Provide an overall assessment summary based on the weighted parameters above, highlighting the key observations from this standardized patient encounter.
|
| 215 |
+
|
| 216 |
## DETAILED EVALUATION BY PARAMETER
|
| 217 |
For each parameter with weight > 0, provide:
|
| 218 |
- Parameter Name: [Name]
|
| 219 |
- Weight: [X/10]
|
| 220 |
- Score: [X/10]
|
| 221 |
+
- Specific Observations: [What was observed in the encounter]
|
| 222 |
+
- Strengths: [What was done well]
|
| 223 |
+
- Areas for Improvement: [Specific recommendations]
|
| 224 |
+
|
| 225 |
## KEY STRENGTHS
|
| 226 |
+
Top 3-5 strengths observed in this clinical encounter (prioritize based on weighted parameters)
|
| 227 |
+
|
| 228 |
## CRITICAL IMPROVEMENTS NEEDED
|
| 229 |
+
Top 3-5 areas needing improvement for future SP encounters (prioritize based on weighted parameters)
|
| 230 |
+
|
| 231 |
## WEIGHTED FINAL SCORE
|
| 232 |
Calculate the weighted average score:
|
| 233 |
+
- History Taking: {history_taking_weight}/10 weight × [score]/10
|
| 234 |
- Communication: {communication_weight}/10 weight × [score]/10
|
| 235 |
+
- Clinical Reasoning: {clinical_reasoning_weight}/10 weight × [score]/10
|
| 236 |
+
- Physical Examination: {physical_exam_weight}/10 weight × [score]/10
|
| 237 |
+
- Professionalism: {professionalism_weight}/10 weight × [score]/10
|
| 238 |
+
|
| 239 |
TOTAL WEIGHTED SCORE: [X]/10
|
| 240 |
Performance Level: [Exemplary (8.5-10)/Proficient (7-8.4)/Developing (5-6.9)/Needs Improvement (0-4.9)]
|
| 241 |
+
OSCE Station Result: [Pass/Borderline/Fail based on score]
|
| 242 |
+
|
| 243 |
## AUDIO SUMMARY
|
| 244 |
+
[Create a 60-second spoken summary focusing on: the overall weighted score, top strengths demonstrated in this SP encounter, critical improvements needed for future clinical encounters, and 2-3 actionable recommendations for the learner. Write in natural, conversational tone suitable for text-to-speech feedback.]
|
| 245 |
"""
|
| 246 |
|
| 247 |
return prompt
|
|
|
|
| 406 |
)
|
| 407 |
|
| 408 |
# Add title
|
| 409 |
+
elements.append(Paragraph("Standardized Patient Encounter Assessment Report", title_style))
|
| 410 |
+
elements.append(Paragraph("(OSCE-Style Clinical Skills Evaluation)", body_style))
|
| 411 |
elements.append(Spacer(1, 12))
|
| 412 |
|
| 413 |
# Add timestamp
|
|
|
|
| 416 |
elements.append(Spacer(1, 20))
|
| 417 |
|
| 418 |
# Add parameter settings
|
| 419 |
+
elements.append(Paragraph("<b>OSCE Evaluation Parameters Used:</b>", heading_style))
|
| 420 |
+
elements.append(Paragraph(f"History Taking and Interview Skills: {param1}/10", body_style))
|
| 421 |
+
elements.append(Paragraph(f"Communication and Rapport: {param2}/10", body_style))
|
| 422 |
+
elements.append(Paragraph(f"Clinical Reasoning and Assessment: {param3}/10", body_style))
|
| 423 |
+
elements.append(Paragraph(f"Physical Examination Technique: {param4}/10", body_style))
|
| 424 |
+
elements.append(Paragraph(f"Professionalism and Empathy: {param5}/10", body_style))
|
| 425 |
elements.append(Spacer(1, 20))
|
| 426 |
|
| 427 |
# Process the assessment text into PDF-friendly format
|
|
|
|
| 455 |
print(f"PDF generation failed: {str(e)}")
|
| 456 |
# Fallback to text file
|
| 457 |
temp_txt = tempfile.NamedTemporaryFile(delete=False, suffix='.txt', mode='w')
|
| 458 |
+
temp_txt.write("Standardized Patient Encounter Assessment Report\n")
|
| 459 |
+
temp_txt.write("(OSCE-Style Clinical Skills Evaluation)\n")
|
| 460 |
temp_txt.write("="*60 + "\n")
|
| 461 |
temp_txt.write(f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
| 462 |
temp_txt.write("="*60 + "\n\n")
|
| 463 |
+
temp_txt.write(f"Parameters: History Taking={param1}, Communication={param2}, Clinical Reasoning={param3}, Physical Exam={param4}, Professionalism={param5}\n\n")
|
| 464 |
temp_txt.write(assessment_text)
|
| 465 |
temp_txt.close()
|
| 466 |
return temp_txt.name
|
|
|
|
| 664 |
print(f"Resized video: {new_file_size_mb:.1f}MB (saved {file_size_mb - new_file_size_mb:.1f}MB)")
|
| 665 |
|
| 666 |
# Start assessment with parameters
|
| 667 |
+
print(f"Starting Standardized Patient Encounter Assessment...")
|
| 668 |
+
print(f"Parameters: History Taking={param1}, Communication={param2}, Clinical Reasoning={param3}, Physical Exam={param4}, Professionalism={param5}")
|
| 669 |
|
| 670 |
assessment_result, p1, p2, p3, p4, p5 = assessor.analyze_video(video_to_process, param1, param2, param3, param4, param5)
|
| 671 |
|
|
|
|
| 696 |
# Create enhanced visual summary HTML with parameter information
|
| 697 |
summary_html = f"""
|
| 698 |
<div style="max-width:800px; margin:20px auto; padding:30px; border-radius:15px; box-shadow:0 2px 10px rgba(0,0,0,0.08); background:white;">
|
| 699 |
+
<h2 style="text-align:center; color:#111827; margin-bottom:30px; font-weight:600;">Standardized Patient Assessment Summary</h2>
|
| 700 |
|
| 701 |
<div style="background:#F0F9FF; padding:20px; border-radius:10px; margin-bottom:30px; border:1px solid #BAE6FD;">
|
| 702 |
<h3 style="color:#0369A1; margin-top:0; margin-bottom:15px; font-weight:600;">Overall Weighted Assessment</h3>
|
|
|
|
| 706 |
<div style="display:flex; justify-content:space-around; margin:30px 0;">
|
| 707 |
<div style="text-align:center;">
|
| 708 |
<div style="font-size:48px; font-weight:bold; color:{color};">{weighted_score:.1f}/10</div>
|
| 709 |
+
<div style="color:#4B5563; margin-top:10px; font-weight:500;">OSCE Score</div>
|
| 710 |
</div>
|
| 711 |
<div style="text-align:center;">
|
| 712 |
<div style="font-size:48px; font-weight:bold; color:{color};">{percentage:.0f}%</div>
|
|
|
|
| 717 |
<div style="font-size:24px; font-weight:bold; color:{color};">Performance Level: {level}</div>
|
| 718 |
</div>
|
| 719 |
<div style="margin-top:30px;">
|
| 720 |
+
<h3 style="color:#111827; margin-bottom:20px; font-weight:600;">Your OSCE Evaluation Parameters:</h3>
|
| 721 |
<div style="background:#F8FAFC; padding:20px; border-radius:10px; border:1px solid #E2E8F0;">
|
| 722 |
<div style="display:flex; justify-content:space-between; margin:10px 0;">
|
| 723 |
+
<span style="color:#374151; font-weight:500;">History Taking & Interview:</span>
|
| 724 |
<span style="color:#111827; font-weight:bold;">{param1}/10</span>
|
| 725 |
</div>
|
| 726 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
|
|
| 728 |
</div>
|
| 729 |
|
| 730 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 731 |
+
<span style="color:#374151; font-weight:500;">Communication & Rapport:</span>
|
| 732 |
<span style="color:#111827; font-weight:bold;">{param2}/10</span>
|
| 733 |
</div>
|
| 734 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
|
|
| 736 |
</div>
|
| 737 |
|
| 738 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 739 |
+
<span style="color:#374151; font-weight:500;">Clinical Reasoning:</span>
|
| 740 |
<span style="color:#111827; font-weight:bold;">{param3}/10</span>
|
| 741 |
</div>
|
| 742 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
|
|
| 744 |
</div>
|
| 745 |
|
| 746 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 747 |
+
<span style="color:#374151; font-weight:500;">Physical Examination:</span>
|
| 748 |
<span style="color:#111827; font-weight:bold;">{param4}/10</span>
|
| 749 |
</div>
|
| 750 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
|
|
|
| 752 |
</div>
|
| 753 |
|
| 754 |
<div style="display:flex; justify-content:space-between; margin:10px 0; margin-top:20px;">
|
| 755 |
+
<span style="color:#374151; font-weight:500;">Professionalism & Empathy:</span>
|
| 756 |
<span style="color:#111827; font-weight:bold;">{param5}/10</span>
|
| 757 |
</div>
|
| 758 |
<div style="height:8px; background:#E5E7EB; border-radius:4px; margin:5px 0;">
|
| 759 |
+
<div style="height:100%; background:#8B5CF6; border-radius:4px; width:{param5*10}%;"></div>
|
| 760 |
</div>
|
| 761 |
</div>
|
| 762 |
</div>
|
| 763 |
<div style="margin-top:30px; padding:20px; background:#FFF7ED; border-radius:10px; border-left:4px solid #EA580C;">
|
| 764 |
<p style="text-align:center; color:#431407; margin:0; font-weight:600;">
|
| 765 |
Listen to the 1-minute audio summary for key findings<br>
|
| 766 |
+
Download the PDF report for complete OSCE documentation
|
| 767 |
</p>
|
| 768 |
</div>
|
| 769 |
</div>
|
|
|
|
| 782 |
return process_video_with_gpu(video, resize_option, param1, param2, param3, param4, param5)
|
| 783 |
|
| 784 |
# Create and launch the Gradio interface with parameter controls
|
| 785 |
+
print("Launching Standardized Patient Assessment Tool...")
|
| 786 |
|
| 787 |
+
with gr.Blocks(title="Standardized Patient Assessment Tool", theme=gr.themes.Soft()) as demo:
|
| 788 |
|
| 789 |
gr.Markdown("""
|
| 790 |
+
# Standardized Patient Encounter Assessment Tool
|
| 791 |
+
|
| 792 |
+
**OSCE-Style Clinical Skills Evaluation with Customizable Parameters**
|
| 793 |
+
|
| 794 |
+
This tool analyzes Standardized Patient (SP) encounter videos and evaluates clinical competencies
|
| 795 |
+
based on your prioritized assessment criteria. Perfect for medical education, nursing programs,
|
| 796 |
+
and healthcare professional training.
|
| 797 |
|
|
|
|
|
|
|
| 798 |
Set higher values for areas you want to prioritize in the assessment.
|
| 799 |
---
|
| 800 |
""")
|
|
|
|
| 841 |
)
|
| 842 |
|
| 843 |
gr.Markdown("### Evaluation Parameters")
|
| 844 |
+
gr.Markdown("**Set the importance (0-10) for each OSCE assessment area:**")
|
| 845 |
|
| 846 |
+
# Add the 5 parameter sliders for SP encounters
|
| 847 |
param1_slider = gr.Slider(
|
| 848 |
minimum=0,
|
| 849 |
maximum=10,
|
| 850 |
value=8,
|
| 851 |
step=1,
|
| 852 |
+
label="History Taking & Interview Skills",
|
| 853 |
+
info="HPI, PMH, medications, allergies, social history, ROS, questioning technique"
|
| 854 |
)
|
| 855 |
|
| 856 |
param2_slider = gr.Slider(
|
| 857 |
minimum=0,
|
| 858 |
maximum=10,
|
| 859 |
+
value=9,
|
| 860 |
step=1,
|
| 861 |
+
label="Communication & Rapport",
|
| 862 |
+
info="Introduction, active listening, patient-friendly language, non-verbal cues"
|
| 863 |
)
|
| 864 |
|
| 865 |
param3_slider = gr.Slider(
|
| 866 |
minimum=0,
|
| 867 |
maximum=10,
|
| 868 |
+
value=7,
|
| 869 |
step=1,
|
| 870 |
+
label="Clinical Reasoning & Assessment",
|
| 871 |
+
info="Differential diagnosis, red flags, diagnostic thinking, clinical frameworks"
|
| 872 |
)
|
| 873 |
|
| 874 |
param4_slider = gr.Slider(
|
| 875 |
minimum=0,
|
| 876 |
maximum=10,
|
| 877 |
+
value=6,
|
| 878 |
step=1,
|
| 879 |
+
label="Physical Examination Technique",
|
| 880 |
+
info="Hand hygiene, systematic approach, correct technique, patient comfort"
|
| 881 |
)
|
| 882 |
|
| 883 |
param5_slider = gr.Slider(
|
| 884 |
minimum=0,
|
| 885 |
maximum=10,
|
| 886 |
+
value=8,
|
| 887 |
step=1,
|
| 888 |
+
label="Professionalism & Empathy",
|
| 889 |
+
info="Patient dignity, empathetic responses, cultural sensitivity, ethics"
|
| 890 |
)
|
| 891 |
|
| 892 |
gr.Markdown("""
|
| 893 |
### Instructions:
|
| 894 |
+
1. **Set your OSCE evaluation parameters** (higher = more important)
|
| 895 |
+
2. **Select video resolution** (lower = faster processing)
|
| 896 |
+
3. **Upload** a recorded SP encounter or **Record** live
|
| 897 |
4. Click **Analyze Video** to start assessment
|
| 898 |
+
5. Review OSCE-style results weighted by your priorities
|
| 899 |
""")
|
| 900 |
|
| 901 |
with gr.Column(scale=2):
|
|
|
|
| 936 |
# Footer
|
| 937 |
gr.Markdown("""
|
| 938 |
---
|
| 939 |
+
### About Standardized Patient Assessment
|
| 940 |
+
This tool uses Google's Gemini AI to evaluate clinical encounters based on OSCE-style criteria.
|
| 941 |
+
|
| 942 |
+
**Evaluation Parameters:**
|
| 943 |
+
- **History Taking (8-10)**: Essential for diagnostic encounters
|
| 944 |
+
- **Communication (8-10)**: Critical for all patient interactions
|
| 945 |
+
- **Clinical Reasoning (6-8)**: Important for diagnostic scenarios
|
| 946 |
+
- **Physical Exam (4-7)**: Weight based on encounter type
|
| 947 |
+
- **Professionalism (7-9)**: Always important in clinical settings
|
| 948 |
|
| 949 |
+
**OSCE Scoring:**
|
| 950 |
+
- Exemplary (8.5-10): Exceeds expectations - Clear Pass
|
| 951 |
+
- Proficient (7-8.4): Meets expectations - Pass
|
| 952 |
+
- Developing (5-6.9): Borderline performance - Borderline Pass
|
| 953 |
+
- Needs Improvement (0-4.9): Below expectations - Fail
|
| 954 |
|
| 955 |
+
**Powered by Google Gemini 2.0 Flash | Designed for Medical Education**
|
|
|
|
|
|
|
| 956 |
""")
|
| 957 |
|
| 958 |
# Auto-save video when recording stops
|