package openai import ( "context" "fmt" "sync" ) // MenuRequest contains parameters for weekly menu generation. type MenuRequest struct { UserGoal string DailyCalories int Restrictions []string CuisinePrefs []string AvailableProducts []string Lang string // ISO 639-1 target language code, e.g. "en", "ru" } // DayPlan is the AI-generated plan for a single day. type DayPlan struct { Day int `json:"day"` Meals []MealEntry `json:"meals"` } // MealEntry is a single meal within a day plan. type MealEntry struct { MealType string `json:"meal_type"` // breakfast | lunch | dinner Recipe Recipe `json:"recipe"` } // GenerateMenu produces a 7-day × 3-meal plan by issuing three parallel // GenerateRecipes calls (one per meal type). This avoids token-limit errors // that arise from requesting 21 full recipes in a single prompt. func (c *Client) GenerateMenu(ctx context.Context, req MenuRequest) ([]DayPlan, error) { type mealSlot struct { mealType string fraction float64 // share of daily calories } slots := []mealSlot{ {"breakfast", 0.25}, {"lunch", 0.40}, {"dinner", 0.35}, } type mealResult struct { recipes []Recipe err error } results := make([]mealResult, len(slots)) var wg sync.WaitGroup for i, slot := range slots { wg.Add(1) go func(idx int, mealType string, fraction float64) { defer wg.Done() // Scale daily calories to what this meal should contribute. mealCal := int(float64(req.DailyCalories) * fraction) r, err := c.GenerateRecipes(ctx, RecipeRequest{ UserGoal: req.UserGoal, DailyCalories: mealCal * 3, // prompt divides by 3 internally Restrictions: req.Restrictions, CuisinePrefs: req.CuisinePrefs, Count: 7, AvailableProducts: req.AvailableProducts, Lang: req.Lang, }) results[idx] = mealResult{r, err} }(i, slot.mealType, slot.fraction) } wg.Wait() for i, res := range results { if res.err != nil { return nil, fmt.Errorf("generate %s: %w", slots[i].mealType, res.err) } if len(res.recipes) == 0 { return nil, fmt.Errorf("no %s recipes returned", slots[i].mealType) } // Pad to exactly 7 by repeating the last recipe. for len(results[i].recipes) < 7 { results[i].recipes = append(results[i].recipes, results[i].recipes[len(results[i].recipes)-1]) } } days := make([]DayPlan, 7) for day := range 7 { days[day] = DayPlan{ Day: day + 1, Meals: []MealEntry{ {MealType: slots[0].mealType, Recipe: results[0].recipes[day]}, {MealType: slots[1].mealType, Recipe: results[1].recipes[day]}, {MealType: slots[2].mealType, Recipe: results[2].recipes[day]}, }, } } return days, nil }