fix: Phase 0b - score functions use English focus area keys
Root cause: All 3 score functions returned None because they queried German focus area keys that don't exist in database (migration 031 uses English keys). Changes: - body_progress_score: körpergewicht/körperfett/muskelmasse → weight_loss/muscle_gain/body_recomposition - nutrition_score: ernährung_basis/proteinzufuhr/kalorienbilanz → protein_intake/calorie_balance/macro_consistency/meal_timing/hydration - activity_score: kraftaufbau/cardio/bewegungsumfang/trainingsqualität → strength/aerobic_endurance/flexibility/rhythm/coordination (grouped) Result: Scores now calculate correctly with existing focus area weights. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
63bd103b2c
commit
cc76ae677b
|
|
@ -341,59 +341,72 @@ def calculate_activity_score(profile_id: str, focus_weights: Optional[Dict] = No
|
|||
from calculations.scores import get_user_focus_weights
|
||||
focus_weights = get_user_focus_weights(profile_id)
|
||||
|
||||
# Activity-related focus areas
|
||||
activity_focus = {
|
||||
'kraftaufbau': focus_weights.get('kraftaufbau', 0),
|
||||
'cardio': focus_weights.get('cardio', 0),
|
||||
'bewegungsumfang': focus_weights.get('bewegungsumfang', 0),
|
||||
'trainingsqualität': focus_weights.get('trainingsqualität', 0),
|
||||
'ability_balance': focus_weights.get('ability_balance', 0),
|
||||
}
|
||||
# Activity-related focus areas (English keys from DB)
|
||||
# Strength training
|
||||
strength = focus_weights.get('strength', 0)
|
||||
strength_endurance = focus_weights.get('strength_endurance', 0)
|
||||
power = focus_weights.get('power', 0)
|
||||
total_strength = strength + strength_endurance + power
|
||||
|
||||
total_activity_weight = sum(activity_focus.values())
|
||||
# Endurance training
|
||||
aerobic = focus_weights.get('aerobic_endurance', 0)
|
||||
anaerobic = focus_weights.get('anaerobic_endurance', 0)
|
||||
cardiovascular = focus_weights.get('cardiovascular_health', 0)
|
||||
total_cardio = aerobic + anaerobic + cardiovascular
|
||||
|
||||
# Mobility/Coordination
|
||||
flexibility = focus_weights.get('flexibility', 0)
|
||||
mobility = focus_weights.get('mobility', 0)
|
||||
balance = focus_weights.get('balance', 0)
|
||||
reaction = focus_weights.get('reaction', 0)
|
||||
rhythm = focus_weights.get('rhythm', 0)
|
||||
coordination = focus_weights.get('coordination', 0)
|
||||
total_ability = flexibility + mobility + balance + reaction + rhythm + coordination
|
||||
|
||||
total_activity_weight = total_strength + total_cardio + total_ability
|
||||
|
||||
if total_activity_weight == 0:
|
||||
return None # No activity goals
|
||||
|
||||
components = []
|
||||
|
||||
# 1. Weekly minutes (if bewegungsumfang goal)
|
||||
if activity_focus['bewegungsumfang'] > 0:
|
||||
minutes = calculate_training_minutes_week(profile_id)
|
||||
if minutes is not None:
|
||||
# WHO: 150-300 min/week
|
||||
if 150 <= minutes <= 300:
|
||||
minutes_score = 100
|
||||
elif minutes < 150:
|
||||
minutes_score = max(40, (minutes / 150) * 100)
|
||||
else:
|
||||
minutes_score = max(80, 100 - ((minutes - 300) / 10))
|
||||
# 1. Weekly minutes (general activity volume)
|
||||
minutes = calculate_training_minutes_week(profile_id)
|
||||
if minutes is not None:
|
||||
# WHO: 150-300 min/week
|
||||
if 150 <= minutes <= 300:
|
||||
minutes_score = 100
|
||||
elif minutes < 150:
|
||||
minutes_score = max(40, (minutes / 150) * 100)
|
||||
else:
|
||||
minutes_score = max(80, 100 - ((minutes - 300) / 10))
|
||||
|
||||
components.append(('minutes', minutes_score, activity_focus['bewegungsumfang']))
|
||||
# Volume relevant for all activity types (20% base weight)
|
||||
components.append(('minutes', minutes_score, total_activity_weight * 0.2))
|
||||
|
||||
# 2. Quality sessions (if trainingsqualität goal)
|
||||
if activity_focus['trainingsqualität'] > 0:
|
||||
quality_pct = calculate_quality_sessions_pct(profile_id)
|
||||
if quality_pct is not None:
|
||||
components.append(('quality', quality_pct, activity_focus['trainingsqualität']))
|
||||
# 2. Quality sessions (always relevant)
|
||||
quality_pct = calculate_quality_sessions_pct(profile_id)
|
||||
if quality_pct is not None:
|
||||
# Quality gets 10% base weight
|
||||
components.append(('quality', quality_pct, total_activity_weight * 0.1))
|
||||
|
||||
# 3. Strength presence (if kraftaufbau goal)
|
||||
if activity_focus['kraftaufbau'] > 0:
|
||||
# 3. Strength presence (if strength focus active)
|
||||
if total_strength > 0:
|
||||
strength_score = _score_strength_presence(profile_id)
|
||||
if strength_score is not None:
|
||||
components.append(('strength', strength_score, activity_focus['kraftaufbau']))
|
||||
components.append(('strength', strength_score, total_strength))
|
||||
|
||||
# 4. Cardio presence (if cardio goal)
|
||||
if activity_focus['cardio'] > 0:
|
||||
# 4. Cardio presence (if cardio focus active)
|
||||
if total_cardio > 0:
|
||||
cardio_score = _score_cardio_presence(profile_id)
|
||||
if cardio_score is not None:
|
||||
components.append(('cardio', cardio_score, activity_focus['cardio']))
|
||||
components.append(('cardio', cardio_score, total_cardio))
|
||||
|
||||
# 5. Ability balance (if ability_balance goal)
|
||||
if activity_focus['ability_balance'] > 0:
|
||||
# 5. Ability balance (if mobility/coordination focus active)
|
||||
if total_ability > 0:
|
||||
balance_score = _score_ability_balance(profile_id)
|
||||
if balance_score is not None:
|
||||
components.append(('balance', balance_score, activity_focus['ability_balance']))
|
||||
components.append(('balance', balance_score, total_ability))
|
||||
|
||||
if not components:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -339,12 +339,12 @@ def calculate_body_progress_score(profile_id: str, focus_weights: Optional[Dict]
|
|||
from calculations.scores import get_user_focus_weights
|
||||
focus_weights = get_user_focus_weights(profile_id)
|
||||
|
||||
# Get all body-related focus area weights
|
||||
body_weight = focus_weights.get('körpergewicht', 0)
|
||||
body_fat_weight = focus_weights.get('körperfett', 0)
|
||||
muscle_weight = focus_weights.get('muskelmasse', 0)
|
||||
# Get all body-related focus area weights (English keys from DB)
|
||||
weight_loss = focus_weights.get('weight_loss', 0)
|
||||
muscle_gain = focus_weights.get('muscle_gain', 0)
|
||||
body_recomp = focus_weights.get('body_recomposition', 0)
|
||||
|
||||
total_body_weight = body_weight + body_fat_weight + muscle_weight
|
||||
total_body_weight = weight_loss + muscle_gain + body_recomp
|
||||
|
||||
if total_body_weight == 0:
|
||||
return None # No body-related goals
|
||||
|
|
@ -352,23 +352,23 @@ def calculate_body_progress_score(profile_id: str, focus_weights: Optional[Dict]
|
|||
# Calculate component scores (0-100)
|
||||
components = []
|
||||
|
||||
# Weight trend component (if weight goal active)
|
||||
if body_weight > 0:
|
||||
# Weight trend component (if weight loss goal active)
|
||||
if weight_loss > 0:
|
||||
weight_score = _score_weight_trend(profile_id)
|
||||
if weight_score is not None:
|
||||
components.append(('weight', weight_score, body_weight))
|
||||
components.append(('weight', weight_score, weight_loss))
|
||||
|
||||
# Body composition component (if BF% or LBM goal active)
|
||||
if body_fat_weight > 0 or muscle_weight > 0:
|
||||
# Body composition component (if muscle gain or recomp goal active)
|
||||
if muscle_gain > 0 or body_recomp > 0:
|
||||
comp_score = _score_body_composition(profile_id)
|
||||
if comp_score is not None:
|
||||
components.append(('composition', comp_score, body_fat_weight + muscle_weight))
|
||||
components.append(('composition', comp_score, muscle_gain + body_recomp))
|
||||
|
||||
# Waist circumference component (proxy for health)
|
||||
waist_score = _score_waist_trend(profile_id)
|
||||
if waist_score is not None:
|
||||
# Waist gets 20% base weight + bonus from BF% goals
|
||||
waist_weight = 20 + (body_fat_weight * 0.3)
|
||||
# Waist gets 20% base weight + bonus from weight loss goals
|
||||
waist_weight = 20 + (weight_loss * 0.3)
|
||||
components.append(('waist', waist_score, waist_weight))
|
||||
|
||||
if not components:
|
||||
|
|
|
|||
|
|
@ -341,45 +341,44 @@ def calculate_nutrition_score(profile_id: str, focus_weights: Optional[Dict] = N
|
|||
from calculations.scores import get_user_focus_weights
|
||||
focus_weights = get_user_focus_weights(profile_id)
|
||||
|
||||
# Nutrition-related focus areas
|
||||
nutrition_focus = {
|
||||
'ernährung_basis': focus_weights.get('ernährung_basis', 0),
|
||||
'ernährung_makros': focus_weights.get('ernährung_makros', 0),
|
||||
'proteinzufuhr': focus_weights.get('proteinzufuhr', 0),
|
||||
'kalorienbilanz': focus_weights.get('kalorienbilanz', 0),
|
||||
}
|
||||
# Nutrition-related focus areas (English keys from DB)
|
||||
protein_intake = focus_weights.get('protein_intake', 0)
|
||||
calorie_balance = focus_weights.get('calorie_balance', 0)
|
||||
macro_consistency = focus_weights.get('macro_consistency', 0)
|
||||
meal_timing = focus_weights.get('meal_timing', 0)
|
||||
hydration = focus_weights.get('hydration', 0)
|
||||
|
||||
total_nutrition_weight = sum(nutrition_focus.values())
|
||||
total_nutrition_weight = protein_intake + calorie_balance + macro_consistency + meal_timing + hydration
|
||||
|
||||
if total_nutrition_weight == 0:
|
||||
return None # No nutrition goals
|
||||
|
||||
components = []
|
||||
|
||||
# 1. Calorie target adherence (if kalorienbilanz goal active)
|
||||
if nutrition_focus['kalorienbilanz'] > 0:
|
||||
# 1. Calorie target adherence (if calorie_balance goal active)
|
||||
if calorie_balance > 0:
|
||||
calorie_score = _score_calorie_adherence(profile_id)
|
||||
if calorie_score is not None:
|
||||
components.append(('calories', calorie_score, nutrition_focus['kalorienbilanz']))
|
||||
components.append(('calories', calorie_score, calorie_balance))
|
||||
|
||||
# 2. Protein target adherence (always important if any nutrition goal)
|
||||
protein_score = calculate_protein_adequacy_28d(profile_id)
|
||||
if protein_score is not None:
|
||||
# Higher weight if protein-specific goal
|
||||
protein_weight = nutrition_focus['proteinzufuhr'] or (total_nutrition_weight * 0.3)
|
||||
components.append(('protein', protein_score, protein_weight))
|
||||
# 2. Protein target adherence (if protein_intake goal active)
|
||||
if protein_intake > 0:
|
||||
protein_score = calculate_protein_adequacy_28d(profile_id)
|
||||
if protein_score is not None:
|
||||
components.append(('protein', protein_score, protein_intake))
|
||||
|
||||
# 3. Intake consistency (always relevant)
|
||||
consistency_score = calculate_macro_consistency_score(profile_id)
|
||||
if consistency_score is not None:
|
||||
consistency_weight = total_nutrition_weight * 0.2
|
||||
components.append(('consistency', consistency_score, consistency_weight))
|
||||
# 3. Intake consistency (if macro_consistency goal active)
|
||||
if macro_consistency > 0:
|
||||
consistency_score = calculate_macro_consistency_score(profile_id)
|
||||
if consistency_score is not None:
|
||||
components.append(('consistency', consistency_score, macro_consistency))
|
||||
|
||||
# 4. Macro balance (if makros goal active)
|
||||
if nutrition_focus['ernährung_makros'] > 0:
|
||||
# 4. Macro balance (always relevant if any nutrition goal)
|
||||
if total_nutrition_weight > 0:
|
||||
macro_score = _score_macro_balance(profile_id)
|
||||
if macro_score is not None:
|
||||
components.append(('macros', macro_score, nutrition_focus['ernährung_makros']))
|
||||
# Use 20% of total weight for macro balance
|
||||
components.append(('macros', macro_score, total_nutrition_weight * 0.2))
|
||||
|
||||
if not components:
|
||||
return None
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user