mitai-jinkendo/backend/routers/evaluation.py
Lars 1b9cd6d5e6
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
feat: Training Type Profiles - Phase 1.1 Foundation (#15)
## Implemented

### DB-Schema (Migrations)
- Migration 013: training_parameters table (16 standard parameters)
- Migration 014: training_types.profile + activity_log.evaluation columns
- Performance metric calculations (avg_hr_percent, kcal_per_km)

### Backend - Rule Engine
- RuleEvaluator: Generic rule evaluation with 9 operators
  - gte, lte, gt, lt, eq, neq, between, in, not_in
  - Weighted scoring system
  - Pass strategies: all_must_pass, weighted_score, at_least_n

- IntensityZoneEvaluator: HR zone analysis
- TrainingEffectsEvaluator: Abilities development

### Backend - Master Evaluator
- TrainingProfileEvaluator: 7-dimensional evaluation
  1. Minimum Requirements (Quality Gates)
  2. Intensity Zones (HR zones)
  3. Training Effects (Abilities)
  4. Periodization (Frequency & Recovery)
  5. Performance Indicators (KPIs)
  6. Safety (Warnings)
  7. AI Context (simplified for MVP)

- evaluation_helper.py: Utilities for loading + saving
- routers/evaluation.py: API endpoints
  - POST /api/evaluation/activity/{id}
  - POST /api/evaluation/batch
  - GET /api/evaluation/parameters

### Integration
- main.py: Router registration

## TODO (Phase 1.2)
- Auto-evaluation on activity INSERT/UPDATE
- Admin-UI for profile editing
- User-UI for results display

## Testing
-  Syntax checks passed
- 🔲 Runtime testing pending (after auto-evaluation)

Part of Issue #15 - Training Type Profiles System
2026-03-23 10:49:26 +01:00

147 lines
3.7 KiB
Python

"""
Evaluation Endpoints - Training Type Profiles
Endpoints for activity evaluation and re-evaluation.
Issue: #15
Date: 2026-03-23
"""
import logging
from typing import Optional
from fastapi import APIRouter, HTTPException, Depends
from db import get_db, get_cursor, r2d
from auth import require_auth, require_admin
from evaluation_helper import (
evaluate_and_save_activity,
batch_evaluate_activities,
load_parameters_registry
)
router = APIRouter(prefix="/api/evaluation", tags=["evaluation"])
logger = logging.getLogger(__name__)
@router.get("/parameters")
def list_parameters(session: dict = Depends(require_auth)):
"""
List all available training parameters.
"""
with get_db() as conn:
cur = get_cursor(conn)
parameters = load_parameters_registry(cur)
return {
"parameters": list(parameters.values()),
"count": len(parameters)
}
@router.post("/activity/{activity_id}")
def evaluate_activity(
activity_id: str,
session: dict = Depends(require_auth)
):
"""
Evaluates or re-evaluates a single activity.
Returns the evaluation result.
"""
profile_id = session['profile_id']
with get_db() as conn:
cur = get_cursor(conn)
# Load activity
cur.execute("""
SELECT id, profile_id, date, training_type_id, duration_min,
hr_avg, hr_max, distance_km, kcal_active, kcal_resting,
rpe, pace_min_per_km, cadence, elevation_gain
FROM activity_log
WHERE id = %s AND profile_id = %s
""", (activity_id, profile_id))
activity = cur.fetchone()
if not activity:
raise HTTPException(404, "Activity not found")
activity_dict = dict(activity)
# Evaluate
result = evaluate_and_save_activity(
cur,
activity_dict["id"],
activity_dict,
activity_dict["training_type_id"],
profile_id
)
if not result:
return {
"message": "No profile configured for this training type",
"evaluation": None
}
return {
"message": "Activity evaluated",
"evaluation": result
}
@router.post("/batch")
def batch_evaluate(
limit: Optional[int] = None,
session: dict = Depends(require_auth)
):
"""
Re-evaluates all activities for the current user.
Optional limit parameter for testing.
"""
profile_id = session['profile_id']
with get_db() as conn:
cur = get_cursor(conn)
stats = batch_evaluate_activities(cur, profile_id, limit)
return {
"message": "Batch evaluation completed",
"stats": stats
}
@router.post("/batch/all")
def batch_evaluate_all(session: dict = Depends(require_admin)):
"""
Admin-only: Re-evaluates all activities for all users.
Use with caution on large databases!
"""
with get_db() as conn:
cur = get_cursor(conn)
# Get all profiles
cur.execute("SELECT id FROM profiles")
profiles = cur.fetchall()
total_stats = {
"profiles": len(profiles),
"total": 0,
"evaluated": 0,
"skipped": 0,
"errors": 0
}
for profile in profiles:
profile_id = profile['id']
stats = batch_evaluate_activities(cur, profile_id)
total_stats["total"] += stats["total"]
total_stats["evaluated"] += stats["evaluated"]
total_stats["skipped"] += stats["skipped"]
total_stats["errors"] += stats["errors"]
return {
"message": "Batch evaluation for all users completed",
"stats": total_stats
}