fix(byt-ratt): bredda urvalet - alla lampliga ratter, inte bara det man har hemma
Ny 'swap'-vy i rekommendationsmotorn med lag tackningsvikt (30->6) sa betyg/smak/ratt maltidstyp styr i stallet for 'har hemma'. Byt rätt- skarmen anropar view=swap, kringgar vardags-tidsgransen och hojer limit till 20. Loser: bara ~5 val vid byte.
This commit is contained in:
@@ -410,7 +410,9 @@ export async function recommendationRoutes(app: FastifyInstance) {
|
||||
// maten de faktiskt bett om (spec §28) – en kräftskiva eller ett bak tar
|
||||
// tid. Tiden blir mjuk rankning i stället för diskvalificerande filter.
|
||||
// En uttrycklig tidsgräns i förfrågan (q.maxMinutes) respekteras alltid.
|
||||
const hasExplicitIntent = !!(q.holiday || q.tag || q.search);
|
||||
// "swap" räknas som uttrycklig avsikt: byt rätt ska inte hårt gömmas av
|
||||
// hushållets vardags-tidsgräns, annars kvar bara några få snabba rätter.
|
||||
const hasExplicitIntent = !!(q.holiday || q.tag || q.search || q.view === "swap");
|
||||
|
||||
const ctx: RecommendationContext = {
|
||||
mealType: q.mealType,
|
||||
|
||||
@@ -34,8 +34,11 @@ export default function SwapMealScreen() {
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ["swap-options", mealType],
|
||||
// view=swap: bredda urvalet – alla lämpliga rätter, inte bara det man har hemma.
|
||||
queryFn: () =>
|
||||
api<WhatToEatResponse>(`/v1/recommendations/what-to-eat?limit=10&mealType=${mealType}`),
|
||||
api<WhatToEatResponse>(
|
||||
`/v1/recommendations/what-to-eat?limit=20&view=swap&mealType=${mealType}`,
|
||||
),
|
||||
});
|
||||
|
||||
const swap = useMutation({
|
||||
|
||||
@@ -150,9 +150,40 @@ export const NON_PERSONALIZED_WEIGHTS: ScoringWeights = {
|
||||
};
|
||||
|
||||
/** Tillåtna vyer för "Vad ska vi äta?". */
|
||||
export type RecommendationView = "default" | "taste" | "health" | "pantry";
|
||||
export type RecommendationView = "default" | "taste" | "health" | "pantry" | "swap";
|
||||
|
||||
export const RECOMMENDATION_VIEWS: RecommendationView[] = ["default", "taste", "health", "pantry"];
|
||||
export const RECOMMENDATION_VIEWS: RecommendationView[] = [
|
||||
"default",
|
||||
"taste",
|
||||
"health",
|
||||
"pantry",
|
||||
"swap",
|
||||
];
|
||||
|
||||
/**
|
||||
* Byt rätt-vyn: användaren vill se ALLA lämpliga rätter att byta till, inte
|
||||
* bara det de råkar ha hemma. Täckning/utgångsdatum blir bara små tie-breakers;
|
||||
* betyg, smak och rätt måltidstyp styr. (Löser: "byt rätt" gav bara ~5 val.)
|
||||
*/
|
||||
export const SWAP_VIEW_WEIGHTS: ScoringWeights = {
|
||||
coverage: 6,
|
||||
expiry: 4,
|
||||
nutritionFit: 10,
|
||||
taste: 12,
|
||||
rating: 14,
|
||||
season: 5,
|
||||
holiday: 4,
|
||||
time: 4,
|
||||
budget: 4,
|
||||
variety: 8,
|
||||
weather: 2,
|
||||
craving: 10,
|
||||
mealFit: 14,
|
||||
dietAffinity: 10,
|
||||
memoryFit: 6,
|
||||
tasteFit: 6,
|
||||
cookingAssumptionFit: 4,
|
||||
};
|
||||
|
||||
/** Fördefinierade vikter för smak-vyn (S4). */
|
||||
export const TASTE_VIEW_WEIGHTS: ScoringWeights = {
|
||||
@@ -226,6 +257,8 @@ export function viewWeights(view: RecommendationView): ScoringWeights {
|
||||
return HEALTH_VIEW_WEIGHTS;
|
||||
case "pantry":
|
||||
return PANTRY_VIEW_WEIGHTS;
|
||||
case "swap":
|
||||
return SWAP_VIEW_WEIGHTS;
|
||||
default:
|
||||
return DEFAULT_WEIGHTS;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,6 @@ export const whatToEatQuerySchema = z.object({
|
||||
includeLeftovers: z.coerce.boolean().default(true),
|
||||
limit: z.coerce.number().int().min(1).max(20).default(5),
|
||||
/** Personaliseringsvy: smak, hälsa eller lager. Kräver personalization-samtycke. */
|
||||
view: z.enum(["default", "taste", "health", "pantry"]).default("default"),
|
||||
view: z.enum(["default", "taste", "health", "pantry", "swap"]).default("default"),
|
||||
});
|
||||
export type WhatToEatQuery = z.infer<typeof whatToEatQuerySchema>;
|
||||
|
||||
Reference in New Issue
Block a user