feat: kitchen screen, scan dedup, gemini-3.5-flash-lite, seed grapes/beetroot/pea shoots
This commit is contained in:
@@ -266,7 +266,7 @@ export class GeminiAamosClient implements AamosClient {
|
||||
constructor(config: GeminiAamosClientConfig) {
|
||||
this.cfg = {
|
||||
apiKey: config.apiKey,
|
||||
model: config.model ?? "gemini-2.5-flash",
|
||||
model: config.model ?? "gemini-3.5-flash-lite",
|
||||
timeoutMs: config.timeoutMs ?? 60_000,
|
||||
dailyBudgetUsd: config.dailyBudgetUsd ?? 0,
|
||||
promptVersion: config.promptVersion ?? "gemini-fridge-v1",
|
||||
@@ -856,6 +856,11 @@ Identifiera varje livsmedelsprodukt du ser. För varje produkt, svara med:
|
||||
- sistaForbruk: sista förbrukningsdatum om det syns (YYYY-MM-DD), annars null
|
||||
- konfidens: 0.0–1.0
|
||||
|
||||
Viktigt:
|
||||
- Kvantitet: uppskatta den FAKTISKA synliga/kvarvarande mängden, inte tryckta förpackningsantal. Ett tomt eller öppnat paket ska ha låg kvantitet (nära 0), även om lådan säger t.ex. "24-pack". Är du osäker, gissa lågt och sänk konfidensen.
|
||||
- Svenska mjölk- och mejerifärger: röd förpackning = standardmjölk 3%, grön = mellanmjölk 1,5%, blå = lättmjölk 0,5%. Använd färgen för att avgöra fetthalt.
|
||||
- Hellre lägre konfidens än en exakt gissning när du är osäker.
|
||||
|
||||
Svara ENDAST med giltig JSON i exakt detta format:
|
||||
{
|
||||
"items": [...],
|
||||
|
||||
@@ -67,7 +67,7 @@ describe("GeminiAamosClient", () => {
|
||||
const budget = new MemoryBudgetStore();
|
||||
const client = new GeminiAamosClient({
|
||||
apiKey: "test-key",
|
||||
model: "gemini-2.5-flash",
|
||||
model: "gemini-3.5-flash-lite",
|
||||
fetchImpl: makeFetch(JPEG_BYTES),
|
||||
budgetStore: budget,
|
||||
dailyBudgetUsd: 10,
|
||||
@@ -82,7 +82,7 @@ describe("GeminiAamosClient", () => {
|
||||
|
||||
expect(result.status).toBe("ok");
|
||||
expect(result.output).not.toBeNull();
|
||||
expect(result.modelVersion).toBe("gemini-2.5-flash");
|
||||
expect(result.modelVersion).toBe("gemini-3.5-flash-lite");
|
||||
expect(result.costUsd).toBeGreaterThan(0);
|
||||
expect(result.inputTokens).toBe(392);
|
||||
expect(result.outputTokens).toBe(121);
|
||||
|
||||
@@ -978,6 +978,9 @@ export const SEED_INGREDIENTS: SeedIngredient[] = [
|
||||
ing("lingonberry_jam", "Lingonsylt", "Lingonberry jam", "skafferi", { n: { kcal: 200, p: 0.3, k: 49, f: 0.2, s: 45 }, isVegan: true, isVegetarian: true }),
|
||||
ing("prinskorv", "Prinskorv", "Cocktail sausage", "chark", { n: { kcal: 280, p: 11, k: 3, f: 25, mf: 9, salt: 2 }, isPork: true }),
|
||||
ing("rye_flour", "Rågmjöl", "Rye flour", "skafferi", { n: { kcal: 325, p: 9, k: 60, f: 2, fib: 14 }, containsGluten: true, allergens: ["gluten"], isVegan: true, isVegetarian: true }),
|
||||
ing("grape", "Vindruvor", "Grapes", "frukt", { n: { kcal: 69, p: 0.7, k: 18, f: 0.2, fib: 0.9, s: 15 }, isVegan: true, isVegetarian: true, aliases: ["druvor", "vindruva", "roda druvor", "röda druvor", "grona druvor", "gröna druvor", "drue druvor", "drue", "grapes"] }),
|
||||
ing("beetroot", "Rödbetor", "Beetroot", "gronsaker", { n: { kcal: 43, p: 1.6, k: 10, f: 0.2, fib: 2.8, s: 7 }, isVegan: true, isVegetarian: true, aliases: ["rödbeta", "rodbeta", "rödbetor", "rodbetor", "inlagda rödbetor", "inlagda rodbetor", "skivad rödbeta", "skivade rödbetor", "beetroot", "beets", "red beets"] }),
|
||||
ing("pea_shoots", "Ärtskott", "Pea shoots", "gronsaker", { n: { kcal: 42, p: 4, k: 4, f: 0.5, fib: 2 }, isVegan: true, isVegetarian: true, aliases: ["ärtskott", "artskott", "ertskott", "artiskott", "pea shoots"] })
|
||||
];
|
||||
|
||||
export const SEED_INGREDIENT_IDS = new Set(SEED_INGREDIENTS.map((i) => i.id));
|
||||
|
||||
@@ -24,7 +24,8 @@ export interface PlanDefinition {
|
||||
googleProductId: string;
|
||||
}
|
||||
|
||||
export const TRIAL_DAYS = 7;
|
||||
export const TRIAL_DAYS = 14;
|
||||
export const TRIAL_SCANS = 25;
|
||||
|
||||
export const PLAN_DEFINITIONS: Record<SubscriptionPlan, PlanDefinition> = {
|
||||
free: {
|
||||
@@ -33,7 +34,7 @@ export const PLAN_DEFINITIONS: Record<SubscriptionPlan, PlanDefinition> = {
|
||||
priceMinorPerMonth: 0,
|
||||
currency: "SEK",
|
||||
maxHouseholdMembers: 1,
|
||||
aiScansPerMonth: 10,
|
||||
aiScansPerMonth: 5,
|
||||
weekPlanning: false,
|
||||
advancedNutrition: false,
|
||||
communityPublish: false,
|
||||
@@ -46,7 +47,7 @@ export const PLAN_DEFINITIONS: Record<SubscriptionPlan, PlanDefinition> = {
|
||||
priceMinorPerMonth: 7900,
|
||||
currency: "SEK",
|
||||
maxHouseholdMembers: 3,
|
||||
aiScansPerMonth: 300,
|
||||
aiScansPerMonth: 100,
|
||||
weekPlanning: true,
|
||||
advancedNutrition: true,
|
||||
communityPublish: true,
|
||||
@@ -59,7 +60,7 @@ export const PLAN_DEFINITIONS: Record<SubscriptionPlan, PlanDefinition> = {
|
||||
priceMinorPerMonth: 12900,
|
||||
currency: "SEK",
|
||||
maxHouseholdMembers: 6,
|
||||
aiScansPerMonth: 600,
|
||||
aiScansPerMonth: 200,
|
||||
weekPlanning: true,
|
||||
advancedNutrition: true,
|
||||
communityPublish: true,
|
||||
@@ -72,7 +73,7 @@ export const PLAN_DEFINITIONS: Record<SubscriptionPlan, PlanDefinition> = {
|
||||
priceMinorPerMonth: 16900,
|
||||
currency: "SEK",
|
||||
maxHouseholdMembers: 12,
|
||||
aiScansPerMonth: 1000,
|
||||
aiScansPerMonth: 400,
|
||||
weekPlanning: true,
|
||||
advancedNutrition: true,
|
||||
communityPublish: true,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
PLAN_DEFINITIONS,
|
||||
TRIAL_DAYS,
|
||||
TRIAL_SCANS,
|
||||
type Entitlements,
|
||||
type SubscriptionPlan,
|
||||
type SubscriptionStatus,
|
||||
@@ -67,7 +68,7 @@ export function computeEntitlements(
|
||||
plan: "family",
|
||||
status: "trial",
|
||||
maxHouseholdMembers: def.maxHouseholdMembers,
|
||||
aiScansPerMonth: def.aiScansPerMonth,
|
||||
aiScansPerMonth: TRIAL_SCANS,
|
||||
aiScansUsedThisMonth: usage.aiScansUsedThisMonth,
|
||||
weekPlanning: true,
|
||||
advancedNutrition: true,
|
||||
|
||||
Reference in New Issue
Block a user