ai cooking
0
fork

Configure Feed

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

let people ask questions on old recipes (#511)

Co-authored-by: paul miller <paul.miller>

authored by

Paul Miller
paul miller
and committed by
GitHub
562477fd 88bca347

+23 -24
+5 -6
internal/ai/client.go
··· 250 250 if question == "" { 251 251 return nil, fmt.Errorf("question is required") 252 252 } 253 - if previousResponseID == "" { 254 - return nil, fmt.Errorf("response ID is required for questions") 255 - } 256 253 client := openai.NewClient(option.WithAPIKey(c.apiKey)) 257 254 258 255 params := responses.ResponseNewParams{ 259 - Model: c.model, 260 - PreviousResponseID: openai.String(previousResponseID), 261 - Instructions: openai.String("Answer the user's question about the recipe in plain text. Be concise and do not regenerate the full recipe or output JSON."), 256 + Model: c.model, 257 + Instructions: openai.String("Answer the user's question about the recipe in plain text. Be concise and do not regenerate the full recipe or output JSON."), 262 258 Input: responses.ResponseNewParamsInputUnion{ 263 259 OfInputItemList: []responses.ResponseInputItemUnionParam{user(question)}, 264 260 }, 265 261 Store: openai.Bool(true), 262 + } 263 + if previousResponseID != "" { 264 + params.PreviousResponseID = openai.String(previousResponseID) 266 265 } 267 266 resp, err := client.Responses.New(ctx, params) 268 267 if err != nil {
+17 -3
internal/recipes/server.go
··· 5 5 "bytes" 6 6 "context" 7 7 "encoding/base64" 8 + "encoding/json" 8 9 "errors" 9 10 "fmt" 10 11 "html/template" ··· 366 367 http.Error(w, "missing question", http.StatusBadRequest) 367 368 return 368 369 } 370 + 369 371 recipeTitle := strings.TrimSpace(r.FormValue("recipe_title")) 370 372 questionForModel := question 371 373 if recipeTitle != "" { 374 + // we could drop this after first question 372 375 questionForModel = fmt.Sprintf("Regarding %s: %s", recipeTitle, question) 373 376 } 374 377 375 378 responseID := strings.TrimSpace(r.FormValue("response_id")) 376 379 if responseID == "" { 377 - slog.ErrorContext(ctx, "failed to load response id", "hash", hash) 378 - http.Error(w, "lost context on this recipe", http.StatusInternalServerError) 379 - return 380 + slog.ErrorContext(ctx, "no response id falling back", "hash", hash) 381 + r, err := s.SingleFromCache(ctx, hash) 382 + if err != nil { 383 + slog.ErrorContext(ctx, "failed to load response id", "hash", hash) 384 + http.Error(w, "lost context on this recipe", http.StatusInternalServerError) 385 + return 386 + } 387 + rjson, err := json.Marshal(r) 388 + if err != nil { 389 + slog.ErrorContext(ctx, "failed to load response id", "hash", hash) 390 + http.Error(w, "lost context on this recipe", http.StatusInternalServerError) 391 + return 392 + } 393 + questionForModel = fmt.Sprintf("Regarding this json recipe %s: %s", rjson, question) 380 394 } 381 395 382 396 // this is going to take a while. Start a go routine? and spin?
+1 -15
internal/templates/recipe.html
··· 108 108 <p class="text-xs text-gray-500">Ask about the recipe and share how it turned out.</p> 109 109 </div> 110 110 111 - {{if and .ServerSignedIn .ResponseID}} 111 + {{if .ServerSignedIn }} 112 112 <form method="POST" 113 113 action="/recipe/{{.RecipeHash}}/question" 114 114 hx-post="/recipe/{{.RecipeHash}}/question" ··· 146 146 </div> 147 147 </form> 148 148 <p id="question-error" class="hidden text-sm font-medium text-red-700">Could not answer your question. Please try again.</p> 149 - {{else if .ServerSignedIn}} 150 - <div class="flex flex-wrap items-center gap-3"> 151 - <p class="text-sm text-gray-500">Chef chat isn't available for this recipe yet.</p> 152 - <button type="button" 153 - id="cooked-feedback-button" 154 - hx-post="/recipe/{{.RecipeHash}}/feedback" 155 - hx-vals='{"cooked":"true"}' 156 - hx-swap="none" 157 - hx-disabled-elt="#cooked-feedback-button" 158 - onclick="document.getElementById('feedback-panel').classList.remove('hidden'); document.getElementById('feedback-status').textContent='';" 159 - class="inline-flex items-center justify-center rounded-lg border border-brand-300 bg-white px-4 py-2.5 text-sm font-semibold text-brand-700 shadow-sm transition hover:border-brand-400 hover:bg-brand-50 focus:outline-none focus:ring-2 focus:ring-brand-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:text-brand-400"> 160 - {{if .Feedback.Cooked}}Update feedback{{else}}I cooked it!{{end}} 161 - </button> 162 - </div> 163 149 {{else}} 164 150 <a href="{{SignInPath (print "/recipe/" .RecipeHash)}}" 165 151 class="inline-flex items-center justify-center rounded-lg border border-brand-300 bg-white px-4 py-2 text-sm font-semibold text-brand-700 shadow-sm transition hover:bg-brand-50 focus:outline-none focus:ring-2 focus:ring-brand-400 focus:ring-offset-2">