57 lines
2.8 KiB
JavaScript
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 }
|
|
}
|