# KitchenOwl Recipe Import (Doris-managed) ## Why this exists KitchenOwl's built-in import/scrape flow is unreliable for the way John and Leanne actually send recipe links around. This repo-side helper gives Doris a safer path: 1. try KitchenOwl's native `/recipe/scrape` endpoint for sites it understands 2. if that fails, fetch the page directly 3. extract schema.org `Recipe` JSON-LD 4. normalize ingredients/tags/timings into KitchenOwl's create-recipe payload 5. optionally create the recipe through the KitchenOwl API That means Doris can ingest recipe links from chat without depending on KitchenOwl's flaky native importer. ## Script ```bash automation/bin/kitchenowl_recipe_import.py ``` Default mode is **dry-run**. It prints the normalized KitchenOwl payload and does **not** create anything unless `--create` is passed. ## Required env vars Put these in a live `.env` file or export them ad hoc. Do **not** commit live secrets. ```env KITCHENOWL_BASE_URL=https://owl.paccoco.com KITCHENOWL_API_TOKEN=CHANGE_ME KITCHENOWL_HOUSEHOLD_ID=1 ``` Notes: - `KITCHENOWL_API_TOKEN` should be a long-lived token for a user who can create recipes in the target household. - `KITCHENOWL_HOUSEHOLD_ID` for the current live instance is `1` (`Stafford's`) unless that changes later. ## Usage ### Dry-run a link ```bash cd /home/fizzlepoof/repos/truenas-stacks export KITCHENOWL_BASE_URL=https://owl.paccoco.com export KITCHENOWL_API_TOKEN=...redacted... export KITCHENOWL_HOUSEHOLD_ID=1 automation/bin/kitchenowl_recipe_import.py --pretty \ "https://example.com/my-recipe" ``` ### Actually create the recipe ```bash automation/bin/kitchenowl_recipe_import.py --pretty --create \ "https://example.com/my-recipe" ``` ### Import several links at once ```bash automation/bin/kitchenowl_recipe_import.py --create --pretty \ "https://example.com/recipe-1" \ "https://example.com/recipe-2" ``` ## Behavior details ### Strategy order By default the helper tries: 1. `GET /api/household//recipe/scrape?url=...` 2. if KitchenOwl returns `Unsupported website` or otherwise fails, Doris falls back to direct HTML fetch + JSON-LD parse If you want to skip the built-in scrape and go straight to Doris mode: ```bash automation/bin/kitchenowl_recipe_import.py --skip-kitchenowl-scrape --pretty URL ``` ### Duplicate protection Before creating a recipe, the helper loads existing household recipes and skips creation if it finds: - an exact matching `source` URL, or - an exact matching recipe `name` To force duplicates anyway: ```bash automation/bin/kitchenowl_recipe_import.py --create --allow-duplicates URL ``` ### Visibility KitchenOwl visibility enum: - `0` = private (default) - `1` = link - `2` = public Example: ```bash automation/bin/kitchenowl_recipe_import.py --create --visibility 0 URL ``` ## What parses well The fallback parser works best on recipe pages that expose proper schema.org `Recipe` JSON-LD, which many decent recipe sites do. It pulls: - name - description - instructions - ingredient list - total/prep/cook time - yield/servings - categories/cuisine/keywords → KitchenOwl tags ## Known limitations - Some sites block scraping aggressively; Doris first tries normal fetch, then falls back to `curl` headers for better odds. - Ingredient normalization is heuristic, not magic. It aims for a sane KitchenOwl item name plus a description/amount, but some weird ingredients may still need manual cleanup. - Image upload/import is not wired yet in this helper. - The helper expects structured JSON-LD. If a site hides the recipe entirely in client-side blobs or anti-bot nonsense, manual copy/paste may still be needed. - `GET /api/settings` on the live KitchenOwl instance currently returns `500`, but that does not block recipe import. ## Doris workflow expectation Preferred operator flow when John or Leanne sends recipe links: 1. Doris runs a dry-run first when the site is unfamiliar or suspicious. 2. If the normalized payload looks sane, Doris reruns with `--create`. 3. If the page is too messy, Doris asks for the raw ingredients/steps and imports it manually. That keeps KitchenOwl as the recipe store while making Doris the reliable intake layer.