ai cooking
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cook time and cost (#285)

* cook time and cost

* Update recipe guidelines and verification steps

Removed the requirement for recipes to take under 1 hour to prepare and updated the calorie count description. Enhanced verification steps for recipe generation.

authored by

Paul Miller and committed by
GitHub
9d280a87 62f6bd7e

+45 -9
+12 -4
internal/ai/client.go
··· 39 39 type Recipe struct { 40 40 Title string `json:"title"` 41 41 Description string `json:"description"` 42 + CookTime string `json:"cook_time"` 43 + CostEstimate string `json:"cost_estimate"` 42 44 Ingredients []Ingredient `json:"ingredients"` 43 45 Instructions []string `json:"instructions"` 44 46 Health string `json:"health"` ··· 57 59 fnv := fnv.New128a() 58 60 lo.Must(io.WriteString(fnv, r.Title)) 59 61 lo.Must(io.WriteString(fnv, r.Description)) 62 + lo.Must(io.WriteString(fnv, r.CookTime)) 63 + lo.Must(io.WriteString(fnv, r.CostEstimate)) 60 64 for _, ing := range r.Ingredients { 61 65 lo.Must(io.WriteString(fnv, ing.Name)) 62 66 lo.Must(io.WriteString(fnv, ing.Quantity)) ··· 105 109 - Each meal must feature a protein and at least one side of either a vegetable and/or a starch. A combined dish (such as a pasta, stew, or similar) that incorporates a vegetable or starch is also good. 106 110 - Recipes should use diverse cooking methods and represent a variety of cuisines. 107 111 - Provide clear, step-by-step instructions and an ingredient list for each recipe. repeat amounts and prep for each recipe in instructions. 108 - - Recipes should take under 1 hour to prepare, unless the user asks for something longer 109 - - Optionally include a wine pairing suggestion for each recipe if appropriate. Suggest a couple of styles and a local brand if possible. Really put your Sommielier hat on for this. 112 + - Optionally include a wine pairing suggestion for each recipe if appropriate. Suggest a couple of styles. Really put your Sommielier hat on for this. 110 113 - Prioritize ingredients that are on sale (the bigger the discount, the higher the priority but but don't pay more for something on sale than a similar ingredient that isn't) 111 114 112 115 ··· 114 117 - Each recipe includes: 115 118 - Title 116 119 - Description: Try to sell the dish and add some flair. 120 + - Estimated cook time (for example: "35 minutes") 121 + - Estimated total cost in dollars (for example: "$18-24") 117 122 - Ingredient list: should include quantities and price if in input. 118 123 - Step-by-step instructions starting with prep. Don't prefix with numbers. 119 - - A guess at calorie count and healthiness 124 + - Estimated Calorie count and other nutrient health tips. 120 125 - Optional wine pairing guidance. 121 126 - Three wine or less wine styles. 122 127 123 128 # Planning & Verification 124 - - Before generating each recipe, reference your checklist to ensure variety in cooking methods and cuisines, and confirm ingredient prioritization matches sale/seasonal data.` 129 + - Reference your checklist to ensure variety in cooking methods and cuisines 130 + - confirm ingredient prioritization matches sale/seasonal data. 131 + - Check cooktime and cost match instructions and ingredient list` 125 132 126 133 func responseToShoppingList(ctx context.Context, resp *responses.Response) (*ShoppingList, error) { 127 134 slog.InfoContext(ctx, "API usage", slog.Any("usage", json.RawMessage(resp.Usage.RawJSON()))) ··· 255 262 messages = append(messages, user("Prioritize ingredients that are in season for the current date and user's state location "+date.Format("January 2nd")+" in "+location.State+".")) 256 263 messages = append(messages, user("Default: each recipe should serve 2 people.")) 257 264 messages = append(messages, user("Default: generate 3 recipes")) 265 + messages = append(messages, user("Default: prep and cook time under 1 hour")) 258 266 messages = append(messages, user("Default: cooking methods: oven, stove, grill, slow cooker")) 259 267 //location and date for seasonal ingredientss 260 268
+5 -3
internal/ai/recipe_test.go
··· 6 6 7 7 func TestRecipeComputeHash(t *testing.T) { 8 8 recipe := Recipe{ 9 - Title: "Test Recipe", 10 - Description: "A delicious test recipe", 9 + Title: "Test Recipe", 10 + Description: "A delicious test recipe", 11 + CookTime: "35 minutes", 12 + CostEstimate: "$18-24", 11 13 Ingredients: []Ingredient{ 12 14 {Name: "Ingredient 1", Quantity: "1 cup", Price: "2.99"}, 13 15 {Name: "Ingredient 2", Quantity: "2 tbsp", Price: "0.99"}, ··· 21 23 if hash1 == "" { 22 24 t.Fatal("hash should not be empty") 23 25 } 24 - if hash1 != "1YjiZBQUCmlXuNTAK9m6fA==" { 26 + if hash1 != "YK2TFI6O3tGLPAxPjqMPEw==" { 25 27 t.Fatalf("Hash changed by json marshalling: %s", hash1) 26 28 } 27 29
+16 -2
internal/recipes/html_test.go
··· 36 36 var list = ai.ShoppingList{ 37 37 Recipes: []ai.Recipe{ 38 38 { 39 - Title: "Test Recipe", 40 - Description: "A simple quail recipe", 39 + Title: "Test Recipe", 40 + Description: "A simple quail recipe", 41 + CookTime: "35 minutes", 42 + CostEstimate: "$18-24", 41 43 Ingredients: []ai.Ingredient{ 42 44 {Name: "quail", Quantity: "1 cup", Price: "2.00"}, 43 45 {Name: "kohlrabi", Quantity: "2 tbsp", Price: "1.50"}, ··· 62 64 t.Error("Want ok statuscode") 63 65 } 64 66 isValidHTML(t, html) 67 + if !strings.Contains(html, "Cook time:") { 68 + t.Error("shopping list HTML should contain cook time") 69 + } 70 + if !strings.Contains(html, "Estimated cost:") { 71 + t.Error("shopping list HTML should contain estimated cost") 72 + } 65 73 } 66 74 67 75 func TestFormatMail_ValidHTML(t *testing.T) { ··· 185 193 } 186 194 if !strings.Contains(html, `id="question-thread"`) { 187 195 t.Error("recipe HTML should contain question thread container") 196 + } 197 + if !strings.Contains(html, "Cook time:") { 198 + t.Error("recipe HTML should contain cook time") 199 + } 200 + if !strings.Contains(html, "Estimated cost:") { 201 + t.Error("recipe HTML should contain estimated cost") 188 202 } 189 203 if !strings.Contains(html, `id="question-error"`) { 190 204 t.Error("recipe HTML should contain question error surface")
+6
internal/templates/recipe.html
··· 75 75 </div> 76 76 77 77 <div class="space-y-2 text-sm text-gray-600"> 78 + {{if .Recipe.CookTime}} 79 + <p><span class="font-semibold text-brand-700">Cook time:</span> {{.Recipe.CookTime}}</p> 80 + {{end}} 81 + {{if .Recipe.CostEstimate}} 82 + <p><span class="font-semibold text-brand-700">Estimated cost:</span> {{.Recipe.CostEstimate}}</p> 83 + {{end}} 78 84 <p><span class="font-semibold text-brand-700">Health notes:</span> {{.Recipe.Health}}</p> 79 85 <p><span class="font-semibold text-brand-700">Drink pairing:</span> {{.Recipe.DrinkPairing}}</p> 80 86 </div>
+6
internal/templates/shoppinglist.html
··· 118 118 </div> 119 119 120 120 <div class="space-y-2 text-sm text-ink-600"> 121 + {{if .CookTime}} 122 + <p><span class="font-semibold text-brand-700">Cook time:</span> {{.CookTime}}</p> 123 + {{end}} 124 + {{if .CostEstimate}} 125 + <p><span class="font-semibold text-brand-700">Estimated cost:</span> {{.CostEstimate}}</p> 126 + {{end}} 121 127 <p><span class="font-semibold text-brand-700">Health notes:</span> {{.Health}}</p> 122 128 <p><span class="font-semibold text-brand-700">Drink pairing:</span> {{.DrinkPairing}}</p> 123 129 </div>