Conversation
WalkthroughThis PR introduces a new score module—a FastAPI-based video scoring service that analyzes video frames using MediaPipe pose estimation to detect activities (running, walking, squats, etc.), extract pose-derived features, compute temporal statistics, and provide structured scoring summaries. Includes containerization, project configuration, and geometric utilities. Changes
Sequence DiagramsequenceDiagram
participant Client as HTTP Client
participant API as FastAPI App
participant CV as OpenCV
participant MP as MediaPipe Pose
participant Est as Estimator
participant Util as Utils
Client->>API: POST /api/score (video file)
API->>API: Validate file extension
API->>API: Save temp file
API->>CV: Open video
CV-->>API: Video stream
loop For each frame
CV->>CV: Read frame
CV-->>API: Frame data
API->>MP: Estimate pose
MP-->>API: Landmarks (33 points)
API->>Util: landmark() - scale/normalize
Util-->>API: Normalized landmarks array
API->>API: frame_features_from_xyvis()
API->>Util: dist(), angle_at(), torso_angle_deg()
Util-->>API: Geometric features
API->>API: Build feature dict
API->>Est: push(features)
Est->>Est: Buffer frame, update temporal stats
Est-->>API: ✓
end
API->>Est: detect()
Est->>Est: _temporal_stats() - compute medians, FFT, speeds
Est->>Est: _logistic() - scale scores
Est->>Est: form_score() - percentile for label
Est-->>API: (label, score, confidence)
API->>API: Build ScoreSummary
API->>CV: Release video
API->>API: Delete temp file
API-->>Client: ScoreSummary JSON (200 OK)
alt Error occurs
API-->>Client: HTTP 400/500 + error details
API->>API: Cleanup temp file
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (7)
score/Dockerfile (1)
5-12: Consider--no-install-recommendsto keep image smaller.
Not required, but typically helps for slim images.score/score/utils.py (1)
42-56: Remove redundantint()calls aroundround().
round()already returns an integer in Python 3 when called with a single argument. The static analysis tool correctly identified this.def landmark(landmarks: Sequence[Any], image_width: int, image_height: int) -> np.ndarray: # 33*3 out: np.ndarray = np.zeros((33, 3), dtype=np.float32) for i, lm in enumerate(landmarks): - x = int(round(lm.x * image_width)) - y = int(round(lm.y * image_height)) + x = round(lm.x * image_width) + y = round(lm.y * image_height) # x ∈ [0, W−1] x = min(max(x, 0), image_width - 1) # y ∈ [0, H−1] y = min(max(y, 0), image_height - 1) vis = getattr(lm, "visibility", None) or getattr(lm, "presence", None) or 1.0 out[i, 0] = x out[i, 1] = y out[i, 2] = float(vis) return outscore/app.py (2)
186-187: Chain exceptions for better debugging.Use
raise ... from eto preserve the exception chain and provide better stack traces.except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to save uploaded file: {e}") + raise HTTPException(status_code=500, detail=f"Failed to save uploaded file: {e}") from e
200-201: Chain exceptions for better debugging.Same issue as above—use exception chaining.
except Exception as e: - raise HTTPException(status_code=500, detail=f"Processing failed: {e}") + raise HTTPException(status_code=500, detail=f"Processing failed: {e}") from escore/features.py (3)
102-121: Inefficient list comprehension on every push.Line 120 creates a new filtered list on every
push()call to check standing initialization. This O(n) operation per frame could be optimized by tracking the count incrementally.Consider tracking the count of high-knee frames incrementally:
+ self._high_knee_count: int = 0Then in
push():if not self.standing_initialized and feat["avg_knee"] > 150: if self.standing_hip_y is None: self.standing_hip_y = feat["hip_y"] else: self.standing_hip_y = 0.95 * self.standing_hip_y + 0.05 * feat["hip_y"] - - if len([b for b in self.buf if b.get("valid") and b["avg_knee"] > 150]) > self.fps * 1.0: + self._high_knee_count += 1 + if self._high_knee_count > self.fps * 1.0: self.standing_initialized = TrueNote: You'd also need to decrement the count when old frames fall out of the window if precision matters.
198-286: Consider extracting magic numbers to named constants.The
detectmethod contains many hardcoded thresholds (e.g.,k=0.8, x0=2.0,0.45,0.3, etc.) that control activity classification. While functional, these would be easier to tune and understand as named constants or a configuration object.Example:
# At module level or in class RUNNING_FREQ_TARGET = 2.2 RUNNING_PERIODIC_K = 0.8 RUNNING_PERIODIC_X0 = 2.0 # ... etc
288-345: Consider using a dispatch table instead of if-elif chain.The
form_scoremethod has a long if-elif chain for each activity type. A dictionary-based dispatch would be more maintainable and extensible.Example pattern:
def form_score(self, label: str, med: Optional[Dict[str, float]]) -> float: if med is None: return 0.0 score_funcs = { "running": self._score_running, "walking": self._score_walking, # ... etc } func = score_funcs.get(label) return func(med) if func else 0.0
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
score/input/input.mp4is excluded by!**/*.mp4score/uv.lockis excluded by!**/*.lock
📒 Files selected for processing (11)
score/.gitignore(1 hunks)score/.python-version(1 hunks)score/Dockerfile(1 hunks)score/README.md(1 hunks)score/app.py(1 hunks)score/build.sh(1 hunks)score/features.py(1 hunks)score/input/curl.sh(1 hunks)score/pyproject.toml(1 hunks)score/run.sh(1 hunks)score/score/utils.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
score/features.py (1)
score/score/utils.py (3)
dist(6-7)angle_at(10-27)torso_angle_deg(31-40)
score/app.py (1)
score/features.py (5)
frame_features_from_xyvis(9-74)Estimator(76-345)push(102-121)detect(198-286)_temporal_stats(123-192)
🪛 Ruff (0.14.8)
score/features.py
85-85: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
286-286: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
score/app.py
52-52: Unused function argument: annotated_output_path
(ARG001)
56-56: Avoid specifying long messages outside the exception class
(TRY003)
70-70: Avoid specifying long messages outside the exception class
(TRY003)
78-78: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
79-79: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
170-170: Do not perform function call File in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
(B008)
176-176: Unused function argument: save_annotated
(ARG001)
186-186: Do not catch blind exception: Exception
(BLE001)
187-187: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
199-199: Consider moving this statement to an else block
(TRY300)
200-200: Do not catch blind exception: Exception
(BLE001)
201-201: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
205-206: try-except-pass detected, consider logging the exception
(S110)
205-205: Do not catch blind exception: Exception
(BLE001)
210-210: Possible binding to all interfaces
(S104)
score/score/utils.py
14-14: Comment contains ambiguous − (MINUS SIGN). Did you mean - (HYPHEN-MINUS)?
(RUF003)
16-16: Comment contains ambiguous − (MINUS SIGN). Did you mean - (HYPHEN-MINUS)?
(RUF003)
30-30: Comment contains ambiguous − (MINUS SIGN). Did you mean - (HYPHEN-MINUS)?
(RUF003)
32-32: Comment contains ambiguous − (MINUS SIGN). Did you mean - (HYPHEN-MINUS)?
(RUF003)
38-38: Comment contains ambiguous − (MINUS SIGN). Did you mean - (HYPHEN-MINUS)?
(RUF003)
46-46: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
47-47: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
48-48: Comment contains ambiguous − (MINUS SIGN). Did you mean - (HYPHEN-MINUS)?
(RUF003)
50-50: Comment contains ambiguous − (MINUS SIGN). Did you mean - (HYPHEN-MINUS)?
(RUF003)
🪛 Shellcheck (0.11.0)
score/run.sh
[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
(SC2148)
score/build.sh
[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
(SC2148)
score/input/curl.sh
[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
(SC2148)
🔇 Additional comments (9)
score/.python-version (1)
1-1: Good pin for local tooling (pyenv/asdf).
Matches the service’s Python 3.12 baseline.score/.gitignore (1)
1-216: Solid, comprehensive Python/tooling ignores.
No concerns from what’s included here.score/score/utils.py (3)
1-7: LGTM!The
distfunction is a clean implementation of Euclidean distance using numpy'slinalg.norm.
10-27: LGTM!The
angle_atfunction correctly handles the degenerate case (zero-length vectors) and clamps the cosine value to avoid domain errors inarccos. The implementation is mathematically sound.
31-40: LGTM!The
torso_angle_degfunction correctly computes the torso angle and normalizes it to [0, 90] range usingmin(ang, 180 - ang).score/app.py (1)
208-210: Binding to all interfaces (0.0.0.0) in development mode.Running with
host="0.0.0.0"exposes the service to all network interfaces, which may be acceptable for containerized deployments but could be a security concern during local development.Consider using
127.0.0.1for local development or making the host configurable via environment variable:if __name__ == "__main__": import uvicorn - uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True) + import os + host = os.environ.get("HOST", "127.0.0.1") + uvicorn.run("app:app", host=host, port=8000, reload=True)score/features.py (3)
9-74: LGTM!The
frame_features_from_xyvisfunction is well-structured with clear landmark extraction and feature computation. The visibility threshold check (0.12) provides a reasonable guard against unreliable pose estimates.
76-100: LGTM!The
Estimatorconstructor properly initializes bounded deques for efficient sliding window management and sets sensible defaults.
123-192: LGTM!The
_temporal_statsmethod computes comprehensive temporal statistics including FFT-based periodicity analysis. The implementation handles edge cases (empty buffers, single-element arrays) appropriately.
| from score.utils import landmark | ||
| from features import frame_features_from_xyvis, Estimator |
There was a problem hiding this comment.
Inconsistent import paths.
The imports use different path styles: from score.utils import landmark (absolute) vs from features import ... (relative/implicit). This may cause import errors depending on how the module is run.
from score.utils import landmark
-from features import frame_features_from_xyvis, Estimator
+from score.features import frame_features_from_xyvis, Estimator📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| from score.utils import landmark | |
| from features import frame_features_from_xyvis, Estimator | |
| from score.utils import landmark | |
| from score.features import frame_features_from_xyvis, Estimator |
🤖 Prompt for AI Agents
In score/app.py around lines 13 to 14, the imports are inconsistent: one uses
the package path (from score.utils import landmark) while the other uses a bare
module name (from features import ...), which can break depending on how the
package is executed; make them consistent by changing the second import to the
package-qualified form (e.g., from score.features import
frame_features_from_xyvis, Estimator) or, if this file is intended to be an
intra-package import, use a relative import (e.g., from .features import
frame_features_from_xyvis, Estimator); ensure the package has an __init__.py and
adjust PYTHONPATH/run configuration if necessary.
| def analyze_video( | ||
| input_path: Union[str, Path], | ||
| mode: str = "auto", | ||
| max_width: Optional[int] = None, | ||
| model_complexity: int = 0, | ||
| min_det_conf: float = 0.5, | ||
| min_track_conf: float = 0.5, | ||
| annotated_output_path: Optional[Union[str, Path]] = None, | ||
| ) -> ScoreSummary: |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove unused annotated_output_path parameter.
This parameter is declared but never used in the function body. Either implement the annotated video output functionality or remove the parameter to avoid confusion.
def analyze_video(
input_path: Union[str, Path],
mode: str = "auto",
max_width: Optional[int] = None,
model_complexity: int = 0,
min_det_conf: float = 0.5,
min_track_conf: float = 0.5,
- annotated_output_path: Optional[Union[str, Path]] = None,
) -> ScoreSummary:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def analyze_video( | |
| input_path: Union[str, Path], | |
| mode: str = "auto", | |
| max_width: Optional[int] = None, | |
| model_complexity: int = 0, | |
| min_det_conf: float = 0.5, | |
| min_track_conf: float = 0.5, | |
| annotated_output_path: Optional[Union[str, Path]] = None, | |
| ) -> ScoreSummary: | |
| def analyze_video( | |
| input_path: Union[str, Path], | |
| mode: str = "auto", | |
| max_width: Optional[int] = None, | |
| model_complexity: int = 0, | |
| min_det_conf: float = 0.5, | |
| min_track_conf: float = 0.5, | |
| ) -> ScoreSummary: |
🧰 Tools
🪛 Ruff (0.14.8)
52-52: Unused function argument: annotated_output_path
(ARG001)
🤖 Prompt for AI Agents
In score/app.py around lines 45 to 53, the function analyze_video declares an
unused parameter annotated_output_path; remove this parameter from the function
signature and any external callers, or implement annotated video output: if
keeping it, add logic to write the annotated frames/video to the provided path
(validate path, open writer, draw annotations per frame, close writer) and
update the return to include the output path; otherwise delete the parameter and
update type hints and all references to avoid unused-argument confusion.
| out_w: int = int(round(in_w * scale)) | ||
| out_h: int = int(round(in_h * scale)) | ||
|
|
||
| out = None |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Dead code: out variable initialized but never assigned.
The out variable is initialized to None and checked in finally, but it's never assigned a VideoWriter instance. This suggests incomplete implementation of annotated video output.
Either implement the video writer functionality or remove the dead code:
- out = None
-
estimator = Estimator(fps=fps, window_seconds=3.0, stable_threshold=3, mode=mode)And in the finally block:
finally:
cap.release()
- if out is not None:
- out.release()
pose.close()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| out = None | |
| estimator = Estimator(fps=fps, window_seconds=3.0, stable_threshold=3, mode=mode) |
| out = None | |
| finally: | |
| cap.release() | |
| pose.close() |
🤖 Prompt for AI Agents
In score/app.py around line 81, the variable `out` is initialized to None but
never assigned or used, leaving dead code and an unsafe finally block; either
remove `out` and its release logic or implement annotated video output: create a
cv2.VideoWriter with correct codec, frame size and fps before processing, assign
it to `out`, write annotated frames to `out` inside the processing loop, and in
the finally block check and call `out.release()` only if `out` is not None; also
add any necessary cv2 import or parameter handling for output path, codec, and
fps.
| @app.post("/api/score", response_model=ScoreSummary) | ||
| async def api_score( | ||
| file: UploadFile = File(...), | ||
| mode: str = Form("auto"), | ||
| max_width: Optional[int] = Form(None), | ||
| model_complexity: int = Form(0), | ||
| min_det_conf: float = Form(0.5), | ||
| min_track_conf: float = Form(0.5), | ||
| save_annotated: bool = Form(False), | ||
| ): |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove unused save_annotated parameter.
Similar to annotated_output_path, this parameter is declared but never used. The annotated video feature appears incomplete.
@app.post("/api/score", response_model=ScoreSummary)
async def api_score(
file: UploadFile = File(...),
mode: str = Form("auto"),
max_width: Optional[int] = Form(None),
model_complexity: int = Form(0),
min_det_conf: float = Form(0.5),
min_track_conf: float = Form(0.5),
- save_annotated: bool = Form(False),
):🧰 Tools
🪛 Ruff (0.14.8)
170-170: Do not perform function call File in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
(B008)
176-176: Unused function argument: save_annotated
(ARG001)
🤖 Prompt for AI Agents
In score/app.py around lines 168 to 177, the save_annotated parameter is
declared on the api_score endpoint but never used; remove save_annotated: bool =
Form(False) from the function signature, update any OpenAPI docs or tests that
reference this parameter, and delete any dead code or comments related to the
annotated-video feature; run linters/tests to ensure no remaining references
break the build.
| if not file.filename.lower().endswith((".mp4", ".mov", ".m4v")): | ||
| raise HTTPException(status_code=400, detail="Unsupported file extension. Please upload MP4/MOV/M4V.") |
There was a problem hiding this comment.
Potential bypass via case sensitivity.
file.filename could be None for some upload scenarios. Consider adding a null check.
- if not file.filename.lower().endswith((".mp4", ".mov", ".m4v")):
+ if not file.filename or not file.filename.lower().endswith((".mp4", ".mov", ".m4v")):
raise HTTPException(status_code=400, detail="Unsupported file extension. Please upload MP4/MOV/M4V.")🤖 Prompt for AI Agents
In score/app.py around lines 178 to 179, the current filename check assumes
file.filename is non-null which can be bypassed; add a null check for file and
file.filename first and raise the same 400 HTTPException if missing, otherwise
perform the case-insensitive extension check (e.g., use
file.filename.lower().endswith(...)) so uploads with no filename or a None
filename are rejected before calling .lower().
| RUN apt-get update && apt-get install -y \ | ||
| build-essential \ | ||
| cmake \ | ||
| ffmpeg \ | ||
| libsm6 \ | ||
| libxext6 \ | ||
| curl \ | ||
| && apt-get clean && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| COPY pyproject.toml uv.lock ./ | ||
| COPY score/ ./score | ||
| COPY app.py . | ||
| COPY features.py . | ||
|
|
||
| RUN python -m venv /opt/venv | ||
| ENV PATH="/opt/venv/bin:$PATH" | ||
|
|
||
| RUN pip install --upgrade pip setuptools wheel | ||
|
|
||
| RUN pip install . | ||
|
|
There was a problem hiding this comment.
Docker build ignores uv.lock, creating non-reproducible installs.
The Dockerfile copies uv.lock on line 8 but then runs pip install . (line 22), which resolves dependencies from pyproject.toml at build time. Since pyproject.toml specifies flexible versions (e.g., numpy >=1.19.0, opencv-python >=4.5.0), builds at different times will pull different minor/patch versions, breaking reproducibility.
Use uv to sync directly from the lockfile instead:
RUN pip install --upgrade pip setuptools wheel
+RUN pip install uv
-RUN pip install .
+RUN uv sync --frozenThis ensures every build uses exact versions pinned in uv.lock, eliminating the reproducibility gap.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| RUN apt-get update && apt-get install -y \ | |
| build-essential \ | |
| cmake \ | |
| ffmpeg \ | |
| libsm6 \ | |
| libxext6 \ | |
| curl \ | |
| && apt-get clean && rm -rf /var/lib/apt/lists/* | |
| COPY pyproject.toml uv.lock ./ | |
| COPY score/ ./score | |
| COPY app.py . | |
| COPY features.py . | |
| RUN python -m venv /opt/venv | |
| ENV PATH="/opt/venv/bin:$PATH" | |
| RUN pip install --upgrade pip setuptools wheel | |
| RUN pip install . | |
| RUN apt-get update && apt-get install -y \ | |
| build-essential \ | |
| cmake \ | |
| ffmpeg \ | |
| libsm6 \ | |
| libxext6 \ | |
| curl \ | |
| && apt-get clean && rm -rf /var/lib/apt/lists/* | |
| COPY pyproject.toml uv.lock ./ | |
| COPY score/ ./score | |
| COPY app.py . | |
| COPY features.py . | |
| RUN python -m venv /opt/venv | |
| ENV PATH="/opt/venv/bin:$PATH" | |
| RUN pip install --upgrade pip setuptools wheel | |
| RUN pip install uv | |
| RUN uv sync --frozen | |
🤖 Prompt for AI Agents
In score/Dockerfile around lines 5 to 25 the build copies uv.lock but still runs
a plain pip install ., causing dependency resolution from pyproject.toml rather
than exact versions from uv.lock; to fix, after creating and activating the venv
and upgrading pip/setuptools/wheel, install the uv CLI into the venv and run uv
to sync the environment from uv.lock so the exact pinned versions are installed,
then continue with pip install . for the local package; ensure uv.lock is copied
before the sync step and keep the install/sync steps inside the Dockerfile build
sequence.
| curl -X POST "http://localhost:8000/api/score" \ | ||
| -F "file=@input.mp4" \ | ||
| -F "mode=running" \ | ||
| -F "max_width=640" No newline at end of file |
There was a problem hiding this comment.
Improve curl script ergonomics (shebang, fail fast, stable file path).
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
-curl -X POST "http://localhost:8000/api/score" \
- -F "file=@input.mp4" \
+curl --fail-with-body -sS -X POST "http://localhost:8000/api/score" \
+ -F "file=@${SCRIPT_DIR}/input.mp4" \
-F "mode=running" \
-F "max_width=640"🧰 Tools
🪛 Shellcheck (0.11.0)
[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
(SC2148)
🤖 Prompt for AI Agents
In score/input/curl.sh around lines 1 to 4, the script lacks a shebang,
fail-fast behavior, and a stable file path; update the script to start with a
shebang (#!/usr/bin/env bash), enable strict/fail-fast mode (set -euo pipefail
or at least set -e), resolve the input file relative to the script directory
(e.g. INPUT="$(dirname "$0")/input.mp4") to avoid cwd issues, and make curl fail
loudly by adding --fail --show-error (and optionally --silent) to the curl
invocation while keeping the form fields.
| [project] | ||
| name = "score" | ||
| version = "0.1.0" | ||
| description = "Add your description here" | ||
| readme = "README.md" | ||
| requires-python = ">=3.12" | ||
| dependencies = [ | ||
| "fastapi>=0.124.2", | ||
| "mediapipe>=0.10.13", | ||
| "numpy>=1.26.4", | ||
| "opencv-python>=4.11.0.86", | ||
| "python-multipart>=0.0.20", | ||
| "uvicorn>=0.38.0", | ||
| ] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
git ls-files | grep -E "(uv\.lock|poetry\.lock|requirements|Dockerfile|\.github)" | head -20Repository: befoafsuger/rizap2025
Length of output: 124
🏁 Script executed:
find . -maxdepth 2 -type f \( -name "uv.lock" -o -name "Dockerfile" -o -name "*.yml" -o -name "*.yaml" \) 2>/dev/nullRepository: befoafsuger/rizap2025
Length of output: 181
🌐 Web query:
mediapipe 0.10.13 Python 3.12 compatibility support
💡 Result:
Yes — MediaPipe 0.10.13 has prebuilt wheels for CPython 3.12 (cp312) on PyPI (Windows/macOS/manylinux variants), so it is compatible with Python 3.12 — install with pip (e.g. pip install mediapipe==0.10.13). [1][2]
Sources:
- MediaPipe 0.10.13 files on PyPI (shows cp312 wheels). [1]
- MediaPipe build docs (Python build pipeline tested up through 3.12). [2]
References
[1] https://pypi.org/project/mediapipe/0.10.13/#files
[2] https://ai.google.dev/edge/mediapipe/solutions/build_python
🌐 Web query:
opencv-python 4.11.0.86 Python 3.12 wheels support
💡 Result:
Yes — opencv-python 4.11.0.86 includes fixes for and provides wheels for Python 3.12. [1][2]
Sources:
- opencv-python release notes (4.11.0.86): "Added Python 3.13 support · Fixed build with Python 3.12". [1]
- opencv-python project documentation / CI: lists Python 3.12 among supported Python versions for pre-built wheels. [2]
🏁 Script executed:
cat score/DockerfileRepository: befoafsuger/rizap2025
Length of output: 593
🏁 Script executed:
cat .github/workflows/format.ymlRepository: befoafsuger/rizap2025
Length of output: 1132
Versioning strategy: >= constraints are not enforced by the lockfile in Docker builds.
The uv.lock file exists but the Dockerfile uses RUN pip install . instead of installing from the lock, which resolves dependencies using the >= constraints in pyproject.toml. This creates a risk of dependency drift between local development and production. Consider updating the Dockerfile to enforce the lock (e.g., RUN pip install -e . --require-hashes or using uv pip install if using uv as the dependency manager).
Good news: mediapipe 0.10.13 and opencv-python 4.11.0.86 are both compatible with Python 3.12—no concerns there.
| # score algorithm | ||
|
|
||
| def dist | ||
| -> ユークリッド距離 | ||
|
|
||
| def angle_at | ||
| -> 余弦定理 角度計算 | ||
|
|
||
| def torso_angle_deg | ||
| -> atan2の方位角算出 No newline at end of file |
There was a problem hiding this comment.
Make README valid Markdown (code fences or bullet list), avoid def pseudo-syntax.
Right now it looks like malformed Python and won’t render nicely.
# score algorithm
-def dist
--> ユークリッド距離
+## Utilities
+
+- `dist`: ユークリッド距離
-def angle_at
--> 余弦定理 角度計算
+- `angle_at`: 余弦定理で角度計算
-def torso_angle_deg
--> atan2の方位角算出
+- `torso_angle_deg`: `atan2` で方位角算出📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # score algorithm | |
| def dist | |
| -> ユークリッド距離 | |
| def angle_at | |
| -> 余弦定理 角度計算 | |
| def torso_angle_deg | |
| -> atan2の方位角算出 | |
| # score algorithm | |
| ## Utilities | |
| - `dist`: ユークリッド距離 | |
| - `angle_at`: 余弦定理で角度計算 | |
| - `torso_angle_deg`: `atan2` で方位角算出 |
🤖 Prompt for AI Agents
In score/README.md around lines 1 to 10, the current content uses "def"
pseudo-syntax and looks like malformed Python; replace it with valid Markdown by
converting each entry into either a bullet list or fenced code blocks with brief
descriptions — e.g., a bullet list of function names (dist, angle_at,
torso_angle_deg) followed by short descriptions (Euclidean distance; angle via
law of cosines; torso angle using atan2) or use fenced code blocks to show
function signatures and then plain text descriptions below each; remove the
"def" prefix so the file renders as proper Markdown.
| @@ -0,0 +1 @@ | |||
| docker run -d --name score-api -p 8000:8000 score-api | |||
There was a problem hiding this comment.
Add shebang + handle “container already exists” for local dev.
+#!/usr/bin/env bash
+set -euo pipefail
+
+docker rm -f score-api >/dev/null 2>&1 || true
-docker run -d --name score-api -p 8000:8000 score-api
+docker run -d --name score-api -p 8000:8000 score-api📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| docker run -d --name score-api -p 8000:8000 score-api | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| docker rm -f score-api >/dev/null 2>&1 || true | |
| docker run -d --name score-api -p 8000:8000 score-api |
🧰 Tools
🪛 Shellcheck (0.11.0)
[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
(SC2148)
🤖 Prompt for AI Agents
In score/run.sh around line 1, the script lacks a shebang and doesn't handle the
case where a container named score-api already exists; add a shebang (e.g.,
#!/usr/bin/env bash) at the top, make the script executable, and before running
docker run check for an existing container (docker ps -aq -f name=^/score-api$),
and if found stop and remove it (docker stop ... && docker rm ...) or exit with
a clear message; then run docker run -d --name score-api -p 8000:8000 score-api.
Ensure the check is robust (matches exact name) and uses exit codes to surface
failures.
スコアアルゴリズムのAPIです。./score/inputフォルダに動画データとcurlを置きました。
Summary by CodeRabbit
New Features
/api/scoreAPI endpoint for video analysis with activity detection (running, walking, squat, lunge, pushup, plank, jumping jack, situp, burpee, standing).Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.