Latest state on privte laptop
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from dotenv import load_dotenv, set_key
|
||||
|
||||
@@ -34,7 +34,7 @@ class EnvManager:
|
||||
# Reload after setting
|
||||
self.load_service_env(service, override=True)
|
||||
|
||||
def get_status(self, service: str, required_keys: list[str]) -> Dict[str, Any]:
|
||||
def get_status(self, service: str, required_keys: List[str]) -> Dict[str, Any]:
|
||||
"""Check if required keys are set for a service."""
|
||||
# Reload just in case
|
||||
self.load_service_env(service)
|
||||
|
||||
@@ -89,8 +89,19 @@ class RecommendationEngine:
|
||||
Validation Rules:
|
||||
- SportTypes: RUNNING=1, CYCLING=2
|
||||
- StepTypes: WARMUP=1, COOLDOWN=2, INTERVAL=3, RECOVERY=4, REST=5, REPEAT=6
|
||||
- EndCondition: DISTANCE=1, TIME=2, LAP_BUTTON=7
|
||||
- EndCondition: DISTANCE=1, TIME=2, LAP_BUTTON=7, ITERATIONS=7
|
||||
- TargetType: NO_TARGET=1, HEART_RATE=2, PACE=4 (Speed)
|
||||
|
||||
CRITICAL SCHEMA RULE:
|
||||
Steps MUST use nested objects for types. Do NOT use flat IDs.
|
||||
Example Step:
|
||||
{
|
||||
"type": "ExecutableStepDTO",
|
||||
"stepOrder": 1,
|
||||
"stepType": { "stepTypeId": 1, "stepTypeKey": "warmup" },
|
||||
"endCondition": { "conditionTypeId": 2, "conditionTypeKey": "time" },
|
||||
"endConditionValue": 600
|
||||
}
|
||||
"""
|
||||
|
||||
user_prompt = f"User Request: {prompt}"
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Dict, Any
|
||||
|
||||
# Ensure we can import from src
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from common.env_manager import EnvManager
|
||||
from garmin.workout_manager import WorkoutManager
|
||||
|
||||
def load_sample_workout() -> Dict[str, Any]:
|
||||
"""Create a minimal valid workout for testing."""
|
||||
return {
|
||||
"workoutName": "Test Workout",
|
||||
"description": "Base for AI test",
|
||||
"sportType": {
|
||||
"sportTypeId": 1,
|
||||
"sportTypeKey": "running"
|
||||
},
|
||||
"workoutSegments": [
|
||||
{
|
||||
"segmentOrder": 1,
|
||||
"sportType": {
|
||||
"sportTypeId": 1,
|
||||
"sportTypeKey": "running"
|
||||
},
|
||||
"workoutSteps": [
|
||||
{
|
||||
"type": "ExecutableStepDTO",
|
||||
"stepOrder": 1,
|
||||
"stepTypeId": 1,
|
||||
"childStepId": None,
|
||||
"endConditionId": 2,
|
||||
"endConditionValue": 300,
|
||||
"targetTypeId": 1,
|
||||
"targetValueOne": 10.0,
|
||||
"targetValueTwo": 12.0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
def test_ai_modification():
|
||||
print("\n--- Testing AI Workout Modifier ---")
|
||||
|
||||
# 1. Setup Environment
|
||||
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../.."))
|
||||
env = EnvManager(root_dir)
|
||||
env.load_service_env("gemini")
|
||||
|
||||
api_key = os.getenv("GEMINI_API_KEY")
|
||||
if not api_key:
|
||||
print("SKIP: GEMINI_API_KEY not found in environment.")
|
||||
return
|
||||
|
||||
# 2. Prepare Data
|
||||
manager = WorkoutManager()
|
||||
original_workout = load_sample_workout()
|
||||
|
||||
# 3. specific instruction
|
||||
prompt = "Add a 10 minute cooldown at the end."
|
||||
print(f"Prompt: {prompt}")
|
||||
|
||||
# 4. Execute AI Modification
|
||||
try:
|
||||
modified_workout = manager.generate_workout_json(prompt, existing_workout=original_workout)
|
||||
|
||||
# 5. Verify Structure (Schema Validation)
|
||||
errors = manager.validate_workout_json(modified_workout)
|
||||
if errors:
|
||||
print(f"FAIL: Schema Validation Errors: {json.dumps(errors, indent=2)}")
|
||||
print(f"Invalid Workout JSON: {json.dumps(modified_workout, indent=2)}")
|
||||
return
|
||||
|
||||
# 6. Verify Content Logic
|
||||
segments = modified_workout.get("workoutSegments", [])
|
||||
if not segments:
|
||||
print("FAIL: No segments found in modified workout.")
|
||||
return
|
||||
|
||||
steps = segments[0].get("workoutSteps", [])
|
||||
last_step = steps[-1] if steps else None
|
||||
|
||||
# Check if last step looks like a cooldown
|
||||
# stepTypeId 4 = Cooldown (usually, or we check description/type)
|
||||
is_cooldown = last_step and (last_step.get("stepTypeId") == 4 or "cool" in str(last_step).lower())
|
||||
|
||||
if is_cooldown:
|
||||
print("PASS: Cooldown added successfully.")
|
||||
print(f"Modified Steps Count: {len(steps)}")
|
||||
else:
|
||||
print("WARN: Could not strictly verify cooldown type, but schema is valid.")
|
||||
print(f"Last Step: {json.dumps(last_step, indent=2)}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"FAIL: Exception during AI processing: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_ai_modification()
|
||||
Reference in New Issue
Block a user