- Added new functions for BMI and goal weight/body fat percentage retrieval in `body_metrics.py`. - Introduced training frequency and inter-session gap calculations in `activity_metrics.py`. - Updated placeholder registrations to include new metrics for nutrition and activity. - Improved data handling in `placeholder_resolver.py` for better integration of new metrics. - Enhanced documentation across modules to reflect the new functionalities. These updates improve the accuracy and comprehensiveness of health and fitness assessments within the application.
185 lines
8.3 KiB
Python
185 lines
8.3 KiB
Python
"""
|
|
Registry: Trainings-Häufigkeit, Pausen zwischen Einheiten, wöchentliche Session-JSON (KI-Rohkontext).
|
|
"""
|
|
|
|
from placeholder_registry import (
|
|
PlaceholderMetadata,
|
|
MissingValuePolicy,
|
|
EvidenceType,
|
|
OutputType,
|
|
PlaceholderType,
|
|
register_placeholder,
|
|
)
|
|
|
|
|
|
def _ev(meta: PlaceholderMetadata, field: str, et: EvidenceType = EvidenceType.CODE_DERIVED):
|
|
meta.set_evidence(field, et)
|
|
|
|
|
|
def register_activity_session_insights():
|
|
md_freq = PlaceholderMetadata(
|
|
key="training_frequency_by_type_md",
|
|
category="Aktivität",
|
|
description=(
|
|
"Markdown-Tabelle: pro Trainingsart (activity_type) Sessions, Ø/Woche, "
|
|
"Dauer, kcal, HF, RPE, kcal/min (Intensitätsproxy)"
|
|
),
|
|
resolver_module="backend/placeholder_resolver.py",
|
|
resolver_function="get_training_frequency_by_type_md",
|
|
data_layer_module="backend/data_layer/activity_metrics.py",
|
|
data_layer_function="get_training_frequency_by_type_data",
|
|
source_tables=["activity_log"],
|
|
semantic_contract=(
|
|
"Aggregat über activity_log gruppiert nach activity_type (Roh-Label). "
|
|
"sessions_per_week = count / (days/7). avg_kcal_per_min = Summe kcal / Summe min."
|
|
),
|
|
business_meaning="KI: Häufigkeit & Belastung pro Sportart, Erholungs-/Überlastungs-Kontext",
|
|
unit="Markdown",
|
|
time_window="default 28 Tage",
|
|
output_type=OutputType.TEXT_SUMMARY,
|
|
placeholder_type=PlaceholderType.INTERPRETED,
|
|
format_hint="GitHub-Flavored Markdown-Tabelle",
|
|
example_output="| Art | n | Ø/Woche | … |",
|
|
minimum_data_requirements="Mindestens eine Session im Fenster",
|
|
quality_filter_policy=None,
|
|
confidence_logic="Wie calculate_confidence anhand Session-Anzahl",
|
|
missing_value_policy=MissingValuePolicy(
|
|
available=False,
|
|
value_raw=None,
|
|
missing_reason="no_data",
|
|
legacy_display="Keine Trainingsdaten",
|
|
),
|
|
known_limitations=(
|
|
"Gruppierung nach activity_type-String (Import-Namen), nicht nur training_type_id. "
|
|
"HF/RPE oft NULL je nach Quelle. Pausen-Analyse separater Platzhalter."
|
|
),
|
|
layer_1_decision="activity_metrics.get_training_frequency_by_type_data",
|
|
layer_2a_decision="get_training_frequency_by_type_md",
|
|
layer_2b_reuse_possible=True,
|
|
architecture_alignment="Phase 0c",
|
|
issue_53_alignment="Layer 1",
|
|
evidence={},
|
|
)
|
|
for f in (
|
|
"key", "category", "description", "resolver_module", "resolver_function",
|
|
"data_layer_module", "data_layer_function", "source_tables", "semantic_contract",
|
|
"unit", "time_window", "output_type", "placeholder_type", "format_hint",
|
|
"example_output", "minimum_data_requirements", "confidence_logic",
|
|
"missing_value_policy", "layer_1_decision", "layer_2a_decision",
|
|
"layer_2b_reuse_possible", "architecture_alignment", "issue_53_alignment",
|
|
):
|
|
_ev(md_freq, f)
|
|
_ev(md_freq, "business_meaning", EvidenceType.DRAFT_DERIVED)
|
|
_ev(md_freq, "known_limitations", EvidenceType.MIXED)
|
|
register_placeholder(md_freq)
|
|
|
|
md_gap = PlaceholderMetadata(
|
|
key="training_inter_session_gap_md",
|
|
category="Aktivität",
|
|
description="Median/Mittel/Min der Stunden zwischen aufeinanderfolgenden Trainingseinheiten",
|
|
resolver_module="backend/placeholder_resolver.py",
|
|
resolver_function="get_training_inter_session_gap_md",
|
|
data_layer_module="backend/data_layer/activity_metrics.py",
|
|
data_layer_function="get_training_inter_session_gap_data",
|
|
source_tables=["activity_log"],
|
|
semantic_contract=(
|
|
"Sessions chronologisch; Zeitstempel = date + start_time oder 12:00. "
|
|
"Lücken in Stunden zwischen aufeinanderfolgenden Starts."
|
|
),
|
|
business_meaning="KI: ausreichend Erholung zwischen Belastungen? Doppelbelastung?",
|
|
unit="Markdown",
|
|
time_window="default 28 Tage",
|
|
output_type=OutputType.TEXT_SUMMARY,
|
|
placeholder_type=PlaceholderType.INTERPRETED,
|
|
format_hint="Kurzer Markdown-Fließtext",
|
|
example_output="**Pause zwischen Trainings** …",
|
|
minimum_data_requirements="Mindestens 2 Sessions",
|
|
quality_filter_policy=None,
|
|
confidence_logic="calculate_confidence über Session-Anzahl",
|
|
missing_value_policy=MissingValuePolicy(
|
|
available=False,
|
|
value_raw=None,
|
|
missing_reason="insufficient_data",
|
|
legacy_display="Zu wenige Trainings",
|
|
),
|
|
known_limitations=(
|
|
"Kein Unterscheidung aktiv/passiv außerhalb activity_log. "
|
|
"Fehlende Uhrzeit verzerrt Reihenfolge am selben Tag nicht (nur ein künstlicher Mittag)."
|
|
),
|
|
layer_1_decision="activity_metrics.get_training_inter_session_gap_data",
|
|
layer_2a_decision="get_training_inter_session_gap_md",
|
|
layer_2b_reuse_possible=True,
|
|
architecture_alignment="Phase 0c",
|
|
issue_53_alignment="Layer 1",
|
|
evidence={},
|
|
)
|
|
for f in (
|
|
"key", "category", "description", "resolver_module", "resolver_function",
|
|
"data_layer_module", "data_layer_function", "source_tables", "semantic_contract",
|
|
"unit", "time_window", "output_type", "placeholder_type", "format_hint",
|
|
"example_output", "minimum_data_requirements", "confidence_logic",
|
|
"missing_value_policy", "layer_1_decision", "layer_2a_decision",
|
|
"layer_2b_reuse_possible", "architecture_alignment", "issue_53_alignment",
|
|
):
|
|
_ev(md_gap, f)
|
|
_ev(md_gap, "business_meaning", EvidenceType.DRAFT_DERIVED)
|
|
_ev(md_gap, "known_limitations", EvidenceType.MIXED)
|
|
register_placeholder(md_gap)
|
|
|
|
pj = PlaceholderMetadata(
|
|
key="training_sessions_recent_json",
|
|
category="Aktivität",
|
|
description=(
|
|
"JSON: letzte ISO-Kalenderwochen mit Einheiten (Datum, Art, Dauer, kcal, HF Ø/max, RPE, Kategorie)"
|
|
),
|
|
resolver_module="backend/placeholder_resolver.py",
|
|
resolver_function="_safe_json",
|
|
data_layer_module="backend/data_layer/activity_metrics.py",
|
|
data_layer_function="get_training_sessions_recent_weeks_data",
|
|
source_tables=["activity_log", "training_types"],
|
|
semantic_contract=(
|
|
"Struktur weeks[].week_iso, sessions[] mit Feldern für KI-Auswertung. "
|
|
"Default 4 ISO-Wochen zurück."
|
|
),
|
|
business_meaning="Rohkontext für wochenweise Auswertung (Erholung, Intensität) in der KI",
|
|
unit="JSON string",
|
|
time_window="4 ISO-Wochen (28 Tage Datenfenster)",
|
|
output_type=OutputType.JSON,
|
|
placeholder_type=PlaceholderType.RAW_DATA,
|
|
format_hint="JSON-Objekt als String",
|
|
example_output='{"weeks":[...],"meta":{...}}',
|
|
minimum_data_requirements="Optional Sessions; meta.confidence bei leer insufficient",
|
|
quality_filter_policy=None,
|
|
confidence_logic="meta.confidence aus Session-Anzahl",
|
|
missing_value_policy=MissingValuePolicy(
|
|
available=False,
|
|
value_raw=None,
|
|
missing_reason="no_data",
|
|
legacy_display="{}",
|
|
),
|
|
known_limitations=(
|
|
"Token-Länge bei vielen Sessions beachten. training_type_name nur bei gesetztem training_type_id."
|
|
),
|
|
layer_1_decision="activity_metrics.get_training_sessions_recent_weeks_data",
|
|
layer_2a_decision="_safe_json('training_sessions_recent_json')",
|
|
layer_2b_reuse_possible=True,
|
|
architecture_alignment="Phase 0c",
|
|
issue_53_alignment="Layer 1",
|
|
evidence={},
|
|
)
|
|
for f in (
|
|
"key", "category", "description", "resolver_module", "resolver_function",
|
|
"data_layer_module", "data_layer_function", "source_tables", "semantic_contract",
|
|
"unit", "time_window", "output_type", "placeholder_type", "format_hint",
|
|
"example_output", "minimum_data_requirements", "confidence_logic",
|
|
"missing_value_policy", "layer_1_decision", "layer_2a_decision",
|
|
"layer_2b_reuse_possible", "architecture_alignment", "issue_53_alignment",
|
|
):
|
|
_ev(pj, f)
|
|
_ev(pj, "business_meaning", EvidenceType.DRAFT_DERIVED)
|
|
_ev(pj, "known_limitations", EvidenceType.MIXED)
|
|
register_placeholder(pj)
|
|
|
|
|
|
register_activity_session_insights()
|