File size: 3,163 Bytes
557ee65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
from typing import Optional, Any
from domain.training.weekly_snapshot import WeeklySnapshot
from domain.training.weekly_trend import WeeklyTrend
from domain.runner_positioning import RunnerPositioning, TrainingPhase
from domain.training.training_recommendation import TrainingRecommendation
from _app.presentation.ui_text import get_text

class RecommendationService:
    """
    Stateless service to generate training recommendations based on positioning.
    """

    def generate(
        self,
        snapshot: WeeklySnapshot,
        trend: WeeklyTrend,
        positioning: Any, # Can be RunnerPositioning or WeeklyPositioning
        language: str = "en"
    ) -> TrainingRecommendation:
        """
        Pure rule-based logic to map positioning to training focus and session types.
        """
        # Mapping from positioning focus or status
        # Handle both Domain (RunnerPositioning) and Application (WeeklyPositioning) models
        if hasattr(positioning, "recommended_focus"):
            focus_val = positioning.recommended_focus
        else:
            # Fallback for WeeklyPositioning (Application Layer)
            status_map = {
                "CONSTRUCTIVE_ADAPTATION": "INTENSITY",
                "PRODUCTIVE_LOAD": "CONSISTENCY",
                "STRAIN": "RECOVERY",
                "PLATEAU": "MAINTENANCE"
            }
            focus_val = status_map.get(getattr(positioning, "status", ""), "MAINTENANCE")

        focus_key = focus_val.lower()
        
        # Initial recommendation mapping as per requirements:
        # Building Momentum (CONSTRUCTIVE_ADAPTATION) -> introduce_intensity / tempo_intervals
        # Maintaining Consistency (PRODUCTIVE_LOAD) -> build_endurance / long_run
        # Recovery (STRAIN) -> protect_recovery / easy_run
        # Default -> maintain_consistency
        
        mapping = {
            "RECOVERY": {
                "focus": "protect_recovery",
                "session_type": "easy_run",
                "confidence": 0.9
            },
            "CONSISTENCY": {
                "focus": "build_endurance",
                "session_type": "long_run",
                "confidence": 0.8
            },
            "INTENSITY": {
                "focus": "introduce_intensity",
                "session_type": "tempo_intervals",
                "confidence": 0.85
            },
            "MAINTENANCE": {
                "focus": "maintain_consistency",
                "session_type": "steady_run",
                "confidence": 0.75
            }
        }
        
        rec_data = mapping.get(focus_val, {
            "focus": "maintain_consistency",
            "session_type": "steady_run",
            "confidence": 0.5
        })
        
        # Resolve localized description
        description = get_text(f"rec_desc_{rec_data['focus']}", language)
        
        return TrainingRecommendation(
            focus=get_text(f"rec_focus_{rec_data['focus']}", language),
            session_type=get_text(f"rec_session_{rec_data['session_type']}", language),
            description=description,
            confidence=rec_data["confidence"]
        )