lots of stuff, don't truly remember

This commit is contained in:
Blake Ridgway
2026-05-17 20:39:47 -05:00
parent 178ffb3425
commit dc4fe558b7
35 changed files with 3501 additions and 112 deletions

133
internal/ai/handler.go Normal file
View File

@@ -0,0 +1,133 @@
package ai
import (
"encoding/json"
"log"
"net/http"
"rideaware/internal/config"
"rideaware/internal/middleware"
)
type Handler struct {
service *Service
}
func NewHandler() *Handler {
return &Handler{
service: NewService(),
}
}
// GenerateRecommendations POST /api/protected/ai/generate
func (h *Handler) GenerateRecommendations(w http.ResponseWriter, r *http.Request) {
claims := r.Context().Value(middleware.UserContextKey).(*config.CustomClaims)
if claims == nil {
respondError(w, http.StatusUnauthorized, "unauthorized")
return
}
var req GenerateRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
respondError(w, http.StatusBadRequest, "invalid request body")
return
}
// Validate request
if err := validateGenerateRequest(req); err != nil {
respondError(w, http.StatusBadRequest, err.Error())
return
}
log.Printf("[AI] User %d requesting %d-day plan (focus: %v, intensity: %s)",
claims.UserID, req.PlanDuration, req.FocusAreas, req.IntensityLevel)
// Generate workouts
response, err := h.service.GenerateWorkouts(claims.UserID, req)
if err != nil {
log.Printf("[AI] Generation error for user %d: %v", claims.UserID, err)
respondError(w, http.StatusInternalServerError, "failed to generate workouts: "+err.Error())
return
}
log.Printf("[AI] Successfully generated %d workouts for user %d (total TSS: %.1f)",
len(response.Workouts), claims.UserID, response.TotalTSS)
respondJSON(w, http.StatusOK, response)
}
// ScheduleRecommendations POST /api/protected/ai/schedule
func (h *Handler) ScheduleRecommendations(w http.ResponseWriter, r *http.Request) {
claims := r.Context().Value(middleware.UserContextKey).(*config.CustomClaims)
if claims == nil {
respondError(w, http.StatusUnauthorized, "unauthorized")
return
}
var req struct {
RecommendationID uint `json:"recommendation_id"`
WorkoutIndices []int `json:"workout_indices"` // Which workouts to schedule
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
respondError(w, http.StatusBadRequest, "invalid request")
return
}
if req.RecommendationID == 0 {
respondError(w, http.StatusBadRequest, "recommendation_id is required")
return
}
log.Printf("[AI] User %d scheduling %d workouts from recommendation %d",
claims.UserID, len(req.WorkoutIndices), req.RecommendationID)
// Schedule selected workouts
workouts, err := h.service.ScheduleWorkouts(claims.UserID, req.RecommendationID, req.WorkoutIndices)
if err != nil {
log.Printf("[AI] Schedule error for user %d: %v", claims.UserID, err)
respondError(w, http.StatusInternalServerError, err.Error())
return
}
log.Printf("[AI] Successfully scheduled %d workouts for user %d", len(workouts), claims.UserID)
respondJSON(w, http.StatusCreated, map[string]interface{}{
"scheduled_count": len(workouts),
"workouts": workouts,
})
}
// GetRecommendationHistory GET /api/protected/ai/history
func (h *Handler) GetRecommendationHistory(w http.ResponseWriter, r *http.Request) {
claims := r.Context().Value(middleware.UserContextKey).(*config.CustomClaims)
if claims == nil {
respondError(w, http.StatusUnauthorized, "unauthorized")
return
}
history, err := h.service.GetUserRecommendations(claims.UserID, 10)
if err != nil {
log.Printf("[AI] Failed to fetch history for user %d: %v", claims.UserID, err)
respondError(w, http.StatusInternalServerError, "failed to fetch history")
return
}
// Return empty array instead of null
if history == nil {
history = []AIRecommendation{}
}
respondJSON(w, http.StatusOK, history)
}
// Helper functions
func respondJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
func respondError(w http.ResponseWriter, status int, message string) {
respondJSON(w, status, map[string]string{"error": message})
}