Spaces:
Paused
Paused
Enhanced golf swing analysis system with professional benchmarks and UI improvements
Browse filesMajor updates:
- Updated coach_prompt.md with 7 LPGA professional swing analyses (Lydia Ko, Nelly Korda, Park Sunghyun, Minjee Lee, Hyoo Joo Kim, Nasa Hataoka)
- Added comprehensive amateur swing issues reference and calibration data
- Implemented automatic AI-generated overall swing summary at top of analysis
- Fixed critical knee flexion calculation bug in llm_analyzer.py (vector calculation error)
- Enhanced UI with subtle developer tools and improved Step 1 video upload tips
- Added professional standards calibration ranges (25-35° back tilt, 16-28° knee flexion)
- Streamlined analysis display with overall summary above metric cards
- app/models/coach_prompt.md +230 -102
- app/models/llm_analyzer.py +35 -10
- app/streamlit_app.py +99 -54
app/models/coach_prompt.md
CHANGED
|
@@ -1,101 +1,224 @@
|
|
| 1 |
# Golf Swing Analysis
|
| 2 |
|
| 3 |
## PROFESSIONAL BENCHMARKS FOR CALIBRATION
|
| 4 |
-
Use these professional standards as your 100% reference for scoring. These represent elite-level golf swing mechanics based on actual
|
| 5 |
|
| 6 |
### Professional Golfer Analysis Summary (100% Reference Standards):
|
| 7 |
|
| 8 |
-
**
|
| 9 |
-
-
|
| 10 |
-
-
|
| 11 |
-
-
|
| 12 |
-
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
-
|
| 24 |
-
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
-
|
| 28 |
-
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
-
|
| 38 |
-
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
-
|
| 52 |
-
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
-
|
| 56 |
-
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
-
|
| 62 |
-
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
### **AMATEUR REFERENCE EXAMPLES FOR CALIBRATION:**
|
| 66 |
|
| 67 |
-
**
|
| 68 |
-
|
| 69 |
-
-
|
| 70 |
-
-
|
| 71 |
-
|
| 72 |
-
-
|
| 73 |
-
-
|
| 74 |
-
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
## CURRENT SWING ANALYSIS
|
| 101 |
|
|
@@ -110,6 +233,8 @@ Use these professional standards as your 100% reference for scoring. These repre
|
|
| 110 |
**GOLF SWING ANALYSIS FORMAT**
|
| 111 |
Use the benchmarks above to guide your evaluation. Follow this exact format:
|
| 112 |
|
|
|
|
|
|
|
| 113 |
**PERFORMANCE_CLASSIFICATION:** [XX%]
|
| 114 |
(XX = number from 10% to 100%)
|
| 115 |
|
|
@@ -120,7 +245,7 @@ For each of the 5 DTL-reliable core metrics below, write exactly 3 sentences eva
|
|
| 120 |
2. Second sentence: Compare the specific value to professional ranges
|
| 121 |
3. Third sentence: Brief explanation of impact on swing performance
|
| 122 |
|
| 123 |
-
**1. Shaft
|
| 124 |
[3 sentences about club shaft position relative to target line at top]
|
| 125 |
|
| 126 |
**2. Head Sway Evaluation:**
|
|
@@ -129,7 +254,7 @@ For each of the 5 DTL-reliable core metrics below, write exactly 3 sentences eva
|
|
| 129 |
**3. Back Tilt @ Setup Evaluation:**
|
| 130 |
[3 sentences about spine forward tilt angle during setup position]
|
| 131 |
|
| 132 |
-
**4. Knee
|
| 133 |
[3 sentences about knee flexion angle during setup position]
|
| 134 |
|
| 135 |
**5. Wrist Pattern Evaluation:**
|
|
@@ -137,13 +262,13 @@ For each of the 5 DTL-reliable core metrics below, write exactly 3 sentences eva
|
|
| 137 |
|
| 138 |
**SCORING GUIDELINES (Use to help decide % score)**
|
| 139 |
|
| 140 |
-
| Metric | Professional Standard | Note |
|
| 141 |
-
|
| 142 |
-
| Shaft Angle @ Top |
|
| 143 |
-
| Head Sway | <15% shoulder width | Stable head during swing |
|
| 144 |
-
| Back Tilt @ Setup |
|
| 145 |
-
| Knee
|
| 146 |
-
| Wrist Pattern |
|
| 147 |
|
| 148 |
**Classification Bands:**
|
| 149 |
- **90–100%**: Tour-level
|
|
@@ -155,12 +280,15 @@ For each of the 5 DTL-reliable core metrics below, write exactly 3 sentences eva
|
|
| 155 |
- **10–39%**: Novice
|
| 156 |
|
| 157 |
**STYLE & FORMATTING RULES:**
|
| 158 |
-
- Use these headers: PERFORMANCE_CLASSIFICATION, Metric Evaluations, and the 5 numbered metric sections
|
| 159 |
-
- No emojis anywhere in the response
|
|
|
|
| 160 |
- Write exactly 3 sentences for each metric evaluation
|
| 161 |
-
- Tie all evaluations to professional standards and ranges
|
| 162 |
- Use a positive, coaching tone throughout
|
| 163 |
- Avoid saying "perfect" — say "strong" or "meets standards"
|
| 164 |
-
- Focus on biomechanics and compare actual values to
|
|
|
|
|
|
|
| 165 |
|
| 166 |
|
|
|
|
| 1 |
# Golf Swing Analysis
|
| 2 |
|
| 3 |
## PROFESSIONAL BENCHMARKS FOR CALIBRATION
|
| 4 |
+
Use these professional standards as your 100% reference for scoring. These represent elite-level golf swing mechanics based on actual professional analysis:
|
| 5 |
|
| 6 |
### Professional Golfer Analysis Summary (100% Reference Standards):
|
| 7 |
|
| 8 |
+
**Lydia Ko Iron (LPGA Tour Professional):** https://www.youtube.com/shorts/ING2iZ3M8wg
|
| 9 |
+
- Shaft Plane @ Top: Slightly Laid-off — 🟢 Mild laid-off bias — Confidence ~75%
|
| 10 |
+
- Back Tilt @ Setup: 33.9° — 🟢 On-plane posture — Confidence ~85%
|
| 11 |
+
- Knee Flexion: 27.6° — 🟢 Athletic — Confidence ~60%
|
| 12 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 — Confidence ~75%
|
| 13 |
+
- Power Source: Hip-Led — 🟢 60% hip power
|
| 14 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% DTL-only
|
| 15 |
+
|
| 16 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 17 |
+
• Shaft Angle @ Top: -26.2° (status: needs_work)
|
| 18 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 19 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 20 |
+
• Shoulder Rotation @ Top: 45.0° (status: ok)
|
| 21 |
+
|
| 22 |
+
**Nelly Korda Iron (Pink):** https://www.youtube.com/shorts/GRzaXCNJq1o
|
| 23 |
+
- Shaft Plane @ Top: Neutral — 🟢 Good plane control
|
| 24 |
+
- Back Tilt @ Setup: 34.9° — 🟢 On-plane posture — Confidence ~85%
|
| 25 |
+
- Knee Flexion: 18.7° — 🟢 Athletic — Confidence ~60%
|
| 26 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 — Confidence ~75%
|
| 27 |
+
- Power Source: Hip-Led — 🟢 60% hip power
|
| 28 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% DTL-only
|
| 29 |
+
|
| 30 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 31 |
+
• Shaft Angle @ Top: None° (status: club_not_visible)
|
| 32 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 33 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 34 |
+
• Shoulder Rotation @ Top: 45.0° (status: ok)
|
| 35 |
+
|
| 36 |
+
**Nelly Korda Iron (Blue):** https://www.youtube.com/shorts/M1eaHdaSzh4
|
| 37 |
+
- Shaft Plane @ Top: Neutral — 🟢 Good plane control
|
| 38 |
+
- Back Tilt @ Setup: 31.2° — 🟢 On-plane posture — Confidence ~85%
|
| 39 |
+
- Knee Flexion: 16.4° — 🟢 Athletic — Confidence ~60%
|
| 40 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 — Confidence ~75%
|
| 41 |
+
- Power Source: Hip-Led — 🟢 60% hip power
|
| 42 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% DTL-only
|
| 43 |
+
|
| 44 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 45 |
+
• Shaft Angle @ Top: None° (status: club_not_visible)
|
| 46 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 47 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 48 |
+
• Shoulder Rotation @ Top: 45.0° (status: ok)
|
| 49 |
+
|
| 50 |
+
**Park Sunghyun Iron:** https://www.youtube.com/shorts/imtyz_n06gA
|
| 51 |
+
- Back Tilt @ Setup: 29.2° — 🟢 On-plane posture — Confidence ~90%
|
| 52 |
+
- Knee Flexion: 25.9° — 🟢 Athletic — Confidence ~90%
|
| 53 |
+
- Wrist Pattern: Inconsistent Pattern — 🟠 — Confidence ~75% approx.
|
| 54 |
+
💡 Tip: Work on consistent wrist angles.
|
| 55 |
+
- Kinematic Sequence (DTL-approx): Good Hip Turn — 🟢 Good hip rotation DTL-only
|
| 56 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% approx. DTL-only
|
| 57 |
+
|
| 58 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 59 |
+
• Shaft Angle @ Top: None° (status: Unavailable (club occluded))
|
| 60 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 61 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 62 |
+
• Shoulder Rotation @ Top: None° (status: DTL proxy only, low confidence)
|
| 63 |
+
|
| 64 |
+
**Minjee Lee Driver:** https://www.youtube.com/shorts/Ioo3VSiCUhs
|
| 65 |
+
- Back Tilt @ Setup: 27.6° — 🟠 Slightly out of range — Confidence ~90%
|
| 66 |
+
- Knee Flexion: 24.8° — 🟢 Athletic — Confidence ~90%
|
| 67 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 Needs work — Confidence ~75% approx.
|
| 68 |
+
- Kinematic Sequence (DTL-approx): Good Hip Turn — 🟢 Good hip rotation
|
| 69 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% approx. DTL-only
|
| 70 |
+
|
| 71 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 72 |
+
• Shaft Angle @ Top: None° (status: Unavailable (club occluded))
|
| 73 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 74 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 75 |
+
• Shoulder Rotation @ Top: None° (status: DTL proxy only, low confidence)
|
| 76 |
+
|
| 77 |
+
**Hyoo Joo Kim Iron:** https://www.youtube.com/watch?v=zDheOLEEmdU&t=7s
|
| 78 |
+
- Back Tilt @ Setup: 27.3° — 🟠 Slightly out of range — Confidence ~90%
|
| 79 |
+
- Knee Flexion: 26.8° — 🟢 Athletic — Confidence ~90%
|
| 80 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 Needs work — Confidence ~75% approx.
|
| 81 |
+
- Kinematic Sequence (DTL-approx): Good Hip Turn — 🟢 Good hip rotation
|
| 82 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% approx. DTL-only
|
| 83 |
+
|
| 84 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 85 |
+
• Shaft Angle @ Top: None° (status: target_line_error)
|
| 86 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 87 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 88 |
+
• Shoulder Rotation @ Top: None° (status: DTL proxy only, low confidence)
|
| 89 |
+
|
| 90 |
+
**Nasa Hataoka Iron:** https://www.youtube.com/shorts/sMqEwl1Tfus
|
| 91 |
+
- Back Tilt @ Setup: 25.3° — 🟠 Slightly out of range — Confidence ~90%
|
| 92 |
+
- Knee Flexion: 24.1° — 🟢 Athletic — Confidence ~90%
|
| 93 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 Needs work — Confidence ~75% approx.
|
| 94 |
+
- Kinematic Sequence (DTL-approx): Good Hip Turn — 🟢 Good hip rotation
|
| 95 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% approx. DTL-only
|
| 96 |
+
|
| 97 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 98 |
+
• Shaft Angle @ Top: None° (status: target_line_error)
|
| 99 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 100 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 101 |
+
• Shoulder Rotation @ Top: None° (status: DTL proxy only, low confidence)
|
| 102 |
|
| 103 |
### **AMATEUR REFERENCE EXAMPLES FOR CALIBRATION:**
|
| 104 |
|
| 105 |
+
**90% Amateur Swing:**
|
| 106 |
+
Known problems: Wrist casting during downswing/impact, lacks powerful hip rotation, possibly too much knee flex
|
| 107 |
+
- Shaft Plane @ Top: Neutral — 🟢 Good plane control — Confidence ~85%
|
| 108 |
+
- Back Tilt @ Setup: 69.4° — 🔴 Likely problematic — Confidence ~60% - detected wrong
|
| 109 |
+
💡 Tip: Typical tour range ≈30–40°.
|
| 110 |
+
- Knee Flexion: 26.0° — 🟢 Athletic — Confidence ~60%
|
| 111 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 — Confidence ~75%
|
| 112 |
+
- Power Source: Hip-Led — 🟢 60% hip power
|
| 113 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% DTL-only
|
| 114 |
+
|
| 115 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 116 |
+
• Shaft Angle @ Top: -6.8° (status: good)
|
| 117 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 118 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 119 |
+
• Shoulder Rotation @ Top: 45.0° (status: ok)
|
| 120 |
+
|
| 121 |
+
**40-50% Male Amateur Swing:**
|
| 122 |
+
Known problems: Standing up during impact, head movement severe, bent arms in follow through, inconsistent swing path and ball contact, wrong stance because the club is too short for his height, some wrist casting during impact
|
| 123 |
+
- Back Tilt @ Setup: 39.0° — 🟠 Slightly out of range — Confidence ~90%
|
| 124 |
+
- Knee Flexion: 39.4° — 🟠 Too bent — Confidence ~90%
|
| 125 |
+
- Wrist Pattern: Set-Hold-Release — Excellent — 🟢 Needs work — Confidence ~75% approx.
|
| 126 |
+
- Kinematic Sequence (DTL-approx): Good Hip Turn — 🟢 Good hip rotation
|
| 127 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% approx. DTL-only
|
| 128 |
+
|
| 129 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 130 |
+
• Shaft Angle @ Top: None° (status: target_line_error)
|
| 131 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 132 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 133 |
+
• Shoulder Rotation @ Top: None° (status: DTL proxy only, low confidence)
|
| 134 |
+
|
| 135 |
+
**40-50% Female Amateur Swing:**
|
| 136 |
+
Known problems: Hands keep going at the top of backswing when they should stop, wrist casting, hands leading downswing not hips, standing up during impact, head movement
|
| 137 |
+
- Knee Flexion: 33.8° — 🟠 Slightly too bent — Confidence ~90%
|
| 138 |
+
- Wrist Pattern: Inconsistent Pattern — 🟠 Needs work — Confidence ~75% approx.
|
| 139 |
+
💡 Tip: Work on consistent wrist angles.
|
| 140 |
+
- Kinematic Sequence (DTL-approx): Good Hip Turn — 🟢 Good hip rotation
|
| 141 |
+
- Shoulder Turn Quality: Excellent — 🟢 Complete shoulder rotation — Confidence ~70% approx. DTL-only
|
| 142 |
+
|
| 143 |
+
Raw values for qualitative assessments - for calibration purposes:
|
| 144 |
+
• Shaft Angle @ Top: None° (status: target_line_error)
|
| 145 |
+
• Hip Rotation @ Impact: None° (status: needs_face_on)
|
| 146 |
+
• X-Factor @ Top: None° (status: needs_face_on)
|
| 147 |
+
• Shoulder Rotation @ Top: None° (status: DTL proxy only, low confidence)
|
| 148 |
+
|
| 149 |
+
### **KEY AMATEUR SWING PROBLEMS FOR EVALUATION REFERENCE:**
|
| 150 |
+
**Common Issues in 40-50% Level Swings:**
|
| 151 |
+
- **Standing up during impact** (loss of posture maintenance)
|
| 152 |
+
- **Severe head movement** (stability and consistency issues)
|
| 153 |
+
- **Wrist casting** (early release, loss of lag)
|
| 154 |
+
- **Hands leading downswing instead of hips** (poor kinematic sequence)
|
| 155 |
+
- **Excessive knee flexion** (39.4° male, 33.8° female vs 16-28° professional range)
|
| 156 |
+
- **Back tilt out of professional range** (39.0° vs 25-35° professional range)
|
| 157 |
+
- **Inconsistent swing path and ball contact**
|
| 158 |
+
- **Equipment issues** (wrong club length affecting stance and mechanics)
|
| 159 |
+
- **Bent arms in follow through** (loss of extension and power)
|
| 160 |
+
- **Hands continuing at top when they should stop** (over-swing, timing issues)
|
| 161 |
+
|
| 162 |
+
**Evaluation Emphasis Points:**
|
| 163 |
+
- Knee flexion >35° should be flagged as problematic for power and stability
|
| 164 |
+
- Back tilt >35° indicates setup issues that affect entire swing
|
| 165 |
+
- Wrist casting patterns significantly impact ball striking and distance
|
| 166 |
+
- Head movement and standing up during impact are major consistency killers
|
| 167 |
+
- Poor kinematic sequence (hands before hips) reduces power generation
|
| 168 |
+
|
| 169 |
+
### **COMPREHENSIVE AMATEUR SWING ISSUES REFERENCE:**
|
| 170 |
+
|
| 171 |
+
**Swing Mechanics & Tempo Issues:**
|
| 172 |
+
1. **Over-Swinging:**
|
| 173 |
+
- Swinging with excessive force leads to loss of control and poor tempo
|
| 174 |
+
- Makes it harder to stay connected and achieve consistent contact
|
| 175 |
+
- Often results in loss of balance and timing
|
| 176 |
+
|
| 177 |
+
2. **Over-the-Top Swing Path:**
|
| 178 |
+
- Golfer starts downswing from the outside, causing club to swing across the ball
|
| 179 |
+
- Results in pulls, slices, and inconsistent ball striking
|
| 180 |
+
- Common in amateur swings due to improper sequencing
|
| 181 |
+
|
| 182 |
+
3. **Lack of Weight Transfer:**
|
| 183 |
+
- Not shifting weight from back foot to lead foot during downswing
|
| 184 |
+
- Reduces power generation and can cause inconsistent contact
|
| 185 |
+
- Often combined with poor hip rotation
|
| 186 |
+
|
| 187 |
+
4. **Poor Rotation & Early Extension:**
|
| 188 |
+
- Lack of proper body rotation through the swing
|
| 189 |
+
- Hips moving towards the ball during downswing (early extension)
|
| 190 |
+
- Leads to loss of posture and inconsistent strike patterns
|
| 191 |
+
|
| 192 |
+
5. **"Lifting" the Ball:**
|
| 193 |
+
- Attempting to lift the ball into the air rather than hitting down and through
|
| 194 |
+
- Common counter-intuitive mistake that leads to poor contact
|
| 195 |
+
- Results in topped shots and inconsistent ball flight
|
| 196 |
+
|
| 197 |
+
6. **Wrist Casting:**
|
| 198 |
+
- Early release of wrist hinge, reducing power and distance
|
| 199 |
+
- Loss of lag angle that professionals maintain
|
| 200 |
+
- Significantly impacts ball compression and distance
|
| 201 |
+
|
| 202 |
+
7. **Moving Head/Standing Up in Swing:**
|
| 203 |
+
- Loss of spine angle and posture during swing
|
| 204 |
+
- Creates inconsistent contact points
|
| 205 |
+
- Major factor in amateur swing inconsistency
|
| 206 |
+
|
| 207 |
+
**Impact on Evaluation:**
|
| 208 |
+
- Look for combinations of these issues in amateur swings
|
| 209 |
+
- Multiple issues often compound each other (e.g., over-swinging + early extension)
|
| 210 |
+
- Early extension and standing up are visible in DTL analysis as posture loss
|
| 211 |
+
- Weight transfer issues may manifest as poor hip rotation or kinematic sequence problems
|
| 212 |
+
- Over-the-top swing path affects shaft plane and swing consistency
|
| 213 |
+
|
| 214 |
+
### **PROFESSIONAL STANDARDS CALIBRATION (100% Level):**
|
| 215 |
+
**Core Biomechanical Metrics (Based on 7 LPGA Tour Professionals):**
|
| 216 |
+
- **Back Tilt @ Setup**: 25-35° (Professional range: Nasa 25.3° to Nelly Blue 34.9°)
|
| 217 |
+
- **Knee Flexion**: 16-28° (Professional range: Nelly Blue 16.4° to Lydia Ko 27.6°)
|
| 218 |
+
- **Shaft Plane @ Top**: Neutral to slightly laid-off (Professional plane control when visible)
|
| 219 |
+
- **Wrist Pattern**: Set-Hold-Release sequence (Excellent timing and control across all professionals)
|
| 220 |
+
- **Power Source**: Hip-Led 60% hip power (Professional power generation standard)
|
| 221 |
+
- **Shoulder Turn Quality**: Excellent complete rotation (Consistent across all professionals)
|
| 222 |
|
| 223 |
## CURRENT SWING ANALYSIS
|
| 224 |
|
|
|
|
| 233 |
**GOLF SWING ANALYSIS FORMAT**
|
| 234 |
Use the benchmarks above to guide your evaluation. Follow this exact format:
|
| 235 |
|
| 236 |
+
**OVERALL_SUMMARY:** [1-2 sentences maximum providing a concise evaluation of the swing's overall quality and main strengths/areas for improvement]
|
| 237 |
+
|
| 238 |
**PERFORMANCE_CLASSIFICATION:** [XX%]
|
| 239 |
(XX = number from 10% to 100%)
|
| 240 |
|
|
|
|
| 245 |
2. Second sentence: Compare the specific value to professional ranges
|
| 246 |
3. Third sentence: Brief explanation of impact on swing performance
|
| 247 |
|
| 248 |
+
**1. Shaft Plane @ Top Evaluation:**
|
| 249 |
[3 sentences about club shaft position relative to target line at top]
|
| 250 |
|
| 251 |
**2. Head Sway Evaluation:**
|
|
|
|
| 254 |
**3. Back Tilt @ Setup Evaluation:**
|
| 255 |
[3 sentences about spine forward tilt angle during setup position]
|
| 256 |
|
| 257 |
+
**4. Knee Flexion @ Setup Evaluation:**
|
| 258 |
[3 sentences about knee flexion angle during setup position]
|
| 259 |
|
| 260 |
**5. Wrist Pattern Evaluation:**
|
|
|
|
| 262 |
|
| 263 |
**SCORING GUIDELINES (Use to help decide % score)**
|
| 264 |
|
| 265 |
+
| Metric | Professional Standard | Amateur Problem Indicators | Note |
|
| 266 |
+
|--------|----------------------|---------------------------|------|
|
| 267 |
+
| Shaft Angle @ Top | Neutral to slightly laid-off | N/A (often not visible) | Neutral (0°), slightly laid-off (-26°) acceptable |
|
| 268 |
+
| Head Sway | <15% shoulder width | Severe movement (40-50% level) | Stable head during swing |
|
| 269 |
+
| Back Tilt @ Setup | 25-35° | >35° problematic (39° seen in 40-50% level) | Forward spine tilt from vertical |
|
| 270 |
+
| Knee Flexion @ Setup | 16-28° | >35° problematic (33-39° seen in 40-50% level) | Athletic stance flexion |
|
| 271 |
+
| Wrist Pattern | Set-Hold-Release sequence | Casting, inconsistent patterns | Excellent timing and control, no early casting |
|
| 272 |
|
| 273 |
**Classification Bands:**
|
| 274 |
- **90–100%**: Tour-level
|
|
|
|
| 280 |
- **10–39%**: Novice
|
| 281 |
|
| 282 |
**STYLE & FORMATTING RULES:**
|
| 283 |
+
- Use these headers: OVERALL_SUMMARY, PERFORMANCE_CLASSIFICATION, Metric Evaluations, and the 5 numbered metric sections
|
| 284 |
+
- No emojis anywhere in the response
|
| 285 |
+
- Write 1-2 sentences maximum for the overall summary - be concise and highlight main strengths/improvement areas
|
| 286 |
- Write exactly 3 sentences for each metric evaluation
|
| 287 |
+
- Tie all evaluations to professional standards and ranges based on 7 LPGA Tour professionals (Lydia Ko, Nelly Korda, Park Sunghyun, Minjee Lee, Hyoo Joo Kim, Nasa Hataoka)
|
| 288 |
- Use a positive, coaching tone throughout
|
| 289 |
- Avoid saying "perfect" — say "strong" or "meets standards"
|
| 290 |
+
- Focus on biomechanics and compare actual values to professional ranges (25-35° back tilt, 16-28° knee flexion, etc.)
|
| 291 |
+
- Consider common amateur swing issues when evaluating: over-swinging, over-the-top path, lack of weight transfer, early extension, lifting the ball, wrist casting, head movement/standing up
|
| 292 |
+
- Look for combinations of swing problems that often compound each other in amateur golfers
|
| 293 |
|
| 294 |
|
app/models/llm_analyzer.py
CHANGED
|
@@ -1186,8 +1186,10 @@ def calculate_knee_bend_degree(pose_data, address_idx):
|
|
| 1186 |
knee_point = kp[25][:2]
|
| 1187 |
ankle_point = kp[27][:2]
|
| 1188 |
|
| 1189 |
-
# Calculate vectors
|
| 1190 |
-
|
|
|
|
|
|
|
| 1191 |
shin_vector = (ankle_point[0] - knee_point[0], ankle_point[1] - knee_point[1])
|
| 1192 |
|
| 1193 |
# Calculate angle between thigh and shin vectors
|
|
@@ -1201,19 +1203,23 @@ def calculate_knee_bend_degree(pose_data, address_idx):
|
|
| 1201 |
cos_angle = dot_product / (thigh_magnitude * shin_magnitude)
|
| 1202 |
cos_angle = max(-1.0, min(1.0, cos_angle)) # Clamp to valid range
|
| 1203 |
|
| 1204 |
-
# Calculate the angle
|
| 1205 |
-
# This
|
| 1206 |
angle_between_rad = math.acos(cos_angle)
|
| 1207 |
-
|
| 1208 |
|
| 1209 |
-
#
|
| 1210 |
-
# When
|
| 1211 |
-
|
| 1212 |
-
knee_flexion_deg = 180.0 - hip_knee_ankle_angle
|
| 1213 |
|
| 1214 |
# Ensure flexion is non-negative
|
| 1215 |
knee_flexion_deg = max(0.0, knee_flexion_deg)
|
| 1216 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1217 |
|
| 1218 |
return knee_flexion_deg
|
| 1219 |
|
|
@@ -1352,6 +1358,7 @@ def parse_and_format_analysis(raw_analysis):
|
|
| 1352 |
"""
|
| 1353 |
# Default structure
|
| 1354 |
formatted_analysis = {
|
|
|
|
| 1355 |
'classification': 50, # Default to 50%
|
| 1356 |
'metric_evaluations': {
|
| 1357 |
'shaft_angle': '',
|
|
@@ -1362,6 +1369,14 @@ def parse_and_format_analysis(raw_analysis):
|
|
| 1362 |
}
|
| 1363 |
}
|
| 1364 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1365 |
# Extract percentage classification using the new structured format
|
| 1366 |
classification_match = re.search(r'\*\*PERFORMANCE_CLASSIFICATION:\*\*\s*\[?(\d+)%?\]?', raw_analysis, re.IGNORECASE)
|
| 1367 |
if classification_match:
|
|
@@ -1577,7 +1592,7 @@ def display_formatted_analysis(analysis_data):
|
|
| 1577 |
|
| 1578 |
def display_formatted_analysis(analysis_data):
|
| 1579 |
"""
|
| 1580 |
-
Display the formatted analysis with individual metric evaluations
|
| 1581 |
|
| 1582 |
Args:
|
| 1583 |
analysis_data (dict): Structured analysis data from parse_and_format_analysis
|
|
@@ -1587,6 +1602,16 @@ def display_formatted_analysis(analysis_data):
|
|
| 1587 |
|
| 1588 |
st.markdown("---")
|
| 1589 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1590 |
# Display metric evaluations
|
| 1591 |
st.subheader("Individual Metric Evaluations")
|
| 1592 |
|
|
|
|
| 1186 |
knee_point = kp[25][:2]
|
| 1187 |
ankle_point = kp[27][:2]
|
| 1188 |
|
| 1189 |
+
# Calculate vectors from knee joint
|
| 1190 |
+
# Vector from knee to hip (thigh direction)
|
| 1191 |
+
thigh_vector = (hip_point[0] - knee_point[0], hip_point[1] - knee_point[1])
|
| 1192 |
+
# Vector from knee to ankle (shin direction)
|
| 1193 |
shin_vector = (ankle_point[0] - knee_point[0], ankle_point[1] - knee_point[1])
|
| 1194 |
|
| 1195 |
# Calculate angle between thigh and shin vectors
|
|
|
|
| 1203 |
cos_angle = dot_product / (thigh_magnitude * shin_magnitude)
|
| 1204 |
cos_angle = max(-1.0, min(1.0, cos_angle)) # Clamp to valid range
|
| 1205 |
|
| 1206 |
+
# Calculate the angle between the thigh and shin vectors
|
| 1207 |
+
# This gives us the internal angle at the knee joint
|
| 1208 |
angle_between_rad = math.acos(cos_angle)
|
| 1209 |
+
internal_knee_angle = math.degrees(angle_between_rad)
|
| 1210 |
|
| 1211 |
+
# For knee flexion: when the leg is straight, internal angle ≈ 180°, flexion ≈ 0°
|
| 1212 |
+
# When knee is bent, internal angle < 180°, so flexion = 180° - internal_angle
|
| 1213 |
+
knee_flexion_deg = 180.0 - internal_knee_angle
|
|
|
|
| 1214 |
|
| 1215 |
# Ensure flexion is non-negative
|
| 1216 |
knee_flexion_deg = max(0.0, knee_flexion_deg)
|
| 1217 |
|
| 1218 |
+
# Debug check: ensure we're returning the flexion angle, not the hip-knee-ankle angle
|
| 1219 |
+
# If we see large angles (>90°) being returned, there's likely a calculation error
|
| 1220 |
+
if knee_flexion_deg > 90.0:
|
| 1221 |
+
# This suggests we might be returning the wrong angle - return None for safety
|
| 1222 |
+
return None
|
| 1223 |
|
| 1224 |
return knee_flexion_deg
|
| 1225 |
|
|
|
|
| 1358 |
"""
|
| 1359 |
# Default structure
|
| 1360 |
formatted_analysis = {
|
| 1361 |
+
'overall_summary': '', # New field for overall summary
|
| 1362 |
'classification': 50, # Default to 50%
|
| 1363 |
'metric_evaluations': {
|
| 1364 |
'shaft_angle': '',
|
|
|
|
| 1369 |
}
|
| 1370 |
}
|
| 1371 |
|
| 1372 |
+
# Extract overall summary
|
| 1373 |
+
summary_match = re.search(r'\*\*OVERALL_SUMMARY:\*\*\s*(.*?)(?=\*\*PERFORMANCE_CLASSIFICATION|\*\*|$)', raw_analysis, re.IGNORECASE | re.DOTALL)
|
| 1374 |
+
if summary_match:
|
| 1375 |
+
summary_text = summary_match.group(1).strip()
|
| 1376 |
+
# Clean up the text and remove extra whitespace/newlines
|
| 1377 |
+
summary_clean = re.sub(r'\s+', ' ', summary_text).strip()
|
| 1378 |
+
formatted_analysis['overall_summary'] = summary_clean
|
| 1379 |
+
|
| 1380 |
# Extract percentage classification using the new structured format
|
| 1381 |
classification_match = re.search(r'\*\*PERFORMANCE_CLASSIFICATION:\*\*\s*\[?(\d+)%?\]?', raw_analysis, re.IGNORECASE)
|
| 1382 |
if classification_match:
|
|
|
|
| 1592 |
|
| 1593 |
def display_formatted_analysis(analysis_data):
|
| 1594 |
"""
|
| 1595 |
+
Display the formatted analysis with overall summary and individual metric evaluations
|
| 1596 |
|
| 1597 |
Args:
|
| 1598 |
analysis_data (dict): Structured analysis data from parse_and_format_analysis
|
|
|
|
| 1602 |
|
| 1603 |
st.markdown("---")
|
| 1604 |
|
| 1605 |
+
# Display overall summary at the top if available
|
| 1606 |
+
overall_summary = analysis_data.get('overall_summary', '')
|
| 1607 |
+
if overall_summary:
|
| 1608 |
+
st.markdown(f"""
|
| 1609 |
+
<div style='background-color: #e8f4fd; padding: 20px; border-radius: 10px; margin-bottom: 20px; border-left: 5px solid #1f77b4;'>
|
| 1610 |
+
<h3 style='color: #1f77b4; margin-top: 0; margin-bottom: 10px;'>🎯 Overall Swing Assessment</h3>
|
| 1611 |
+
<p style='margin: 0; line-height: 1.6; font-size: 16px; color: #2c3e50;'>{overall_summary}</p>
|
| 1612 |
+
</div>
|
| 1613 |
+
""", unsafe_allow_html=True)
|
| 1614 |
+
|
| 1615 |
# Display metric evaluations
|
| 1616 |
st.subheader("Individual Metric Evaluations")
|
| 1617 |
|
app/streamlit_app.py
CHANGED
|
@@ -306,12 +306,18 @@ def get_knee_flexion_grading(value, confidence):
|
|
| 306 |
if 15 <= value <= 30:
|
| 307 |
badge = "🟢"
|
| 308 |
label = "Athletic"
|
| 309 |
-
elif (12 <= value < 15)
|
| 310 |
badge = "🟠"
|
| 311 |
-
label = "Slightly
|
| 312 |
-
elif (
|
| 313 |
badge = "🟠"
|
| 314 |
-
label = "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
else:
|
| 316 |
badge = "🔴"
|
| 317 |
label = "Likely problematic"
|
|
@@ -364,7 +370,7 @@ def get_wrist_pattern_grading(pattern_data, confidence):
|
|
| 364 |
return {
|
| 365 |
'display_value': label,
|
| 366 |
'badge': badge,
|
| 367 |
-
'label': "", #
|
| 368 |
'confidence': confidence,
|
| 369 |
'tip': tip
|
| 370 |
}
|
|
@@ -1453,7 +1459,10 @@ def render_step_1():
|
|
| 1453 |
"""Step 1: Upload Swing Video"""
|
| 1454 |
st.markdown('<h2 style="color: #0B3B0B; font-family: Georgia, serif;">Step 1: Upload Your Video</h2>', unsafe_allow_html=True)
|
| 1455 |
|
| 1456 |
-
st.markdown("**Choose your input method below
|
|
|
|
|
|
|
|
|
|
| 1457 |
|
| 1458 |
col1, col2 = st.columns(2)
|
| 1459 |
|
|
@@ -1636,61 +1645,97 @@ def render_step_4():
|
|
| 1636 |
data['analysis_data']['core_metrics'] = core_metrics
|
| 1637 |
|
| 1638 |
|
| 1639 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1640 |
display_new_grading_scheme(core_metrics)
|
| 1641 |
|
| 1642 |
-
#
|
| 1643 |
-
|
| 1644 |
-
|
| 1645 |
-
|
| 1646 |
-
# Shaft angle raw value
|
| 1647 |
-
shaft_raw = core_metrics.get("shaft_angle_top", {}).get('value')
|
| 1648 |
-
shaft_status = core_metrics.get("shaft_angle_top", {}).get('status', 'n/a')
|
| 1649 |
-
st.write(f"• **Shaft Angle @ Top**: {shaft_raw}° (status: {shaft_status})")
|
| 1650 |
-
|
| 1651 |
-
# Hip rotation raw value
|
| 1652 |
-
hip_raw = core_metrics.get("hip_rotation_impact_deg", {}).get('value')
|
| 1653 |
-
hip_status = core_metrics.get("hip_rotation_impact_deg", {}).get('status', 'n/a')
|
| 1654 |
-
st.write(f"• **Hip Rotation @ Impact**: {hip_raw}° (status: {hip_status})")
|
| 1655 |
-
|
| 1656 |
-
# X-factor raw value (bonus)
|
| 1657 |
-
xfactor_raw = core_metrics.get("x_factor_top_deg", {}).get('value')
|
| 1658 |
-
xfactor_status = core_metrics.get("x_factor_top_deg", {}).get('status', 'n/a')
|
| 1659 |
-
st.write(f"• **X-Factor @ Top**: {xfactor_raw}° (status: {xfactor_status})")
|
| 1660 |
-
|
| 1661 |
-
# Shoulder rotation raw value
|
| 1662 |
-
shoulder_raw = core_metrics.get("shoulder_rotation_top_deg", {}).get('value')
|
| 1663 |
-
shoulder_status = core_metrics.get("shoulder_rotation_top_deg", {}).get('status', 'n/a')
|
| 1664 |
-
st.write(f"• **Shoulder Rotation @ Top**: {shoulder_raw}° (status: {shoulder_status})")
|
| 1665 |
-
|
| 1666 |
-
st.write("---")
|
| 1667 |
-
st.write("**Calibration Notes:**")
|
| 1668 |
-
st.write("- Use these raw numbers to adjust qualitative thresholds")
|
| 1669 |
-
st.write("- Shaft angle: Professional range ~±0-20°, >35° likely calibration error")
|
| 1670 |
-
st.write("- Hip rotation: 25°+ = High Hip Turn, 18-24° = Good Hip Turn, 12-17° = Moderate Hip Turn, 8-11° = Limited Hip Turn, <8° = Minimal Hip Turn")
|
| 1671 |
-
st.write("- X-Factor: Separation between shoulders and hips at top")
|
| 1672 |
-
st.write("- **Note**: DTL-only view shows kinematic sequence approximation, not actual power percentage distribution")
|
| 1673 |
-
st.write("- **Framework**: For accurate power source analysis, face-on view is required")
|
| 1674 |
|
| 1675 |
-
|
|
|
|
| 1676 |
|
| 1677 |
-
|
| 1678 |
-
|
| 1679 |
-
|
| 1680 |
-
|
| 1681 |
-
if 'prompt' in st.session_state.analysis_data:
|
| 1682 |
-
st.markdown("### 🤖 Original LLM Prompt")
|
| 1683 |
-
st.info("This is the exact prompt that was prepared for AI analysis:")
|
| 1684 |
|
| 1685 |
-
|
| 1686 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1687 |
|
| 1688 |
-
|
| 1689 |
-
|
| 1690 |
-
|
| 1691 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1692 |
else:
|
| 1693 |
-
st.error("No prompt data available.
|
| 1694 |
|
| 1695 |
else:
|
| 1696 |
st.error("No analysis data available. Please analyze a video first.")
|
|
|
|
| 306 |
if 15 <= value <= 30:
|
| 307 |
badge = "🟢"
|
| 308 |
label = "Athletic"
|
| 309 |
+
elif (12 <= value < 15):
|
| 310 |
badge = "🟠"
|
| 311 |
+
label = "Slightly too stiff"
|
| 312 |
+
elif (30 < value <= 35):
|
| 313 |
badge = "🟠"
|
| 314 |
+
label = "Slightly too bent"
|
| 315 |
+
elif (8 <= value < 12):
|
| 316 |
+
badge = "🟠"
|
| 317 |
+
label = "Too stiff"
|
| 318 |
+
elif (35 < value <= 40):
|
| 319 |
+
badge = "🟠"
|
| 320 |
+
label = "Too bent"
|
| 321 |
else:
|
| 322 |
badge = "🔴"
|
| 323 |
label = "Likely problematic"
|
|
|
|
| 370 |
return {
|
| 371 |
'display_value': label,
|
| 372 |
'badge': badge,
|
| 373 |
+
'label': "Needs work", # Add descriptive text after badge
|
| 374 |
'confidence': confidence,
|
| 375 |
'tip': tip
|
| 376 |
}
|
|
|
|
| 1459 |
"""Step 1: Upload Swing Video"""
|
| 1460 |
st.markdown('<h2 style="color: #0B3B0B; font-family: Georgia, serif;">Step 1: Upload Your Video</h2>', unsafe_allow_html=True)
|
| 1461 |
|
| 1462 |
+
st.markdown("**Choose your input method below.**")
|
| 1463 |
+
st.markdown("💡 **Tips:**")
|
| 1464 |
+
st.markdown("- Aim for a video of 5 seconds or less")
|
| 1465 |
+
st.markdown("- Make sure the video is in a down the line view, not face forward")
|
| 1466 |
|
| 1467 |
col1, col2 = st.columns(2)
|
| 1468 |
|
|
|
|
| 1645 |
data['analysis_data']['core_metrics'] = core_metrics
|
| 1646 |
|
| 1647 |
|
| 1648 |
+
# Generate and display LLM analysis automatically at the top
|
| 1649 |
+
if 'llm_analysis' not in st.session_state:
|
| 1650 |
+
# Generate LLM analysis automatically on first load
|
| 1651 |
+
with st.spinner("Generating AI swing analysis..."):
|
| 1652 |
+
try:
|
| 1653 |
+
# Prepare data for LLM analysis
|
| 1654 |
+
analysis_data = data.get('analysis_data', {})
|
| 1655 |
+
if not analysis_data:
|
| 1656 |
+
# Fallback: prepare data if not already done
|
| 1657 |
+
analysis_data = prepare_data_for_llm(pose_data, swing_phases, data.get('trajectory_data', {}), fps=30.0, frame_shape=None)
|
| 1658 |
+
|
| 1659 |
+
# Generate LLM analysis
|
| 1660 |
+
raw_analysis = generate_swing_analysis(pose_data, swing_phases, data.get('trajectory_data', {}))
|
| 1661 |
+
|
| 1662 |
+
if raw_analysis and not raw_analysis.startswith("Error:"):
|
| 1663 |
+
# Parse and format the analysis
|
| 1664 |
+
formatted_analysis = parse_and_format_analysis(raw_analysis)
|
| 1665 |
+
|
| 1666 |
+
# Store the analysis in session state for future reference
|
| 1667 |
+
st.session_state.llm_analysis = {
|
| 1668 |
+
'raw': raw_analysis,
|
| 1669 |
+
'formatted': formatted_analysis
|
| 1670 |
+
}
|
| 1671 |
+
else:
|
| 1672 |
+
# Store error state
|
| 1673 |
+
st.session_state.llm_analysis = {
|
| 1674 |
+
'error': raw_analysis or "Failed to generate analysis"
|
| 1675 |
+
}
|
| 1676 |
+
|
| 1677 |
+
except Exception as e:
|
| 1678 |
+
# Store error state
|
| 1679 |
+
st.session_state.llm_analysis = {
|
| 1680 |
+
'error': f"Error generating AI analysis: {str(e)}"
|
| 1681 |
+
}
|
| 1682 |
+
|
| 1683 |
+
# Display the overall summary at the very top if analysis was successful
|
| 1684 |
+
if 'llm_analysis' in st.session_state and 'formatted' in st.session_state.llm_analysis:
|
| 1685 |
+
formatted_analysis = st.session_state.llm_analysis['formatted']
|
| 1686 |
+
overall_summary = formatted_analysis.get('overall_summary', '')
|
| 1687 |
+
if overall_summary:
|
| 1688 |
+
st.markdown(f"""
|
| 1689 |
+
<div style='background-color: #e8f4fd; padding: 20px; border-radius: 10px; margin-bottom: 20px; border-left: 5px solid #1f77b4;'>
|
| 1690 |
+
<h3 style='color: #1f77b4; margin-top: 0; margin-bottom: 10px;'>🎯 Overall Swing Assessment</h3>
|
| 1691 |
+
<p style='margin: 0; line-height: 1.6; font-size: 16px; color: #2c3e50;'>{overall_summary}</p>
|
| 1692 |
+
</div>
|
| 1693 |
+
""", unsafe_allow_html=True)
|
| 1694 |
+
elif 'llm_analysis' in st.session_state and 'error' in st.session_state.llm_analysis:
|
| 1695 |
+
st.warning(f"AI Analysis unavailable: {st.session_state.llm_analysis['error']}")
|
| 1696 |
+
|
| 1697 |
+
# Display the new grading scheme below the summary
|
| 1698 |
display_new_grading_scheme(core_metrics)
|
| 1699 |
|
| 1700 |
+
# Developer tools (small and subtle)
|
| 1701 |
+
st.write("")
|
| 1702 |
+
st.write("")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1703 |
|
| 1704 |
+
# Small developer buttons in bottom right corner
|
| 1705 |
+
dev_col1, dev_col2, dev_col3 = st.columns([4, 1, 1])
|
| 1706 |
|
| 1707 |
+
with dev_col2:
|
| 1708 |
+
if st.button("📊 Debug", key="debug_calibration", help="View calibration data"):
|
| 1709 |
+
with st.expander("Calibration Data", expanded=True):
|
| 1710 |
+
st.caption("Raw values for qualitative assessments:")
|
|
|
|
|
|
|
|
|
|
| 1711 |
|
| 1712 |
+
# Shaft angle raw value
|
| 1713 |
+
shaft_raw = core_metrics.get("shaft_angle_top", {}).get('value')
|
| 1714 |
+
shaft_status = core_metrics.get("shaft_angle_top", {}).get('status', 'n/a')
|
| 1715 |
+
st.caption(f"Shaft Angle @ Top: {shaft_raw}° ({shaft_status})")
|
| 1716 |
+
|
| 1717 |
+
# Hip rotation raw value
|
| 1718 |
+
hip_raw = core_metrics.get("hip_rotation_impact_deg", {}).get('value')
|
| 1719 |
+
hip_status = core_metrics.get("hip_rotation_impact_deg", {}).get('status', 'n/a')
|
| 1720 |
+
st.caption(f"Hip Rotation @ Impact: {hip_raw}° ({hip_status})")
|
| 1721 |
+
|
| 1722 |
+
# X-factor raw value (bonus)
|
| 1723 |
+
xfactor_raw = core_metrics.get("x_factor_top_deg", {}).get('value')
|
| 1724 |
+
xfactor_status = core_metrics.get("x_factor_top_deg", {}).get('status', 'n/a')
|
| 1725 |
+
st.caption(f"X-Factor @ Top: {xfactor_raw}° ({xfactor_status})")
|
| 1726 |
|
| 1727 |
+
# Shoulder rotation raw value
|
| 1728 |
+
shoulder_raw = core_metrics.get("shoulder_rotation_top_deg", {}).get('value')
|
| 1729 |
+
shoulder_status = core_metrics.get("shoulder_rotation_top_deg", {}).get('status', 'n/a')
|
| 1730 |
+
st.caption(f"Shoulder Rotation @ Top: {shoulder_raw}° ({shoulder_status})")
|
| 1731 |
+
|
| 1732 |
+
with dev_col3:
|
| 1733 |
+
if st.button("🔍 Prompt", key="show_prompt_btn", help="View LLM prompt"):
|
| 1734 |
+
if 'prompt' in st.session_state.analysis_data:
|
| 1735 |
+
with st.expander("LLM Prompt", expanded=True):
|
| 1736 |
+
st.code(st.session_state.analysis_data['prompt'], language="text")
|
| 1737 |
else:
|
| 1738 |
+
st.error("No prompt data available.")
|
| 1739 |
|
| 1740 |
else:
|
| 1741 |
st.error("No analysis data available. Please analyze a video first.")
|