feat: Phase 0c - body_metrics.py module complete
Data Layer: - get_latest_weight_data() - most recent weight with date - get_weight_trend_data() - already existed (PoC) - get_body_composition_data() - already existed (PoC) - get_circumference_summary_data() - already existed (PoC) Placeholder Layer: - get_latest_weight() - refactored to use data layer - get_caliper_summary() - refactored to use get_body_composition_data - get_weight_trend() - already refactored (PoC) - get_latest_bf() - already refactored (PoC) - get_circ_summary() - already refactored (PoC) body_metrics.py now complete with all 4 functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b4558b0582
commit
6c23973c5d
|
|
@ -45,6 +45,7 @@ __all__ = [
|
|||
'serialize_dates',
|
||||
|
||||
# Body Metrics
|
||||
'get_latest_weight_data',
|
||||
'get_weight_trend_data',
|
||||
'get_body_composition_data',
|
||||
'get_circumference_summary_data',
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Body Metrics Data Layer
|
|||
Provides structured data for body composition and measurements.
|
||||
|
||||
Functions:
|
||||
- get_latest_weight_data(): Most recent weight entry
|
||||
- get_weight_trend_data(): Weight trend with slope and direction
|
||||
- get_body_composition_data(): Body fat percentage and lean mass
|
||||
- get_circumference_summary_data(): Latest circumference measurements
|
||||
|
|
@ -21,6 +22,51 @@ from db import get_db, get_cursor, r2d
|
|||
from data_layer.utils import calculate_confidence, safe_float
|
||||
|
||||
|
||||
def get_latest_weight_data(
|
||||
profile_id: str
|
||||
) -> Dict:
|
||||
"""
|
||||
Get most recent weight entry.
|
||||
|
||||
Args:
|
||||
profile_id: User profile ID
|
||||
|
||||
Returns:
|
||||
{
|
||||
"weight": float, # kg
|
||||
"date": date,
|
||||
"confidence": str
|
||||
}
|
||||
|
||||
Migration from Phase 0b:
|
||||
OLD: get_latest_weight() returned formatted string "85.0 kg"
|
||||
NEW: Returns structured data {"weight": 85.0, "date": ...}
|
||||
"""
|
||||
with get_db() as conn:
|
||||
cur = get_cursor(conn)
|
||||
cur.execute(
|
||||
"""SELECT weight, date FROM weight_log
|
||||
WHERE profile_id=%s
|
||||
ORDER BY date DESC
|
||||
LIMIT 1""",
|
||||
(profile_id,)
|
||||
)
|
||||
row = cur.fetchone()
|
||||
|
||||
if not row:
|
||||
return {
|
||||
"weight": 0.0,
|
||||
"date": None,
|
||||
"confidence": "insufficient"
|
||||
}
|
||||
|
||||
return {
|
||||
"weight": safe_float(row['weight']),
|
||||
"date": row['date'],
|
||||
"confidence": "high"
|
||||
}
|
||||
|
||||
|
||||
def get_weight_trend_data(
|
||||
profile_id: str,
|
||||
days: int = 28
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from db import get_db, get_cursor, r2d
|
|||
|
||||
# Phase 0c: Import data layer
|
||||
from data_layer.body_metrics import (
|
||||
get_latest_weight_data,
|
||||
get_weight_trend_data,
|
||||
get_body_composition_data,
|
||||
get_circumference_summary_data
|
||||
|
|
@ -51,15 +52,18 @@ def get_profile_data(profile_id: str) -> Dict:
|
|||
|
||||
|
||||
def get_latest_weight(profile_id: str) -> Optional[str]:
|
||||
"""Get latest weight entry."""
|
||||
with get_db() as conn:
|
||||
cur = get_cursor(conn)
|
||||
cur.execute(
|
||||
"SELECT weight FROM weight_log WHERE profile_id=%s ORDER BY date DESC LIMIT 1",
|
||||
(profile_id,)
|
||||
)
|
||||
row = cur.fetchone()
|
||||
return f"{row['weight']:.1f} kg" if row else "nicht verfügbar"
|
||||
"""
|
||||
Get latest weight entry.
|
||||
|
||||
Phase 0c: Refactored to use data_layer.body_metrics.get_latest_weight_data()
|
||||
This function now only FORMATS the data for AI consumption.
|
||||
"""
|
||||
data = get_latest_weight_data(profile_id)
|
||||
|
||||
if data['confidence'] == 'insufficient':
|
||||
return "nicht verfügbar"
|
||||
|
||||
return f"{data['weight']:.1f} kg"
|
||||
|
||||
|
||||
def get_weight_trend(profile_id: str, days: int = 28) -> str:
|
||||
|
|
@ -129,22 +133,19 @@ def get_nutrition_avg(profile_id: str, field: str, days: int = 30) -> str:
|
|||
|
||||
|
||||
def get_caliper_summary(profile_id: str) -> str:
|
||||
"""Get latest caliper measurements summary."""
|
||||
with get_db() as conn:
|
||||
cur = get_cursor(conn)
|
||||
cur.execute(
|
||||
"""SELECT body_fat_pct, sf_method, date FROM caliper_log
|
||||
WHERE profile_id=%s AND body_fat_pct IS NOT NULL
|
||||
ORDER BY date DESC LIMIT 1""",
|
||||
(profile_id,)
|
||||
)
|
||||
row = r2d(cur.fetchone()) if cur.rowcount > 0 else None
|
||||
"""
|
||||
Get latest caliper measurements summary.
|
||||
|
||||
if not row:
|
||||
return "keine Caliper-Messungen"
|
||||
Phase 0c: Refactored to use data_layer.body_metrics.get_body_composition_data()
|
||||
This function now only FORMATS the data for AI consumption.
|
||||
"""
|
||||
data = get_body_composition_data(profile_id)
|
||||
|
||||
method = row.get('sf_method', 'unbekannt')
|
||||
return f"{row['body_fat_pct']:.1f}% ({method} am {row['date']})"
|
||||
if data['confidence'] == 'insufficient':
|
||||
return "keine Caliper-Messungen"
|
||||
|
||||
method = data.get('method', 'unbekannt')
|
||||
return f"{data['body_fat_pct']:.1f}% ({method} am {data['date']})"
|
||||
|
||||
|
||||
def get_circ_summary(profile_id: str) -> str:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user