Skip to content

๐Ÿ“š Swing-Analysis Documentation โ€‹

English | ็ฎ€ไฝ“ไธญๆ–‡

What is this? โ€‹

Swing-Analysis wraps a battle-tested tennis-swing auto-segmentation pipeline into a serviceable Python backend with a pluggable UI layer. Three algorithm scripts are vendored byte-for-byte into backend/core/ โ€” no modifications, no surprises. When the underlying source improves, you literally cp the new files in.

The repository ships three deliverables:

  1. A self-contained CLI (python -m backend.cli) โ€” fastest way to verify the pipeline produces what you expect, no service required.
  2. A FastAPI service (python -m backend.service) โ€” REST + WebSocket over 127.0.0.1:8321. Used by the Electron GUI; tomorrow, by a browser or mobile client.
  3. An Electron + React desktop GUI (npm run dev) โ€” the first front-end consumer. Owns the sidecar lifecycle, drives the user through pick video โ†’ tune โ†’ watch progress โ†’ review segments โ†’ seek & download.

๐Ÿ“‘ Documentation Index โ€‹

ChapterContentsFor whom
00 ยท IntroductionProject positioning, the vendor-first decoupling story, when to use thisEveryone โ€” start here
01 ยท Getting StartedPrerequisites, install, first run (CLI / REST / GUI) in under 10 minutesNew users
02 ยท ArchitectureLayered design (core / service / cli / electron), vendor strategy, lock disciplineCurious / contributors
03 ยท CLI UsageAll flags, output schema, exit codes, sample invocationUsers running batch jobs
04 ยท REST APIEvery endpoint, payload schemas, WebSocket event types, Range streaming, curl recipesAPI integrators
05 ยท Electron GUISidecar lifecycle, dev workflow, UI layout, debuggingGUI users / contributors
06 ยท AlgorithmHow the v2.1 two-pass cutting pipeline works under the hood (online + offline)Algorithm tuners
07 ยท TroubleshootingCommon pitfalls and fixesStuck users

Core Idea โ€‹

                       algorithm (truth)
                            โ”‚
                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                โ”‚                       โ”‚
         run_pipeline()           run_pipeline()
                โ”‚                       โ”‚
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚  CLI  entry   โ”‚       โ”‚ REST/WS entry โ”‚
        โ”‚  backend.cli  โ”‚       โ”‚ service.app   โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚                       โ”‚
        terminal UI              Electron / browser /
                                 mobile / curl
  • Vendor first. Algorithm libraries are copied verbatim into backend/core/; no edits inside the vendored copy. Drift between this repo and the underlying source is resolved by cp, not by hand-merging.
  • Pipeline as the seam. run_pipeline() is the only function that touches the algorithm. It takes callbacks (progress_cb, on_segment, should_cancel) instead of writing to a terminal. The HTTP service and the CLI both call it.
  • Plug any UI. Want a Jupyter widget? A Streamlit page? An iOS app? They all speak REST + WebSocket and download artifacts from /api/artifacts/<id>/.... The algorithm doesn't know or care.

Why "two UIs over one pipeline"? โ€‹

A CLI is a UI. An HTTP service is a UI. An Electron app is a UI. They differ in transport and rendering, but not in what they ask the algorithm to do. Decoupling at this seam gives you:

  • Test the algorithm without UI noise. Run the CLI on a fixture video and eyeball segments.json. No browser, no DevTools, no flaky WS.
  • Test the UI without re-implementing the algorithm. The GUI is a thin shell: pick a video, fill a form, show progress, list segments. No MediaPipe or OpenCV anywhere on the renderer side.
  • Replace either side freely. Tomorrow the CLI becomes a notebook widget; the Electron app becomes a Streamlit page. The algorithm stays put.

Project layout โ€‹

backend/
  core/
    segment_swing.py        โ† vendored, do NOT edit (wrist-signal cut)
    analyze_swing.py        โ† vendored, do NOT edit (33-point + clips)
    gen_skeleton_anim.py    โ† vendored, do NOT edit (RTMDet + RTMPose / MP)
  service/
    pipeline.py            โ† run_pipeline(): the seam
    jobs.py                โ† JobManager + WS broadcast
    app.py                 โ† FastAPI routes
    __main__.py            โ† uvicorn entry
    schemas.py             โ† pydantic wire types
  cli.py                   โ† CLI entry (same pipeline)
  models/pose_landmarker_lite.task    โ† committed, 5.5 MB
src/
  main/index.ts            โ† PythonSidecar lifecycle
  preload/index.ts         โ† contextBridge
  renderer/                โ† React UI
scripts/fetch-model.sh     โ† MediaPipe CDN fallback downloader
docs/                      โ† you are here

The three vendored scripts in backend/core/ are also independently runnable โ€” see 02 ยท Architecture and 03 ยท CLI Usage.

Verification recipe โ€‹

bash
# 1. health
curl http://127.0.0.1:8321/api/health
# {"status":"ok","version":"0.1.0","model_ready":true,...}

# 2. submit
curl -X POST http://127.0.0.1:8321/api/jobs \
     -H 'Content-Type: application/json' \
     -d '{"video_path":"/abs/fdl.mp4","params":{"max_frames":1500}}'
# {"job_id":"51b71ad9db8b"}

# 3. poll
curl http://127.0.0.1:8321/api/jobs/51b71ad9db8b | jq '.state, (.segments|length)'
# "done"
# 3

# 4. video Range
curl -H 'Range: bytes=0-1023' \
     'http://127.0.0.1:8321/api/videos?path=/abs/fdl.mp4' -o /dev/null -D -
# HTTP/1.1 206 Partial Content
# Content-Range: bytes 0-1023/25243119

# 5. download artifacts
curl http://127.0.0.1:8321/api/artifacts/51b71ad9db8b/segments.json -o seg.json

License โ€‹

See LICENSE.