Files
herbapi/tools/enrichment/seed_fungi.py
T
florian.berthold 2cfa57a188 Add insect domain + fungi summary blurb fallback + seed_fungi
Insect domain (migration 016): insects table with order/family taxonomy,
beneficial/pest role, beneficial_roles, pest_severity, host_plant_slugs,
preys_on, life cycle, active months, attracted_by (cross-domain plant links).
Insect+CreateInsect models, db/insects.rs CRUD (role/order filters),
api/insects.rs, /api/v1/insects routes + summary. Wired into stats/export/llms.
Fungus summary now falls back to culinary_uses/habitat for the blurb.
seed_fungi.py committed (15 curated mushrooms).
2026-06-05 21:46:28 +02:00

130 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""
Seed a curated starter set of common cultivated & foraged mushrooms into the
unified API's fungi domain. Conservative, widely-documented mycological facts.
Idempotent: skips fungi whose slug already exists.
Run: HERBAPI_TOKEN=... python3 seed_fungi.py
"""
import json
import os
import urllib.error
import urllib.request
BASE = os.environ.get("HERBAPI_BASE", "http://herbapi01.corp.sub-net.at:8080/api/v1")
TOKEN = os.environ.get("HERBAPI_TOKEN", "")
def api(path, method="GET", data=None):
r = urllib.request.Request(
BASE + path,
data=json.dumps(data).encode() if data is not None else None,
method=method,
)
r.add_header("Authorization", "Bearer " + TOKEN)
r.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(r) as resp:
return resp.status, json.loads(resp.read().decode())
except urllib.error.HTTPError as e:
return e.code, e.read().decode()[:200]
FUNGI = [
{"name_scientific": "Pleurotus ostreatus", "name_de": "Austernseitling", "name_en": "Oyster mushroom",
"family_scientific": "Pleurotaceae", "edibility": "edible", "cultivation": "both", "saprobic": True,
"substrate": ["hardwood_logs", "straw", "woodchips", "coffee_grounds"], "fruiting_months": [10, 11, 12, 1, 2],
"habitat": "On dead and dying hardwoods, especially beech and poplar.", "spore_print_color": "white-lilac",
"culinary_uses": "Widely cultivated culinary mushroom; mild, anise-like flavour.", "native_range": "Cosmopolitan"},
{"name_scientific": "Lentinula edodes", "name_de": "Shiitake", "name_en": "Shiitake",
"family_scientific": "Omphalotaceae", "edibility": "edible", "cultivation": "cultivated", "saprobic": True,
"substrate": ["hardwood_logs", "sawdust_blocks"], "habitat": "On dead hardwood logs (oak, beech, hornbeam).",
"culinary_uses": "Major culinary and medicinal mushroom.", "medicinal_uses": "Lentinan (beta-glucan) studied for immune support.",
"native_range": "East Asia"},
{"name_scientific": "Hericium erinaceus", "name_de": "Igel-Stachelbart", "name_en": "Lion's mane",
"family_scientific": "Hericiaceae", "edibility": "edible", "cultivation": "both", "saprobic": True, "parasitic": True,
"substrate": ["hardwood_logs", "sawdust_blocks"], "habitat": "On wounds of living and dead hardwoods (beech, oak).",
"culinary_uses": "Seafood-like texture.", "medicinal_uses": "Studied for nerve growth factor / cognitive support.",
"native_range": "Northern Hemisphere temperate"},
{"name_scientific": "Stropharia rugosoannulata", "name_de": "Riesenträuschling", "name_en": "King stropharia",
"family_scientific": "Strophariaceae", "edibility": "edible", "cultivation": "cultivated", "saprobic": True,
"substrate": ["woodchips", "straw"], "fruiting_months": [6, 7, 8, 9, 10],
"habitat": "Woodchip beds and garden mulch; a classic permaculture companion.", "spore_print_color": "purple-brown",
"culinary_uses": "Wine cap; good when young.", "native_range": "Europe, North America"},
{"name_scientific": "Agaricus bisporus", "name_de": "Zuchtchampignon", "name_en": "Button mushroom",
"family_scientific": "Agaricaceae", "edibility": "edible", "cultivation": "cultivated", "saprobic": True,
"substrate": ["composted_manure"], "spore_print_color": "dark brown",
"culinary_uses": "The common cultivated white/cremini/portobello mushroom.", "native_range": "Cosmopolitan"},
{"name_scientific": "Coprinus comatus", "name_de": "Schopftintling", "name_en": "Shaggy ink cap",
"family_scientific": "Agaricaceae", "edibility": "edible", "cultivation": "wild", "saprobic": True,
"fruiting_months": [9, 10, 11], "habitat": "Disturbed grassy ground, lawns, road verges.", "spore_print_color": "black",
"culinary_uses": "Edible when young and white; deliquesces quickly.", "native_range": "Cosmopolitan"},
{"name_scientific": "Cantharellus cibarius", "name_de": "Pfifferling", "name_en": "Chanterelle",
"family_scientific": "Cantharellaceae", "edibility": "edible", "cultivation": "wild", "mycorrhizal": True,
"fruiting_months": [7, 8, 9, 10], "habitat": "Mycorrhizal with oak, beech, birch and conifers in mossy woodland.",
"spore_print_color": "pale yellow", "culinary_uses": "Prized edible; apricot aroma.", "native_range": "Northern Hemisphere"},
{"name_scientific": "Boletus edulis", "name_de": "Steinpilz", "name_en": "Porcini",
"family_scientific": "Boletaceae", "edibility": "edible", "cultivation": "wild", "mycorrhizal": True,
"fruiting_months": [8, 9, 10], "habitat": "Mycorrhizal with spruce, pine, oak and beech.", "spore_print_color": "olive-brown",
"culinary_uses": "Premier wild edible bolete.", "native_range": "Northern Hemisphere"},
{"name_scientific": "Morchella esculenta", "name_de": "Speisemorchel", "name_en": "Morel",
"family_scientific": "Morchellaceae", "edibility": "edible_with_caution", "cultivation": "wild", "saprobic": True,
"fruiting_months": [4, 5], "habitat": "Spring; ash, elm, apple orchards and disturbed ground.",
"edibility_notes": "Must be thoroughly cooked; never eaten raw.", "spore_print_color": "cream-yellow",
"culinary_uses": "Highly prized spring edible.", "native_range": "Northern Hemisphere temperate"},
{"name_scientific": "Grifola frondosa", "name_de": "Klapperschwamm", "name_en": "Hen of the woods",
"family_scientific": "Meripilaceae", "edibility": "edible", "cultivation": "both", "parasitic": True, "saprobic": True,
"fruiting_months": [9, 10, 11], "habitat": "Base of old oaks (and other hardwoods).",
"culinary_uses": "Maitake; choice edible.", "medicinal_uses": "Beta-glucans studied for immune support.",
"native_range": "Northern Hemisphere"},
{"name_scientific": "Flammulina velutipes", "name_de": "Samtfußrübling", "name_en": "Velvet shank",
"family_scientific": "Physalacriaceae", "edibility": "edible", "cultivation": "both", "saprobic": True,
"substrate": ["hardwood_logs"], "fruiting_months": [11, 12, 1, 2], "habitat": "Clusters on dead hardwood in winter.",
"culinary_uses": "Wild form of cultivated enoki.", "native_range": "Northern Hemisphere"},
{"name_scientific": "Ganoderma lucidum", "name_de": "Glänzender Lackporling", "name_en": "Reishi",
"family_scientific": "Ganodermataceae", "edibility": "medicinal", "cultivation": "both", "saprobic": True, "parasitic": True,
"substrate": ["hardwood_logs", "sawdust_blocks"], "habitat": "Base of hardwoods, especially oak.",
"edibility_notes": "Too woody/bitter to eat; used as tea/extract.", "medicinal_uses": "Traditional tonic; triterpenes and beta-glucans.",
"native_range": "Temperate and subtropical"},
{"name_scientific": "Laetiporus sulphureus", "name_de": "Schwefelporling", "name_en": "Chicken of the woods",
"family_scientific": "Fomitopsidaceae", "edibility": "edible_with_caution", "cultivation": "wild", "parasitic": True,
"fruiting_months": [6, 7, 8, 9], "habitat": "Bracket on living and dead hardwoods (oak, sweet chestnut, willow).",
"edibility_notes": "Eat only young, well-cooked; some people react. Avoid specimens on conifers/yew.",
"culinary_uses": "Chicken-like texture when young.", "native_range": "Northern Hemisphere"},
{"name_scientific": "Amanita phalloides", "name_de": "Grüner Knollenblätterpilz", "name_en": "Death cap",
"family_scientific": "Amanitaceae", "edibility": "deadly", "cultivation": "wild", "mycorrhizal": True,
"fruiting_months": [8, 9, 10], "habitat": "Mycorrhizal with oak and other broadleaves.",
"edibility_notes": "DEADLY POISONOUS — amatoxins; responsible for most fatal mushroom poisonings. Do not eat.",
"spore_print_color": "white", "native_range": "Europe (introduced elsewhere)"},
{"name_scientific": "Pholiota nameko", "name_de": "Toskanapilz", "name_en": "Nameko",
"family_scientific": "Strophariaceae", "edibility": "edible", "cultivation": "cultivated", "saprobic": True,
"substrate": ["hardwood_logs", "sawdust_blocks"], "habitat": "On hardwood logs and stumps.",
"culinary_uses": "Gelatinous cap; popular in Japanese cuisine.", "native_range": "East Asia"},
]
def main():
if not TOKEN:
raise SystemExit("HERBAPI_TOKEN not set")
existing = {f["slug"] for f in api("/fungi?per_page=100")[1]["data"]}
created = skipped = errors = 0
for f in FUNGI:
import re
slug = re.sub(r"[^a-z0-9]+", "-", f["name_scientific"].lower()).strip("-")
if slug in existing:
print(f"skip {slug} (exists)")
skipped += 1
continue
code, resp = api("/fungi", "POST", f)
if code == 200:
print(f"created {slug}")
created += 1
else:
print(f"ERROR {slug}: {code} {resp}")
errors += 1
print(f"\ncreated={created} skipped={skipped} errors={errors}")
if __name__ == "__main__":
main()