package ai import ( "database/sql/driver" "time" "rideaware/internal/workout" ) // GenerateRequest is the user's request for AI workout generation type GenerateRequest struct { PlanDuration int `json:"plan_duration"` // Number of days (1, 7, 14, 28) FocusAreas []string `json:"focus_areas"` // ["endurance", "threshold", "vo2max", "recovery", "sprint", "sweet_spot"] IntensityLevel string `json:"intensity_level"` // "easy", "moderate", "hard" WeeklyHours int `json:"weekly_hours"` // Available training hours per week StartDate string `json:"start_date"` // YYYY-MM-DD IncludeRest bool `json:"include_rest"` // Whether to include rest days TargetEventID *uint `json:"target_event_id"` // Optional target event to periodize for } // GenerateResponse contains AI-generated workouts type GenerateResponse struct { Workouts []AIWorkout `json:"workouts"` Rationale string `json:"rationale"` // AI's explanation TotalTSS float64 `json:"total_tss"` RecommendationID uint `json:"recommendation_id"` } // AIWorkout represents a single AI-generated workout type AIWorkout struct { Title string `json:"title"` Description string `json:"description"` Type string `json:"type"` ScheduledDate string `json:"scheduled_date"` Duration int `json:"duration"` // seconds Segments []workout.WorkoutSegment `json:"segments"` EstimatedTSS float64 `json:"estimated_tss"` Notes string `json:"notes"` } // AIRecommendation database model type AIRecommendation struct { ID uint `gorm:"primaryKey" json:"id"` UserID uint `gorm:"not null;index" json:"user_id"` PromptContext JSONB `gorm:"type:jsonb" json:"prompt_context"` AIResponse string `json:"ai_response"` GeneratedWorkouts JSONB `gorm:"type:jsonb" json:"generated_workouts"` Parameters JSONB `gorm:"type:jsonb" json:"parameters"` Status string `gorm:"default:'generated'" json:"status"` CreatedAt time.Time `json:"created_at"` } func (AIRecommendation) TableName() string { return "ai_recommendations" } // JSONB type for PostgreSQL JSONB columns type JSONB struct { Data []byte } // Scan implements sql.Scanner interface func (j *JSONB) Scan(value interface{}) error { if value == nil { j.Data = []byte("{}") return nil } bytes, ok := value.([]byte) if !ok { return nil } j.Data = bytes return nil } // Value implements driver.Valuer interface func (j JSONB) Value() (driver.Value, error) { if len(j.Data) == 0 { return []byte("{}"), nil } return j.Data, nil } // MarshalJSON implements json.Marshaler func (j JSONB) MarshalJSON() ([]byte, error) { if len(j.Data) == 0 { return []byte("{}"), nil } return j.Data, nil } // UnmarshalJSON implements json.Unmarshaler func (j *JSONB) UnmarshalJSON(data []byte) error { j.Data = data return nil } // UserContext contains all user data sent to AI type UserContext struct { FTP int `json:"ftp"` MaxHR int `json:"max_hr"` RestingHR int `json:"resting_hr"` Weight float64 `json:"weight"` TrainingGoal string `json:"training_goal"` WeeklyHours int `json:"weekly_hours"` RecentWorkouts []RecentWorkoutSummary `json:"recent_workouts"` TrainingLoad TrainingLoadSummary `json:"training_load"` UpcomingEvents []UpcomingEventSummary `json:"upcoming_events,omitempty"` TargetEvent *UpcomingEventSummary `json:"target_event,omitempty"` Nutrition *NutritionContext `json:"nutrition,omitempty"` } // NutritionContext contains nutrition data for AI type NutritionContext struct { Goal string `json:"goal"` DailyCalories int `json:"daily_calories"` ProteinG int `json:"protein_g"` CarbsG int `json:"carbs_g"` FatG int `json:"fat_g"` DietaryPref string `json:"dietary_preference"` } // UpcomingEventSummary summarizes an upcoming race/event for AI context type UpcomingEventSummary struct { Name string `json:"name"` Date string `json:"date"` EventType string `json:"event_type"` Distance float64 `json:"distance"` Priority string `json:"priority"` DaysAway int `json:"days_away"` } // RecentWorkoutSummary summarizes a completed workout type RecentWorkoutSummary struct { Date string `json:"date"` Type string `json:"type"` Duration int `json:"duration"` AvgPower int `json:"avg_power"` TSS float64 `json:"tss"` } // TrainingLoadSummary contains CTL/ATL/TSB metrics type TrainingLoadSummary struct { CTL float64 `json:"ctl"` // Chronic Training Load (42-day EMA) ATL float64 `json:"atl"` // Acute Training Load (7-day EMA) TSB float64 `json:"tsb"` // Training Stress Balance (CTL - ATL) } // DeepSeek API structures type DeepSeekRequest struct { Model string `json:"model"` Messages []DeepSeekMessage `json:"messages"` Temperature float64 `json:"temperature"` MaxTokens int `json:"max_tokens,omitempty"` } type DeepSeekMessage struct { Role string `json:"role"` Content string `json:"content"` } type DeepSeekResponse struct { Choices []struct { Message DeepSeekMessage `json:"message"` } `json:"choices"` Error *struct { Message string `json:"message"` Type string `json:"type"` } `json:"error"` }