fix
This commit is contained in:
@@ -25,6 +25,7 @@ from backend.app.services.zones import calculate_power_zones, calculate_hr_zones
|
||||
from backend.app.services.power_curve import calculate_power_curve
|
||||
from backend.app.services.intervals import detect_intervals
|
||||
from backend.app.services.ai_summary import generate_summary
|
||||
from backend.app.services.coaching import link_activity_to_plan
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -48,31 +49,38 @@ async def upload_activity(
|
||||
file_path.write_bytes(content)
|
||||
|
||||
# 1. Parse FIT
|
||||
activity, data_points = parse_fit_file(content, rider.id, str(file_path))
|
||||
activity, data_points, exercise_sets = parse_fit_file(content, rider.id, str(file_path))
|
||||
if exercise_sets:
|
||||
activity.exercise_sets = exercise_sets
|
||||
|
||||
# Auto-link to training plan
|
||||
await link_activity_to_plan(activity, rider.id, session)
|
||||
|
||||
session.add(activity)
|
||||
await session.flush()
|
||||
|
||||
# 2. Save data points
|
||||
for dp in data_points:
|
||||
dp.activity_id = activity.id
|
||||
session.add_all(data_points)
|
||||
# 2. Save data points (if any — strength workouts may have none)
|
||||
if data_points:
|
||||
for dp in data_points:
|
||||
dp.activity_id = activity.id
|
||||
session.add_all(data_points)
|
||||
|
||||
# 3. Calculate & save metrics (with FTP if available)
|
||||
metrics = calculate_metrics(data_points, activity, ftp=rider.ftp)
|
||||
if metrics:
|
||||
session.add(metrics)
|
||||
# 3. Calculate & save metrics (with FTP if available)
|
||||
metrics = calculate_metrics(data_points, activity, ftp=rider.ftp)
|
||||
if metrics:
|
||||
session.add(metrics)
|
||||
|
||||
# 4. Detect & save intervals
|
||||
intervals = detect_intervals(data_points, ftp=rider.ftp)
|
||||
for interval in intervals:
|
||||
interval.activity_id = activity.id
|
||||
session.add_all(intervals)
|
||||
# 4. Detect & save intervals
|
||||
intervals = detect_intervals(data_points, ftp=rider.ftp)
|
||||
for interval in intervals:
|
||||
interval.activity_id = activity.id
|
||||
session.add_all(intervals)
|
||||
|
||||
# 5. Calculate & save power curve
|
||||
curve_data = calculate_power_curve(data_points)
|
||||
if curve_data:
|
||||
pc = PowerCurve(activity_id=activity.id, curve_data=curve_data)
|
||||
session.add(pc)
|
||||
# 5. Calculate & save power curve
|
||||
curve_data = calculate_power_curve(data_points)
|
||||
if curve_data:
|
||||
pc = PowerCurve(activity_id=activity.id, curve_data=curve_data)
|
||||
session.add(pc)
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(activity)
|
||||
|
||||
@@ -9,6 +9,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from backend.app.core.auth import get_current_rider
|
||||
from backend.app.core.database import get_session
|
||||
from backend.app.models.activity import Activity
|
||||
from backend.app.models.coaching import CoachingChat
|
||||
from backend.app.models.rider import Rider
|
||||
from backend.app.models.training import TrainingPlan
|
||||
@@ -243,11 +244,74 @@ async def get_today(
|
||||
rider: Rider = Depends(get_current_rider),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Get today's planned workout."""
|
||||
"""Get today's planned workout with linked activity if any."""
|
||||
workout = await get_today_workout(rider, session)
|
||||
if not workout:
|
||||
return None
|
||||
|
||||
# Check if there's already a linked activity for today
|
||||
linked_query = (
|
||||
select(Activity)
|
||||
.where(Activity.training_plan_id == uuid.UUID(workout["plan_id"]))
|
||||
.where(Activity.plan_week == workout["week_number"])
|
||||
.where(Activity.plan_day == workout["day"])
|
||||
)
|
||||
linked_result = await session.execute(linked_query)
|
||||
linked = linked_result.scalar_one_or_none()
|
||||
workout["linked_activity_id"] = str(linked.id) if linked else None
|
||||
workout["completed"] = linked is not None
|
||||
return workout
|
||||
|
||||
|
||||
# --- Activity-Plan linking ---
|
||||
|
||||
class LinkRequest(BaseModel):
|
||||
activity_id: str
|
||||
plan_id: str
|
||||
week: int
|
||||
day: str
|
||||
|
||||
|
||||
@router.post("/link")
|
||||
async def link_activity(
|
||||
body: LinkRequest,
|
||||
rider: Rider = Depends(get_current_rider),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Manually link an activity to a planned workout day."""
|
||||
activity = await session.get(Activity, uuid.UUID(body.activity_id))
|
||||
if not activity or activity.rider_id != rider.id:
|
||||
raise HTTPException(status_code=404, detail="Activity not found")
|
||||
|
||||
plan = await session.get(TrainingPlan, uuid.UUID(body.plan_id))
|
||||
if not plan or plan.rider_id != rider.id:
|
||||
raise HTTPException(status_code=404, detail="Plan not found")
|
||||
|
||||
activity.training_plan_id = plan.id
|
||||
activity.plan_week = body.week
|
||||
activity.plan_day = body.day
|
||||
await session.commit()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.post("/unlink/{activity_id}")
|
||||
async def unlink_activity(
|
||||
activity_id: uuid.UUID,
|
||||
rider: Rider = Depends(get_current_rider),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Remove link between activity and planned workout."""
|
||||
activity = await session.get(Activity, activity_id)
|
||||
if not activity or activity.rider_id != rider.id:
|
||||
raise HTTPException(status_code=404, detail="Activity not found")
|
||||
|
||||
activity.training_plan_id = None
|
||||
activity.plan_week = None
|
||||
activity.plan_day = None
|
||||
await session.commit()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
# --- Adjustment chat ---
|
||||
|
||||
@router.post("/plan/adjust")
|
||||
|
||||
Reference in New Issue
Block a user