Add R-based EPUB cookbook ingestion and knowledge pipeline - #4
Add R-based EPUB cookbook ingestion and knowledge pipeline#4charles-hebert wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 82a981aec7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "SELECT ir.id, ir.recipe_id, ir.raw_text | ||
| FROM ingredients_raw ir | ||
| LEFT JOIN ingredients i ON i.recipe_id = ir.recipe_id AND i.name = ir.raw_text | ||
| ORDER BY ir.id" |
There was a problem hiding this comment.
Filter out already-normalized ingredient rows
normalize_ingredients() currently selects every ingredients_raw record on each run because the LEFT JOIN is not followed by a filter like WHERE i.id IS NULL, so refreshes keep reprocessing old rows. Because ingredients has no unique key that matches the insert shape, the later ON CONFLICT DO NOTHING will not prevent duplicate ingredient rows, and downstream scoring/quantity calculations (e.g., meal planning and shopping lists) will drift upward after each rerun.
Useful? React with 👍 / 👎.
| prompt <- paste( | ||
| "Extract recipes from this text. Return strict JSON with key recipes.", | ||
| "Each recipe must include: title, ingredients (array of strings),", | ||
| "instructions (array of strings), servings, time_minutes.", | ||
| "If uncertain, return best effort and keep fields nullable.", | ||
| "Text:", raw_text | ||
| ) |
There was a problem hiding this comment.
Chunk EPUB text before calling recipe extraction model
parse_recipes_with_llm() sends the full EPUB text in a single prompt ("Text:", raw_text) and never uses the existing split_recipe_blocks() helper, so larger cookbooks can exceed chat completion context/request limits and fail extraction entirely. This makes ingestion brittle for full-book inputs, which are the primary use case of this script.
Useful? React with 👍 / 👎.
Motivation
pgvectorfor vector embeddings to enable semantic search and fridge-based suggestions.Description
epub_cookbook_ingestor.r, an R script that implements EPUB extraction, LLM-powered recipe parsing, ingredient normalization, alias upserts, and insertion into a PostgreSQL schema defined inSCHEMA_SQL(includesvectorextension andrecipe_embeddingswith aVECTOR(384)column).httr2inopenai_chat_json()and uses LLM prompts for recipe JSON extraction and canonical ingredient normalization inparse_recipes_with_llm()andcanonicalize_ingredient().build_ingredient_graph(),build_substitution_graph()), meal planning and shopping list helpers (meal_plan(),shopping_list()), and embedding/semantic search functions that call Pythonsentence-transformersviareticulate(embed_recipes(),semantic_search()).main()), environment-driven configuration viaCONFIG(expectsOPENAI_API_KEYand PostgreSQL env vars), and ann8nworkflow markdown generator (write_n8n_workflow_markdown()).Testing
Rscript -e "parse(file='epub_cookbook_ingestor.r'); cat('OK\n')"which failed becauseRscriptis not installed in the current environment (automated parse test failed).reticulate) should be validated in a host environment withRscript, PostgreSQL withvectorextension, andOPENAI_API_KEYconfigured.Codex Task