Skip to main content

System Dependency Manager - A collection of reusable Python modules for AI services

Project description

CAEMA Utils

System Dependency Manager - A collection of reusable Python modules for AI services.

Python 3.9+ License: MIT

Available Modules

Module Description Status
pose_estimation AI-powered body pose analysis using YOLOv8 Stable (v0.1.4)

Installation

Step-by-Step Install (Recommended)

Run these commands one by one:

# Step 1: Install the package with all dependencies
pip install "caema-utils[all]"

# Step 2: Fix OpenCV for headless servers (Codespaces, Docker, cloud VMs)
# ultralytics installs opencv-python which requires libGL - we need headless version
pip uninstall opencv-python opencv-python-headless -y
pip install opencv-python-headless --force-reinstall --no-deps

# Step 3: Verify installation
pose-server --check

You should see: All dependencies OK!

Quick Install (One Command)

pip install "caema-utils[all]" && pip uninstall opencv-python opencv-python-headless -y && pip install opencv-python-headless --force-reinstall --no-deps && pose-server --check

Troubleshooting

If you see libGL.so.1: cannot open shared object file or No module named 'cv2':

pip uninstall opencv-python opencv-python-headless -y
pip install opencv-python-headless --force-reinstall --no-deps

Why this happens: The ultralytics package requires opencv-python>=4.6.0 which gets installed automatically. However, opencv-python requires libGL.so.1 which doesn't exist on headless servers (Codespaces, Docker, cloud VMs). The solution is to replace it with opencv-python-headless which provides the same functionality without the GUI dependencies.

From GitHub

pip install "caema-utils[all] @ git+https://github.com/msorozabal/Utils.git"
pip uninstall opencv-python opencv-python-headless -y
pip install opencv-python-headless --force-reinstall --no-deps
pose-server --check

Pose Estimation Module

AI-powered body pose analysis using YOLOv8 for biomechanical evaluation.

Features

  • Detects 17 body keypoints (COCO format)
  • Calculates biomechanical angles (neck, shoulders, spine, knees, etc.)
  • Generates text analysis of postural findings
  • Returns annotated images with skeleton overlay
  • Multiple input formats: file path, bytes, numpy array
  • Multiple output formats: bytes, base64, numpy array, file

Quick Start

from caema_utils.pose_estimation import PoseEstimator

# Initialize (downloads model on first run)
estimator = PoseEstimator(model_size="nano")

# Analyze from file
result = estimator.analyze("photo.jpg")

if result['success']:
    print(f"Confidence: {result['confidence']:.1%}")
    print(f"Analysis:\n{result['analysis']}")

    # Save annotated image
    with open("output.png", "wb") as f:
        f.write(result['annotated_image_bytes'])

Model Sizes

Size Model Speed Accuracy Use Case
nano yolov8n-pose Fastest Good Real-time, mobile
small yolov8s-pose Fast Better Balanced
medium yolov8m-pose Medium High Production
large yolov8l-pose Slow Higher Quality-critical
xlarge yolov8x-pose Slowest Highest Research

API Reference

PoseEstimator

