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',
|
'serialize_dates',
|
||||||
|
|
||||||
# Body Metrics
|
# Body Metrics
|
||||||
|
'get_latest_weight_data',
|
||||||
'get_weight_trend_data',
|
'get_weight_trend_data',
|
||||||
'get_body_composition_data',
|
'get_body_composition_data',
|
||||||
'get_circumference_summary_data',
|
'get_circumference_summary_data',
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ Body Metrics Data Layer
|
||||||
Provides structured data for body composition and measurements.
|
Provides structured data for body composition and measurements.
|
||||||
|
|
||||||
Functions:
|
Functions:
|
||||||
|
- get_latest_weight_data(): Most recent weight entry
|
||||||
- get_weight_trend_data(): Weight trend with slope and direction
|
- get_weight_trend_data(): Weight trend with slope and direction
|
||||||
- get_body_composition_data(): Body fat percentage and lean mass
|
- get_body_composition_data(): Body fat percentage and lean mass
|
||||||
- get_circumference_summary_data(): Latest circumference measurements
|
- 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
|
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(
|
def get_weight_trend_data(
|
||||||
profile_id: str,
|
profile_id: str,
|
||||||
days: int = 28
|
days: int = 28
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from db import get_db, get_cursor, r2d
|
||||||
|
|
||||||
# Phase 0c: Import data layer
|
# Phase 0c: Import data layer
|
||||||
from data_layer.body_metrics import (
|
from data_layer.body_metrics import (
|
||||||
|
get_latest_weight_data,
|
||||||
get_weight_trend_data,
|
get_weight_trend_data,
|
||||||
get_body_composition_data,
|
get_body_composition_data,
|
||||||
get_circumference_summary_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]:
|
def get_latest_weight(profile_id: str) -> Optional[str]:
|
||||||
"""Get latest weight entry."""
|
"""
|
||||||
with get_db() as conn:
|
Get latest weight entry.
|
||||||
cur = get_cursor(conn)
|
|
||||||
cur.execute(
|
Phase 0c: Refactored to use data_layer.body_metrics.get_latest_weight_data()
|
||||||
"SELECT weight FROM weight_log WHERE profile_id=%s ORDER BY date DESC LIMIT 1",
|
This function now only FORMATS the data for AI consumption.
|
||||||
(profile_id,)
|
"""
|
||||||
)
|
data = get_latest_weight_data(profile_id)
|
||||||
row = cur.fetchone()
|
|
||||||
return f"{row['weight']:.1f} kg" if row else "nicht verfügbar"
|
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:
|
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:
|
def get_caliper_summary(profile_id: str) -> str:
|
||||||
"""Get latest caliper measurements summary."""
|
"""
|
||||||
with get_db() as conn:
|
Get latest caliper measurements summary.
|
||||||
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
|
|
||||||
|
|
||||||
if not row:
|
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)
|
||||||
|
|
||||||
|
if data['confidence'] == 'insufficient':
|
||||||
return "keine Caliper-Messungen"
|
return "keine Caliper-Messungen"
|
||||||
|
|
||||||
method = row.get('sf_method', 'unbekannt')
|
method = data.get('method', 'unbekannt')
|
||||||
return f"{row['body_fat_pct']:.1f}% ({method} am {row['date']})"
|
return f"{data['body_fat_pct']:.1f}% ({method} am {data['date']})"
|
||||||
|
|
||||||
|
|
||||||
def get_circ_summary(profile_id: str) -> str:
|
def get_circ_summary(profile_id: str) -> str:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user