fix(recipe-generation): robustare Gemini-enheter, butter-densitet, utökad pilot-output
This commit is contained in:
@@ -362,6 +362,14 @@ export class GeminiAamosClient implements AamosClient {
|
|||||||
const costUsd = this.estimateCostUsd(inputTokens, outputTokens);
|
const costUsd = this.estimateCostUsd(inputTokens, outputTokens);
|
||||||
await this.recordSpend(costUsd);
|
await this.recordSpend(costUsd);
|
||||||
|
|
||||||
|
// Normalisera enheter defensivt: Gemini kan ibland returnera "dl"/"msk"/"st".
|
||||||
|
for (const c of parsed.candidates) {
|
||||||
|
for (const ing of c.ingredients) {
|
||||||
|
const normalized = normalizeUnit(String(ing.unit));
|
||||||
|
if (normalized) ing.unit = normalized as typeof ing.unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const latencyMs = Date.now() - started;
|
const latencyMs = Date.now() - started;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -411,7 +419,7 @@ Begränsningar:
|
|||||||
Regler:
|
Regler:
|
||||||
- Recepten ska vara realistiska vardagsrätter för svenska hushåll.
|
- Recepten ska vara realistiska vardagsrätter för svenska hushåll.
|
||||||
- Stegen ska vara tydliga, med rimliga tider och temperaturer.
|
- Stegen ska vara tydliga, med rimliga tider och temperaturer.
|
||||||
- Använd svenska mått (g, dl, msk, tsk, st).
|
- Använd ENDAST dessa exakta enhetskoder: GRAM, KILOGRAM, MILLILITER, DECILITER, LITER, TEASPOON, TABLESPOON, CUP_US, COUNT, PORTION, PINCH, SLICE, CLOVE, CAN, PACKAGE. Aldrig "g", "dl", "msk", "tsk", "st".
|
||||||
- Formuleringen ska vara mjölkprincips-vänlig: ingen svinnskam, inget "släng".
|
- Formuleringen ska vara mjölkprincips-vänlig: ingen svinnskam, inget "släng".
|
||||||
- Varje ingrediens MÅSTE finnas i katalogen ovan.
|
- Varje ingrediens MÅSTE finnas i katalogen ovan.
|
||||||
- Svara ENDAST med giltig JSON i exakt detta format:
|
- Svara ENDAST med giltig JSON i exakt detta format:
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ export const SEED_INGREDIENTS: SeedIngredient[] = [
|
|||||||
...vgt,
|
...vgt,
|
||||||
allergens: ["milk"],
|
allergens: ["milk"],
|
||||||
containsLactose: true,
|
containsLactose: true,
|
||||||
|
densityGPerMl: 0.91,
|
||||||
n: { kcal: 744, p: 0.6, k: 0.7, f: 82, mf: 52, salt: 1.2 },
|
n: { kcal: 744, p: 0.6, k: 0.7, f: 82, mf: 52, salt: 1.2 },
|
||||||
shelfLifeGuidance: { fridge: 60 },
|
shelfLifeGuidance: { fridge: 60 },
|
||||||
defaultPriceMinorPerKg: 11000,
|
defaultPriceMinorPerKg: 11000,
|
||||||
|
|||||||
@@ -110,11 +110,23 @@ async function main() {
|
|||||||
rejectedCount: result.rejectedCount,
|
rejectedCount: result.rejectedCount,
|
||||||
candidates: result.verificationResults.map((r) => ({
|
candidates: result.verificationResults.map((r) => ({
|
||||||
title: r.candidate.titleSv,
|
title: r.candidate.titleSv,
|
||||||
|
descriptionSv: r.candidate.descriptionSv,
|
||||||
status: r.status,
|
status: r.status,
|
||||||
reasons: r.reasons,
|
reasons: r.reasons,
|
||||||
allergens: r.allergens,
|
allergens: r.allergens,
|
||||||
nutritionPerPortion: r.nutritionPerPortion,
|
nutritionPerPortion: r.nutritionPerPortion,
|
||||||
ingredients: r.candidate.ingredients.map((i) => i.canonicalIngredientId),
|
ingredients: r.candidate.ingredients.map((i) => ({
|
||||||
|
id: i.canonicalIngredientId,
|
||||||
|
name: i.displayNameSv,
|
||||||
|
quantity: i.quantity,
|
||||||
|
unit: i.unit,
|
||||||
|
optional: i.optional,
|
||||||
|
})),
|
||||||
|
steps: r.candidate.steps.map((s, idx) => ({
|
||||||
|
number: idx + 1,
|
||||||
|
instruction: s.instructionSv,
|
||||||
|
durationMinutes: s.durationMinutes ?? null,
|
||||||
|
})),
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user