Tofu/scripts/import-recipes/cli/importOdtFiles.js
2026-09-18 01:41:02 +02:00

57 lines
2.8 KiB
JavaScript

import { join } from 'node:path'
import { MODEL_ID } from '#import-recipes/extraction/MODEL_ID.js'
import { alignParsedIngredients } from '#import-recipes/recipes/alignParsedIngredients.js'
import { buildRecipeDocument } from '#import-recipes/recipes/buildRecipeDocument.js'
import { extractRecipe } from '#import-recipes/extraction/extractRecipe.js'
import { makeUniqueRecipeId } from '#import-recipes/recipes/makeUniqueRecipeId.js'
import { readOdtParagraphs } from '#import-recipes/odt/readOdtParagraphs.js'
import { slugifyRecipeName } from '#import-recipes/recipes/slugifyRecipeName.js'
import { writeJsonFile } from '#import-recipes/cli/writeJsonFile.js'
// The run itself, one document at a time, written to disk as it goes so an
// interrupted run keeps what it already paid for. Every step of a file either
// succeeds or is recorded as a failure - nothing here stops the loop.
export async function importOdtFiles({ client, sourceDir, outDir, fileNames }) {
const recipes = []
const failures = []
const usage = { input: 0, output: 0 }
for (const fileName of fileNames) {
const reading = readOdtParagraphs(join(sourceDir, fileName))
if (!reading.ok) {
failures.push({ fileName, reason: reading.reason })
console.log(`${fileName} - FAILED: ${reading.reason}`)
continue
}
const extraction = await extractRecipe({ client, fileName, paragraphs: reading.paragraphs })
if (!extraction.ok) {
failures.push({ fileName, reason: extraction.reason })
console.log(`${fileName} - FAILED: ${extraction.reason}`)
continue
}
usage.input += extraction.usage?.input_tokens ?? 0
usage.output += extraction.usage?.output_tokens ?? 0
const { recipe } = extraction
const { parsedIngredients, repaired } = alignParsedIngredients(recipe.recipeIngredient, recipe.parsedIngredients)
const document = buildRecipeDocument({
recipe,
parsedIngredients,
fileName,
importedAt: new Date().toISOString(),
model: MODEL_ID
})
const slug = slugifyRecipeName(document.name) || slugifyRecipeName(fileName) || 'recette'
const id = makeUniqueRecipeId(slug, recipes.map((entry) => entry.id))
try {
writeJsonFile(join(outDir, 'recipes', `${id}.json`), document)
} catch (error) {
failures.push({ fileName, reason: `could not be written (${error.message})` })
console.log(`${fileName} - FAILED: ${error.message}`)
continue
}
recipes.push({ id, document })
const lines = repaired === 1 ? 'line' : 'lines'
const realigned = repaired > 0 ? ` [${repaired} ingredient ${lines} realigned]` : ''
console.log(`${fileName} - ${document.name} (${document.recipeIngredient.length} ingredients, ${document.recipeInstructions.length} steps)${realigned}`)
}
return { recipes, failures, usage }
}