BladeSzaSza commited on
Commit
49fadc3
Β·
verified Β·
1 Parent(s): 3732b46

feat: ZeroGPU startup fix + FMS scoring sheet download + judge prompt alignment

Browse files
.gitattributes CHANGED
@@ -35,3 +35,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  docs/FormScout-FMS-Spec.md.pdf filter=lfs diff=lfs merge=lfs -text
37
  docs/plans/FormScout-Build-Prompt.md.pdf filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  docs/FormScout-FMS-Spec.md.pdf filter=lfs diff=lfs merge=lfs -text
37
  docs/plans/FormScout-Build-Prompt.md.pdf filter=lfs diff=lfs merge=lfs -text
38
+ assets/screenings/active-straight-leg-raise.png filter=lfs diff=lfs merge=lfs -text
39
+ assets/screenings/deep-squat.png filter=lfs diff=lfs merge=lfs -text
40
+ assets/screenings/hurdle-step.png filter=lfs diff=lfs merge=lfs -text
41
+ assets/screenings/inline-lunge.png filter=lfs diff=lfs merge=lfs -text
42
+ assets/screenings/rotary-stability.png filter=lfs diff=lfs merge=lfs -text
43
+ assets/screenings/shoulder-mobility.png filter=lfs diff=lfs merge=lfs -text
44
+ assets/screenings/trunk-stability-push-up.png filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -64,6 +64,28 @@ SCORE_DESCRIPTIONS = {
64
  0: "Pain reported β€” clinician referral required",
65
  }
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  # ─── Processing ──────────────────────────────────────────────────────────────
69
 
@@ -370,6 +392,15 @@ def build_app() -> gr.Blocks:
370
  scale=1,
371
  )
372
 
 
 
 
 
 
 
 
 
 
373
  _available_models = config.available_pose_models() or config.POSE_MODELS
374
  _default_model = (
375
  config.DEFAULT_POSE_MODEL
@@ -380,6 +411,7 @@ def build_app() -> gr.Blocks:
380
  choices=list(_available_models.keys()),
381
  value=_default_model,
382
  label="Pose Model",
 
383
  )
384
 
385
  overlay_layers = gr.CheckboxGroup(
@@ -452,6 +484,11 @@ def build_app() -> gr.Blocks:
452
  side = {"N/A": "na", "Left": "left", "Right": "right"}.get(side_display, "na")
453
  return process_video(video, test_name, side, pose_model_key, overlay_layers, sess)
454
 
 
 
 
 
 
455
  submit_btn.click(
456
  fn=_map_inputs,
457
  inputs=[video_input, test_dropdown, side_dropdown, pose_model_dropdown,
@@ -481,4 +518,5 @@ def build_app() -> gr.Blocks:
481
 
482
  if __name__ == "__main__":
483
  app = build_app()
484
- app.launch(theme=formscout_theme(), css=FORMSCOUT_CSS)
 
 
64
  0: "Pain reported β€” clinician referral required",
65
  }
66
 
67
+ # Per-test illustration shown as a movement guide (test_key -> filename).
68
+ _ASSET_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "screenings")
69
+ SCREENING_ASSETS = {
70
+ "deep_squat": "deep-squat.png",
71
+ "hurdle_step": "hurdle-step.png",
72
+ "inline_lunge": "inline-lunge.png",
73
+ "shoulder_mobility": "shoulder-mobility.png",
74
+ "active_slr": "active-straight-leg-raise.png",
75
+ "trunk_stability_pushup": "trunk-stability-push-up.png",
76
+ "rotary_stability": "rotary-stability.png",
77
+ }
78
+
79
+
80
+ def _screening_image(test_display_name: str) -> str | None:
81
+ """Resolve the movement-guide image path for a dropdown display name."""
82
+ key = {name: val for name, val in FMS_TESTS}.get(test_display_name)
83
+ fname = SCREENING_ASSETS.get(key)
84
+ if not fname:
85
+ return None
86
+ path = os.path.join(_ASSET_DIR, fname)
87
+ return path if os.path.exists(path) else None
88
+
89
 
90
  # ─── Processing ──────────────────────────────────────────────────────────────
91
 
 
392
  scale=1,
393
  )
394
 
395
+ movement_guide = gr.Image(
396
+ value=_screening_image("Deep Squat"),
397
+ label="Movement guide",
398
+ interactive=False,
399
+ buttons=[], # no download/share/fullscreen overlay
400
+ height=240,
401
+ elem_id="movement-guide",
402
+ )
403
+
404
  _available_models = config.available_pose_models() or config.POSE_MODELS
405
  _default_model = (
406
  config.DEFAULT_POSE_MODEL
 
411
  choices=list(_available_models.keys()),
412
  value=_default_model,
413
  label="Pose Model",
414
+ elem_id="pose-model-dd",
415
  )
416
 
