Created
September 10, 2023 10:39
-
-
Save lindell/2a08c49fccb070887a037357b5194e3d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import OpenAI from 'openai'; | |
import clipboard from 'clipboardy'; | |
const openai = new OpenAI({ | |
apiKey: null, // defaults to process.env["OPENAI_API_KEY"] | |
}); | |
const instruction = `You are an ingredient extractor. | |
Given a set of ingredients and steps in a recipe. Determine which ingredients are mentioned in each steps.`; | |
const schema = { | |
"type": "object", | |
"properties": { | |
"steps": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"step": { | |
"type": "number", | |
"description": "The step number" | |
}, | |
"ingredients": { | |
"type": "array", | |
"description": "A list of ingredients used in this step", | |
"items": { | |
"type": "number", | |
"description": "The ingredient number" | |
} | |
}, | |
}, | |
}, | |
}, | |
}, | |
} | |
async function main() { | |
const data = clipboard.readSync(); | |
const recipe = JSON.parse(data); | |
const ingredients = recipe.recipeIngredient; | |
const ingredientList = ingredients | |
.map((ingredient, i) => { | |
if (ingredient.title) { | |
return `\n${ingredient.title})\n${i + 1}: ${ingredientName(ingredient)}`; | |
} else { | |
return `${i + 1}: ${ingredientName(ingredient)}`; | |
} | |
}) | |
.join("\n"); | |
const unusedIngredients = new Set(ingredients.map((_, i) => i + 1)); | |
const steps = recipe. | |
recipeInstructions.map((instruction, i) => `${i + 1}) ${instruction.text}`). | |
join('\n'); | |
const toSend = `The list of ingredients:\n${ingredientList}\n\nThe recipe steps:\n${steps}`; | |
console.log(`This will be sent to the API:\n${toSend}`); | |
const split = await getIngredientSplit(toSend); | |
console.log(JSON.stringify(split, null, 2)); | |
recipe.recipeInstructions.forEach((instruction, i) => { | |
const stepSplits = split.steps.find(s => s.step === i + 1); | |
if (!stepSplits) { | |
return; | |
} | |
const refList = stepSplits.ingredients.map(ingredientNo => { | |
let refId; | |
if (unusedIngredients.has(ingredientNo)) { | |
refId = ingredients[ingredientNo - 1].referenceId; | |
unusedIngredients.delete(ingredientNo); | |
} | |
return { | |
referenceId: refId, | |
}; | |
}).filter(ref => ref.referenceId); | |
instruction.ingredientReferences = refList; | |
}); | |
const final = JSON.stringify(recipe, null, 2); | |
clipboard.writeSync(final); | |
// Print how it was split for easier debugging | |
const stepsWithIngredients = recipe. | |
recipeInstructions.map((instruction, i) => { | |
const instructions = `${i + 1}) ${instruction.text}`; | |
const stepSplits = split.steps.find(s => s.step === i + 1); | |
const ingredientList = stepSplits.ingredients. | |
map(ingredientNo => ingredientName(ingredients[ingredientNo - 1])). | |
join(', '); | |
return `${instructions}\n${ingredientList}` | |
}). | |
join('\n\n'); | |
console.log(stepsWithIngredients); | |
if (unusedIngredients.size !== 0) { | |
console.warn("Ingredient list is not empty, still contains: " | |
+ Array.from(unusedIngredients.values()).map(n => ingredientName(ingredients[n-1])).join(", ") | |
); | |
} | |
} | |
function ingredientName(ingredient) { | |
return ingredient.food?.name || ingredient.display; | |
} | |
async function getIngredientSplit(toSend) { | |
const completion = await openai.chat.completions.create({ | |
model: 'gpt-4', | |
// model: 'gpt-3.5-turbo', | |
// model: 'gpt-3.5-turbo-16k', | |
messages: [ | |
{ role: "system", "content": instruction }, | |
{ role: 'user', content: toSend }, | |
], | |
functions: [{ name: "split_into_steps", parameters: schema }], | |
function_call: { name: "split_into_steps" }, | |
temperature: 0.2, | |
}); | |
console.log(completion); | |
const ret = completion.choices[0].message.function_call.arguments; | |
return JSON.parse(ret); | |
} | |
main().catch(e => console.log(e)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment