feat: add rematch functionality for recipe ingredients and enhance inventory management
Test Suite / test (24.15.0) (push) Has been cancelled

- Added a new API path for rematching recipe ingredients in `api_paths.dart`.
- Implemented a manual product creation dialog in `inventory_screen.dart` to allow users to create new products directly.
- Integrated the rematch functionality in `recipe_repository.dart` to handle rematching of recipe ingredients.
- Updated the recipe detail screen to include a button for triggering the rematch process.
- Introduced a new `RecipeMatchingService` in the backend to handle ingredient matching logic.
- Added database migration to include `aiEngineEnabled` column in the User table.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Nils-Johan Gynther
2026-05-06 09:20:31 +02:00
parent 9fe85a719c
commit 04b1fc3024
53 changed files with 1420 additions and 652 deletions
+44 -1
View File
@@ -1,8 +1,10 @@
import { PrismaService } from '../prisma/prisma.service';
import { AiService } from '../ai/ai.service';
type AnalysisStatus = 'exact_match' | 'covered_by_pantry' | 'substitutable' | 'missing';
export declare class RecipeAnalysisService {
private readonly prisma;
constructor(prisma: PrismaService);
private readonly aiService;
constructor(prisma: PrismaService, aiService: AiService);
private getAccessibleRecipe;
private calculateAvailableQuantity;
analyzeRecipeIngredients(id: number, userId: number): Promise<{
@@ -46,5 +48,46 @@ export declare class RecipeAnalysisService {
missingQuantity: number;
}[];
}>;
rematchRecipeIngredients(id: number, userId: number): Promise<{
recipeId: number;
ingredients: ({
ingredientId: any;
rawName: any;
quantity: number;
unit: any;
note: any;
status: AnalysisStatus;
matchedProductId: any;
matchedProductName: any;
source: string;
availableQuantity: number;
missingQuantity: number;
} | {
ingredientId: any;
rawName: any;
quantity: number;
unit: any;
note: any;
status: AnalysisStatus;
matchedProductId: any;
matchedProductName: any;
source: null;
availableQuantity: number;
missingQuantity: number;
})[];
summary: {
exactCount: number;
pantryCount: number;
substituteCount: number;
missingCount: number;
};
shoppingListCandidates: {
ingredientId: any;
rawName: any;
quantity: number;
unit: any;
missingQuantity: number;
}[];
}>;
}
export {};
+61 -2
View File
@@ -13,9 +13,11 @@ exports.RecipeAnalysisService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
const units_1 = require("../common/utils/units");
const ai_service_1 = require("../ai/ai.service");
let RecipeAnalysisService = class RecipeAnalysisService {
constructor(prisma) {
constructor(prisma, aiService) {
this.prisma = prisma;
this.aiService = aiService;
}
async getAccessibleRecipe(id, userId) {
const recipe = await this.prisma.recipe.findFirst({
@@ -65,16 +67,51 @@ let RecipeAnalysisService = class RecipeAnalysisService {
}
async analyzeRecipeIngredients(id, userId) {
const recipe = await this.getAccessibleRecipe(id, userId);
const user = await this.prisma.user.findUnique({
where: { id: userId },
select: { aiEngineEnabled: true },
});
const pantryItems = await this.prisma.pantryItem.findMany({
where: { userId },
select: { productId: true },
});
const pantryProductIds = new Set(pantryItems.map((p) => p.productId));
const userInventory = await this.prisma.inventoryItem.findMany({
select: { productId: true },
});
const availableProductIds = new Set([
...pantryItems.map((p) => p.productId),
...userInventory.map((i) => i.productId),
]);
const availableProducts = availableProductIds.size > 0
? await this.prisma.product.findMany({
where: { id: { in: Array.from(availableProductIds) }, isActive: true },
select: { id: true, name: true, canonicalName: true },
})
: [];
const ingredients = await Promise.all(recipe.ingredients.map(async (ingredient) => {
const requiredQuantity = Number(ingredient.quantity ?? 0);
const requiredUnit = (ingredient.unit ?? '').trim();
const rawName = (ingredient.rawName ?? '').trim() || 'Okänd ingrediens';
if (!ingredient.productId || !ingredient.product) {
const aiMatches = user?.aiEngineEnabled ? await this.aiService.suggestIngredientMatches(rawName, availableProducts) : [];
const aiBest = aiMatches[0];
if (aiBest) {
const matched = availableProducts.find((p) => p.id === aiBest.productId);
return {
ingredientId: ingredient.id,
rawName,
quantity: requiredQuantity,
unit: requiredUnit,
note: ingredient.note ?? null,
status: 'substitutable',
matchedProductId: aiBest.productId,
matchedProductName: matched?.canonicalName || matched?.name || null,
source: 'ai_match',
availableQuantity: 0,
missingQuantity: requiredQuantity,
};
}
return {
ingredientId: ingredient.id,
rawName,
@@ -172,6 +209,24 @@ let RecipeAnalysisService = class RecipeAnalysisService {
};
}
}
const aiSubs = user?.aiEngineEnabled ? await this.aiService.suggestSubstitutions(rawName, availableProducts) : [];
const aiBestSub = aiSubs[0];
if (aiBestSub) {
const aiProduct = availableProducts.find((p) => p.id === aiBestSub.productId);
return {
ingredientId: ingredient.id,
rawName,
quantity: requiredQuantity,
unit: requiredUnit,
note: ingredient.note ?? null,
status: 'substitutable',
matchedProductId: aiBestSub.productId,
matchedProductName: aiProduct?.canonicalName || aiProduct?.name || null,
source: 'ai_substitute',
availableQuantity,
missingQuantity: Math.max(0, requiredQuantity - availableQuantity),
};
}
return {
ingredientId: ingredient.id,
rawName,
@@ -208,10 +263,14 @@ let RecipeAnalysisService = class RecipeAnalysisService {
shoppingListCandidates,
};
}
async rematchRecipeIngredients(id, userId) {
return this.analyzeRecipeIngredients(id, userId);
}
};
exports.RecipeAnalysisService = RecipeAnalysisService;
exports.RecipeAnalysisService = RecipeAnalysisService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
ai_service_1.AiService])
], RecipeAnalysisService);
//# sourceMappingURL=recipe-analysis.service.js.map
File diff suppressed because one or more lines are too long
+17
View File
@@ -0,0 +1,17 @@
export type ProductMatchCandidate = {
id: number;
name: string;
canonicalName: string | null;
normalizedName: string;
};
export type IngredientSuggestion = {
productId: number;
productName: string;
score: number;
};
export declare class RecipeMatchingService {
private normalize;
private levenshtein;
private scoreProducts;
buildIngredientSuggestions(rawName: string, alternatives: string[] | undefined, products: ProductMatchCandidate[]): IngredientSuggestion[];
}
+78
View File
@@ -0,0 +1,78 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RecipeMatchingService = void 0;
const common_1 = require("@nestjs/common");
let RecipeMatchingService = class RecipeMatchingService {
normalize(value) {
return value
.toLowerCase()
.trim()
.replace(/[^a-zåäö0-9\s]/gi, '')
.replace(/\s+/g, ' ');
}
levenshtein(a, b) {
const m = a.length;
const n = b.length;
const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
dp[i][j] =
a[i - 1] === b[j - 1]
? dp[i - 1][j - 1]
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
}
}
return dp[m][n];
}
scoreProducts(query, products) {
const normalizedQuery = this.normalize(query);
return products
.map((product) => {
const targetName = this.normalize(product.canonicalName || product.name);
const targetNormalized = this.normalize(product.normalizedName);
if (targetNormalized === normalizedQuery || targetName === normalizedQuery) {
return { product, score: 100 };
}
if (targetName.includes(normalizedQuery) || normalizedQuery.includes(targetName)) {
return { product, score: 70 };
}
const dist = this.levenshtein(normalizedQuery, targetName);
const maxLen = Math.max(normalizedQuery.length, targetName.length);
const similarity = maxLen === 0 ? 100 : Math.round((1 - dist / maxLen) * 100);
return { product, score: similarity };
})
.filter((s) => s.score >= 40)
.sort((a, b) => b.score - a.score)
.slice(0, 5);
}
buildIngredientSuggestions(rawName, alternatives, products) {
const variants = alternatives && alternatives.length > 1 ? alternatives : [rawName];
const seenIds = new Set();
return variants
.flatMap((variant) => this.scoreProducts(variant, products))
.filter((s) => {
if (seenIds.has(s.product.id))
return false;
seenIds.add(s.product.id);
return true;
})
.sort((a, b) => b.score - a.score)
.slice(0, 5)
.map((s) => ({
productId: s.product.id,
productName: s.product.canonicalName || s.product.name,
score: s.score,
}));
}
};
exports.RecipeMatchingService = RecipeMatchingService;
exports.RecipeMatchingService = RecipeMatchingService = __decorate([
(0, common_1.Injectable)()
], RecipeMatchingService);
//# sourceMappingURL=recipe-matching.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"recipe-matching.service.js","sourceRoot":"","sources":["../../src/recipes/recipe-matching.service.ts"],"names":[],"mappings":"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"}
+176 -137
View File
@@ -23,11 +23,7 @@ export declare class RecipesController {
quantity: number;
unit: string;
note: string | null;
suggestions: {
productId: number;
productName: string;
score: number;
}[];
suggestions: import("./recipe-matching.service").IngredientSuggestion[];
}[];
}>;
getAiSuggestions(user: {
@@ -56,30 +52,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -90,16 +86,16 @@ export declare class RecipesController {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
})[]>;
getInventoryPreview(id: number, user: {
userId: number;
@@ -157,7 +153,7 @@ export declare class RecipesController {
quantity: number;
unit: any;
note: any;
status: "missing" | "exact_match" | "covered_by_pantry" | "substitutable";
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
matchedProductId: any;
matchedProductName: any;
source: string;
@@ -169,7 +165,50 @@ export declare class RecipesController {
quantity: number;
unit: any;
note: any;
status: "missing" | "exact_match" | "covered_by_pantry" | "substitutable";
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
matchedProductId: any;
matchedProductName: any;
source: null;
availableQuantity: number;
missingQuantity: number;
})[];
summary: {
exactCount: number;
pantryCount: number;
substituteCount: number;
missingCount: number;
};
shoppingListCandidates: {
ingredientId: any;
rawName: any;
quantity: number;
unit: any;
missingQuantity: number;
}[];
}>;
rematchRecipeIngredients(id: number, user: {
userId: number;
}): Promise<{
recipeId: number;
ingredients: ({
ingredientId: any;
rawName: any;
quantity: number;
unit: any;
note: any;
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
matchedProductId: any;
matchedProductName: any;
source: string;
availableQuantity: number;
missingQuantity: number;
} | {
ingredientId: any;
rawName: any;
quantity: number;
unit: any;
note: any;
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
matchedProductId: any;
matchedProductName: any;
source: null;
@@ -211,30 +250,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -245,16 +284,16 @@ export declare class RecipesController {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
create(createRecipeDto: CreateRecipeDto, user: {
userId: number;
@@ -273,30 +312,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -304,16 +343,16 @@ export declare class RecipesController {
analysisStatus: string | null;
})[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
update(id: number, createRecipeDto: CreateRecipeDto, user: {
userId: number;
@@ -332,30 +371,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -363,16 +402,16 @@ export declare class RecipesController {
analysisStatus: string | null;
})[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
remove(id: number, user: {
userId: number;
@@ -398,30 +437,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -432,16 +471,16 @@ export declare class RecipesController {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
addIngredient(id: number, ingredient: CreateIngredientDto, user: {
userId: number;
@@ -459,30 +498,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -510,30 +549,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -544,16 +583,16 @@ export declare class RecipesController {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
shareRecipe(id: number, dto: ShareRecipeDto, user: {
userId: number;
@@ -576,30 +615,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -610,16 +649,16 @@ export declare class RecipesController {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
unshareRecipe(id: number, username: string, user: {
userId: number;
@@ -642,30 +681,30 @@ export declare class RecipesController {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: import("@prisma/client/runtime/library").Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
matchConfidence: number | null;
@@ -676,16 +715,16 @@ export declare class RecipesController {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
}
export {};
+11
View File
@@ -49,6 +49,9 @@ let RecipesController = class RecipesController {
getRecipeAnalysis(id, user) {
return this.recipeAnalysisService.analyzeRecipeIngredients(id, user.userId);
}
rematchRecipeIngredients(id, user) {
return this.recipeAnalysisService.rematchRecipeIngredients(id, user.userId);
}
findOne(id, user) {
return this.recipesService.findOne(id, user.userId);
}
@@ -115,6 +118,14 @@ __decorate([
__metadata("design:paramtypes", [Number, Object]),
__metadata("design:returntype", void 0)
], RecipesController.prototype, "getRecipeAnalysis", null);
__decorate([
(0, common_1.Post)(':id/rematch'),
__param(0, (0, common_1.Param)('id', common_1.ParseIntPipe)),
__param(1, (0, current_user_decorator_1.CurrentUser)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Object]),
__metadata("design:returntype", void 0)
], RecipesController.prototype, "rematchRecipeIngredients", null);
__decorate([
(0, common_1.Get)(':id'),
__param(0, (0, common_1.Param)('id', common_1.ParseIntPipe)),
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"recipes.controller.js","sourceRoot":"","sources":["../../src/recipes/recipes.controller.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"recipes.controller.js","sourceRoot":"","sources":["../../src/recipes/recipes.controller.ts"],"names":[],"mappings":"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"}
+2 -1
View File
@@ -13,6 +13,7 @@ const ai_module_1 = require("../ai/ai.module");
const recipes_controller_1 = require("./recipes.controller");
const recipes_service_1 = require("./recipes.service");
const recipe_analysis_service_1 = require("./recipe-analysis.service");
const recipe_matching_service_1 = require("./recipe-matching.service");
let RecipesModule = class RecipesModule {
};
exports.RecipesModule = RecipesModule;
@@ -20,7 +21,7 @@ exports.RecipesModule = RecipesModule = __decorate([
(0, common_1.Module)({
imports: [prisma_module_1.PrismaModule, ai_module_1.AiModule],
controllers: [recipes_controller_1.RecipesController],
providers: [recipes_service_1.RecipesService, recipe_analysis_service_1.RecipeAnalysisService],
providers: [recipes_service_1.RecipesService, recipe_analysis_service_1.RecipeAnalysisService, recipe_matching_service_1.RecipeMatchingService],
})
], RecipesModule);
//# sourceMappingURL=recipes.module.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"recipes.module.js","sourceRoot":"","sources":["../../src/recipes/recipes.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2DAAuD;AACvD,+CAA2C;AAC3C,6DAAyD;AACzD,uDAAmD;AACnD,uEAAkE;AAO3D,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IALzB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,EAAE,oBAAQ,CAAC;QACjC,WAAW,EAAE,CAAC,sCAAiB,CAAC;QAChC,SAAS,EAAE,CAAC,gCAAc,EAAE,+CAAqB,CAAC;KACnD,CAAC;GACW,aAAa,CAAG"}
{"version":3,"file":"recipes.module.js","sourceRoot":"","sources":["../../src/recipes/recipes.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2DAAuD;AACvD,+CAA2C;AAC3C,6DAAyD;AACzD,uDAAmD;AACnD,uEAAkE;AAClE,uEAAkE;AAO3D,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IALzB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,EAAE,oBAAQ,CAAC;QACjC,WAAW,EAAE,CAAC,sCAAiB,CAAC;QAChC,SAAS,EAAE,CAAC,gCAAc,EAAE,+CAAqB,EAAE,+CAAqB,CAAC;KAC1E,CAAC;GACW,aAAa,CAAG"}
+134 -136
View File
@@ -4,6 +4,7 @@ import { AiService } from '../ai/ai.service';
import { CreateRecipeDto } from './dto/create-recipe.dto';
import { CreateIngredientDto } from './dto/create-ingredient.dto';
import { ParseMarkdownDto } from './dto/parse-markdown.dto';
import { RecipeMatchingService } from './recipe-matching.service';
export interface AiRecipeSuggestion {
name: string;
description: string;
@@ -14,8 +15,9 @@ export interface AiRecipeSuggestion {
export declare class RecipesService {
private readonly prisma;
private readonly aiService;
private readonly recipeMatchingService;
private readonly logger;
constructor(prisma: PrismaService, aiService: AiService);
constructor(prisma: PrismaService, aiService: AiService, recipeMatchingService: RecipeMatchingService);
private throwRecipeNotFound;
private normalizeIngredientName;
private assertProductsActive;
@@ -85,30 +87,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -119,16 +121,16 @@ export declare class RecipesService {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
})[]>;
findOne(id: number, userId: number): Promise<{
owner: {
@@ -149,30 +151,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -183,16 +185,16 @@ export declare class RecipesService {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
update(id: number, updateRecipeDto: CreateRecipeDto, userId: number): Promise<{
ingredients: ({
@@ -209,30 +211,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -240,16 +242,16 @@ export declare class RecipesService {
analysisStatus: string | null;
})[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
remove(id: number, userId: number): Promise<void>;
updateImage(id: number, sourceUrl: string, userId: number): Promise<{
@@ -271,30 +273,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -305,16 +307,16 @@ export declare class RecipesService {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
setVisibility(id: number, userId: number, isPublic: boolean): Promise<{
owner: {
@@ -335,30 +337,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -369,16 +371,16 @@ export declare class RecipesService {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
shareWithUser(id: number, ownerId: number, username: string): Promise<{
owner: {
@@ -399,30 +401,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -433,16 +435,16 @@ export declare class RecipesService {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
unshareWithUser(id: number, ownerId: number, username: string): Promise<{
owner: {
@@ -463,30 +465,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -497,16 +499,16 @@ export declare class RecipesService {
userId: number;
}[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
create(createRecipeDto: CreateRecipeDto, userId: number): Promise<{
ingredients: ({
@@ -523,30 +525,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -554,16 +556,16 @@ export declare class RecipesService {
analysisStatus: string | null;
})[];
} & {
id: number;
name: string;
isPublic: boolean;
id: number;
createdAt: Date;
updatedAt: Date;
ownerId: number | null;
description: string | null;
instructions: string | null;
imageUrl: string | null;
servings: number | null;
isPublic: boolean;
ownerId: number | null;
createdAt: Date;
updatedAt: Date;
}>;
addIngredient(id: number, ingredient: CreateIngredientDto, userId: number): Promise<{
product: ({
@@ -579,30 +581,30 @@ export declare class RecipesService {
fiber: number | null;
} | null;
} & {
id: number;
name: string;
ownerId: number;
createdAt: Date;
updatedAt: Date;
status: string;
normalizedName: string;
category: string | null;
status: string;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
categoryId: number | null;
createdAt: Date;
updatedAt: Date;
ownerId: number;
isPrivate: boolean;
}) | null;
} & {
id: number;
createdAt: Date;
updatedAt: Date;
recipeId: number;
productId: number | null;
rawName: string;
rawLine: string | null;
quantity: Prisma.Decimal | null;
unit: string | null;
recipeId: number;
rawName: string;
rawLine: string | null;
note: string | null;
alternativeProductIds: Prisma.JsonValue | null;
matchConfidence: number | null;
@@ -623,11 +625,7 @@ export declare class RecipesService {
quantity: number;
unit: string;
note: string | null;
suggestions: {
productId: number;
productName: string;
score: number;
}[];
suggestions: import("./recipe-matching.service").IngredientSuggestion[];
}[];
}>;
}
+6 -54
View File
@@ -19,11 +19,13 @@ const ai_service_1 = require("../ai/ai.service");
const download_image_1 = require("../common/utils/download-image");
const recipe_parser_1 = require("../common/utils/recipe-parser");
const units_1 = require("../common/utils/units");
const recipe_matching_service_1 = require("./recipe-matching.service");
const IMAGE_DEST_DIR = process.env.IMAGE_DEST_DIR || '/app/recipe-images';
let RecipesService = RecipesService_1 = class RecipesService {
constructor(prisma, aiService) {
constructor(prisma, aiService, recipeMatchingService) {
this.prisma = prisma;
this.aiService = aiService;
this.recipeMatchingService = recipeMatchingService;
this.logger = new common_1.Logger(RecipesService_1.name);
}
throwRecipeNotFound(id) {
@@ -608,59 +610,8 @@ Regler:
where: { isActive: true },
select: { id: true, name: true, canonicalName: true, normalizedName: true },
});
const normalize = (s) => s.toLowerCase().trim().replace(/[^a-zåäö0-9\s]/gi, '').replace(/\s+/g, ' ');
const levenshtein = (a, b) => {
const m = a.length;
const n = b.length;
const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
dp[i][j] =
a[i - 1] === b[j - 1]
? dp[i - 1][j - 1]
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
}
}
return dp[m][n];
};
const ingredientsWithSuggestions = parsed.ingredients.map((ingredient) => {
const alternatives = ingredient.alternatives?.length > 1
? ingredient.alternatives
: [ingredient.rawName];
const scoreProduct = (query) => allProducts
.map((product) => {
const targetName = normalize(product.canonicalName || product.name);
const targetNormalized = normalize(product.normalizedName);
if (targetNormalized === query || targetName === query) {
return { product, score: 100 };
}
if (targetName.includes(query) || query.includes(targetName)) {
return { product, score: 70 };
}
const dist = levenshtein(query, targetName);
const maxLen = Math.max(query.length, targetName.length);
const similarity = maxLen === 0 ? 100 : Math.round((1 - dist / maxLen) * 100);
return { product, score: similarity };
})
.filter((s) => s.score >= 40)
.sort((a, b) => b.score - a.score)
.slice(0, 5);
const seenIds = new Set();
const scored = alternatives
.flatMap((alt) => scoreProduct(normalize(alt)))
.filter((s) => {
if (seenIds.has(s.product.id))
return false;
seenIds.add(s.product.id);
return true;
})
.sort((a, b) => b.score - a.score)
.slice(0, 5)
.map((s) => ({
productId: s.product.id,
productName: s.product.canonicalName || s.product.name,
score: s.score,
}));
const scored = this.recipeMatchingService.buildIngredientSuggestions(ingredient.rawName, ingredient.alternatives, allProducts);
return {
rawName: ingredient.rawName,
rawLine: ingredient.rawName,
@@ -683,6 +634,7 @@ exports.RecipesService = RecipesService;
exports.RecipesService = RecipesService = RecipesService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
ai_service_1.AiService])
ai_service_1.AiService,
recipe_matching_service_1.RecipeMatchingService])
], RecipesService);
//# sourceMappingURL=recipes.service.js.map
File diff suppressed because one or more lines are too long