417
  overlay_layers = gr.CheckboxGroup(
 
484
  side = {"N/A": "na", "Left": "left", "Right": "right"}.get(side_display, "na")
485
  return process_video(video, test_name, side, pose_model_key, overlay_layers, sess)
486
 
487
+ # Swap the movement-guide illustration when the selected test changes.
488
+ test_dropdown.change(
489
+ fn=_screening_image, inputs=[test_dropdown], outputs=[movement_guide],
490
+ )
491
+
492
  submit_btn.click(
493
  fn=_map_inputs,
494
  inputs=[video_input, test_dropdown, side_dropdown, pose_model_dropdown,
 
518
 
519
  if __name__ == "__main__":
520
  app = build_app()
521
+ app.launch(theme=formscout_theme(), css=FORMSCOUT_CSS,
522
+ allowed_paths=[_ASSET_DIR])
assets/screenings/active-straight-leg-raise.png ADDED

Git LFS Details

  • SHA256: ff1c9bd59b925d8cdee50c26569d47df10b1492e87c97fca54fe70e5f986657c
  • Pointer size: 131 Bytes
  • Size of remote file: 907 kB
assets/screenings/deep-squat.png ADDED

Git LFS Details

  • SHA256: c88a8e4be38bdf0225bdafcff54501314cab251525e4a0d64f54e96904387219
  • Pointer size: 131 Bytes
  • Size of remote file: 933 kB
assets/screenings/hurdle-step.png ADDED

Git LFS Details

  • SHA256: f0ae14712b910507ca135d0f5e8c630d6bb836e7dbfb0933aff307e6a6245ad5
  • Pointer size: 132 Bytes
  • Size of remote file: 1.53 MB
assets/screenings/inline-lunge.png ADDED

Git LFS Details

  • SHA256: 97213a46f9d34ce15ce88366e9955bc215346b125f7f4ac9a8b5b57a30621f3c
  • Pointer size: 131 Bytes
  • Size of remote file: 895 kB
assets/screenings/rotary-stability.png ADDED

Git LFS Details

  • SHA256: 6383d753060411151b4d93c7b9b3301094bf8353c96f3fee32698fded4cdc283
  • Pointer size: 131 Bytes
  • Size of remote file: 901 kB
assets/screenings/shoulder-mobility.png ADDED

Git LFS Details

  • SHA256: 555593ae4d722428ec47f16d6080916c7bc57df12d3b22d5e86999d01c3b0fad
  • Pointer size: 131 Bytes
  • Size of remote file: 929 kB
assets/screenings/trunk-stability-push-up.png ADDED

Git LFS Details

  • SHA256: 404fe27f03e717bcb2528dc384368ac0c0b7fd656d69116c5076bb61bb9e12fa
  • Pointer size: 131 Bytes
  • Size of remote file: 881 kB
formscout/ui/theme.py CHANGED
@@ -16,6 +16,8 @@ SAGE_DEEP = "#9cbcad"
16
  TEAL = "#2b8a8a"
17
  TEAL_HOVER = "#1f6e6e"
18
  TEAL_DEEP = "#175757"
 
 
19
  GOLD = "#e0a43b"
20
  GOLD_DEEP = "#cf922a"
21
  INK = "#243a34"
@@ -116,6 +118,29 @@ FORMSCOUT_CSS = f"""
116
  color: {GOLD_DEEP};
117
  }}
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  /* Score display */
120
  .score-card {{
121
  background: rgba(43, 138, 138, 0.08);
 
16
  TEAL = "#2b8a8a"
17
  TEAL_HOVER = "#1f6e6e"
18
  TEAL_DEEP = "#175757"
19
+ TEAL_LIGHT = "#d6ecec"
20
+ TEAL_LIGHT_HOVER = "#bfe3e3"
21
  GOLD = "#e0a43b"
22
  GOLD_DEEP = "#cf922a"
23
  INK = "#243a34"
 
118
  color: {GOLD_DEEP};
119
  }}
120
 
121
+ /* Pose Model dropdown β€” light-teal option cells (scoped, no other dropdowns affected) */
122
+ #pose-model-dd ul.options {{
123
+ background: {TEAL_LIGHT} !important;
124
+ }}
125
+ #pose-model-dd ul.options li.item {{
126
+ background: {TEAL_LIGHT} !important;
127
+ color: {INK} !important;
128
+ }}
129
+ #pose-model-dd ul.options li.item:hover,
130
+ #pose-model-dd ul.options li.item.active {{
131
+ background: {TEAL_LIGHT_HOVER} !important;
132
+ }}
133
+
134
+ /* Movement-guide illustration β€” rounded card matching the test selection */
135
+ #movement-guide img {{
136
+ border-radius: 12px;
137
+ object-fit: contain;
138
+ }}
139
+ #movement-guide {{
140
+ border: 1px solid rgba(43, 138, 138, 0.22);
141
+ border-radius: 14px;
142
+ }}
143
+
144
  /* Score display */
145
  .score-card {{
146
  background: rgba(43, 138, 138, 0.08);