fix(ingest): resolve Docling stacked fraction OCR artifacts into clean measurements
This commit is contained in:
@@ -222,13 +222,23 @@ function parseMetricAmount(str) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cleanFractionText(str) {
|
||||||
|
if (!str) return "";
|
||||||
|
return str
|
||||||
|
.replace(/[\r\n]+/g, " ")
|
||||||
|
.replace(/(\d+)\s*\/\s*\1\s*\/\s*(\d+)/g, (m, a, b) => `${a}/${b}`)
|
||||||
|
.replace(/(\d+)\s*\/\s*(\d+)/g, (m, a, b) => `${a}/${b}`)
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
function parseUsFallback(text, name) {
|
function parseUsFallback(text, name) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
if (/zest/i.test(name)) return { quantity: 1, unit_id: "each", notes: "Zest of 1" };
|
if (/zest/i.test(name)) return { quantity: 1, unit_id: "each", notes: "Zest of 1" };
|
||||||
if (/vanilla bean/i.test(name)) return { quantity: 1, unit_id: "each", notes: "1 bean" };
|
if (/vanilla bean/i.test(name)) return { quantity: 1, unit_id: "each", notes: "1 bean" };
|
||||||
return { quantity: 1, unit_id: "gram", notes: "To taste / as needed" };
|
return { quantity: 1, unit_id: "gram", notes: "To taste / as needed" };
|
||||||
}
|
}
|
||||||
const s = text.replace(/[\r\n\s]+/g, " ").trim().toLowerCase();
|
const s = cleanFractionText(text).toLowerCase();
|
||||||
if (s.includes("1/8") || s.includes("⅛")) return { quantity: 0.6, unit_id: "gram", notes: "⅛ tsp" };
|
if (s.includes("1/8") || s.includes("⅛")) return { quantity: 0.6, unit_id: "gram", notes: "⅛ tsp" };
|
||||||
if (s.includes("1/4") || s.includes("¼")) return { quantity: 1.25, unit_id: "gram", notes: "¼ tsp" };
|
if (s.includes("1/4") || s.includes("¼")) return { quantity: 1.25, unit_id: "gram", notes: "¼ tsp" };
|
||||||
if (s.includes("1/2") || s.includes("½")) return { quantity: 2.5, unit_id: "gram", notes: "½ tsp" };
|
if (s.includes("1/2") || s.includes("½")) return { quantity: 2.5, unit_id: "gram", notes: "½ tsp" };
|
||||||
@@ -244,23 +254,23 @@ function parseUsFallback(text, name) {
|
|||||||
|
|
||||||
const ozMatch = s.match(/^([\d.]+)\s*oz$/);
|
const ozMatch = s.match(/^([\d.]+)\s*oz$/);
|
||||||
if (ozMatch && parseFloat(ozMatch[1]) > 0) {
|
if (ozMatch && parseFloat(ozMatch[1]) > 0) {
|
||||||
return { quantity: Math.round(parseFloat(ozMatch[1]) * 28.3495 * 100) / 100, unit_id: "gram", notes: text };
|
return { quantity: Math.round(parseFloat(ozMatch[1]) * 28.3495 * 100) / 100, unit_id: "gram", notes: cleanFractionText(text) };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { quantity: 1, unit_id: "gram", notes: text };
|
return { quantity: 1, unit_id: "gram", notes: cleanFractionText(text) };
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanIngredientName(raw) {
|
function cleanIngredientName(raw) {
|
||||||
let name = raw.trim().replace(/^[\s•\-\*]+/, "");
|
let cleaned = cleanFractionText(raw).replace(/^[\s•\-\*]+/, "");
|
||||||
let notes = null;
|
let notes = null;
|
||||||
|
|
||||||
const parenMatch = name.match(/^([^(]+)\s*\(([^)]+)\)$/);
|
const parenMatch = cleaned.match(/^([^(]+)\s*\(([^)]+)\)$/);
|
||||||
if (parenMatch) {
|
if (parenMatch) {
|
||||||
name = parenMatch[1].trim();
|
cleaned = parenMatch[1].trim();
|
||||||
notes = parenMatch[2].trim();
|
notes = parenMatch[2].trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
return { name, notes };
|
return { name: cleaned, notes };
|
||||||
}
|
}
|
||||||
|
|
||||||
function inferIngredientId(name) {
|
function inferIngredientId(name) {
|
||||||
@@ -397,9 +407,9 @@ export function parseDoclingBook(doclingJson, targetPages = null) {
|
|||||||
const row = grid.get(r);
|
const row = grid.get(r);
|
||||||
if (!row) continue;
|
if (!row) continue;
|
||||||
|
|
||||||
const ingText = row.get(0) || "";
|
const ingText = cleanFractionText(row.get(0) || "");
|
||||||
const metricText = row.get(1) || "";
|
const metricText = cleanFractionText(row.get(1) || "");
|
||||||
const usText = row.get(2) || "";
|
const usText = cleanFractionText(row.get(2) || "");
|
||||||
|
|
||||||
if (/total weight/i.test(ingText)) {
|
if (/total weight/i.test(ingText)) {
|
||||||
const parsedTotal = parseMetricAmount(metricText) || parseMetricAmount(usText);
|
const parsedTotal = parseMetricAmount(metricText) || parseMetricAmount(usText);
|
||||||
|
|||||||
Reference in New Issue
Block a user