feat(receipt-import): enhance bread category detection and improve session management
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -60,6 +60,22 @@ function hasPorkLikeSignal(normalized: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function hasBreadLikeSignal(normalized: string): boolean {
|
||||
return (
|
||||
/\brostbrod\b/.test(normalized) ||
|
||||
/\brost\s*n\s*toast\b/.test(normalized) ||
|
||||
/\broast\s*n\s*toast\b/.test(normalized) ||
|
||||
/\btoastbrod\b/.test(normalized) ||
|
||||
/\bformbrod\b/.test(normalized) ||
|
||||
/\blantbrod\b/.test(normalized) ||
|
||||
/\bfullkornsbrod\b/.test(normalized) ||
|
||||
/\bfranska\b/.test(normalized) ||
|
||||
/\blimpa\b/.test(normalized) ||
|
||||
/\bbrod\b/.test(normalized) ||
|
||||
/\btoast\b/.test(normalized)
|
||||
);
|
||||
}
|
||||
|
||||
function inferPackageDebugFromRawName(rawName: string): {
|
||||
packageCount: number;
|
||||
packQuantity: number | null;
|
||||
@@ -465,6 +481,24 @@ export class ReceiptImportService {
|
||||
);
|
||||
}
|
||||
|
||||
private resolveBreadCategory(
|
||||
categories: Awaited<ReturnType<CategoriesService['findFlattened']>>,
|
||||
) {
|
||||
return (
|
||||
categories.find(
|
||||
(c) =>
|
||||
c.name.toLowerCase() === 'rostbröd' &&
|
||||
c.path.toLowerCase().startsWith('bröd & kakor > bröd > '),
|
||||
) ||
|
||||
categories.find(
|
||||
(c) =>
|
||||
c.name.toLowerCase() === 'bröd' &&
|
||||
c.path.toLowerCase() === 'bröd & kakor > bröd',
|
||||
) ||
|
||||
categories.find((c) => c.path.toLowerCase() === 'bröd & kakor')
|
||||
);
|
||||
}
|
||||
|
||||
private applyHardCategoryOverrides(
|
||||
signalText: string,
|
||||
suggestion: CategorySuggestion,
|
||||
@@ -531,6 +565,14 @@ export class ReceiptImportService {
|
||||
// ── Regel: Kött/chark (bacon/fläsk m.m.) ────────────────────────────
|
||||
const hasPorkSignal = hasPorkLikeSignal(normalized);
|
||||
|
||||
const hasToastBreadSignal = hasBreadLikeSignal(normalized);
|
||||
|
||||
if (hasToastBreadSignal) {
|
||||
const bread = this.resolveBreadCategory(categories);
|
||||
const hit = toSuggestion(bread, 'high');
|
||||
if (hit) return hit;
|
||||
}
|
||||
|
||||
if (hasPorkSignal) {
|
||||
const l3Pork = this.resolvePorkCategory(categories);
|
||||
const hit = toSuggestion(l3Pork, 'high');
|
||||
@@ -975,6 +1017,28 @@ export class ReceiptImportService {
|
||||
};
|
||||
}
|
||||
|
||||
const hasToastBreadSignal = hasBreadLikeSignal(normalized);
|
||||
|
||||
if (hasToastBreadSignal) {
|
||||
const aiPath = suggestion.path.toLowerCase();
|
||||
const isOutsideBread = !aiPath.startsWith('bröd & kakor > bröd');
|
||||
if (!isOutsideBread) return suggestion;
|
||||
|
||||
const bread = this.resolveBreadCategory(categories);
|
||||
if (!bread) return suggestion;
|
||||
|
||||
this.logger.log(
|
||||
`AI contradiction-guard: "${rawName}" remappas från "${suggestion.path}" till "${bread.path}"`,
|
||||
);
|
||||
return {
|
||||
categoryId: bread.id,
|
||||
categoryName: bread.name,
|
||||
path: bread.path,
|
||||
confidence: 'high',
|
||||
usedFallback: true,
|
||||
};
|
||||
}
|
||||
|
||||
return suggestion;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user