fix: reconstruct missing placeholders + fix SQL column names
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s

Added missing placeholders:
- caliper_summary, circ_summary (body measurements)
- goal_weight, goal_bf_pct (goals from profile)
- nutrition_days (count of nutrition entries)
- protein_ziel_low/high (calculated from weight)

Fixed SQL errors:
- protein → protein_g
- fat → fat_g
- carb → carbs_g

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-26 09:03:35 +01:00
parent f4d1fd4de1
commit 0f2b85c6de

View File

@ -79,9 +79,19 @@ def get_nutrition_avg(profile_id: str, field: str, days: int = 30) -> str:
with get_db() as conn: with get_db() as conn:
cur = get_cursor(conn) cur = get_cursor(conn)
cutoff = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d') cutoff = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d')
# Map field names to actual column names
field_map = {
'protein': 'protein_g',
'fat': 'fat_g',
'carb': 'carbs_g',
'kcal': 'kcal'
}
db_field = field_map.get(field, field)
cur.execute( cur.execute(
f"""SELECT AVG({field}) as avg FROM nutrition_log f"""SELECT AVG({db_field}) as avg FROM nutrition_log
WHERE profile_id=%s AND date >= %s AND {field} IS NOT NULL""", WHERE profile_id=%s AND date >= %s AND {db_field} IS NOT NULL""",
(profile_id, cutoff) (profile_id, cutoff)
) )
row = cur.fetchone() row = cur.fetchone()
@ -93,6 +103,105 @@ def get_nutrition_avg(profile_id: str, field: str, days: int = 30) -> str:
return "nicht verfügbar" return "nicht verfügbar"
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 bf_jpl, bf_katch, date FROM caliper_log
WHERE profile_id=%s AND bf_jpl IS NOT NULL
ORDER BY date DESC LIMIT 1""",
(profile_id,)
)
row = r2d(cur.fetchone()) if cur.rowcount > 0 else None
if not row:
return "keine Caliper-Messungen"
return f"JPL: {row['bf_jpl']:.1f}% (Katch: {row['bf_katch']:.1f}% am {row['date']})"
def get_circ_summary(profile_id: str) -> str:
"""Get latest circumference measurements summary."""
with get_db() as conn:
cur = get_cursor(conn)
cur.execute(
"""SELECT brust, taille, huefte, date FROM circumference_log
WHERE profile_id=%s
ORDER BY date DESC LIMIT 1""",
(profile_id,)
)
row = r2d(cur.fetchone()) if cur.rowcount > 0 else None
if not row:
return "keine Umfangsmessungen"
parts = []
if row.get('brust'): parts.append(f"Brust {row['brust']}cm")
if row.get('taille'): parts.append(f"Taille {row['taille']}cm")
if row.get('huefte'): parts.append(f"Hüfte {row['huefte']}cm")
return f"{', '.join(parts)} ({row['date']})" if parts else "keine Daten"
def get_goal_weight(profile_id: str) -> str:
"""Get goal weight from profile."""
profile = get_profile_data(profile_id)
goal = profile.get('goal_weight')
return f"{goal:.1f}" if goal else "nicht gesetzt"
def get_goal_bf_pct(profile_id: str) -> str:
"""Get goal body fat percentage from profile."""
profile = get_profile_data(profile_id)
goal = profile.get('goal_bf_pct')
return f"{goal:.1f}" if goal else "nicht gesetzt"
def get_nutrition_days(profile_id: str, days: int = 30) -> str:
"""Get number of days with nutrition data."""
with get_db() as conn:
cur = get_cursor(conn)
cutoff = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d')
cur.execute(
"""SELECT COUNT(DISTINCT date) as days FROM nutrition_log
WHERE profile_id=%s AND date >= %s""",
(profile_id, cutoff)
)
row = cur.fetchone()
return str(row['days']) if row else "0"
def get_protein_ziel_low(profile_id: str) -> str:
"""Calculate lower protein target based on current weight (1.6g/kg)."""
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()
if row:
return f"{int(row['weight'] * 1.6)}"
return "nicht verfügbar"
def get_protein_ziel_high(profile_id: str) -> str:
"""Calculate upper protein target based on current weight (2.2g/kg)."""
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()
if row:
return f"{int(row['weight'] * 2.2)}"
return "nicht verfügbar"
def get_activity_summary(profile_id: str, days: int = 14) -> str: def get_activity_summary(profile_id: str, days: int = 14) -> str:
"""Get activity summary for recent period.""" """Get activity summary for recent period."""
with get_db() as conn: with get_db() as conn:
@ -194,12 +303,19 @@ PLACEHOLDER_MAP: Dict[str, Callable[[str], str]] = {
'{{weight_trend}}': get_weight_trend, '{{weight_trend}}': get_weight_trend,
'{{kf_aktuell}}': get_latest_bf, '{{kf_aktuell}}': get_latest_bf,
'{{bmi}}': lambda pid: calculate_bmi(pid), '{{bmi}}': lambda pid: calculate_bmi(pid),
'{{caliper_summary}}': get_caliper_summary,
'{{circ_summary}}': get_circ_summary,
'{{goal_weight}}': get_goal_weight,
'{{goal_bf_pct}}': get_goal_bf_pct,
# Ernährung # Ernährung
'{{kcal_avg}}': lambda pid: get_nutrition_avg(pid, 'kcal', 30), '{{kcal_avg}}': lambda pid: get_nutrition_avg(pid, 'kcal', 30),
'{{protein_avg}}': lambda pid: get_nutrition_avg(pid, 'protein', 30), '{{protein_avg}}': lambda pid: get_nutrition_avg(pid, 'protein', 30),
'{{carb_avg}}': lambda pid: get_nutrition_avg(pid, 'carb', 30), '{{carb_avg}}': lambda pid: get_nutrition_avg(pid, 'carb', 30),
'{{fat_avg}}': lambda pid: get_nutrition_avg(pid, 'fat', 30), '{{fat_avg}}': lambda pid: get_nutrition_avg(pid, 'fat', 30),
'{{nutrition_days}}': lambda pid: get_nutrition_days(pid, 30),
'{{protein_ziel_low}}': get_protein_ziel_low,
'{{protein_ziel_high}}': get_protein_ziel_high,
# Training # Training
'{{activity_summary}}': get_activity_summary, '{{activity_summary}}': get_activity_summary,