2cfa57a188
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).
130 lines
8.8 KiB
Python
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()
|