class PoseEstimator:
    def __init__(self, model_size: str = "nano"):
        """
        Initialize pose estimator.

        Args:
            model_size: "nano", "small", "medium", "large", or "xlarge"
        """

    def analyze(
        self,
        image: Union[str, Path, bytes],
        output_format: str = "bytes",
        save_path: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        Analyze body posture from image.

        Args:
            image: Path to image file or image bytes
            output_format: "bytes", "base64", "array", or "file"
            save_path: If output_format="file", save path for annotated image

        Returns:
            {
                'success': bool,
                'keypoints': Dict[str, List[float]],  # name -> [x, y, confidence]
                'angles': Dict[str, float],  # angle_name -> degrees
                'confidence': float,  # 0-1
                'analysis': str,  # Text analysis
                'annotated_image_*': ...,  # Image in requested format
            }
        """

Response Structure

{
    'success': True,
    'keypoints': {
        'nose': [256.5, 128.3, 0.95],
        'left_shoulder': [200.1, 180.2, 0.92],
        'right_shoulder': [312.8, 178.9, 0.93],
        # ... 17 keypoints total
    },
    'angles': {
        'neck_tilt': 5.2,
        'shoulder_angle': 3.1,
        'hip_angle': 2.8,
        'spine_angle': 4.5,
        'left_elbow': 165.3,
        'right_elbow': 168.7,
        'left_knee': 175.2,
        'right_knee': 176.8,
    },
    'confidence': 0.93,
    'analysis': 'OK: Body alignment within normal parameters\nOK: No significant postural deviations detected',
    'annotated_image_bytes': b'...',  # PNG image with skeleton overlay
}

HTTP API Server

The module includes a built-in FastAPI server for HTTP access.

Start the Server

# Check dependencies first
pose-server --check

# Start server (localhost only)
pose-server --port 8005

# Accept connections from other machines
pose-server --host 0.0.0.0 --port 8005

# With auto-reload for development
pose-server --host 0.0.0.0 --port 8005 --reload

API Endpoints

Endpoint Method Description
/ GET API info
/health GET Health check
/analyze POST Full analysis (JSON + base64 image)
/analyze/image POST Returns annotated image directly
/analyze/json-only POST Analysis without image
/docs GET OpenAPI documentation

curl Examples

# Health check
curl http://localhost:8005/health

# Full analysis with annotated image (base64)
curl -X POST "http://localhost:8005/analyze" \
     -H "accept: application/json" \
     -F "file=@photo.jpg"

# Get annotated image directly (save to file)
curl -X POST "http://localhost:8005/analyze/image" \
     -F "file=@photo.jpg" \
     --output annotated.png

# JSON only (faster, no image)
curl -X POST "http://localhost:8005/analyze/json-only" \
     -F "file=@photo.jpg"

Complete Example: Test from Scratch (Codespaces/Cloud)

Run these commands step by step:

# Step 1: Install
pip install "caema-utils[all]"

# Step 2: Fix OpenCV (IMPORTANT: uninstall BOTH packages first)
pip uninstall opencv-python opencv-python-headless -y
pip install opencv-python-headless --force-reinstall --no-deps

# Step 3: Verify (should say "All dependencies OK!")
pose-server --check

# Step 4: Download a test image
curl -o test.jpg "https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=400"

# Step 5: Start server
pose-server --host 0.0.0.0 --port 8005 &
sleep 10

# Step 6: Test health endpoint
curl http://localhost:8005/health

# Step 7: Analyze the test image (JSON response)
curl -X POST "http://localhost:8005/analyze/json-only" -F "file=@test.jpg"

# Step 8: Get annotated image with skeleton overlay
curl -X POST "http://localhost:8005/analyze/image" -F "file=@test.jpg" --output result.png

# Step 9: Check the result file was created (should be > 10KB)
ls -la result.png

Testing from Another Machine

On the SERVER machine:

# Step 1: Install
pip install "caema-utils[all]"

# Step 2: Fix OpenCV
pip uninstall opencv-python opencv-python-headless -y
pip install opencv-python-headless --force-reinstall --no-deps

# Step 3: Verify
pose-server --check

# Step 4: Start server
pose-server --host 0.0.0.0 --port 8005

On the CLIENT machine:

# Replace <SERVER_IP> with actual IP
curl http://<SERVER_IP>:8005/health
curl -X POST "http://<SERVER_IP>:8005/analyze" -F "file=@your_image.jpg"
curl -X POST "http://<SERVER_IP>:8005/analyze/image" -F "file=@your_image.jpg" --output result.png

Note: Ensure port 8005 is open in your firewall (sudo ufw allow 8005 on Ubuntu).

Response Example

{
  "success": true,
  "filename": "photo.jpg",
  "keypoints": {
    "nose": [256.5, 128.3, 0.95],
    "left_shoulder": [200.1, 180.2, 0.92]
  },
  "angles": {
    "neck_tilt": 5.2,
    "shoulder_angle": 3.1
  },
  "confidence": 0.93,
  "analysis": "OK: Body alignment within normal parameters",
  "annotated_image_base64": "iVBORw0KGgoAAAANS..."
}

Integration Examples

FastAPI Integration

from fastapi import FastAPI, File, UploadFile
from caema_utils.pose_estimation import PoseEstimator

app = FastAPI()
estimator = PoseEstimator(model_size="nano")

@app.post("/api/analyze")
async def analyze(file: UploadFile = File(...)):
    content = await file.read()
    result = estimator.analyze(content, output_format="base64")
    return result

Flask Integration

from flask import Flask, request, jsonify
from caema_utils.pose_estimation import PoseEstimator

app = Flask(__name__)
estimator = PoseEstimator(model_size="nano")

@app.route('/analyze', methods=['POST'])
def analyze():
    file = request.files['image']
    result = estimator.analyze(file.read())
    return jsonify(result)

Async Usage

import asyncio
from concurrent.futures import ThreadPoolExecutor
from caema_utils.pose_estimation import PoseEstimator

estimator = PoseEstimator()
executor = ThreadPoolExecutor(max_workers=4)

async def analyze_async(image_bytes):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(
        executor,
        estimator.analyze,
        image_bytes
    )

Keypoint Reference

The module detects 17 body keypoints in COCO format:

Index Name Description
0 nose Nose tip
1 left_eye Left eye
2 right_eye Right eye
3 left_ear Left ear
4 right_ear Right ear
5 left_shoulder Left shoulder
6 right_shoulder Right shoulder
7 left_elbow Left elbow
8 right_elbow Right elbow
9 left_wrist Left wrist
10 right_wrist Right wrist
11 left_hip Left hip
12 right_hip Right hip
13 left_knee Left knee
14 right_knee Right knee
15 left_ankle Left ankle
16 right_ankle Right ankle

Calculated Angles

Angle Description Normal Range
neck_tilt Head tilt from vertical < 10°
shoulder_angle Shoulder level asymmetry < 5°
hip_angle Hip level asymmetry < 5°
spine_angle Spinal lateral deviation < 8°
left_elbow Left elbow flexion 0-180°
right_elbow Right elbow flexion 0-180°
left_knee Left knee flexion 160-190°
right_knee Right knee flexion 160-190°

Development

Running Tests

# Install dev dependencies
pip install -e ".[all,dev]"

# Run tests
pytest tests/ -v

# Run with coverage
pytest tests/ --cov=caema_utils --cov-report=term-missing

Code Quality

# Format code
black src/ tests/

# Lint
ruff src/ tests/

# Type check
mypy src/

Requirements

  • Python 3.9+
  • For pose estimation:
    • numpy < 2.0.0
    • ultralytics >= 8.1.0
    • opencv-python-headless >= 4.9.0
  • For HTTP server:
    • fastapi >= 0.100.0
    • uvicorn >= 0.23.0
    • python-multipart >= 0.0.6

License

MIT License - see LICENSE file.


Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

caema_utils-0.1.4.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

caema_utils-0.1.4-py3-none-any.whl (17.8 kB view details)

Uploaded Python 3

File details

Details for the file caema_utils-0.1.4.tar.gz.

File metadata

  • Download URL: caema_utils-0.1.4.tar.gz
  • Upload date:
  • Size: 21.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.1

File hashes

Hashes for caema_utils-0.1.4.tar.gz
Algorithm Hash digest
SHA256 bfdb8cdff8f4de5eadad8dad6bb5ee97fafbffa5aa85ff7e2a2d8deb5ce6afc5
MD5 a31bccd8b020390d69ed37b780d06c42
BLAKE2b-256 1729d9901fdf93587f9b27fa09fd42a87f467ef1dd2ad910e3013c35dadb27f5

See more details on using hashes here.

File details

Details for the file caema_utils-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: caema_utils-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 17.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.1

File hashes

Hashes for caema_utils-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 0f5abc81d14d6d035f9e623c5d34665a73f31bd10d13c043321ffdfe9c02ceb1
MD5 50b2f96687c1fc3bb7fb165d27f22eab
BLAKE2b-256 6bba022c7c4436c510f61fec438edc5d6e0240491d799146a18105a7701351f3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page