fix(recipe-generation): BRAND.name-interpolation för creatorDisplayName + rubriker/filnamn
feat(recommendation-engine,api): S4 Smak/Hälsa/Lager-vyer för 'Vad ska vi äta?' - Ersätter hårdkodat 'Cibello' i scale-batch, scale-smoke-test och export-verified. - DB-backfill: 224 recept hade 'Cibello AI' i creator_display_name (värdena motsvarar nuvarande BRAND.name, ingen rad ändrades men kontrollen är gjord). - Lägger till view-query-param (default|taste|health|pantry) med fördefinierade ScoringWeights och samtyckesgrind. - Unit-tester för vyer; integrationstester för vy-param, validering och fallback utan personalization-samtycke. - brand-guard grön; pnpm typecheck 19/19; pnpm test --force x2 grönt (34 tasks, 275 tester).
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
rankAll,
|
||||
seasonForDate,
|
||||
summarizeContext,
|
||||
viewWeights,
|
||||
type CookingAssumption,
|
||||
type RecommendationCandidate,
|
||||
type RecommendationContext,
|
||||
@@ -381,11 +382,17 @@ export async function recommendationRoutes(app: FastifyInstance) {
|
||||
? Math.floor((today.getTime() - Date.parse(lastDate)) / 86_400_000)
|
||||
: null,
|
||||
householdRating: householdRatingMap.get(recipe.id) ?? null,
|
||||
ingredientIds: recipeIngredients.map((i) => i.canonicalIngredientId).filter((id): id is string => id != null),
|
||||
ingredientIds: recipeIngredients
|
||||
.map((i) => i.canonicalIngredientId)
|
||||
.filter((id): id is string => id != null),
|
||||
});
|
||||
}
|
||||
|
||||
const weights = personalizationEnabled ? undefined : NON_PERSONALIZED_WEIGHTS;
|
||||
const weights = personalizationEnabled
|
||||
? q.view === "default"
|
||||
? undefined
|
||||
: viewWeights(q.view)
|
||||
: NON_PERSONALIZED_WEIGHTS;
|
||||
let recommendations = rankAll(scoredCandidates, ctx, weights, q.limit);
|
||||
|
||||
// --- 9. AAMOS-omrankning bakom feature flag (aldrig obligatorisk) ---
|
||||
@@ -416,19 +423,20 @@ export async function recommendationRoutes(app: FastifyInstance) {
|
||||
}
|
||||
|
||||
// --- 10. Matlådor först när rimligt (spec §24) ---
|
||||
const mealBoxes = q.includeLeftovers && householdId
|
||||
? await app.db
|
||||
.select()
|
||||
.from(schema.mealBoxes)
|
||||
.where(
|
||||
and(
|
||||
eq(schema.mealBoxes.householdId, householdId),
|
||||
eq(schema.mealBoxes.status, "available"),
|
||||
),
|
||||
)
|
||||
.orderBy(schema.mealBoxes.recommendedUseBy)
|
||||
.limit(5)
|
||||
: [];
|
||||
const mealBoxes =
|
||||
q.includeLeftovers && householdId
|
||||
? await app.db
|
||||
.select()
|
||||
.from(schema.mealBoxes)
|
||||
.where(
|
||||
and(
|
||||
eq(schema.mealBoxes.householdId, householdId),
|
||||
eq(schema.mealBoxes.status, "available"),
|
||||
),
|
||||
)
|
||||
.orderBy(schema.mealBoxes.recommendedUseBy)
|
||||
.limit(5)
|
||||
: [];
|
||||
const mealBoxSuggestions = mealBoxes.map((box) => ({
|
||||
mealBoxId: box.id,
|
||||
titleSv: box.titleSv,
|
||||
@@ -449,6 +457,7 @@ export async function recommendationRoutes(app: FastifyInstance) {
|
||||
remainingKcal: ctx.remainingKcal,
|
||||
remainingProteinG: ctx.remainingProteinG,
|
||||
craving: craving ?? null,
|
||||
view: personalizationEnabled ? q.view : "default",
|
||||
},
|
||||
mealBoxSuggestions,
|
||||
recommendations,
|
||||
|
||||
Reference in New Issue
Block a user