From db4c6567308c0f1f4d4e5290a5c3513b35240221 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Sat, 6 Jun 2026 17:02:45 -0400 Subject: [PATCH] flagging --- apps/web/data/.gitignore | 1 + apps/web/drizzle/0004_add-flagged-content.sql | 14 + apps/web/drizzle/meta/0004_snapshot.json | 469 +++ apps/web/drizzle/meta/_journal.json | 7 + apps/web/package.json | 5 +- apps/web/scripts/.brave-progress.json | 1552 +++++++++- apps/web/scripts/.ddg-progress.json | 2554 ++++++++++++++++- .../scripts/.flagged-content-review-needed.md | 11 + apps/web/scripts/apply-flag-migration.ts | 53 + apps/web/scripts/check-progress.mjs | 19 + apps/web/scripts/generate-flagged-report.ts | 379 +++ apps/web/scripts/scrape-training-dataset.ts | 662 +++-- apps/web/src/app/api/flag/report/route.ts | 143 + apps/web/src/app/api/flag/route.ts | 147 + .../src/app/browse/[plantId]/DiseaseCards.tsx | 73 +- apps/web/src/app/browse/[plantId]/page.tsx | 2 + apps/web/src/components/DiseaseCard.tsx | 155 +- apps/web/src/components/FlagButton.tsx | 178 ++ apps/web/src/components/FlagPlantImage.tsx | 26 + apps/web/src/components/PlantCard.tsx | 17 + apps/web/src/lib/db/index.ts | 9 +- apps/web/src/lib/db/schema.ts | 45 + 22 files changed, 6195 insertions(+), 326 deletions(-) create mode 100644 apps/web/data/.gitignore create mode 100644 apps/web/drizzle/0004_add-flagged-content.sql create mode 100644 apps/web/drizzle/meta/0004_snapshot.json create mode 100644 apps/web/scripts/.flagged-content-review-needed.md create mode 100644 apps/web/scripts/apply-flag-migration.ts create mode 100644 apps/web/scripts/check-progress.mjs create mode 100644 apps/web/scripts/generate-flagged-report.ts create mode 100644 apps/web/src/app/api/flag/report/route.ts create mode 100644 apps/web/src/app/api/flag/route.ts create mode 100644 apps/web/src/components/FlagButton.tsx create mode 100644 apps/web/src/components/FlagPlantImage.tsx diff --git a/apps/web/data/.gitignore b/apps/web/data/.gitignore new file mode 100644 index 0000000..caba867 --- /dev/null +++ b/apps/web/data/.gitignore @@ -0,0 +1 @@ +dataset diff --git a/apps/web/drizzle/0004_add-flagged-content.sql b/apps/web/drizzle/0004_add-flagged-content.sql new file mode 100644 index 0000000..6db2316 --- /dev/null +++ b/apps/web/drizzle/0004_add-flagged-content.sql @@ -0,0 +1,14 @@ +CREATE TABLE `flagged_content` ( + `id` text PRIMARY KEY NOT NULL, + `content_type` text NOT NULL, + `content_id` text NOT NULL, + `field_name` text NOT NULL, + `notes` text DEFAULT '', + `flag_count` integer DEFAULT 1 NOT NULL, + `created_at` text DEFAULT (datetime('now')) NOT NULL, + `updated_at` text DEFAULT (datetime('now')) NOT NULL +); +--> statement-breakpoint +CREATE INDEX `idx_flagged_content_type` ON `flagged_content` (`content_type`); +--> statement-breakpoint +CREATE INDEX `idx_flagged_content_id` ON `flagged_content` (`content_id`); diff --git a/apps/web/drizzle/meta/0004_snapshot.json b/apps/web/drizzle/meta/0004_snapshot.json new file mode 100644 index 0000000..0c7b9b8 --- /dev/null +++ b/apps/web/drizzle/meta/0004_snapshot.json @@ -0,0 +1,469 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "04ff83bd-e207-44d3-b8b7-8f82157bbeb9", + "prevId": "04ff83bd-e207-44d3-b8b7-8f82157bbeb8", + "tables": { + "diseases": { + "name": "diseases", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "plant_id": { + "name": "plant_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scientific_name": { + "name": "scientific_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "causal_agent_type": { + "name": "causal_agent_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "symptoms": { + "name": "symptoms", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "causes": { + "name": "causes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "treatment": { + "name": "treatment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "prevention": { + "name": "prevention", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "lookalike_ids": { + "name": "lookalike_ids", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "prevalence": { + "name": "prevalence", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'uncommon'" + }, + "severity": { + "name": "severity", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(datetime('now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(datetime('now'))" + } + }, + "indexes": { + "idx_diseases_plant_id": { + "name": "idx_diseases_plant_id", + "columns": ["plant_id"], + "isUnique": false + }, + "idx_diseases_causal_agent": { + "name": "idx_diseases_causal_agent", + "columns": ["causal_agent_type"], + "isUnique": false + }, + "idx_diseases_severity": { + "name": "idx_diseases_severity", + "columns": ["severity"], + "isUnique": false + }, + "idx_diseases_prevalence": { + "name": "idx_diseases_prevalence", + "columns": ["prevalence"], + "isUnique": false + } + }, + "foreignKeys": { + "diseases_plant_id_plants_id_fk": { + "name": "diseases_plant_id_plants_id_fk", + "tableFrom": "diseases", + "tableTo": "plants", + "columnsFrom": ["plant_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "flagged_content": { + "name": "flagged_content", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_id": { + "name": "content_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "field_name": { + "name": "field_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "''" + }, + "flag_count": { + "name": "flag_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(datetime('now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(datetime('now'))" + } + }, + "indexes": { + "idx_flagged_content_type": { + "name": "idx_flagged_content_type", + "columns": ["content_type"], + "isUnique": false + }, + "idx_flagged_content_id": { + "name": "idx_flagged_content_id", + "columns": ["content_id"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plant_views": { + "name": "plant_views", + "columns": { + "plant_id": { + "name": "plant_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "view_count": { + "name": "view_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": { + "idx_plant_views_count": { + "name": "idx_plant_views_count", + "columns": ["view_count"], + "isUnique": false + } + }, + "foreignKeys": { + "plant_views_plant_id_plants_id_fk": { + "name": "plant_views_plant_id_plants_id_fk", + "tableFrom": "plant_views", + "tableTo": "plants", + "columnsFrom": ["plant_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plants": { + "name": "plants", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "common_name": { + "name": "common_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scientific_name": { + "name": "scientific_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "family": { + "name": "family", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "care_summary": { + "name": "care_summary", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(datetime('now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(datetime('now'))" + } + }, + "indexes": { + "idx_plants_category": { + "name": "idx_plants_category", + "columns": ["category"], + "isUnique": false + }, + "idx_plants_common_name": { + "name": "idx_plants_common_name", + "columns": ["common_name"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "scrape_sources": { + "name": "scrape_sources", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_scraped_at": { + "name": "last_scraped_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "entries_count": { + "name": "entries_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(datetime('now'))" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/apps/web/drizzle/meta/_journal.json b/apps/web/drizzle/meta/_journal.json index 144f90b..fd7cbc6 100644 --- a/apps/web/drizzle/meta/_journal.json +++ b/apps/web/drizzle/meta/_journal.json @@ -29,6 +29,13 @@ "when": 1749268800000, "tag": "0003_giant_toad", "breakpoints": true + }, + { + "idx": 4, + "version": "6", + "when": 1751846400000, + "tag": "0004_add-flagged-content", + "breakpoints": true } ] } diff --git a/apps/web/package.json b/apps/web/package.json index 27df180..9cd6eea 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,7 +8,10 @@ "start": "next start", "lint": "eslint", "test": "vitest run", - "test:watch": "vitest" + "test:watch": "vitest", + "flagged-report": "npx tsx scripts/generate-flagged-report.ts", + "flagged-report:all": "npx tsx scripts/generate-flagged-report.ts --min-flags=1", + "migrate:flag-system": "npx tsx scripts/apply-flag-migration.ts" }, "dependencies": { "@libsql/client": "^0.17.3", diff --git a/apps/web/scripts/.brave-progress.json b/apps/web/scripts/.brave-progress.json index 8dc17c6..78ef1fc 100644 --- a/apps/web/scripts/.brave-progress.json +++ b/apps/web/scripts/.brave-progress.json @@ -5399,7 +5399,1557 @@ "watermelon-lesion-nematode", "cantaloupe-lesion-nematode", "honeydew-lesion-nematode", - "bitter-melon-lesion-nematode" + "bitter-melon-lesion-nematode", + "chayote-lesion-nematode", + "acorn-squash-lesion-nematode", + "butternut-squash-lesion-nematode", + "calabash-lesion-nematode", + "luffa-lesion-nematode", + "pear-lesion-nematode", + "peach-lesion-nematode", + "cherry-lesion-nematode", + "apricot-lesion-nematode", + "plum-lesion-nematode", + "almond-lesion-nematode", + "strawberry-lesion-nematode", + "raspberry-lesion-nematode", + "blackberry-lesion-nematode", + "blueberry-lesion-nematode", + "cranberry-lesion-nematode", + "rose-lesion-nematode", + "hawthorn-lesion-nematode", + "quince-lesion-nematode", + "cabbage-lesion-nematode", + "broccoli-lesion-nematode", + "cauliflower-lesion-nematode", + "brussels-sprouts-lesion-nematode", + "kale-lesion-nematode", + "bok-choy-lesion-nematode", + "radish-lesion-nematode", + "turnip-lesion-nematode", + "arugula-lesion-nematode", + "collard-greens-lesion-nematode", + "mustard-greens-lesion-nematode", + "horseradish-lesion-nematode", + "wasabi-lesion-nematode", + "green-bean-lesion-nematode", + "peanut-lesion-nematode", + "chickpea-lesion-nematode", + "lentil-lesion-nematode", + "faba-bean-lesion-nematode", + "cowpea-lesion-nematode", + "pigeon-pea-lesion-nematode", + "clover-lesion-nematode", + "peas-lesion-nematode", + "lupine-lesion-nematode", + "wisteria-lesion-nematode", + "robinia-lesion-nematode", + "corn-lesion-nematode", + "wheat-lesion-nematode", + "rice-lesion-nematode", + "barley-lesion-nematode", + "oats-lesion-nematode", + "sorghum-lesion-nematode", + "sugarcane-lesion-nematode", + "bamboo-lesion-nematode", + "turfgrass-lesion-nematode", + "millet-lesion-nematode", + "rye-lesion-nematode", + "sunflower-lesion-nematode", + "lettuce-lesion-nematode", + "artichoke-lesion-nematode", + "chicory-lesion-nematode", + "endive-lesion-nematode", + "daisy-lesion-nematode", + "marigold-lesion-nematode", + "zinnia-lesion-nematode", + "chrysanthemum-lesion-nematode", + "dahlia-lesion-nematode", + "calendula-lesion-nematode", + "echinacea-lesion-nematode", + "yarrow-lesion-nematode", + "tarragon-lesion-nematode", + "stevia-lesion-nematode", + "basil-lesion-nematode", + "mint-lesion-nematode", + "lavender-lesion-nematode", + "rosemary-lesion-nematode", + "thyme-lesion-nematode", + "oregano-lesion-nematode", + "sage-lesion-nematode", + "lemon-balm-lesion-nematode", + "catnip-lesion-nematode", + "coleus-lesion-nematode", + "celery-lesion-nematode", + "parsley-lesion-nematode", + "cilantro-lesion-nematode", + "dill-lesion-nematode", + "fennel-lesion-nematode", + "parsnip-lesion-nematode", + "cumin-lesion-nematode", + "onion-lesion-nematode", + "garlic-lesion-nematode", + "leek-lesion-nematode", + "shallot-lesion-nematode", + "chive-lesion-nematode", + "monstera-lesion-nematode", + "pothos-lesion-nematode", + "peace-lily-lesion-nematode", + "philodendron-lesion-nematode", + "anthurium-lesion-nematode", + "alocasia-lesion-nematode", + "caladium-lesion-nematode", + "aglaonema-lesion-nematode", + "dieffenbachia-lesion-nematode", + "spathiphyllum-lesion-nematode", + "asparagus-lesion-nematode", + "snake-plant-lesion-nematode", + "yucca-lesion-nematode", + "dracaena-lesion-nematode", + "lily-of-the-valley-lesion-nematode", + "hosta-lesion-nematode", + "orchid-phalaenopsis-lesion-nematode", + "orchid-cattleya-lesion-nematode", + "orchid-dendrobium-lesion-nematode", + "orchid-oncidium-lesion-nematode", + "vanilla-lesion-nematode", + "prickly-pear-lesion-nematode", + "barrel-cactus-lesion-nematode", + "christmas-cactus-lesion-nematode", + "saguaro-lesion-nematode", + "aloe-vera-lesion-nematode", + "agave-lesion-nematode", + "echeveria-lesion-nematode", + "jade-plant-lesion-nematode", + "sedum-lesion-nematode", + "haworthia-lesion-nematode", + "poinsettia-lesion-nematode", + "cassava-lesion-nematode", + "castor-bean-lesion-nematode", + "crown-of-thorns-lesion-nematode", + "orange-lesion-nematode", + "lemon-lesion-nematode", + "lime-lesion-nematode", + "grapefruit-lesion-nematode", + "mandarin-lesion-nematode", + "kumquat-lesion-nematode", + "grape-lesion-nematode", + "muscadine-lesion-nematode", + "banana-lesion-nematode", + "plantain-lesion-nematode", + "bird-of-paradise-lesion-nematode", + "avocado-lesion-nematode", + "cinnamon-lesion-nematode", + "bay-laurel-lesion-nematode", + "cocoa-lesion-nematode", + "cotton-lesion-nematode", + "okra-lesion-nematode", + "hibiscus-lesion-nematode", + "hollyhock-lesion-nematode", + "baobab-lesion-nematode", + "durian-lesion-nematode", + "coconut-lesion-nematode", + "oil-palm-lesion-nematode", + "date-palm-lesion-nematode", + "palm-areca-lesion-nematode", + "palm-parlor-lesion-nematode", + "palm-kentia-lesion-nematode", + "mango-lesion-nematode", + "cashew-lesion-nematode", + "pistachio-lesion-nematode", + "poison-ivy-lesion-nematode", + "coffee-lesion-nematode", + "gardenia-lesion-nematode", + "tea-lesion-nematode", + "camellia-lesion-nematode", + "pine-lesion-nematode", + "spruce-lesion-nematode", + "fir-lesion-nematode", + "cedar-lesion-nematode", + "juniper-lesion-nematode", + "cypress-lesion-nematode", + "arborvitae-lesion-nematode", + "oak-lesion-nematode", + "beech-lesion-nematode", + "chestnut-lesion-nematode", + "fiddle-leaf-fig-lesion-nematode", + "rubber-tree-lesion-nematode", + "weeping-fig-lesion-nematode", + "fig-lesion-nematode", + "mulberry-lesion-nematode", + "breadfruit-lesion-nematode", + "eucalyptus-lesion-nematode", + "guava-lesion-nematode", + "clove-lesion-nematode", + "pineapple-lesion-nematode", + "bromeliad-lesion-nematode", + "spanish-moss-lesion-nematode", + "sweet-potato-lesion-nematode", + "morning-glory-lesion-nematode", + "spinach-lesion-nematode", + "swiss-chard-lesion-nematode", + "beet-lesion-nematode", + "quinoa-lesion-nematode", + "amaranth-lesion-nematode", + "rhubarb-lesion-nematode", + "buckwheat-lesion-nematode", + "papaya-lesion-nematode", + "olive-lesion-nematode", + "jasmine-lesion-nematode", + "lilac-lesion-nematode", + "ash-lesion-nematode", + "hops-lesion-nematode", + "hemp-lesion-nematode", + "fern-boston-lesion-nematode", + "fern-maidenhair-lesion-nematode", + "spider-plant-lesion-nematode", + "zz-plant-lesion-nematode", + "prayer-plant-lesion-nematode", + "calathea-lesion-nematode", + "pilea-lesion-nematode", + "tradescantia-lesion-nematode", + "succulent-echeveria-lesion-nematode", + "money-tree-lesion-nematode", + "palm-cat-lesion-nematode", + "ficus-altissima-lesion-nematode", + "string-of-pearls-lesion-nematode", + "burros-tail-lesion-nematode", + "snake-plant-masoniana-lesion-nematode", + "passion-fruit-lesion-nematode", + "kiwi-lesion-nematode", + "lychee-lesion-nematode", + "rambutan-lesion-nematode", + "jackfruit-lesion-nematode", + "dragon-fruit-lesion-nematode", + "pomegranate-lesion-nematode", + "persimmon-lesion-nematode", + "tulip-lesion-nematode", + "daffodil-lesion-nematode", + "iris-lesion-nematode", + "lily-lesion-nematode", + "peony-lesion-nematode", + "hydrangea-lesion-nematode", + "rhododendron-lesion-nematode", + "azalea-lesion-nematode", + "magnolia-lesion-nematode", + "dogwood-lesion-nematode", + "maple-lesion-nematode", + "birch-lesion-nematode", + "elm-lesion-nematode", + "willow-lesion-nematode", + "poplar-lesion-nematode", + "sycamore-lesion-nematode", + "hickory-lesion-nematode", + "pecan-lesion-nematode", + "walnut-lesion-nematode", + "fern-staghorn-powdery-mildew", + "fern-staghorn-anthracnose", + "fern-staghorn-rust", + "fern-staghorn-bacterial-leaf-spot", + "fern-staghorn-blossom-end-rot", + "fern-staghorn-herbicide-injury", + "fern-staghorn-lesion-nematode", + "fern-birds-nest-powdery-mildew", + "fern-birds-nest-anthracnose", + "fern-birds-nest-rust", + "fern-birds-nest-bacterial-leaf-spot", + "fern-birds-nest-blossom-end-rot", + "fern-birds-nest-herbicide-injury", + "fern-birds-nest-lesion-nematode", + "philodendron-brasil-bacterial-leaf-spot-aroids", + "philodendron-brasil-powdery-mildew", + "philodendron-brasil-anthracnose", + "philodendron-brasil-rust", + "philodendron-brasil-bacterial-leaf-spot", + "philodendron-brasil-blossom-end-rot", + "philodendron-brasil-herbicide-injury", + "philodendron-brasil-lesion-nematode", + "philodendron-monstera-bacterial-leaf-spot-aroids", + "philodendron-monstera-powdery-mildew", + "philodendron-monstera-anthracnose", + "philodendron-monstera-rust", + "philodendron-monstera-bacterial-leaf-spot", + "philodendron-monstera-blossom-end-rot", + "philodendron-monstera-herbicide-injury", + "philodendron-monstera-lesion-nematode", + "pothos-marble-queen-bacterial-leaf-spot-aroids", + "pothos-marble-queen-powdery-mildew", + "pothos-marble-queen-anthracnose", + "pothos-marble-queen-rust", + "pothos-marble-queen-bacterial-leaf-spot", + "pothos-marble-queen-blossom-end-rot", + "pothos-marble-queen-herbicide-injury", + "pothos-marble-queen-lesion-nematode", + "peace-lily-sensation-bacterial-leaf-spot-aroids", + "peace-lily-sensation-powdery-mildew", + "peace-lily-sensation-anthracnose", + "peace-lily-sensation-rust", + "peace-lily-sensation-bacterial-leaf-spot", + "peace-lily-sensation-blossom-end-rot", + "peace-lily-sensation-herbicide-injury", + "peace-lily-sensation-lesion-nematode", + "phalaenopsis-orchid-powdery-mildew", + "phalaenopsis-orchid-anthracnose", + "phalaenopsis-orchid-rust", + "phalaenopsis-orchid-bacterial-leaf-spot", + "phalaenopsis-orchid-blossom-end-rot", + "phalaenopsis-orchid-herbicide-injury", + "phalaenopsis-orchid-lesion-nematode", + "cattleya-orchid-powdery-mildew", + "cattleya-orchid-anthracnose", + "cattleya-orchid-rust", + "cattleya-orchid-bacterial-leaf-spot", + "cattleya-orchid-blossom-end-rot", + "cattleya-orchid-herbicide-injury", + "cattleya-orchid-lesion-nematode", + "dendrobium-orchid-powdery-mildew", + "dendrobium-orchid-anthracnose", + "dendrobium-orchid-rust", + "dendrobium-orchid-bacterial-leaf-spot", + "dendrobium-orchid-blossom-end-rot", + "dendrobium-orchid-herbicide-injury", + "dendrobium-orchid-lesion-nematode", + "oncidium-orchid-powdery-mildew", + "oncidium-orchid-anthracnose", + "oncidium-orchid-rust", + "oncidium-orchid-bacterial-leaf-spot", + "oncidium-orchid-blossom-end-rot", + "oncidium-orchid-herbicide-injury", + "oncidium-orchid-lesion-nematode", + "begonia-powdery-mildew", + "begonia-anthracnose", + "begonia-rust", + "begonia-bacterial-leaf-spot", + "begonia-blossom-end-rot", + "begonia-herbicide-injury", + "begonia-lesion-nematode", + "impatiens-powdery-mildew", + "impatiens-anthracnose", + "impatiens-rust", + "impatiens-bacterial-leaf-spot", + "impatiens-blossom-end-rot", + "impatiens-herbicide-injury", + "impatiens-lesion-nematode", + "geranium-powdery-mildew", + "geranium-anthracnose", + "geranium-rust", + "geranium-bacterial-leaf-spot", + "geranium-blossom-end-rot", + "geranium-herbicide-injury", + "geranium-lesion-nematode", + "cyclamen-powdery-mildew", + "cyclamen-anthracnose", + "cyclamen-rust", + "cyclamen-bacterial-leaf-spot", + "cyclamen-blossom-end-rot", + "cyclamen-herbicide-injury", + "cyclamen-lesion-nematode", + "african-violet-powdery-mildew", + "african-violet-anthracnose", + "african-violet-rust", + "african-violet-bacterial-leaf-spot", + "african-violet-blossom-end-rot", + "african-violet-herbicide-injury", + "african-violet-lesion-nematode", + "gloxinia-powdery-mildew", + "gloxinia-anthracnose", + "gloxinia-rust", + "gloxinia-bacterial-leaf-spot", + "gloxinia-blossom-end-rot", + "gloxinia-herbicide-injury", + "gloxinia-lesion-nematode", + "cucumber-horned-powdery-mildew-cucurbits", + "cucumber-horned-angular-leaf-spot-cucurbits", + "cucumber-horned-powdery-mildew", + "cucumber-horned-anthracnose", + "cucumber-horned-rust", + "cucumber-horned-bacterial-leaf-spot", + "cucumber-horned-blossom-end-rot", + "cucumber-horned-herbicide-injury", + "cucumber-horned-lesion-nematode", + "sweet-potato-leaf-powdery-mildew", + "sweet-potato-leaf-anthracnose", + "sweet-potato-leaf-rust", + "sweet-potato-leaf-bacterial-leaf-spot", + "sweet-potato-leaf-blossom-end-rot", + "sweet-potato-leaf-herbicide-injury", + "sweet-potato-leaf-lesion-nematode", + "ivy-english-powdery-mildew", + "ivy-english-anthracnose", + "ivy-english-rust", + "ivy-english-bacterial-leaf-spot", + "ivy-english-blossom-end-rot", + "ivy-english-herbicide-injury", + "ivy-english-lesion-nematode", + "ivy-swedish-powdery-mildew", + "ivy-swedish-anthracnose", + "ivy-swedish-rust", + "ivy-swedish-bacterial-leaf-spot", + "ivy-swedish-blossom-end-rot", + "ivy-swedish-herbicide-injury", + "ivy-swedish-lesion-nematode", + "banana-dwarf-powdery-mildew", + "banana-dwarf-anthracnose", + "banana-dwarf-rust", + "banana-dwarf-bacterial-leaf-spot", + "banana-dwarf-blossom-end-rot", + "banana-dwarf-herbicide-injury", + "banana-dwarf-lesion-nematode", + "mimosa-bacterial-blight-common-halo", + "mimosa-bean-rust", + "mimosa-powdery-mildew", + "mimosa-anthracnose", + "mimosa-rust", + "mimosa-bacterial-leaf-spot", + "mimosa-blossom-end-rot", + "mimosa-herbicide-injury", + "mimosa-lesion-nematode", + "kentucky-coffee-bacterial-blight-common-halo", + "kentucky-coffee-bean-rust", + "kentucky-coffee-powdery-mildew", + "kentucky-coffee-anthracnose", + "kentucky-coffee-rust", + "kentucky-coffee-bacterial-leaf-spot", + "kentucky-coffee-blossom-end-rot", + "kentucky-coffee-herbicide-injury", + "kentucky-coffee-lesion-nematode", + "redbud-bacterial-blight-common-halo", + "redbud-bean-rust", + "redbud-powdery-mildew", + "redbud-anthracnose", + "redbud-rust", + "redbud-bacterial-leaf-spot", + "redbud-blossom-end-rot", + "redbud-herbicide-injury", + "redbud-lesion-nematode", + "tulip-tree-powdery-mildew", + "tulip-tree-anthracnose", + "tulip-tree-rust", + "tulip-tree-bacterial-leaf-spot", + "tulip-tree-blossom-end-rot", + "tulip-tree-herbicide-injury", + "tulip-tree-lesion-nematode", + "sweetgum-powdery-mildew", + "sweetgum-anthracnose", + "sweetgum-rust", + "sweetgum-bacterial-leaf-spot", + "sweetgum-blossom-end-rot", + "sweetgum-herbicide-injury", + "sweetgum-lesion-nematode", + "crabapple-apple-scab", + "crabapple-cedar-apple-rust", + "crabapple-black-spot-rose", + "crabapple-powdery-mildew", + "crabapple-anthracnose", + "crabapple-rust", + "crabapple-bacterial-leaf-spot", + "crabapple-blossom-end-rot", + "crabapple-herbicide-injury", + "crabapple-lesion-nematode", + "serviceberry-apple-scab", + "serviceberry-cedar-apple-rust", + "serviceberry-black-spot-rose", + "serviceberry-powdery-mildew", + "serviceberry-anthracnose", + "serviceberry-rust", + "serviceberry-bacterial-leaf-spot", + "serviceberry-blossom-end-rot", + "serviceberry-herbicide-injury", + "serviceberry-lesion-nematode", + "chokecherry-apple-scab", + "chokecherry-cedar-apple-rust", + "chokecherry-black-spot-rose", + "chokecherry-powdery-mildew", + "chokecherry-anthracnose", + "chokecherry-rust", + "chokecherry-bacterial-leaf-spot", + "chokecherry-blossom-end-rot", + "chokecherry-herbicide-injury", + "chokecherry-lesion-nematode", + "buckeye-powdery-mildew", + "buckeye-anthracnose", + "buckeye-rust", + "buckeye-bacterial-leaf-spot", + "buckeye-blossom-end-rot", + "buckeye-herbicide-injury", + "buckeye-lesion-nematode", + "linden-powdery-mildew", + "linden-anthracnose", + "linden-rust", + "linden-bacterial-leaf-spot", + "linden-blossom-end-rot", + "linden-herbicide-injury", + "linden-lesion-nematode", + "ginkgo-powdery-mildew", + "ginkgo-anthracnose", + "ginkgo-rust", + "ginkgo-bacterial-leaf-spot", + "ginkgo-blossom-end-rot", + "ginkgo-herbicide-injury", + "ginkgo-lesion-nematode", + "ficus-microcarpa-powdery-mildew", + "ficus-microcarpa-anthracnose", + "ficus-microcarpa-rust", + "ficus-microcarpa-bacterial-leaf-spot", + "ficus-microcarpa-blossom-end-rot", + "ficus-microcarpa-herbicide-injury", + "ficus-microcarpa-lesion-nematode", + "schefflera-powdery-mildew", + "schefflera-anthracnose", + "schefflera-rust", + "schefflera-bacterial-leaf-spot", + "schefflera-blossom-end-rot", + "schefflera-herbicide-injury", + "schefflera-lesion-nematode", + "maranta-powdery-mildew", + "maranta-anthracnose", + "maranta-rust", + "maranta-bacterial-leaf-spot", + "maranta-blossom-end-rot", + "maranta-herbicide-injury", + "maranta-lesion-nematode", + "stromanthe-powdery-mildew", + "stromanthe-anthracnose", + "stromanthe-rust", + "stromanthe-bacterial-leaf-spot", + "stromanthe-blossom-end-rot", + "stromanthe-herbicide-injury", + "stromanthe-lesion-nematode", + "bok-choy-shanghai-downy-mildew-brassicas", + "bok-choy-shanghai-alternaria-leaf-spot-brassicas", + "bok-choy-shanghai-powdery-mildew", + "bok-choy-shanghai-anthracnose", + "bok-choy-shanghai-rust", + "bok-choy-shanghai-bacterial-leaf-spot", + "bok-choy-shanghai-blossom-end-rot", + "bok-choy-shanghai-herbicide-injury", + "bok-choy-shanghai-lesion-nematode", + "tatsoi-downy-mildew-brassicas", + "tatsoi-alternaria-leaf-spot-brassicas", + "tatsoi-powdery-mildew", + "tatsoi-anthracnose", + "tatsoi-rust", + "tatsoi-bacterial-leaf-spot", + "tatsoi-blossom-end-rot", + "tatsoi-herbicide-injury", + "tatsoi-lesion-nematode", + "mizuna-downy-mildew-brassicas", + "mizuna-alternaria-leaf-spot-brassicas", + "mizuna-powdery-mildew", + "mizuna-anthracnose", + "mizuna-rust", + "mizuna-bacterial-leaf-spot", + "mizuna-blossom-end-rot", + "mizuna-herbicide-injury", + "mizuna-lesion-nematode", + "kohlrabi-downy-mildew-brassicas", + "kohlrabi-alternaria-leaf-spot-brassicas", + "kohlrabi-powdery-mildew", + "kohlrabi-anthracnose", + "kohlrabi-rust", + "kohlrabi-bacterial-leaf-spot", + "kohlrabi-blossom-end-rot", + "kohlrabi-herbicide-injury", + "kohlrabi-lesion-nematode", + "rapini-downy-mildew-brassicas", + "rapini-alternaria-leaf-spot-brassicas", + "rapini-powdery-mildew", + "rapini-anthracnose", + "rapini-rust", + "rapini-bacterial-leaf-spot", + "rapini-blossom-end-rot", + "rapini-herbicide-injury", + "rapini-lesion-nematode", + "jicama-bacterial-blight-common-halo", + "jicama-bean-rust", + "jicama-powdery-mildew", + "jicama-anthracnose", + "jicama-rust", + "jicama-bacterial-leaf-spot", + "jicama-blossom-end-rot", + "jicama-herbicide-injury", + "jicama-lesion-nematode", + "adzuki-bean-bacterial-blight-common-halo", + "adzuki-bean-bean-rust", + "adzuki-bean-powdery-mildew", + "adzuki-bean-anthracnose", + "adzuki-bean-rust", + "adzuki-bean-bacterial-leaf-spot", + "adzuki-bean-blossom-end-rot", + "adzuki-bean-herbicide-injury", + "adzuki-bean-lesion-nematode", + "mung-bean-bacterial-blight-common-halo", + "mung-bean-bean-rust", + "mung-bean-powdery-mildew", + "mung-bean-anthracnose", + "mung-bean-rust", + "mung-bean-bacterial-leaf-spot", + "mung-bean-blossom-end-rot", + "mung-bean-herbicide-injury", + "mung-bean-lesion-nematode", + "garbanzo-bacterial-blight-common-halo", + "garbanzo-bean-rust", + "garbanzo-powdery-mildew", + "garbanzo-anthracnose", + "garbanzo-rust", + "garbanzo-bacterial-leaf-spot", + "garbanzo-blossom-end-rot", + "garbanzo-herbicide-injury", + "garbanzo-lesion-nematode", + "wiki-actinomycosis", + "wiki-african-cassava-mosaic", + "wiki-aggregate-sheath-spot", + "wiki-algal-disease", + "wiki-alligator-skin", + "wiki-almond-leaf-scorch", + "wiki-alternaria-black-spot", + "wiki-alternaria-cone-disorder", + "wiki-alternaria-diseases", + "wiki-alternaria-spot", + "wiki-american-hawthorn-rust", + "wiki-american-hop-latent", + "wiki-american-leaf-spot", + "wiki-anther-mold", + "wiki-anther-smut", + "wiki-antholysis", + "wiki-aphelenchoides", + "wiki-apple-chlorotic-leaf-spot", + "wiki-apple-flat-apple-disease", + "wiki-apple-flyspeck", + "wiki-apple-fruit-blotch", + "wiki-apple-green-crinkle", + "wiki-apple-joint-infection", + "wiki-apple-leaf-pucker", + "wiki-apple-necrotic-leaf-blotch", + "wiki-apple-rosette", + "wiki-apple-rough-skin", + "wiki-apple-rubbery-wood", + "wiki-apple-rust-mite", + "wiki-apple-scald", + "wiki-apple-silver-leaf", + "wiki-apple-sooty-blotch", + "wiki-apple-star-cracking", + "wiki-apple-stem-pitting", + "wiki-apple-storage-scald", + "wiki-apple-witches-broom", + "wiki-apricot-bare-twig", + "wiki-apricot-chlorotic-leaf-roll", + "wiki-apricot-deformation-mosaic", + "wiki-apricot-line-pattern", + "wiki-apricot-pucker-leaf", + "wiki-apricot-ring-pox", + "wiki-apricot-stone-pitting", + "wiki-arhar-mosaic", + "wiki-armillaria-root-disease", + "wiki-artichoke-curly-dwarf", + "wiki-artichoke-latent-virus", + "wiki-asparagus-1-virus", + "wiki-asparagus-2-virus", + "wiki-aster-yellows-of-carrot", + "wiki-asteroid-spot", + "wiki-avocado-black-streak", + "wiki-avocado-sunblotch", + "wiki-avocado-trunk-pitting", + "wiki-awka-disease", + "wiki-awl-nematode", + "wiki-bacterial-angular-leaf-spot", + "wiki-bacterial-black-spot", + "wiki-bacterial-blast", + "wiki-bacterial-brown-spot", + "wiki-bacterial-fasciation", + "wiki-bacterial-fruit-blotch", + "wiki-bacterial-leaf-scorch", + "wiki-bacterial-pocket", + "wiki-bacterial-pustule", + "wiki-bacterial-speck", + "wiki-bacterial-streak", + "wiki-bacterial-wetwood", + "wiki-banana-blood-disease", + "wiki-banana-bract-mosaic", + "wiki-banana-streak-virus", + "wiki-banana-virus-x", + "wiki-banded-sclerotial-disease", + "wiki-barley-covered-smut", + "wiki-barley-false-loose-smut", + "wiki-barley-loose-smut", + "wiki-barley-net-blotch", + "wiki-barley-scald", + "wiki-barley-spot-blotch", + "wiki-barley-stripe", + "wiki-bayoud", + "wiki-bean-common-mosaic", + "wiki-bean-curly-dwarf-mosaic", + "wiki-bean-golden-yellow-mosaic", + "wiki-beet-black-wood-vessel", + "wiki-beet-distortion-mosaic", + "wiki-beet-latent-rosette", + "wiki-beet-leaf-curl", + "wiki-beet-mosaic", + "wiki-beet-necrotic-yellow-vein", + "wiki-beet-savoy", + "wiki-beet-western-yellows", + "wiki-beet-yellow-net", + "wiki-beet-yellow-stunt", + "wiki-beet-yellow-vein", + "wiki-beet-yellows", + "wiki-belaat", + "wiki-bending-head", + "wiki-black-chaff", + "wiki-black-cross", + "wiki-black-currant-reversion", + "wiki-black-dot-disease", + "wiki-black-foot", + "wiki-black-head-mold", + "wiki-black-head-molds", + "wiki-black-horse", + "wiki-black-kernel", + "wiki-black-knot", + "wiki-black-leaf-streak", + "wiki-black-leg", + "wiki-black-pit", + "wiki-black-pod-disease", + "wiki-black-point", + "wiki-black-pox-of-apple", + "wiki-black-raspberry-streak", + "wiki-black-raspberry-witches-broom", + "wiki-black-root", + "wiki-black-scurf", + "wiki-black-seed-disease", + "wiki-black-smut", + "wiki-black-speck", + "wiki-black-streak", + "wiki-black-streaked-dwarf", + "wiki-black-vine-weevil", + "wiki-black-walnut", + "wiki-black-wood-vessel", + "wiki-blackberry-calico", + "wiki-blackberry-rosette", + "wiki-blackberry-rust", + "wiki-blackberry-sterility", + "wiki-blackleg", + "wiki-blackspot", + "wiki-blanks", + "wiki-blight", + "wiki-blight-leaf-spot", + "wiki-blister-spot-of-apple", + "wiki-blood-disease", + "wiki-blotch", + "wiki-blue-disease", + "wiki-blue-mold-of-apple", + "wiki-blueberry-necrotic-shock", + "wiki-blueberry-red-ringspot", + "wiki-blueberry-scorch", + "wiki-blueberry-shoestring", + "wiki-borro-sec", + "wiki-botrytis-gray-mold", + "wiki-botrytis-leaf-spot", + "wiki-bract-mosaic", + "wiki-bract-spot", + "wiki-bramble-yellow-mosaic", + "wiki-british-tar-spot", + "wiki-broad-bean-stain", + "wiki-broccoli-necrotic-yellows", + "wiki-brooks-fruit-spot-of-apple", + "wiki-brown-berry-disease", + "wiki-brown-blotch", + "wiki-brown-ring-of-roots", + "wiki-brown-root", + "wiki-brown-rust", + "wiki-browning-and-stem-break", + "wiki-brussels-sprout-leaf-spot", + "wiki-bud-and-flower-spot", + "wiki-bugtok", + "wiki-bunch-disease", + "wiki-bunt", + "wiki-bushy-stunt", + "wiki-cabbage-black-leaf-spot", + "wiki-cabbage-clubroot", + "wiki-cabbage-mosaic", + "wiki-cabbage-ring-spot", + "wiki-cabbage-yellows", + "wiki-cacao-swollen-shoot", + "wiki-cacao-yellow-mosaic", + "wiki-cadang-cadang", + "wiki-cane-and-leaf-rust", + "wiki-cane-botrytis", + "wiki-canker-of-apple", + "wiki-cantaloupe-monosporascus-collapse", + "wiki-carnation", + "wiki-carnation-etched-ring", + "wiki-carnation-latent", + "wiki-carnation-ring-spot", + "wiki-cassava-american-latent", + "wiki-cassava-ash", + "wiki-cassava-brown-streak-disease", + "wiki-cassava-common-mosaic", + "wiki-cassava-frog-skin", + "wiki-cassava-frogskin", + "wiki-cassava-symptomless-infections", + "wiki-cassava-vein-mosaic", + "wiki-catface", + "wiki-catkin-blast", + "wiki-cauliflower-mosaic", + "wiki-cedar-rust", + "wiki-cedar-hawthorn-rust", + "wiki-cedar-quince-rust", + "wiki-celery-western-blotch", + "wiki-ceratocystis-stain", + "wiki-cercoseptoria-leaf-spot", + "wiki-cercospora-spot", + "wiki-cherry-bark-disease", + "wiki-cherry-leaf-roll", + "wiki-cherry-leaf-spot", + "wiki-cherry-rasp-leaf", + "wiki-cherry-twisted-leaf", + "wiki-cherry-virus-a", + "wiki-chickpea-bushy-stunt", + "wiki-chickpea-distortion-mosaic", + "wiki-chickpea-filiform", + "wiki-chili-leaf-curl", + "wiki-chilling-injury-of-mango", + "wiki-chinese-cabbage-turnip-mosaic", + "wiki-chino-del-tomate", + "wiki-chlorotic-disease", + "wiki-chlorotic-leaf-roll", + "wiki-chlorotic-leaf-spot", + "wiki-chlorotic-streak", + "wiki-choke", + "wiki-chrysanthemum-aspermy", + "wiki-chrysanthemum-carlavirus", + "wiki-chrysanthemum-leaf-blotch", + "wiki-chrysanthemum-rosette", + "wiki-chrysanthemum-stunt", + "wiki-chrysomyxa-leaf-rust", + "wiki-cigar-end", + "wiki-cineraria-leaf-rust", + "wiki-cinnamon-leaf-spot", + "wiki-citrus-bud-mite", + "wiki-citrus-chlorotic-dwarf", + "wiki-citrus-cracky-bark", + "wiki-citrus-crinkly-leaf", + "wiki-citrus-exocortis", + "wiki-citrus-greening", + "wiki-citrus-impietratura", + "wiki-citrus-infectious-mottle", + "wiki-citrus-leaf-miner", + "wiki-citrus-leprosis", + "wiki-citrus-little-leaf", + "wiki-citrus-nematode", + "wiki-citrus-psorosis", + "wiki-citrus-ringspot", + "wiki-citrus-satsuma-dwarf", + "wiki-citrus-stubborn", + "wiki-citrus-tatting-leaf", + "wiki-citrus-tristeza", + "wiki-citrus-vein-enation", + "wiki-citrus-yellow-vein", + "wiki-cladosporium-leaf-spot", + "wiki-clover-phyllody", + "wiki-clover-wound-tumor", + "wiki-clover-yellow-mosaic", + "wiki-club-root-of-canola", + "wiki-coconut-cadang-cadang-viroid", + "wiki-coconut-foliar-decay", + "wiki-coconut-tinangaja", + "wiki-coffee-leaf-rust", + "wiki-coffee-ringspot", + "wiki-collapse", + "wiki-collar-crack", + "wiki-collenchyma", + "wiki-colorado-potato-beetle", + "wiki-common-bean-anthracnose", + "wiki-common-bean-golden-mosaic", + "wiki-common-bean-rust", + "wiki-common-bunt", + "wiki-common-leaf-spot", + "wiki-common-mosaic", + "wiki-common-rust", + "wiki-common-scab", + "wiki-common-smut", + "wiki-concentric-ring-leaf-spot", + "wiki-coral-spot", + "wiki-cordana-leaf-spot", + "wiki-corky-ring-spot", + "wiki-corky-ringspot", + "wiki-corn-anthracnose", + "wiki-corn-common-rust", + "wiki-corn-eyespot", + "wiki-corn-gray-leaf-spot", + "wiki-corn-head-smut", + "wiki-corn-smut", + "wiki-corticium-leaf-spot", + "wiki-coryneum-leaf-spot", + "wiki-cotton-aphid", + "wiki-cotton-leaf-blister", + "wiki-cotton-lint-contamination", + "wiki-cotton-pink-bollworm", + "wiki-cotton-rust", + "wiki-cottony-leak", + "wiki-covered-kernel-smut", + "wiki-covered-smut", + "wiki-cowpea-aphid-borne-mosaic", + "wiki-cowpea-mosaic", + "wiki-cracked-bark", + "wiki-cranberry-false-blossom", + "wiki-cranberry-leaf-spot", + "wiki-crinkle", + "wiki-crown-rust", + "wiki-crumbly-berries", + "wiki-crumbly-berry", + "wiki-crumple-leaf", + "wiki-cryptostictis-leaf-spot", + "wiki-cucumber-green-mottle-mosaic", + "wiki-cucumber-scab", + "wiki-cucumber-vein-yellowing", + "wiki-cucumber-wild-mosaic", + "wiki-curly-top-of-sugar-beet", + "wiki-cyathia-drop", + "wiki-cyclamen-stunt", + "wiki-cyclamen-yellows", + "wiki-cylindrosporium-leaf-spot", + "wiki-dactuliophora-leaf-spot", + "wiki-daffodil-fire", + "wiki-daffodil-leaf-scorch", + "wiki-daffodil-mosaic", + "wiki-daffodil-stripe", + "wiki-dahlia-mosaic", + "wiki-dahlia-ring-spot", + "wiki-dahlia-stunt", + "wiki-damping-off-fusarium", + "wiki-damping-off-of-apple", + "wiki-damping-off-pythium", + "wiki-damping-off-rhizoctonia", + "wiki-date-palm-bayoud-disease", + "wiki-date-palm-black-scorch", + "wiki-date-palm-diplodia-disease", + "wiki-datura-leaf-curl", + "wiki-datura-mosaic", + "wiki-datura-stramonium", + "wiki-dead-arm", + "wiki-decay", + "wiki-deformation-mosaic", + "wiki-diamond-spot", + "wiki-dianthus-mottle", + "wiki-dianthus-ringspot", + "wiki-diaprepes-root-weevil", + "wiki-dickeya", + "wiki-dieback-and-leaf-scorch", + "wiki-dilophospora-leaf-spot", + "wiki-diplodia-disease", + "wiki-diplodia-leaf-streak", + "wiki-dirty-root", + "wiki-discoloration", + "wiki-distortion-mosaic", + "wiki-dock-anthracnose", + "wiki-dogwood-anthracnose", + "wiki-dogwood-leaf-spot", + "wiki-dogwood-spot-anthracnose", + "wiki-dollar-spot", + "wiki-double-blossom", + "wiki-douglas-fir-needle-cast", + "wiki-douglas-fir-root-disease", + "wiki-downy-spot", + "wiki-drop", + "wiki-dropping", + "wiki-drought", + "wiki-dryberry-disease", + "wiki-dutch-elm-disease", + "wiki-dwarf-mistletoe", + "wiki-dwarf-mosaic", + "wiki-dwarfism", + "wiki-early-leaf-spot", + "wiki-early-leaf-spot-of-peanut", + "wiki-eggplant-little-leaf", + "wiki-eggplant-mosaic", + "wiki-eggplant-mottle-dwarf", + "wiki-eggplant-phomopsis", + "wiki-elderberry-leaf-spot", + "wiki-elderberry-virus", + "wiki-elephantiasis", + "wiki-elm-leaf-scorch", + "wiki-elm-mosaic", + "wiki-elm-mottle", + "wiki-elm-stripe", + "wiki-elm-witches-broom", + "wiki-elm-yellows", + "wiki-epicarp-lesion", + "wiki-esca", + "wiki-eucalyptus-leaf-spot", + "wiki-euonymus-anthracnose", + "wiki-euphorbia-mosaic", + "wiki-european-stone-fruit-yellows", + "wiki-evergreen-blackberry", + "wiki-exobasidium-leaf-spot", + "wiki-fabraea-leaf-spot", + "wiki-fabrea-leaf-spot", + "wiki-fairy-ring", + "wiki-fairy-ring-leaf-spot", + "wiki-false-blossom", + "wiki-false-loose-smut", + "wiki-false-root-knot-nematode", + "wiki-fanleaf", + "wiki-ferrugem-do-feijoeiro-comum", + "wiki-filbert-stunt", + "wiki-filiform", + "wiki-flavescence-doree", + "wiki-fleck", + "wiki-fleur", + "wiki-flyspeck-of-apple", + "wiki-foliar-nematode", + "wiki-foliar-nematodes", + "wiki-foliar-vein-yellowing", + "wiki-freckle", + "wiki-frosty-pod", + "wiki-fruit-blotch-of-apple", + "wiki-fruit-chimera", + "wiki-fruit-drop", + "wiki-fungal-brown-spot", + "wiki-fungal-scald", + "wiki-fusariosis", + "wiki-fusarium-bark-disease", + "wiki-fused-fingers", + "wiki-galls", + "wiki-giantism", + "wiki-gnomonia-leaf-spot", + "wiki-golden-mosaic", + "wiki-grape-rust", + "wiki-grassy-shoot", + "wiki-gray-mold-of-apple", + "wiki-gray-snow-mold", + "wiki-gray-streak", + "wiki-gray-wall", + "wiki-grease-spot", + "wiki-greasy-blotch", + "wiki-greasy-center", + "wiki-green-blotch", + "wiki-green-mosaic", + "wiki-green-ring", + "wiki-green-scale", + "wiki-greening", + "wiki-ground-nut-rosette", + "wiki-groundnut-leaf-spot", + "wiki-guinea-grass-mosaic", + "wiki-gummosis", + "wiki-hairy-nightshade", + "wiki-hazelnut-mosaic", + "wiki-hazelnut-yellows", + "wiki-head-mold", + "wiki-head-smut", + "wiki-heart-leaf-disorder", + "wiki-heart-leaf-unfurling-disorder", + "wiki-helenium-s", + "wiki-helminthosporium-leaf-spot", + "wiki-hemp-mosaic", + "wiki-hemp-streak", + "wiki-high-mat", + "wiki-holeus-spot", + "wiki-honey-fungus", + "wiki-hop-latent", + "wiki-hop-mosaic", + "wiki-horn-sprout", + "wiki-horse", + "wiki-huanglongbing", + "wiki-impatiens-necrotic-spot", + "wiki-indian-cassava-mosaic", + "wiki-infectious-bud-failure", + "wiki-japanese-beetle", + "wiki-joint-infection", + "wiki-joint-infection-of-apple", + "wiki-kalancho-mosaic", + "wiki-karnal-bunt", + "wiki-kernel-decay", + "wiki-kernel-molds", + "wiki-kernel-shrivel", + "wiki-kernel-spot", + "wiki-khamedj", + "wiki-knot", + "wiki-lace-leaf", + "wiki-late-leaf-rust", + "wiki-latex-eruption", + "wiki-leaf-and-bud-nematode", + "wiki-leaf-and-pod-spot", + "wiki-leaf-and-stem-nematode", + "wiki-leaf-anthracnose", + "wiki-leaf-bleaching", + "wiki-leaf-blister", + "wiki-leaf-crinkle", + "wiki-leaf-cupping", + "wiki-leaf-glazing", + "wiki-leaf-miner", + "wiki-leaf-mottle", + "wiki-leaf-pucker-of-apple", + "wiki-leaf-roll", + "wiki-leaf-scorch", + "wiki-leaf-streak", + "wiki-leaf-stripe", + "wiki-leaf-yellowing", + "wiki-leak", + "wiki-lettuce-infectious-yellows", + "wiki-lettuce-mosaic", + "wiki-lichen", + "wiki-light-leaf-spot", + "wiki-lime-blotch", + "wiki-line-pattern", + "wiki-lint-contamination", + "wiki-little-cherry", + "wiki-liver-spot", + "wiki-lixa-pequena", + "wiki-loose-kernel-smut", + "wiki-lophodermium-leaf-spot", + "wiki-maize-bushy-stunt", + "wiki-maize-chlorotic-dwarf", + "wiki-maize-chlorotic-mottle", + "wiki-maize-dwarf-mosaic", + "wiki-maize-mosaic", + "wiki-maize-rayado-fino", + "wiki-maize-rough-dwarf", + "wiki-maize-stripe", + "wiki-maize-tassel-abortion", + "wiki-maize-white-line-mosaic", + "wiki-maize-yellow-stripe", + "wiki-malayan-leaf-spot", + "wiki-mancha-angular", + "wiki-mango-scale", + "wiki-marginal-leaf-burn", + "wiki-maturity-bronzing", + "wiki-mealiness", + "wiki-mealybug", + "wiki-mela", + "wiki-mid-vein-spot", + "wiki-mild-mosaic", + "wiki-mildew", + "wiki-milo-disease", + "wiki-minor-leaf-spot", + "wiki-mistletoe", + "wiki-mofo-branco", + "wiki-moko", + "wiki-mold", + "wiki-moldy-core", + "wiki-monilia", + "wiki-moorpark-mottle", + "wiki-mop-top", + "wiki-mosaic-disease", + "wiki-mosaic-or-ringspot", + "wiki-mottle-leaf", + "wiki-mouse-ear", + "wiki-murcha-de-fusario", + "wiki-mycorrhiza", + "wiki-myriogenospora-leaf-binding", + "wiki-myrothecium-leaf-spot", + "wiki-mystrosporium-leaf-spot", + "wiki-navel-orange-worm", + "wiki-neck-blast", + "wiki-necrosis", + "wiki-necrotic-leaf-blotch", + "wiki-necrotic-leaf-blotch-of-apple", + "wiki-necrotic-ring-spot", + "wiki-necrotic-ringspot", + "wiki-nematode", + "wiki-net-blotch", + "wiki-nettlehead", + "wiki-noninfectious-bud-failure", + "wiki-northern-anthracnose", + "wiki-oak-root-fungus", + "wiki-oat-leaf-blotch", + "wiki-oat-mosaic", + "wiki-oat-necrotic-mottle", + "wiki-oat-red-leaf", + "wiki-oat-smut", + "wiki-oidio-do-feijoeiro-comum", + "wiki-olive-leaf-spot", + "wiki-orange-dog", + "wiki-orange-rust", + "wiki-other-nematodes", + "wiki-pale-leaf", + "wiki-palm-leaf-spot", + "wiki-panagrolaimus-nematode", + "wiki-panama-disease", + "wiki-panicum-mosaic", + "wiki-papaya-bunchy-top", + "wiki-pasmo", + "wiki-pea-enation-mosaic", + "wiki-pea-leaf-roll", + "wiki-pea-mosaic", + "wiki-pea-seed-borne-mosaic", + "wiki-pea-seedborne-mosaic", + "wiki-peach-leaf-curl", + "wiki-peach-mosaic-virus", + "wiki-peach-rosette", + "wiki-peach-scab", + "wiki-peach-yellow-bud-mosaic", + "wiki-peach-yellow-mottle", + "wiki-peach-yellows", + "wiki-peanut-mottle-virus", + "wiki-peanut-rust", + "wiki-pear-leaf-blister-mite", + "wiki-pear-leaf-curl", + "wiki-pear-leaf-spot", + "wiki-pear-psylla", + "wiki-pear-rust", + "wiki-pear-slug", + "wiki-pear-stony-pit", + "wiki-pearly-root", + "wiki-pecan-scab", + "wiki-pecky-rice", + "wiki-pelargonium-flower-break", + "wiki-pelargonium-line-pattern", + "wiki-pelargonium-ring-pattern", + "wiki-pelargonium-ringspot", + "wiki-pelargonium-zonale-spot", + "wiki-penicillium-mold", + "wiki-pepper-golden-mosaic", + "wiki-pepper-huasteco", + "wiki-pepper-leaf-curl", + "wiki-pepper-mottle", + "wiki-pepper-veinal-mottle", + "wiki-periconia-leaf-spot", + "wiki-persimmon", + "wiki-pestalosphaeria-leaf-spot", + "wiki-pestalotia-leaf-spot", + "wiki-petal-fall", + "wiki-peter-s-scorch", + "wiki-phaeoisariopsis-leaf-spot", + "wiki-phaeoseptoria-leaf-spot", + "wiki-phomopsis-cane-and-leaf-spot", + "wiki-phony-peach", + "wiki-phyllody", + "wiki-phylloxera", + "wiki-physoderma-brown-spot", + "wiki-phytophthora-leaf-fall", + "wiki-phytoplasma", + "wiki-pierce-s-disease", + "wiki-pin-sized-lesion", + "wiki-pink-snow-mold", + "wiki-pistachio", + "wiki-pitting", + "wiki-pleospora-leaf-spot", + "wiki-plum-pox", + "wiki-pod-mottle", + "wiki-podridao-cinzenta-do-caule", + "wiki-podridao-do-colo", + "wiki-podridao-radicular-de-rhizoctonia", + "wiki-podridao-radicular-seca", + "wiki-pokkah-boeng", + "wiki-postbloom-fruit-drop", + "wiki-potato-leaf-roll", + "wiki-potato-mop-top", + "wiki-potato-scab", + "wiki-potato-spindle-tuber-viroid", + "wiki-potato-x", + "wiki-potato-yellow-dwarf", + "wiki-potexvirus-unnamed", + "wiki-powdery-scab", + "wiki-primula-mosaic", + "wiki-primula-mottle", + "wiki-proliferation", + "wiki-prune-dwarf", + "wiki-prunus-necrotic-ringspot", + "wiki-pseudomonas-leaf-spot", + "wiki-pucciniastrum-leaf-rust", + "wiki-pucker-leaf", + "wiki-purple-blotch", + "wiki-purple-top", + "wiki-pyricularia-leaf-spot", + "wiki-pythium-damping-off", + "wiki-pythium-leak", + "wiki-radish-mosaic", + "wiki-rai-mosaic", + "wiki-ramularia-leaf-spot", + "wiki-raspberry", + "wiki-raspberry-bushy-dwarf", + "wiki-raspberry-leaf-curl", + "wiki-raspberry-leaf-spot", + "wiki-raspberry-mosaic", + "wiki-raspberry-veinbanding-mosaic", + "wiki-raspberry-yellow-dwarf", + "wiki-raspberry-yellow-spot", + "wiki-ratoon-stunting", + "wiki-rayadilla", + "wiki-red-blister", + "wiki-red-blotch", + "wiki-red-boot", + "wiki-red-leaf-blotch", + "wiki-red-leather-disease", + "wiki-red-spider", + "wiki-red-stripe", + "wiki-red-thread", + "wiki-redberry-disease", + "wiki-replant-problem", + "wiki-rhizoctonia-damping-off", + "wiki-rhizoctonia-soreshin", + "wiki-rhizomania", + "wiki-rhynchosia-little-leaf", + "wiki-rhynchosia-mosaic", + "wiki-rice-black-streaked-dwarf", + "wiki-rice-blast", + "wiki-rice-bunts", + "wiki-rice-dwarf", + "wiki-rice-grassy-stunt", + "wiki-rice-ragged-stunt", + "wiki-rice-transitory-yellowing", + "wiki-rice-tungro", + "wiki-rice-yellow-mottle", + "wiki-rind-disease", + "wiki-rind-spot", + "wiki-ringspot", + "wiki-ringspots", + "wiki-rna-virus", + "wiki-root-smallpox-disease", + "wiki-rose-leaf", + "wiki-rose-leaf-curl", + "wiki-rose-mosaic", + "wiki-rose-rosette", + "wiki-rosette-of-apple", + "wiki-rosetting", + "wiki-rough-dwarf", + "wiki-roxana", + "wiki-rubbery-wood-of-apple", + "wiki-rubus-stunt", + "wiki-russet", + "wiki-rust-mite", + "wiki-rust-white", + "wiki-rusty-spot", + "wiki-rye-ergot", + "wiki-satellite-panicum-mosaic", + "wiki-scab-of-apple", + "wiki-scab-of-citrus", + "wiki-scab-of-peach", + "wiki-scald-of-apple", + "wiki-sclerotinia", + "wiki-scopulariopsis-leaf-spot", + "wiki-scorch", + "wiki-seedling-disease", + "wiki-seedling-rust", + "wiki-segmented-banana", + "wiki-septoria-brown-spot", + "wiki-septoria-leaf-blotch", + "wiki-septoria-nodorum-blotch", + "wiki-septoria-tritici-blotch", + "wiki-shenandoah", + "wiki-shothole", + "wiki-silver-leaf-of-apple", + "wiki-silvering-disease", + "wiki-sinaloa-tomato-leaf-curl", + "wiki-slime-flux", + "wiki-slime-mold", + "wiki-small-hop", + "wiki-smut", + "wiki-snow-mold", + "wiki-snow-scald", + "wiki-soilborne-mosaic", + "wiki-sooty-blotch-of-apple", + "wiki-sore-shin", + "wiki-southern-anthracnose", + "wiki-southern-root-knot-nematode", + "wiki-southern-rust", + "wiki-speckle", + "wiki-speckled-blotch", + "wiki-speckled-leaf-blotch", + "wiki-speckled-snow-mold", + "wiki-sphacelia", + "wiki-sphaerotheca-pannosa", + "wiki-spike", + "wiki-spike-leaf", + "wiki-spiral-nematode-root-damage", + "wiki-split-peel", + "wiki-spot-anthracnose", + "wiki-spraing", + "wiki-spring-black-stem", + "wiki-squirter", + "wiki-stackburn", + "wiki-stagonospora-blotch", + "wiki-stagonospora-leaf-spot", + "wiki-stalk-smut", + "wiki-stem-and-bulb-nematode", + "wiki-stem-break", + "wiki-stem-nematode", + "wiki-stem-pitting", + "wiki-stem-pitting-of-apple", + "wiki-stem-rust", + "wiki-stem-smut", + "wiki-stem-splitting", + "wiki-stem-streak", + "wiki-stem-twisting-and-bending", + "wiki-stemphylium-leaf-and-stem-spot", + "wiki-sterility-mosaic", + "wiki-sticky-disease", + "wiki-stigmatomycosis", + "wiki-stippling", + "wiki-stolon-decay", + "wiki-stone-pitting", + "wiki-stony-pit", + "wiki-storage-mold", + "wiki-strawberry", + "wiki-strawberry-leaf-roll", + "wiki-strawberry-leaf-spot", + "wiki-strawberry-yellow-edge", + "wiki-strawbreaker", + "wiki-streak", + "wiki-striatura-ulcerosa", + "wiki-stripe", + "wiki-stripe-rust", + "wiki-stubby-root", + "wiki-stylet-nematode", + "wiki-sudden-death", + "wiki-sugar-end", + "wiki-sugarcane-mosaic", + "wiki-sulfur-deficiency", + "wiki-summer-black-stem", + "wiki-sun-blotch", + "wiki-sun-scald", + "wiki-sunblotch", + "wiki-superelongation", + "wiki-sweet-potato", + "wiki-sweet-potato-virus-disease", + "wiki-sycamore", + "wiki-taches-brunes", + "wiki-taiwan-marginal-scorch", + "wiki-take-all", + "wiki-tan-spot", + "wiki-tatter-leaf", + "wiki-tea", + "wiki-terminal-mottle", + "wiki-thrips", + "wiki-tikka-disease", + "wiki-tilletia", + "wiki-tip-over", + "wiki-tobacco", + "wiki-tobacco-ringspot", + "wiki-tobacco-ringspot-virus", + "wiki-tomato", + "wiki-tomato-aspermy", + "wiki-tomato-leaf-curl", + "wiki-tomato-ringspot", + "wiki-top-spotting", + "wiki-tristeza", + "wiki-tropical-rust", + "wiki-trunk-pitting", + "wiki-turnip-mosaic", + "wiki-twig-die-back", + "wiki-vein-clearing", + "wiki-vein-enation", + "wiki-vein-spot", + "wiki-veinbanding", + "wiki-verbena-latent", + "wiki-water-mold", + "wiki-web-blotch", + "wiki-weevil", + "wiki-western-x-disease", + "wiki-wet-feet", + "wiki-wheat-curl-mite", + "wiki-wheat-soil-borne-mosaic", + "wiki-white-blister", + "wiki-white-bract", + "wiki-white-head", + "wiki-white-pine-blister-rust", + "wiki-white-thread", + "wiki-wilt-of-fruit-bunches", + "wiki-winter-injury", + "wiki-wire-stem", + "wiki-wirestem", + "wiki-wirrega-blotch", + "wiki-witch-s-broom", + "wiki-witches-broom-of-apple", + "wiki-withertip", + "wiki-wood-decay", + "wiki-wood-pocket", + "wiki-wood-stains", + "wiki-woolly-apple-aphid", + "wiki-x-disease", + "wiki-xanthomonas-leaf-spot", + "wiki-xyloporosis", + "wiki-xyloporosis-of-apple", + "wiki-yellow-edge", + "wiki-yellow-leaf-curl", + "wiki-yellow-leaf-spot", + "wiki-yellow-mat", + "wiki-yellow-mosaic", + "wiki-yellow-mottle", + "wiki-yellow-net-vein", + "wiki-yellow-pulp", + "wiki-yellow-shoot", + "wiki-yellow-sigatoka", + "wiki-yellow-stunt", + "wiki-yellowing", + "wiki-zebra-chip", + "wiki-zonate-eye-spot", + "tomato-tomato-fruitworm", + "tomato-tomato-hornworm", + "tomato-tobacco-hornworm", + "tomato-brown-tipped-pearl", + "tomato-eggplant-borer", + "tomato-tomato-fruit-borer", + "tomato-eggplant-leafroller", + "tomato-potato-tuber-moth", + "tomato-tomato-borer", + "tomato-tomato-pinworm", + "tomato-root-knot", + "tomato-sting", + "tomato-stubby-root", + "tomato-autogenous-necrosis", + "tomato-fruit-pox", + "tomato-gold-fleck", + "tomato-graywall", + "potato-potato-cyst-nematode", + "potato-lesion-nematode", + "potato-potato-rot-nematode", + "potato-root-knot-nematode", + "potato-sting-nematode", + "potato-stubby-root-nematode", + "potato-aerial-tubers", + "potato-air-pollution-injury", + "potato-black-heart", + "potato-blackspot-bruise", + "potato-elephant-hide", + "potato-hollow-heart", + "potato-internal-brown-spot-heat-necrosis", + "potato-jelly-end-rot", + "potato-physiological-leaf-roll", + "potato-psyllid-yellows", + "potato-shatter-bruise", + "potato-stem-end-browning", + "apple-dagger-nematode", + "apple-lesion-nematode", + "apple-pin-nematode", + "apple-ring-nematode", + "apple-root-knot-nematode", + "apple-bitter-pit", + "apple-blossom-blast", + "apple-fruit-cracking", + "apple-fruit-russet", + "apple-green-mottle", + "apple-hollow-apple", + "apple-internal-bark-necrosis-measles", + "apple-internal-browning", + "apple-jonathan-spot", + "apple-narrow-leaf", + "apple-necrotic-leaf-blotch-of-golden-delicious", + "apple-spray-injury", + "apple-storage-scald", + "apple-sunscald", + "apple-water-core", + "apricot-lesion", + "apricot-ring", + "apricot-root-knot", + "apricot-apricot-gumboil", + "avocado-algal-spot", + "avocado-blackstreak", + "avocado-littleleaf-rosette", + "avocado-tipburn", + "barley-cereal-cyst-nematode", + "barley-cereal-root-knot-nematode", + "barley-root-gall-nematode", + "barley-root-lesion-nematode", + "barley-stunt-nematode", + "barley-physiological-leaf-spot", + "carrot-cyst-nematode", + "carrot-dagger-nematode", + "carrot-lance-nematode", + "carrot-lesion-nematode", + "carrot-root-knot", + "carrot-sting-nematode", + "carrot-stubby-root-nematodes", + "carrot-crown-rot-disorder" ], "currentKeyIndex": 0, "callsThisKey": 1068, diff --git a/apps/web/scripts/.ddg-progress.json b/apps/web/scripts/.ddg-progress.json index a1afd97..cf8a5d8 100644 --- a/apps/web/scripts/.ddg-progress.json +++ b/apps/web/scripts/.ddg-progress.json @@ -1799,7 +1799,2557 @@ "citrus-fusarium-wilt", "citrus-gray-mold-fruit", "citrus-greasy-spot-and-greasy-spot-rind-blotch", - "citrus-green-mold" + "citrus-green-mold", + "citrus-hendersonula-branch-wilt", + "citrus-leaf-spot", + "citrus-mal-secco", + "citrus-mancha-foliar-de-los-citricos", + "citrus-melanose", + "citrus-mucor-fruit-rot", + "citrus-mushroom-root-rot-shoestring-root-rot-or-oak-root-fungus", + "citrus-phaeoramularia-leaf-and-fruit-spot", + "citrus-phymatotrichum-root-rot", + "citrus-phytophthora-foot-rot-gummosis-and", + "citrus-pink-disease", + "citrus-pink-mold", + "citrus-pleospora-rot", + "citrus-poria-root-rot", + "citrus-post-bloom-fruit-drop", + "citrus-powdery-mildew", + "citrus-rhizopus-rot", + "citrus-rio-grande-gummosis", + "citrus-rootlet-rot", + "citrus-rosellinia-root-rot", + "citrus-scab", + "citrus-sclerotinia-twig-blight-fruit-rot-and-root-rot", + "citrus-septoria-spot", + "citrus-sooty-blotch", + "citrus-sour-rot", + "citrus-sweet-orange-scab", + "citrus-thread-blight", + "citrus-trichoderma-rot", + "citrus-twig-blight", + "citrus-ustulina-root-rot", + "citrus-whisker-mold", + "citrus-white-root-rot", + "coconut-algal-leaf-spot", + "coconut-anthracnose", + "coconut-bitten-leaf", + "coconut-bipolaris-leaf-spot", + "coconut-black-scorch", + "coconut-bud-rot", + "coconut-catacauma-leaf-spot", + "coconut-dry-basal-rot", + "coconut-ganoderma-butt-rot", + "coconut-graphiola-leaf-spot", + "coconut-gray-leaf-blight", + "coconut-koleroga", + "coconut-leaf-blight", + "coconut-leaf-spots", + "coconut-lethal-bole-rot", + "coconut-lixa-grande", + "coconut-lixa-pequea", + "coconut-nut-fall", + "coconut-powdery-mildew", + "coconut-queima-das-folhas", + "coconut-root-rot", + "coconut-stem-bleeding", + "coconut-stigmina-leaf-spot", + "coconut-thread-blight", + "coffee-anthracnose", + "coffee-armillaria-root-rot", + "coffee-algal-red-leaf-spot", + "coffee-bark-disease", + "coffee-berry-blotch", + "coffee-black-rosellinia-root-rot", + "coffee-black-seedling-root-rot", + "coffee-brown-blight", + "coffee-brown-eye-spot", + "coffee-brown-leaf-spot", + "coffee-collar-rot", + "coffee-coffee-berry-disease", + "coffee-die-back", + "coffee-dry-root-rot", + "coffee-leaf-blight", + "coffee-leaf-spot", + "coffee-pink-disease", + "coffee-red-blister-disease-robusta-coffee", + "coffee-red-root-rot", + "coffee-rust-orange-or-leaf-rust", + "coffee-rust-powdery-or-grey-rust", + "coffee-south-america-leaf-spot", + "coffee-thread-blight", + "coffee-tip-blast", + "coffee-tracheomycosis-wilt", + "coffee-wilt", + "coffee-warty-berry", + "corn-anthracnose-leaf-blight-anthracnose-stalk-rot", + "corn-aspergillus-ear-and-kernel-rot", + "corn-banded-leaf-and-sheath-spot", + "corn-black-bundle-disease", + "corn-black-kernel-rot", + "corn-borde-blanco", + "corn-brown-spot-black-spot-stalk-rot", + "corn-cephalosporium-kernel-rot", + "corn-charcoal-rot", + "corn-corticium-ear-rot", + "corn-curvularia-leaf-spot", + "corn-didymella-leaf-spot", + "corn-diplodia-ear-rot-and-stalk-rot", + "corn-diplodia-ear-rot-stalk-rot-seed-rot-seedling-blight", + "corn-diplodia-leaf-spot-or-leaf-streak", + "corn-brown-stripe-downy-mildew", + "corn-crazy-top-downy-mildew", + "corn-green-ear-downy-mildew-graminicola-downy-mildew", + "corn-java-downy-mildew", + "corn-philippine-downy-mildew", + "corn-sorghum-downy-mildew", + "corn-spontaneum-downy-mildew", + "corn-sugarcane-downy-mildew", + "corn-dry-ear-rot-cob-kernel-and-stalk-rot", + "corn-ear-rots-minor", + "corn-ergot-horses-tooth", + "corn-eyespot", + "corn-fusarium-ear-and-stalk-rot", + "corn-fusarium-kernel-root-and-stalk-rot-seed-rot-and-seedling-blight", + "corn-fusarium-stalk-rot-seedling-root-rot", + "corn-gibberella-ear-and-stalk-rot", + "corn-gray-ear-rot", + "corn-corn-grey-leaf-spot-gray-leaf-spot-cercospora-leaf-spot", + "corn-helminthosporium-root-rot", + "corn-hormodendrum-ear-rot-cladosporium-ear-rot", + "corn-hyalothyridium-leaf-spot", + "corn-late-wilt", + "corn-leaf-spots-minor", + "corn-northern-corn-leaf-blight-white-blast-crown-stalk-rot-stripe", + "corn-northern-corn-leaf-spot-helminthosporium-ear-rot-race-1", + "corn-penicillium-ear-rot-blue-eye-blue-mold", + "corn-phaeocytostroma-stalk-rot-and-root-rot", + "corn-phaeosphaeria-leaf-spot", + "corn-physalospora-ear-rot-botryosphaeria-ear-rot", + "corn-pyrenochaeta-stalk-rot-and-root-rot", + "corn-pythium-root-rot", + "corn-pythium-stalk-rot", + "corn-red-kernel-disease-ear-mold-leaf-and-seed-rot", + "corn-rhizoctonia-ear-rot-sclerotial-rot", + "corn-rhizoctonia-root-rot-and-stalk-rot", + "corn-root-rots-minor", + "corn-rostratum-leaf-spot-helminthosporium-leaf-disease-ear-and-stalk-rot", + "corn-rust-common-corn", + "corn-rust-southern-corn", + "corn-rust-tropical-corn", + "corn-sclerotium-ear-rot-southern-blight", + "corn-selenophoma-leaf-spot", + "corn-sheath-rot", + "corn-shuck-rot", + "corn-silage-mold", + "corn-smut-common", + "corn-smut-false", + "corn-smut-head", + "corn-southern-corn-leaf-blight-and-stalk-rot", + "corn-southern-leaf-spot", + "corn-stalk-rots-minor", + "corn-storage-rots", + "corn-tar-spot", + "corn-trichoderma-ear-rot-and-root-rot", + "corn-white-ear-rot-root-and-stalk-rot", + "corn-yellow-leaf-blight", + "corn-zonate-leaf-spot", + "cucumber-alternaria-leaf-blight", + "cucumber-alternaria-leaf-spot", + "cucumber-anthracnose-stem-leaf-and-fruit", + "cucumber-belly-rot", + "cucumber-black-root-rot", + "cucumber-blue-mold-rot", + "cucumber-cephalosporium-root-and-hypocotyl-rot-stem-streak-and-dieback", + "cucumber-cercospora-leaf-spot", + "cucumber-charcoal-rot-vine-decline-and-fruit-rot", + "cucumber-choanephora-fruit-rot", + "cucumber-collapse-of-melon", + "cucumber-corynespora-blighttarget-spot", + "cucumber-crater-rot-fruit", + "cucumber-crown-and-foot-rot", + "cucumber-damping-off", + "cucumber-fusarium-fruit-rot", + "cucumber-fusarium-wilt", + "cucumber-gray-mold", + "cucumber-gummy-stem-blight-vine-decline", + "cucumber-lasiodiplodia-vine-declinefruit-rot", + "cucumber-monosporascus-root-rotmyrothecium-canker-black-canker", + "cucumber-net-spot", + "cucumber-phoma-blight", + "cucumber-purple-stem", + "cucumber-phomopsis-black-stem", + "cucumber-phyllosticta-leaf-spot", + "cucumber-phytophthora-root-rot", + "cucumber-pink-mold-rot", + "cucumber-plectosporium-blight", + "cucumber-pythium-fruit-rot-cottony-leak", + "cucumber-rhizopus-soft-rot-fruit", + "cucumber-scabgummosis", + "cucumber-sclerotinia-stem-rot", + "cucumber-septoria-leaf-blight", + "cucumber-southern-blight-sclerotium-fruit-and-stem-rot", + "cucumber-sudden-wilt", + "cucumber-ulocladium-leaf-spot", + "cucumber-verticillium-wilt", + "cucumber-web-blight", + "grape-alternaria-rot", + "grape-angular-leaf-scorch", + "grape-angular-leaf-spot", + "grape-anthracnose-and-birds-eye-rot", + "grape-armillaria-root-rot-shoestring-root-rot", + "grape-aspergillus-rot", + "grape-black-rot-of-grapes", + "grape-botrytis-grey-rot-or-noble-rot", + "grape-bot-canker", + "grape-ripe-rot", + "lettuce-alternaria-leaf-spot", + "lettuce-anthracnose", + "lettuce-bottom-rot", + "lettuce-cercospora-leaf-spot", + "lettuce-damping-off-pythium", + "lettuce-damping-off-rhizoctonia", + "lettuce-drop-sclerotinia-rot", + "lettuce-gray-mold", + "lettuce-phymatotrichum-root-rot-cotton-root-rot", + "lettuce-powdery-mildew", + "lettuce-septoria-leaf-spot", + "lettuce-southern-blight", + "lettuce-stemphylium-leaf-spot", + "lettuce-wilt-and-leaf-blight", + "mango-alternaria-leaf-spots", + "mango-anthracnoseref-nameploetz-2003", + "mango-black-banded-disease", + "mango-black-mildew", + "mango-black-mold-rot", + "mango-black-rot", + "mango-blossom-blight", + "mango-blue-mold", + "mango-branch-canker", + "mango-branch-necrosis", + "mango-ceratocystis-wilt", + "mango-charcoal-fruit-rot", + "mango-charcoal-root-rot", + "mango-crown-rot", + "mango-crusty-leaf-spot", + "mango-curvularia-blight", + "mango-dieback", + "mango-felt-fungus", + "mango-fruit-rot", + "mango-gray-leaf-spot", + "mango-hendersonia-rot", + "mango-leaf-blight", + "mango-leaf-spot", + "mango-macrophoma-rot", + "mango-mango-malformation", + "mango-mucor-rot", + "mango-mushroom-root-rot", + "mango-phoma-blight", + "mango-phyllosticta-leaf-spot", + "mango-pink-disease", + "mango-powdery-mildew", + "mango-rhizopus-rot", + "mango-root-rot", + "mango-scab", + "mango-sclerotinia-rot", + "mango-seed-rots", + "mango-shoestring-rot", + "mango-sooty-blotch", + "mango-sooty-molds", + "mango-stem-canker", + "mango-stem-end-rot", + "mango-stem-gall", + "mango-stemphylium-rot", + "mango-stigmina-leaf-spot", + "mango-tip-dieback", + "mango-transit-rot", + "mango-trunk-rot", + "mango-twig-blight", + "mango-verticillium-wilt", + "mango-white-sooty-blotch", + "mango-wood-rot", + "papaya-alternaria-fruit-spot", + "papaya-angular-leaf-spot", + "papaya-anthracnose", + "papaya-black-spot", + "papaya-blossom-spot", + "papaya-black-rot", + "papaya-brown-spot", + "papaya-chocolate-spot", + "papaya-collar-rot", + "papaya-foot-rot", + "papaya-fruit-rot", + "papaya-fruit-spot", + "papaya-fusarium-fruit-rot", + "papaya-guignardia-spot", + "papaya-greasy-spot", + "papaya-internal-blight", + "papaya-lasiodiplodia-fruit-rot", + "papaya-leaf-spot", + "papaya-petiole-spot", + "papaya-phytophthora-blight", + "papaya-powdery-mildew", + "papaya-phytophthora-fruit-rot", + "papaya-rhizopus-soft-rot", + "papaya-root-rot", + "papaya-sclerotium-blight", + "papaya-seedling-blight", + "papaya-stem-end-rot", + "papaya-stemphylium-fruit-spot", + "papaya-stem-rot", + "papaya-target-spot", + "papaya-verticillium-wilt", + "papaya-wet-fruit-rot", + "papaya-", + "peanut-alternaria-leaf-blight", + "peanut-alternaria-leaf-spot", + "peanut-alternaria-spot-and-veinal-necrosis", + "peanut-anthracnose", + "peanut-aspergillus-crown-rot", + "peanut-blackhull", + "peanut-botrytis-blight", + "peanut-charcoal-rot-and-macrophomina-leaf-spot", + "peanut-choanephora-leaf-spot", + "peanut-collar-rot", + "peanut-colletotrichum-leaf-spot", + "peanut-cylindrocladium-black-rot", + "peanut-cylindrocladium-leaf-spot", + "peanut-damping-off-aspergillus", + "peanut-damping-off-fusarium", + "peanut-damping-off-pythium", + "peanut-damping-off-rhizoctonia", + "peanut-damping-off-rhizopus", + "peanut-drechslera-leaf-spot", + "peanut-fusarium-peg-and-root-rot", + "peanut-fusarium-wilt", + "peanut-leaf-spot-early", + "peanut-leaf-spot-late", + "peanut-myrothecium-leaf-blight", + "peanut-olpidium-root-rot", + "peanut-pepper-spot-and-scorch", + "peanut-pestalotiopsis-leaf-spot", + "peanut-phoma-leaf-blight", + "peanut-phomopsis-foliar-blight", + "peanut-phomopsis-leaf-spot", + "peanut-phyllosticta-leaf-spot", + "peanut-phymatotrichum-root-rot", + "peanut-pod-rot-pod-breakdown", + "peanut-powdery-mildew", + "peanut-pythium-peg-and-root-rot", + "peanut-pythium-wilt", + "peanut-rhizoctonia-foliar-blight-peg-and-root-rot", + "peanut-scab", + "peanut-sclerotinia-blight", + "peanut-stem-rot-southern-blight", + "peanut-verticillium-wilt", + "peanut-web-blotch-net-blotch", + "peanut-yellow-mold", + "peanut-zonate-leaf-spot", + "pear-alternaria-fruit-rot", + "pear-anthracnose-canker-and-bulls-eye-rot", + "pear-armillaria-root-rot-shoestring-root-rot", + "pear-bitter-rot", + "pear-black-rot-leaf-spot-and-canker", + "pear-black-spot-of-japanese-pear", + "pear-blister-canker", + "pear-blister-disease", + "pear-blue-mold-rot", + "pear-botrytis-spur-and-blossom-blight", + "pear-brown-rot", + "pear-cladosporium-fruit-rot", + "pear-clitocybe-root-rot-mushroom-root-rot", + "pear-coprinus-rot", + "pear-dematophora-root-rot-rosellinia-root-rot", + "pear-diplodia-canker", + "pear-elsinoe-leaf-and-fruit-spot", + "pear-european-canker", + "pear-fabraea-leaf-and-fruit-spot", + "pear-fly-speck", + "pear-gibberella-canker", + "pear-gray-mold-rot", + "pear-late-leaf-spot", + "pear-mucor-fruit-rot", + "pear-mycosphaerella-leaf-spot-ashy-leaf-spot-and-fruit-spot", + "pear-nectria-twig-blight-coral-spot", + "pear-pear-scab", + "pear-perennial-canker", + "pear-phyllosticta-leaf-spot", + "pear-phytophthora-crown-and-root-rot-sprinkler-rot", + "pear-pink-mold-rot", + "pear-powdery-mildew", + "pear-pythium-dieback", + "pear-rhizopus-rot", + "pear-rust-american-hawthorne", + "pear-rust-kerns-pear", + "pear-rust-pacific-coast-pear", + "pear-rust-pear-trellis-european-pear-rust", + "pear-rust-rocky-mountain-pear", + "pear-side-rot", + "pear-silver-leaf", + "pear-sooty-blotch", + "pear-thread-blight-hypochnus-leaf-blight", + "pear-valsa-canker", + "pear-wood-rot", + "pear-xylaria-root-rot", + "pepper-alternaria-stem-canker", + "pepper-anthracnose", + "pepper-black-mold-rot", + "pepper-black-root-rot", + "pepper-black-shoulder", + "pepper-buckeye-rot-of-tomato", + "pepper-cercospora-leaf-mold", + "pepper-charcoal-rot", + "pepper-corky-root-rot", + "pepper-didymella-stem-rot", + "pepper-early-blight", + "pepper-fusarium-crown-and-root-rot", + "pepper-fusarium-wilt", + "pepper-gray-leaf-spot", + "pepper-gray-mold", + "pepper-late-blight", + "pepper-leaf-mold", + "pepper-phoma-rot", + "pepper-pythium-damping-off-and-fruit-rot", + "pepper-rhizoctonia-damping-off-and-fruit-rot", + "pepper-rhizopus-rot", + "pepper-septoria-leaf-spot", + "pepper-sour-rot", + "pepper-southern-blight", + "pepper-target-spot", + "pepper-verticillium-wilt", + "pepper-white-mold", + "pineapple-anthracnose", + "pineapple-pineapple-black-rot", + "pineapple-leaf-spot", + "pineapple-root-rot", + "pineapple-seedling-blight", + "pineapple-white-leaf-spot", + "pineapple-aspergillus-rot", + "pineapple-botryodiplodia-rot", + "pineapple-black-rot-water-blister", + "pineapple-fusariosis-gummosis", + "pineapple-glassy-spoilage", + "pineapple-hendersonula-fruit-rot", + "pineapple-interfruitlet-corking", + "pineapple-leathery-pocket", + "pineapple-nigrospora-fruit-rot", + "pineapple-rhizopus-rot", + "pineapple-yeasty-fermentation", + "rice-aggregate-sheath", + "rice-black-horse-riding", + "rice-blast-leaf-neck-rotten-neck-nodal-and-collar", + "rice-brown-spot", + "rice-crown-sheath-rot", + "rice-eyespot", + "rice-false-smut", + "rice-kernel-smut", + "rice-leaf-smut", + "rice-leaf-scald", + "rice-narrow-brown-leaf-spot", + "rice-root-rots", + "rice-seedling-blight", + "rice-sheath-blight", + "rice-sheath-rot", + "rice-sheath-spot", + "rice-stem-rot", + "rice-water-mold-seed-rot-and-seedling-disease", + "sorghum-acremonium-wilt", + "sorghum-anthracnose-foliar-head-root-and-stalk-rot", + "sorghum-charcoal-rot", + "sorghum-crazy-top-downy-mildew", + "sorghum-damping-off-and-seed-rot", + "sorghum-fusarium-head-blight-root-and-stalk-rot", + "sorghum-grain-storage-mold", + "sorghum-gray-leaf-spot", + "sorghum-latter-leaf-spot", + "sorghum-leaf-blight", + "sorghum-milo-disease-periconia-root-rot", + "sorghum-oval-leaf-spot", + "sorghum-pokkah-boeng-twisted-top", + "sorghum-pythium-root-rot", + "sorghum-rough-leaf-spot", + "sorghum-seedling-blight-and-seed-rot", + "sorghum-smut-covered-kernel", + "sorghum-smut-head", + "sorghum-smut-loose-kernel", + "sorghum-sooty-stripe", + "sorghum-sorghum-downy-mildew", + "sorghum-tar-spot", + "sorghum-target-leaf-spot", + "sorghum-zonate-leaf-spot-and-sheath-blight", + "soybean-alternaria-leaf-spot", + "soybean-anthracnose", + "soybean-black-leaf-blight", + "soybean-black-root-rot", + "soybean-brown-spot", + "soybean-brown-stem-rot", + "soybean-charcoal-rotref-namesoybeanok", + "soybean-choanephora-leaf-blight", + "soybean-damping-off", + "soybean-drechslera-blight", + "soybean-frogeye-leaf-spot", + "soybean-fusarium-root-rot", + "soybean-leptosphaerulina-leaf-spot", + "soybean-mycoleptodiscus-root-rot", + "soybean-neocosmospora-stem-rot", + "soybean-phomopsis-seed-decay", + "soybean-phytophthora-root-and-stem-rot", + "soybean-phyllosticta-leaf-spot", + "soybean-phymatotrichum-root-rot-cotton-root-rot", + "soybean-pod-and-stem-blight", + "soybean-powdery-mildew", + "soybean-purple-seed-stain", + "soybean-pyrenochaeta-leaf-spot", + "soybean-pythium-rot", + "soybean-red-crown-rot", + "soybean-red-leaf-blotch-dactuliophora-leaf-spot", + "soybean-rhizoctonia-aerial-blight", + "soybean-rhizoctonia-root-and-stem-rot", + "soybean-scab", + "soybean-sclerotinia-stem-rot", + "soybean-southern-blight-damping-off-and-stem-rot-sclerotium-blightref-namesoybeanok", + "soybean-stem-canker", + "soybean-stemphylium-leaf-blight", + "soybean-sudden-death-syndrome", + "soybean-target-spot", + "soybean-yeast-spot", + "spinach-anthracnose", + "spinach-aphanomyces-root-rot", + "spinach-cercospora-leaf-spot", + "spinach-damping-off", + "spinach-downy-mildew-blue-mold", + "spinach-fusarium-wilt", + "spinach-leaf-spot", + "spinach-phoma-blight", + "spinach-phytophthora-root-rot", + "spinach-pythium-root-rot", + "spinach-red-rust", + "spinach-seed-mold", + "spinach-white-rust", + "spinach-white-smut", + "strawberry-alternaria-fruit-rot", + "strawberry-anther-and-pistil-blight", + "strawberry-anthracnose-and-anthracnose-fruit-rot-and-black-spot", + "strawberry-armillaria-crown-and-root-rot-shoestring-crown-and-root-rot", + "strawberry-black-leaf-spot", + "strawberry-black-root-rot-disease-complex", + "strawberry-cercospora-leaf-spot", + "strawberry-charcoal-rot", + "strawberry-coniothyrium-diseases", + "strawberry-dematophora-crown-and-root-rot-white-root-rot", + "strawberry-diplodina-rot-leaf-and-stalk-rot", + "strawberry-fruit-rots-in-addition-to-those-appearing-elsewhere-in-this-listing", + "strawberry-byssochlamys-rot", + "strawberry-brown-cap", + "strawberry-fruit-blotch", + "strawberry-gray-mold-leaf-blight-and-dry-crown-rot", + "strawberry-hainesia-leaf-spot", + "strawberry-hard-brown-rot", + "strawberry-leaf-blotch", + "strawberry-leaf-rust", + "strawberry-leather-rot", + "strawberry-lilac-soft-rot", + "strawberry-pestalotia-fruit-rot", + "strawberry-leaf-blight", + "strawberry-postharvest-rots", + "strawberry-phytophthora-crown-and-root-rot", + "strawberry-botrytis-crown-rot", + "strawberry-gray-sterile-fungus-root-rot", + "strawberry-idriella-root-rot", + "strawberry-macrophomina-root-rot", + "strawberry-olpidium-root-infection", + "strawberry-synchytrium-root-gall", + "strawberry-purple-leaf-spot", + "strawberry-red-stele", + "strawberry-rhizoctonia-bud-and-crown-rot-leaf-blight-web-blight-fruit-rot", + "strawberry-rhizopus-rot-leak", + "strawberry-sclerotinia-crown-and-fruit-rot", + "strawberry-septoria-hard-rot-and-leaf-spot", + "strawberry-stunt-pythium-root-rot", + "strawberry-southern-blight-sclerotium-rot", + "strawberry-stem-end-rot", + "strawberry-tan-brown-rot-of-fruit", + "strawberry-verticillium-wilt", + "sugarcane-banded-sclerotial-leaf-disease", + "sugarcane-black-rot", + "sugarcane-black-stripe", + "sugarcane-brown-spot", + "sugarcane-brown-stripe", + "sugarcane-downy-mildew-leaf-splitting-form", + "sugarcane-eye-spot", + "sugarcane-fusarium-sett-and-stem-rot", + "sugarcane-iliau", + "sugarcane-leaf-blast", + "sugarcane-leaf-blight", + "sugarcane-leaf-scorch", + "sugarcane-marasmius-sheath-and-shoot-blight", + "sugarcane-myriogenospora-leaf-binding-tangle-top", + "sugarcane-phyllosticta-leaf-spot", + "sugarcane-phytophthora-rot-of-cuttings", + "sugarcane-pineapple-disease", + "sugarcane-pokkah-boeng-that-may-have-knife-cut-symptoms", + "sugarcane-red-leaf-spot-purple-spot", + "sugarcane-red-rot-of-leaf-sheath-and-sprout-rot", + "sugarcane-red-spot-of-leaf-sheath", + "sugarcane-rhizoctonia-sheath-and-shoot-rot", + "sugarcane-rind-disease-sour-rot", + "sugarcane-ring-spot", + "sugarcane-root-rots", + "sugarcane-rust-common", + "sugarcane-rust-orange", + "sugarcane-schizophyllum-rot", + "sugarcane-sclerophthora-disease", + "sugarcane-seedling-blight", + "sugarcane-sheath-rot", + "sugarcane-smut-culmicolous", + "sugarcane-target-blotch", + "sugarcane-veneer-blotch", + "sugarcane-white-rash", + "sugarcane-wilt", + "sugarcane-yellow-spot", + "sugarcane-zonate-leaf-spot", + "sunflower-alternaria-leaf-blight-stem-spot-and-head-rot", + "sunflower-botrytis-head-rot-gray-mold", + "sunflower-charcoal-rot", + "sunflower-fusarium-stalk-rot", + "sunflower-fusarium-wilt", + "sunflower-myrothecium-leaf-and-stem-spot", + "sunflower-phialophora-yellows", + "sunflower-phoma-black-stem", + "sunflower-phomopsis-brown-stem-canker", + "sunflower-phymatotrichum-root-rot-cotton-root-rot", + "sunflower-phytophthora-stem-rot", + "sunflower-pythium-seedling-blight-and-root-rot", + "sunflower-rhizoctonia-seedling-blight", + "sunflower-rhizopus-head-rot", + "sunflower-sclerotinia-basal-stalk-rot-and-wilt-mid-stalk-rot-head-rot", + "sunflower-sclerotinia-basal-stalk-rot-and-wilt", + "sunflower-sclerotium-basal-stalk-and-root-rot-southern-blight", + "sunflower-septoria-leaf-spot", + "sunflower-verticillium-wilt", + "sunflower-white-rust", + "sunflower-yellow-rust", + "sweet-potato-alternaria-leaf-spot-and-stem-blight", + "sweet-potato-alternaria-storage-rot", + "sweet-potato-black-rot", + "sweet-potato-blue-mold-rot", + "sweet-potato-cercospora-leaf-spot", + "sweet-potato-charcoal-rot", + "sweet-potato-chlorotic-leaf-distortion", + "sweet-potato-circular-spot", + "sweet-potato-end-rot", + "sweet-potato-false-broom-rape", + "sweet-potato-foot-rot", + "sweet-potato-fusarium-root-rot-and-stem-canker", + "sweet-potato-fusarium-wilt-stem-rot", + "sweet-potato-gray-mold-rot", + "sweet-potato-java-black-rot", + "sweet-potato-leaf-mold", + "sweet-potato-mottle-necrosis", + "sweet-potato-phyllosticta-leaf-blight", + "sweet-potato-phymatotrichum-root-rot-cotton-root-rot", + "sweet-potato-pink-root", + "sweet-potato-punky-rot", + "sweet-potato-rhizoctonia-stem-canker-sprout-rot", + "sweet-potato-rhizopus-soft-rot", + "sweet-potato-rootlet-rot", + "sweet-potato-rust-red", + "sweet-potato-rust-white", + "sweet-potato-scab-leaf-and-stem", + "sweet-potato-southern-blight-sclerotial-blight", + "sweet-potato-scurf", + "sweet-potato-septoria-leaf-spot", + "sweet-potato-storage-rot", + "sweet-potato-surface-rot", + "sweet-potato-violet-root-rot", + "sweet-potato-", + "tobacco-anthracnose", + "tobacco-barn-spot", + "tobacco-barn-rot", + "tobacco-black-root-rot", + "tobacco-blue-mold-downy-mildew", + "tobacco-brown-spot", + "tobacco-charcoal-rot", + "tobacco-collar-rot", + "tobacco-damping-off-pythium", + "tobacco-frogeye-leaf-spot", + "tobacco-fusarium-wilt", + "tobacco-gray-mold", + "tobacco-mycosphaerella-leaf-spot", + "tobacco-olpidium-seedling-blight", + "tobacco-phyllosticta-leaf-spot", + "tobacco-powdery-mildew", + "tobacco-ragged-leaf-spot", + "tobacco-scab", + "tobacco-sore-shin-and-damping-off", + "tobacco-southern-stem-rot-southern-blight", + "tobacco-stem-rot-of-transplants", + "tobacco-target-spot", + "tobacco-verticillium-wilt", + "watermelon-alternaria-leaf-blight", + "watermelon-alternaria-leaf-spot", + "watermelon-anthracnose-stem-leaf-and-fruit", + "watermelon-belly-rot", + "watermelon-black-root-rot", + "watermelon-blue-mold-rot", + "watermelon-cephalosporium-root-and-hypocotyl-rot-stem-streak-and-dieback", + "watermelon-cercospora-leaf-spot", + "watermelon-charcoal-rot-vine-decline-and-fruit-rot", + "watermelon-choanephora-fruit-rot", + "watermelon-collapse-of-melon", + "watermelon-corynespora-blighttarget-spot", + "watermelon-crater-rot-fruit", + "watermelon-crown-and-foot-rot", + "watermelon-damping-off", + "watermelon-fusarium-fruit-rot", + "watermelon-fusarium-wilt", + "watermelon-gray-mold", + "watermelon-gummy-stem-blight-vine-decline", + "watermelon-lasiodiplodia-vine-declinefruit-rot", + "watermelon-monosporascus-root-rotmyrothecium-canker-black-canker", + "watermelon-net-spot", + "watermelon-phoma-blight", + "watermelon-purple-stem", + "watermelon-phomopsis-black-stem", + "watermelon-phyllosticta-leaf-spot", + "watermelon-phytophthora-root-rot", + "watermelon-pink-mold-rot", + "watermelon-plectosporium-blight", + "watermelon-powdery-mildew", + "watermelon-pythium-fruit-rot-cottony-leak", + "watermelon-rhizopus-soft-rot-fruit", + "watermelon-scabgummosis", + "watermelon-sclerotinia-stem-rot", + "watermelon-septoria-leaf-blight", + "watermelon-southern-blight-sclerotium-fruit-and-stem-rot", + "watermelon-sudden-wilt", + "watermelon-ulocladium-leaf-spot", + "watermelon-verticillium-wilt", + "watermelon-web-blight", + "wheat-alternaria-leaf-blight", + "wheat-anthracnose", + "wheat-ascochyta-leaf-spot", + "wheat-aureobasidium-decay", + "wheat-black-head-molds-sooty-molds", + "wheat-black-point-kernel-smudge", + "wheat-cephalosporium-stripe", + "wheat-cottony-snow-mold", + "wheat-crown-rot-of-wheatcrown-rot-foot-rot-seedling-blight-dryland-root-rot", + "wheat-dilophospora-leaf-spot-twist", + "wheat-downy-mildew-crazy-top", + "wheat-dwarf-bunt", + "wheat-eyespot-foot-rot-strawbreaker", + "wheat-false-eyespot", + "wheat-flag-smut", + "wheat-foot-rot-dryland-foot-rot", + "wheat-halo-spot", + "wheat-karnal-bunt-partial-bunt", + "wheat-leaf-rust-brown-rust", + "wheat-leptosphaeria-leaf-spot", + "wheat-loose-smut", + "wheat-microscopica-leaf-spot", + "wheat-phoma-spot", + "wheat-pink-snow-mold-fusarium-patch", + "wheat-platyspora-leaf-spot", + "wheat-powdery-mildew", + "wheat-pythium-root-rot", + "wheat-rhizoctonia-root-rot", + "wheat-ring-spot-wirrega-blotch", + "wheat-scab-head-blight-fusarium-head-blight-fhb", + "wheat-sclerotinia-snow-mold-snow-scald", + "wheat-sclerotium-wilt-see-southern-blight", + "wheat-septoria-blotch", + "wheat-sharp-eyespot", + "wheat-snow-rot", + "wheat-southern-blight-sclerotium-base-rot", + "wheat-speckled-snow-mold-gray-snow-mold-or-typhula-blight", + "wheat-spot-blotch", + "wheat-stagonospora-blotchref-nametam-blotch", + "wheat-stem-rust-black-rust", + "wheat-storage-molds", + "wheat-stripe-rust-yellow-rust", + "wheat-tan-spot-yellow-leaf-spot-red-smudge", + "wheat-tar-spot", + "wheat-wheat-blast", + "wheat-zoosporic-root-rot", + "alfalfa-acrocalymma-root-and-crown-rot", + "alfalfa-anthracnose", + "alfalfa-aphanomyces-root-rot", + "alfalfa-black-patch", + "alfalfa-black-root-rot", + "alfalfa-blossom-blight", + "alfalfa-brown-root-rot", + "alfalfa-charcoal-rot", + "alfalfa-corky-root-rot", + "alfalfa-crown-wart", + "alfalfa-cylindrocarpon-root-rot", + "alfalfa-cylindrocladium-root-and-crown-rot", + "alfalfa-damping-off", + "alfalfa-fusarium-wilt", + "alfalfa-lepto-leaf-spot", + "alfalfa-marasmius-root-rot", + "alfalfa-mycoleptodiscus-crown-and-root-rot", + "alfalfa-myrothecium-root-rot", + "alfalfa-phymatotrichum-root-rot-cotton-root-rot-texas-root-rot", + "alfalfa-phytophthora-root-rot", + "alfalfa-powdery-mildew", + "alfalfa-rhizoctonia-root-rot-and-stem-blight", + "alfalfa-rhizopus-sprout-rot", + "alfalfa-sclerotinia-crown-and-stem-rot", + "alfalfa-southern-blight", + "alfalfa-spring-black-stem-and-leaf-spot", + "alfalfa-stagonospora-leaf-spot-and-root-rot", + "alfalfa-stemphylium-leaf-spot", + "alfalfa-summer-black-stem-and-leaf-spot", + "alfalfa-verticillium-wilt", + "alfalfa-violet-root-rot", + "alfalfa-winter-crown-rot-coprinus-snow-mold", + "alfalfa-yellow-leaf-blotch", + "asparagus-anthracnose", + "asparagus-ascochyta-blight", + "asparagus-blue-mold-rot", + "asparagus-cercospora-blight", + "asparagus-dead-stem", + "asparagus-fusarium-crown-and-root-rot", + "asparagus-fusarium-spear-spot", + "asparagus-gray-mold-shoot-blight", + "asparagus-leaf-spot", + "asparagus-phomopsis-blight", + "asparagus-phytophthora-spear-and-crown-rot", + "asparagus-purple-spot", + "asparagus-rhizoctonia-crown-rot", + "asparagus-watery-soft-rot", + "asparagus-zopfia-root-rot", + "asparagus-", + "tea-anthracnoseref-namepandey-et-al-2021", + "tea-armillaria-root-rot", + "tea-birds-eye-spot", + "tea-black-blight", + "tea-black-root-rot", + "tea-black-rot", + "tea-blister-blight", + "tea-botryodiplodia-root-rot", + "tea-brown-blightref-nameidguideref-namepandey-et-al-2021", + "tea-brown-root-rot", + "tea-brown-spot", + "tea-brown-zonate-leaf-blight", + "tea-bud-blight", + "tea-charcoal-stump-rot", + "tea-collar-and-branch-canker", + "tea-collar-rot", + "tea-copper-blight", + "tea-damping-off", + "tea-dieback", + "tea-gray-blightref-nameidguideref-namepandey-et-al-2021", + "tea-gray-mold", + "tea-gray-spot", + "tea-horse-hair-blightref-nameidguide", + "tea-leaf-spot", + "tea-leaf-scab", + "tea-macrophoma-stem-cankerref-namepandey-et-al-2021", + "tea-net-blister-blight", + "tea-pale-brown-root-rot", + "tea-phloem-necrosis", + "tea-phyllosticta-leaf-spot", + "tea-pink-disease", + "tea-poria-root-rot-and-stem-canker", + "tea-purple-root-rot", + "tea-red-leaf-spot", + "tea-red-root-rot", + "tea-red-rust-alga", + "tea-rim-blight", + "tea-root-rot", + "tea-rough-bark", + "tea-sclerotial-blight", + "tea-shoot-withering", + "tea-stump-rot", + "tea-tarry-root-rot", + "tea-thorny-stem-blight", + "tea-thread-blight", + "tea-twig-blight", + "tea-twig-dieback-stem-cankerref-nameidguideref-namepandey-et-al-2021", + "tea-velvet-blight", + "tea-violet-root-rot", + "tea-white-root-rot", + "tea-white-scab", + "tea-wood-rot", + "tea-xylaria-root-rot", + "tomato-blossom-end-rot", + "tomato-herbicide-injury", + "potato-blossom-end-rot", + "potato-herbicide-injury", + "bell-pepper-blossom-end-rot", + "bell-pepper-herbicide-injury", + "chili-pepper-blossom-end-rot", + "chili-pepper-herbicide-injury", + "eggplant-herbicide-injury", + "tobacco-blossom-end-rot", + "tobacco-herbicide-injury", + "tomatillo-blossom-end-rot", + "tomatillo-herbicide-injury", + "petunia-blossom-end-rot", + "petunia-herbicide-injury", + "gooseberry-blossom-end-rot", + "gooseberry-herbicide-injury", + "cucumber-herbicide-injury", + "zucchini-blossom-end-rot", + "zucchini-herbicide-injury", + "summer-squash-blossom-end-rot", + "summer-squash-herbicide-injury", + "winter-squash-blossom-end-rot", + "winter-squash-herbicide-injury", + "pumpkin-blossom-end-rot", + "pumpkin-herbicide-injury", + "watermelon-herbicide-injury", + "cantaloupe-blossom-end-rot", + "cantaloupe-herbicide-injury", + "honeydew-blossom-end-rot", + "honeydew-herbicide-injury", + "bitter-melon-blossom-end-rot", + "bitter-melon-herbicide-injury", + "chayote-blossom-end-rot", + "chayote-herbicide-injury", + "acorn-squash-blossom-end-rot", + "acorn-squash-herbicide-injury", + "butternut-squash-blossom-end-rot", + "butternut-squash-herbicide-injury", + "calabash-blossom-end-rot", + "calabash-herbicide-injury", + "luffa-blossom-end-rot", + "luffa-herbicide-injury", + "apple-blossom-end-rot", + "apple-herbicide-injury", + "pear-blossom-end-rot", + "pear-herbicide-injury", + "peach-blossom-end-rot", + "peach-herbicide-injury", + "cherry-blossom-end-rot", + "cherry-herbicide-injury", + "apricot-blossom-end-rot", + "apricot-herbicide-injury", + "plum-blossom-end-rot", + "plum-herbicide-injury", + "almond-blossom-end-rot", + "almond-herbicide-injury", + "strawberry-blossom-end-rot", + "strawberry-herbicide-injury", + "raspberry-blossom-end-rot", + "raspberry-herbicide-injury", + "blackberry-blossom-end-rot", + "blackberry-herbicide-injury", + "blueberry-blossom-end-rot", + "blueberry-herbicide-injury", + "cranberry-blossom-end-rot", + "cranberry-herbicide-injury", + "rose-blossom-end-rot", + "rose-herbicide-injury", + "hawthorn-blossom-end-rot", + "hawthorn-herbicide-injury", + "quince-blossom-end-rot", + "quince-herbicide-injury", + "cabbage-blossom-end-rot", + "cabbage-herbicide-injury", + "broccoli-blossom-end-rot", + "broccoli-herbicide-injury", + "cauliflower-blossom-end-rot", + "cauliflower-herbicide-injury", + "brussels-sprouts-blossom-end-rot", + "brussels-sprouts-herbicide-injury", + "kale-blossom-end-rot", + "kale-herbicide-injury", + "bok-choy-blossom-end-rot", + "bok-choy-herbicide-injury", + "radish-blossom-end-rot", + "radish-herbicide-injury", + "turnip-blossom-end-rot", + "turnip-herbicide-injury", + "arugula-blossom-end-rot", + "arugula-herbicide-injury", + "collard-greens-blossom-end-rot", + "collard-greens-herbicide-injury", + "mustard-greens-blossom-end-rot", + "mustard-greens-herbicide-injury", + "horseradish-blossom-end-rot", + "horseradish-herbicide-injury", + "wasabi-blossom-end-rot", + "wasabi-herbicide-injury", + "green-bean-blossom-end-rot", + "green-bean-herbicide-injury", + "soybean-blossom-end-rot", + "soybean-herbicide-injury", + "peanut-blossom-end-rot", + "peanut-herbicide-injury", + "chickpea-blossom-end-rot", + "chickpea-herbicide-injury", + "lentil-blossom-end-rot", + "lentil-herbicide-injury", + "faba-bean-blossom-end-rot", + "faba-bean-herbicide-injury", + "cowpea-blossom-end-rot", + "cowpea-herbicide-injury", + "pigeon-pea-blossom-end-rot", + "pigeon-pea-herbicide-injury", + "alfalfa-blossom-end-rot", + "alfalfa-herbicide-injury", + "clover-blossom-end-rot", + "clover-herbicide-injury", + "peas-blossom-end-rot", + "peas-herbicide-injury", + "lupine-blossom-end-rot", + "lupine-herbicide-injury", + "wisteria-blossom-end-rot", + "wisteria-herbicide-injury", + "robinia-blossom-end-rot", + "robinia-herbicide-injury", + "corn-blossom-end-rot", + "corn-herbicide-injury", + "wheat-blossom-end-rot", + "wheat-herbicide-injury", + "rice-blossom-end-rot", + "rice-herbicide-injury", + "barley-blossom-end-rot", + "barley-herbicide-injury", + "oats-blossom-end-rot", + "oats-herbicide-injury", + "sorghum-blossom-end-rot", + "sorghum-herbicide-injury", + "sugarcane-blossom-end-rot", + "sugarcane-herbicide-injury", + "bamboo-blossom-end-rot", + "bamboo-herbicide-injury", + "turfgrass-blossom-end-rot", + "turfgrass-herbicide-injury", + "millet-blossom-end-rot", + "millet-herbicide-injury", + "rye-blossom-end-rot", + "rye-herbicide-injury", + "sunflower-blossom-end-rot", + "sunflower-herbicide-injury", + "lettuce-blossom-end-rot", + "lettuce-herbicide-injury", + "artichoke-blossom-end-rot", + "artichoke-herbicide-injury", + "chicory-blossom-end-rot", + "chicory-herbicide-injury", + "endive-blossom-end-rot", + "endive-herbicide-injury", + "daisy-blossom-end-rot", + "daisy-herbicide-injury", + "marigold-blossom-end-rot", + "marigold-herbicide-injury", + "zinnia-blossom-end-rot", + "zinnia-herbicide-injury", + "chrysanthemum-blossom-end-rot", + "chrysanthemum-herbicide-injury", + "dahlia-blossom-end-rot", + "dahlia-herbicide-injury", + "calendula-blossom-end-rot", + "calendula-herbicide-injury", + "echinacea-blossom-end-rot", + "echinacea-herbicide-injury", + "yarrow-blossom-end-rot", + "yarrow-herbicide-injury", + "tarragon-blossom-end-rot", + "tarragon-herbicide-injury", + "stevia-blossom-end-rot", + "stevia-herbicide-injury", + "basil-blossom-end-rot", + "basil-herbicide-injury", + "mint-blossom-end-rot", + "mint-herbicide-injury", + "lavender-blossom-end-rot", + "lavender-herbicide-injury", + "rosemary-blossom-end-rot", + "rosemary-herbicide-injury", + "thyme-blossom-end-rot", + "thyme-herbicide-injury", + "oregano-blossom-end-rot", + "oregano-herbicide-injury", + "sage-blossom-end-rot", + "sage-herbicide-injury", + "lemon-balm-blossom-end-rot", + "lemon-balm-herbicide-injury", + "catnip-blossom-end-rot", + "catnip-herbicide-injury", + "coleus-blossom-end-rot", + "coleus-herbicide-injury", + "carrot-blossom-end-rot", + "carrot-herbicide-injury", + "celery-blossom-end-rot", + "celery-herbicide-injury", + "parsley-blossom-end-rot", + "parsley-herbicide-injury", + "cilantro-blossom-end-rot", + "cilantro-herbicide-injury", + "dill-blossom-end-rot", + "dill-herbicide-injury", + "fennel-blossom-end-rot", + "fennel-herbicide-injury", + "parsnip-blossom-end-rot", + "parsnip-herbicide-injury", + "cumin-blossom-end-rot", + "cumin-herbicide-injury", + "onion-blossom-end-rot", + "onion-herbicide-injury", + "garlic-blossom-end-rot", + "garlic-herbicide-injury", + "leek-blossom-end-rot", + "leek-herbicide-injury", + "shallot-anthracnose", + "shallot-bacterial-leaf-spot", + "shallot-blossom-end-rot", + "shallot-herbicide-injury", + "chive-powdery-mildew", + "chive-anthracnose", + "chive-bacterial-leaf-spot", + "chive-blossom-end-rot", + "chive-herbicide-injury", + "monstera-bacterial-leaf-spot-aroids", + "monstera-powdery-mildew", + "monstera-anthracnose", + "monstera-bacterial-leaf-spot", + "monstera-blossom-end-rot", + "monstera-herbicide-injury", + "pothos-blossom-end-rot", + "pothos-herbicide-injury", + "peace-lily-blossom-end-rot", + "peace-lily-herbicide-injury", + "philodendron-blossom-end-rot", + "philodendron-herbicide-injury", + "anthurium-blossom-end-rot", + "anthurium-herbicide-injury", + "alocasia-blossom-end-rot", + "alocasia-herbicide-injury", + "caladium-blossom-end-rot", + "caladium-herbicide-injury", + "aglaonema-blossom-end-rot", + "aglaonema-herbicide-injury", + "dieffenbachia-blossom-end-rot", + "dieffenbachia-herbicide-injury", + "spathiphyllum-blossom-end-rot", + "spathiphyllum-herbicide-injury", + "asparagus-blossom-end-rot", + "asparagus-herbicide-injury", + "snake-plant-blossom-end-rot", + "snake-plant-herbicide-injury", + "yucca-blossom-end-rot", + "yucca-herbicide-injury", + "dracaena-blossom-end-rot", + "dracaena-herbicide-injury", + "lily-of-the-valley-blossom-end-rot", + "lily-of-the-valley-herbicide-injury", + "hosta-blossom-end-rot", + "hosta-herbicide-injury", + "orchid-phalaenopsis-blossom-end-rot", + "orchid-phalaenopsis-herbicide-injury", + "orchid-cattleya-blossom-end-rot", + "orchid-cattleya-herbicide-injury", + "orchid-dendrobium-blossom-end-rot", + "orchid-dendrobium-herbicide-injury", + "orchid-oncidium-blossom-end-rot", + "orchid-oncidium-herbicide-injury", + "vanilla-blossom-end-rot", + "vanilla-herbicide-injury", + "prickly-pear-blossom-end-rot", + "prickly-pear-herbicide-injury", + "barrel-cactus-blossom-end-rot", + "barrel-cactus-herbicide-injury", + "christmas-cactus-blossom-end-rot", + "christmas-cactus-herbicide-injury", + "saguaro-blossom-end-rot", + "saguaro-herbicide-injury", + "aloe-vera-blossom-end-rot", + "aloe-vera-herbicide-injury", + "agave-blossom-end-rot", + "agave-herbicide-injury", + "echeveria-blossom-end-rot", + "echeveria-herbicide-injury", + "jade-plant-blossom-end-rot", + "jade-plant-herbicide-injury", + "sedum-blossom-end-rot", + "sedum-herbicide-injury", + "haworthia-blossom-end-rot", + "haworthia-herbicide-injury", + "poinsettia-blossom-end-rot", + "poinsettia-herbicide-injury", + "cassava-blossom-end-rot", + "cassava-herbicide-injury", + "castor-bean-blossom-end-rot", + "castor-bean-herbicide-injury", + "crown-of-thorns-blossom-end-rot", + "crown-of-thorns-herbicide-injury", + "orange-blossom-end-rot", + "orange-herbicide-injury", + "lemon-blossom-end-rot", + "lemon-herbicide-injury", + "lime-blossom-end-rot", + "lime-herbicide-injury", + "grapefruit-blossom-end-rot", + "grapefruit-herbicide-injury", + "mandarin-blossom-end-rot", + "mandarin-herbicide-injury", + "kumquat-blossom-end-rot", + "kumquat-herbicide-injury", + "grape-blossom-end-rot", + "grape-herbicide-injury", + "muscadine-blossom-end-rot", + "muscadine-herbicide-injury", + "banana-blossom-end-rot", + "banana-herbicide-injury", + "plantain-blossom-end-rot", + "plantain-herbicide-injury", + "bird-of-paradise-blossom-end-rot", + "bird-of-paradise-herbicide-injury", + "avocado-blossom-end-rot", + "avocado-herbicide-injury", + "cinnamon-blossom-end-rot", + "cinnamon-herbicide-injury", + "bay-laurel-blossom-end-rot", + "bay-laurel-herbicide-injury", + "cocoa-blossom-end-rot", + "cocoa-herbicide-injury", + "cotton-blossom-end-rot", + "cotton-herbicide-injury", + "okra-blossom-end-rot", + "okra-herbicide-injury", + "hibiscus-blossom-end-rot", + "hibiscus-herbicide-injury", + "hollyhock-bacterial-leaf-spot", + "hollyhock-blossom-end-rot", + "hollyhock-herbicide-injury", + "baobab-powdery-mildew", + "baobab-anthracnose", + "baobab-bacterial-leaf-spot", + "baobab-blossom-end-rot", + "baobab-herbicide-injury", + "durian-powdery-mildew", + "durian-anthracnose", + "durian-bacterial-leaf-spot", + "durian-blossom-end-rot", + "durian-herbicide-injury", + "coconut-blossom-end-rot", + "coconut-herbicide-injury", + "oil-palm-blossom-end-rot", + "oil-palm-herbicide-injury", + "date-palm-blossom-end-rot", + "date-palm-herbicide-injury", + "palm-areca-blossom-end-rot", + "palm-areca-herbicide-injury", + "palm-parlor-blossom-end-rot", + "palm-parlor-herbicide-injury", + "palm-kentia-blossom-end-rot", + "palm-kentia-herbicide-injury", + "mango-blossom-end-rot", + "mango-herbicide-injury", + "cashew-blossom-end-rot", + "cashew-herbicide-injury", + "pistachio-blossom-end-rot", + "pistachio-herbicide-injury", + "poison-ivy-blossom-end-rot", + "poison-ivy-herbicide-injury", + "coffee-blossom-end-rot", + "coffee-herbicide-injury", + "gardenia-blossom-end-rot", + "gardenia-herbicide-injury", + "tea-blossom-end-rot", + "tea-herbicide-injury", + "camellia-blossom-end-rot", + "camellia-herbicide-injury", + "pine-blossom-end-rot", + "pine-herbicide-injury", + "spruce-blossom-end-rot", + "spruce-herbicide-injury", + "fir-blossom-end-rot", + "fir-herbicide-injury", + "cedar-blossom-end-rot", + "cedar-herbicide-injury", + "juniper-blossom-end-rot", + "juniper-herbicide-injury", + "cypress-blossom-end-rot", + "cypress-herbicide-injury", + "arborvitae-blossom-end-rot", + "arborvitae-herbicide-injury", + "oak-blossom-end-rot", + "oak-herbicide-injury", + "beech-blossom-end-rot", + "beech-herbicide-injury", + "chestnut-blossom-end-rot", + "chestnut-herbicide-injury", + "fiddle-leaf-fig-blossom-end-rot", + "fiddle-leaf-fig-herbicide-injury", + "rubber-tree-blossom-end-rot", + "rubber-tree-herbicide-injury", + "weeping-fig-blossom-end-rot", + "weeping-fig-herbicide-injury", + "fig-blossom-end-rot", + "fig-herbicide-injury", + "mulberry-blossom-end-rot", + "mulberry-herbicide-injury", + "breadfruit-blossom-end-rot", + "breadfruit-herbicide-injury", + "eucalyptus-blossom-end-rot", + "eucalyptus-herbicide-injury", + "guava-blossom-end-rot", + "guava-herbicide-injury", + "clove-blossom-end-rot", + "clove-herbicide-injury", + "pineapple-blossom-end-rot", + "pineapple-herbicide-injury", + "bromeliad-blossom-end-rot", + "bromeliad-herbicide-injury", + "spanish-moss-blossom-end-rot", + "spanish-moss-herbicide-injury", + "sweet-potato-blossom-end-rot", + "sweet-potato-herbicide-injury", + "morning-glory-blossom-end-rot", + "morning-glory-herbicide-injury", + "spinach-blossom-end-rot", + "spinach-herbicide-injury", + "swiss-chard-blossom-end-rot", + "swiss-chard-herbicide-injury", + "beet-blossom-end-rot", + "beet-herbicide-injury", + "quinoa-blossom-end-rot", + "quinoa-herbicide-injury", + "amaranth-blossom-end-rot", + "amaranth-herbicide-injury", + "rhubarb-blossom-end-rot", + "rhubarb-herbicide-injury", + "buckwheat-blossom-end-rot", + "buckwheat-herbicide-injury", + "papaya-blossom-end-rot", + "papaya-herbicide-injury", + "olive-blossom-end-rot", + "olive-herbicide-injury", + "jasmine-blossom-end-rot", + "jasmine-herbicide-injury", + "lilac-blossom-end-rot", + "lilac-herbicide-injury", + "ash-blossom-end-rot", + "ash-herbicide-injury", + "hops-blossom-end-rot", + "hops-herbicide-injury", + "hemp-rust", + "hemp-bacterial-leaf-spot", + "hemp-blossom-end-rot", + "hemp-herbicide-injury", + "fern-boston-powdery-mildew", + "fern-boston-anthracnose", + "fern-boston-rust", + "fern-boston-bacterial-leaf-spot", + "fern-boston-blossom-end-rot", + "fern-boston-herbicide-injury", + "fern-maidenhair-powdery-mildew", + "fern-maidenhair-anthracnose", + "fern-maidenhair-rust", + "fern-maidenhair-bacterial-leaf-spot", + "fern-maidenhair-blossom-end-rot", + "fern-maidenhair-herbicide-injury", + "spider-plant-powdery-mildew", + "spider-plant-anthracnose", + "spider-plant-rust", + "spider-plant-bacterial-leaf-spot", + "spider-plant-blossom-end-rot", + "spider-plant-herbicide-injury", + "zz-plant-bacterial-leaf-spot-aroids", + "zz-plant-powdery-mildew", + "zz-plant-anthracnose", + "zz-plant-rust", + "zz-plant-bacterial-leaf-spot", + "zz-plant-blossom-end-rot", + "zz-plant-herbicide-injury", + "prayer-plant-powdery-mildew", + "prayer-plant-anthracnose", + "prayer-plant-rust", + "prayer-plant-bacterial-leaf-spot", + "prayer-plant-blossom-end-rot", + "prayer-plant-herbicide-injury", + "calathea-powdery-mildew", + "calathea-anthracnose", + "calathea-rust", + "calathea-bacterial-leaf-spot", + "calathea-blossom-end-rot", + "calathea-herbicide-injury", + "pilea-powdery-mildew", + "pilea-anthracnose", + "pilea-rust", + "pilea-bacterial-leaf-spot", + "pilea-blossom-end-rot", + "pilea-herbicide-injury", + "tradescantia-powdery-mildew", + "tradescantia-anthracnose", + "tradescantia-rust", + "tradescantia-bacterial-leaf-spot", + "tradescantia-blossom-end-rot", + "tradescantia-herbicide-injury", + "succulent-echeveria-powdery-mildew", + "succulent-echeveria-anthracnose", + "succulent-echeveria-rust", + "succulent-echeveria-bacterial-leaf-spot", + "succulent-echeveria-blossom-end-rot", + "succulent-echeveria-herbicide-injury", + "money-tree-powdery-mildew", + "money-tree-anthracnose", + "money-tree-rust", + "money-tree-bacterial-leaf-spot", + "money-tree-blossom-end-rot", + "money-tree-herbicide-injury", + "palm-cat-powdery-mildew", + "palm-cat-anthracnose", + "palm-cat-rust", + "palm-cat-bacterial-leaf-spot", + "palm-cat-blossom-end-rot", + "palm-cat-herbicide-injury", + "ficus-altissima-powdery-mildew", + "ficus-altissima-anthracnose", + "ficus-altissima-rust", + "ficus-altissima-bacterial-leaf-spot", + "ficus-altissima-blossom-end-rot", + "ficus-altissima-herbicide-injury", + "string-of-pearls-aster-yellows", + "string-of-pearls-powdery-mildew", + "string-of-pearls-anthracnose", + "string-of-pearls-rust", + "string-of-pearls-bacterial-leaf-spot", + "string-of-pearls-blossom-end-rot", + "string-of-pearls-herbicide-injury", + "burros-tail-powdery-mildew", + "burros-tail-anthracnose", + "burros-tail-rust", + "burros-tail-bacterial-leaf-spot", + "burros-tail-blossom-end-rot", + "burros-tail-herbicide-injury", + "snake-plant-masoniana-powdery-mildew", + "snake-plant-masoniana-anthracnose", + "snake-plant-masoniana-rust", + "snake-plant-masoniana-bacterial-leaf-spot", + "snake-plant-masoniana-blossom-end-rot", + "snake-plant-masoniana-herbicide-injury", + "passion-fruit-powdery-mildew", + "passion-fruit-anthracnose", + "passion-fruit-rust", + "passion-fruit-bacterial-leaf-spot", + "passion-fruit-blossom-end-rot", + "passion-fruit-herbicide-injury", + "kiwi-powdery-mildew", + "kiwi-anthracnose", + "kiwi-rust", + "kiwi-bacterial-leaf-spot", + "kiwi-blossom-end-rot", + "kiwi-herbicide-injury", + "lychee-powdery-mildew", + "lychee-anthracnose", + "lychee-rust", + "lychee-bacterial-leaf-spot", + "lychee-blossom-end-rot", + "lychee-herbicide-injury", + "rambutan-powdery-mildew", + "rambutan-anthracnose", + "rambutan-rust", + "rambutan-bacterial-leaf-spot", + "rambutan-blossom-end-rot", + "rambutan-herbicide-injury", + "jackfruit-powdery-mildew", + "jackfruit-anthracnose", + "jackfruit-rust", + "jackfruit-bacterial-leaf-spot", + "jackfruit-blossom-end-rot", + "jackfruit-herbicide-injury", + "dragon-fruit-powdery-mildew", + "dragon-fruit-anthracnose", + "dragon-fruit-rust", + "dragon-fruit-bacterial-leaf-spot", + "dragon-fruit-blossom-end-rot", + "dragon-fruit-herbicide-injury", + "pomegranate-powdery-mildew", + "pomegranate-anthracnose", + "pomegranate-rust", + "pomegranate-bacterial-leaf-spot", + "pomegranate-blossom-end-rot", + "pomegranate-herbicide-injury", + "persimmon-powdery-mildew", + "persimmon-anthracnose", + "persimmon-rust", + "persimmon-bacterial-leaf-spot", + "persimmon-blossom-end-rot", + "persimmon-herbicide-injury", + "tulip-powdery-mildew", + "tulip-anthracnose", + "tulip-rust", + "tulip-bacterial-leaf-spot", + "tulip-blossom-end-rot", + "tulip-herbicide-injury", + "daffodil-powdery-mildew", + "daffodil-anthracnose", + "daffodil-rust", + "daffodil-bacterial-leaf-spot", + "daffodil-blossom-end-rot", + "daffodil-herbicide-injury", + "iris-powdery-mildew", + "iris-anthracnose", + "iris-rust", + "iris-bacterial-leaf-spot", + "iris-blossom-end-rot", + "iris-herbicide-injury", + "lily-powdery-mildew", + "lily-anthracnose", + "lily-rust", + "lily-bacterial-leaf-spot", + "lily-blossom-end-rot", + "lily-herbicide-injury", + "peony-powdery-mildew", + "peony-anthracnose", + "peony-rust", + "peony-bacterial-leaf-spot", + "peony-blossom-end-rot", + "peony-herbicide-injury", + "hydrangea-powdery-mildew", + "hydrangea-anthracnose", + "hydrangea-rust", + "hydrangea-bacterial-leaf-spot", + "hydrangea-blossom-end-rot", + "hydrangea-herbicide-injury", + "rhododendron-mummy-berry-blueberry", + "rhododendron-powdery-mildew", + "rhododendron-anthracnose", + "rhododendron-rust", + "rhododendron-bacterial-leaf-spot", + "rhododendron-blossom-end-rot", + "rhododendron-herbicide-injury", + "azalea-mummy-berry-blueberry", + "azalea-powdery-mildew", + "azalea-anthracnose", + "azalea-rust", + "azalea-bacterial-leaf-spot", + "azalea-blossom-end-rot", + "azalea-herbicide-injury", + "magnolia-powdery-mildew", + "magnolia-anthracnose", + "magnolia-rust", + "magnolia-bacterial-leaf-spot", + "magnolia-blossom-end-rot", + "magnolia-herbicide-injury", + "dogwood-powdery-mildew", + "dogwood-anthracnose", + "dogwood-rust", + "dogwood-bacterial-leaf-spot", + "dogwood-blossom-end-rot", + "dogwood-herbicide-injury", + "maple-powdery-mildew", + "maple-anthracnose", + "maple-rust", + "maple-bacterial-leaf-spot", + "maple-blossom-end-rot", + "maple-herbicide-injury", + "birch-powdery-mildew", + "birch-anthracnose", + "birch-rust", + "birch-bacterial-leaf-spot", + "birch-blossom-end-rot", + "birch-herbicide-injury", + "elm-powdery-mildew", + "elm-anthracnose", + "elm-rust", + "elm-bacterial-leaf-spot", + "elm-blossom-end-rot", + "elm-herbicide-injury", + "willow-powdery-mildew", + "willow-anthracnose", + "willow-rust", + "willow-bacterial-leaf-spot", + "willow-blossom-end-rot", + "willow-herbicide-injury", + "poplar-powdery-mildew", + "poplar-anthracnose", + "poplar-rust", + "poplar-bacterial-leaf-spot", + "poplar-blossom-end-rot", + "poplar-herbicide-injury", + "sycamore-powdery-mildew", + "sycamore-anthracnose", + "sycamore-rust", + "sycamore-bacterial-leaf-spot", + "sycamore-blossom-end-rot", + "sycamore-herbicide-injury", + "hickory-powdery-mildew", + "hickory-anthracnose", + "hickory-rust", + "hickory-bacterial-leaf-spot", + "hickory-blossom-end-rot", + "hickory-herbicide-injury", + "pecan-powdery-mildew", + "pecan-anthracnose", + "pecan-rust", + "pecan-bacterial-leaf-spot", + "pecan-blossom-end-rot", + "pecan-herbicide-injury", + "walnut-powdery-mildew", + "walnut-anthracnose", + "walnut-rust", + "walnut-bacterial-leaf-spot", + "walnut-blossom-end-rot", + "walnut-herbicide-injury", + "tomato-lesion-nematode", + "bell-pepper-lesion-nematode", + "chili-pepper-lesion-nematode", + "eggplant-lesion-nematode", + "tobacco-lesion-nematode", + "tomatillo-lesion-nematode", + "petunia-lesion-nematode", + "gooseberry-lesion-nematode", + "cucumber-lesion-nematode", + "zucchini-lesion-nematode", + "summer-squash-lesion-nematode", + "winter-squash-lesion-nematode", + "pumpkin-lesion-nematode", + "watermelon-lesion-nematode", + "cantaloupe-lesion-nematode", + "honeydew-lesion-nematode", + "bitter-melon-lesion-nematode", + "chayote-lesion-nematode", + "acorn-squash-lesion-nematode", + "butternut-squash-lesion-nematode", + "calabash-lesion-nematode", + "luffa-lesion-nematode", + "pear-lesion-nematode", + "peach-lesion-nematode", + "cherry-lesion-nematode", + "apricot-lesion-nematode", + "plum-lesion-nematode", + "almond-lesion-nematode", + "strawberry-lesion-nematode", + "raspberry-lesion-nematode", + "blackberry-lesion-nematode", + "blueberry-lesion-nematode", + "cranberry-lesion-nematode", + "rose-lesion-nematode", + "hawthorn-lesion-nematode", + "quince-lesion-nematode", + "cabbage-lesion-nematode", + "broccoli-lesion-nematode", + "cauliflower-lesion-nematode", + "brussels-sprouts-lesion-nematode", + "kale-lesion-nematode", + "bok-choy-lesion-nematode", + "radish-lesion-nematode", + "turnip-lesion-nematode", + "arugula-lesion-nematode", + "collard-greens-lesion-nematode", + "mustard-greens-lesion-nematode", + "horseradish-lesion-nematode", + "wasabi-lesion-nematode", + "green-bean-lesion-nematode", + "peanut-lesion-nematode", + "chickpea-lesion-nematode", + "lentil-lesion-nematode", + "faba-bean-lesion-nematode", + "cowpea-lesion-nematode", + "pigeon-pea-lesion-nematode", + "clover-lesion-nematode", + "peas-lesion-nematode", + "lupine-lesion-nematode", + "wisteria-lesion-nematode", + "robinia-lesion-nematode", + "corn-lesion-nematode", + "wheat-lesion-nematode", + "rice-lesion-nematode", + "barley-lesion-nematode", + "oats-lesion-nematode", + "sorghum-lesion-nematode", + "sugarcane-lesion-nematode", + "bamboo-lesion-nematode", + "turfgrass-lesion-nematode", + "millet-lesion-nematode", + "rye-lesion-nematode", + "sunflower-lesion-nematode", + "lettuce-lesion-nematode", + "artichoke-lesion-nematode", + "chicory-lesion-nematode", + "endive-lesion-nematode", + "daisy-lesion-nematode", + "marigold-lesion-nematode", + "zinnia-lesion-nematode", + "chrysanthemum-lesion-nematode", + "dahlia-lesion-nematode", + "calendula-lesion-nematode", + "echinacea-lesion-nematode", + "yarrow-lesion-nematode", + "tarragon-lesion-nematode", + "stevia-lesion-nematode", + "basil-lesion-nematode", + "mint-lesion-nematode", + "lavender-lesion-nematode", + "rosemary-lesion-nematode", + "thyme-lesion-nematode", + "oregano-lesion-nematode", + "sage-lesion-nematode", + "lemon-balm-lesion-nematode", + "catnip-lesion-nematode", + "coleus-lesion-nematode", + "celery-lesion-nematode", + "parsley-lesion-nematode", + "cilantro-lesion-nematode", + "dill-lesion-nematode", + "fennel-lesion-nematode", + "parsnip-lesion-nematode", + "cumin-lesion-nematode", + "onion-lesion-nematode", + "garlic-lesion-nematode", + "leek-lesion-nematode", + "shallot-lesion-nematode", + "chive-lesion-nematode", + "monstera-lesion-nematode", + "pothos-lesion-nematode", + "peace-lily-lesion-nematode", + "philodendron-lesion-nematode", + "anthurium-lesion-nematode", + "alocasia-lesion-nematode", + "caladium-lesion-nematode", + "aglaonema-lesion-nematode", + "dieffenbachia-lesion-nematode", + "spathiphyllum-lesion-nematode", + "asparagus-lesion-nematode", + "snake-plant-lesion-nematode", + "yucca-lesion-nematode", + "dracaena-lesion-nematode", + "lily-of-the-valley-lesion-nematode", + "hosta-lesion-nematode", + "orchid-phalaenopsis-lesion-nematode", + "orchid-cattleya-lesion-nematode", + "orchid-dendrobium-lesion-nematode", + "orchid-oncidium-lesion-nematode", + "vanilla-lesion-nematode", + "prickly-pear-lesion-nematode", + "barrel-cactus-lesion-nematode", + "christmas-cactus-lesion-nematode", + "saguaro-lesion-nematode", + "aloe-vera-lesion-nematode", + "agave-lesion-nematode", + "echeveria-lesion-nematode", + "jade-plant-lesion-nematode", + "sedum-lesion-nematode", + "haworthia-lesion-nematode", + "poinsettia-lesion-nematode", + "cassava-lesion-nematode", + "castor-bean-lesion-nematode", + "crown-of-thorns-lesion-nematode", + "orange-lesion-nematode", + "lemon-lesion-nematode", + "lime-lesion-nematode", + "grapefruit-lesion-nematode", + "mandarin-lesion-nematode", + "kumquat-lesion-nematode", + "grape-lesion-nematode", + "muscadine-lesion-nematode", + "banana-lesion-nematode", + "plantain-lesion-nematode", + "bird-of-paradise-lesion-nematode", + "avocado-lesion-nematode", + "cinnamon-lesion-nematode", + "bay-laurel-lesion-nematode", + "cocoa-lesion-nematode", + "cotton-lesion-nematode", + "okra-lesion-nematode", + "hibiscus-lesion-nematode", + "hollyhock-lesion-nematode", + "baobab-lesion-nematode", + "durian-lesion-nematode", + "coconut-lesion-nematode", + "oil-palm-lesion-nematode", + "date-palm-lesion-nematode", + "palm-areca-lesion-nematode", + "palm-parlor-lesion-nematode", + "palm-kentia-lesion-nematode", + "mango-lesion-nematode", + "cashew-lesion-nematode", + "pistachio-lesion-nematode", + "poison-ivy-lesion-nematode", + "coffee-lesion-nematode", + "gardenia-lesion-nematode", + "tea-lesion-nematode", + "camellia-lesion-nematode", + "pine-lesion-nematode", + "spruce-lesion-nematode", + "fir-lesion-nematode", + "cedar-lesion-nematode", + "juniper-lesion-nematode", + "cypress-lesion-nematode", + "arborvitae-lesion-nematode", + "oak-lesion-nematode", + "beech-lesion-nematode", + "chestnut-lesion-nematode", + "fiddle-leaf-fig-lesion-nematode", + "rubber-tree-lesion-nematode", + "weeping-fig-lesion-nematode", + "fig-lesion-nematode", + "mulberry-lesion-nematode", + "breadfruit-lesion-nematode", + "eucalyptus-lesion-nematode", + "guava-lesion-nematode", + "clove-lesion-nematode", + "pineapple-lesion-nematode", + "bromeliad-lesion-nematode", + "spanish-moss-lesion-nematode", + "sweet-potato-lesion-nematode", + "morning-glory-lesion-nematode", + "spinach-lesion-nematode", + "swiss-chard-lesion-nematode", + "beet-lesion-nematode", + "quinoa-lesion-nematode", + "amaranth-lesion-nematode", + "rhubarb-lesion-nematode", + "buckwheat-lesion-nematode", + "papaya-lesion-nematode", + "olive-lesion-nematode", + "jasmine-lesion-nematode", + "lilac-lesion-nematode", + "ash-lesion-nematode", + "hops-lesion-nematode", + "hemp-lesion-nematode", + "fern-boston-lesion-nematode", + "fern-maidenhair-lesion-nematode", + "spider-plant-lesion-nematode", + "zz-plant-lesion-nematode", + "prayer-plant-lesion-nematode", + "calathea-lesion-nematode", + "pilea-lesion-nematode", + "tradescantia-lesion-nematode", + "succulent-echeveria-lesion-nematode", + "money-tree-lesion-nematode", + "palm-cat-lesion-nematode", + "ficus-altissima-lesion-nematode", + "string-of-pearls-lesion-nematode", + "burros-tail-lesion-nematode", + "snake-plant-masoniana-lesion-nematode", + "passion-fruit-lesion-nematode", + "kiwi-lesion-nematode", + "lychee-lesion-nematode", + "rambutan-lesion-nematode", + "jackfruit-lesion-nematode", + "dragon-fruit-lesion-nematode", + "pomegranate-lesion-nematode", + "persimmon-lesion-nematode", + "tulip-lesion-nematode", + "daffodil-lesion-nematode", + "iris-lesion-nematode", + "lily-lesion-nematode", + "peony-lesion-nematode", + "hydrangea-lesion-nematode", + "rhododendron-lesion-nematode", + "azalea-lesion-nematode", + "magnolia-lesion-nematode", + "dogwood-lesion-nematode", + "maple-lesion-nematode", + "birch-lesion-nematode", + "elm-lesion-nematode", + "willow-lesion-nematode", + "poplar-lesion-nematode", + "sycamore-lesion-nematode", + "hickory-lesion-nematode", + "pecan-lesion-nematode", + "walnut-lesion-nematode", + "fern-staghorn-powdery-mildew", + "fern-staghorn-anthracnose", + "fern-staghorn-rust", + "fern-staghorn-bacterial-leaf-spot", + "fern-staghorn-blossom-end-rot", + "fern-staghorn-herbicide-injury", + "fern-staghorn-lesion-nematode", + "fern-birds-nest-powdery-mildew", + "fern-birds-nest-anthracnose", + "fern-birds-nest-rust", + "fern-birds-nest-bacterial-leaf-spot", + "fern-birds-nest-blossom-end-rot", + "fern-birds-nest-herbicide-injury", + "fern-birds-nest-lesion-nematode", + "philodendron-brasil-bacterial-leaf-spot-aroids", + "philodendron-brasil-powdery-mildew", + "philodendron-brasil-anthracnose", + "philodendron-brasil-rust", + "philodendron-brasil-bacterial-leaf-spot", + "philodendron-brasil-blossom-end-rot", + "philodendron-brasil-herbicide-injury", + "philodendron-brasil-lesion-nematode", + "philodendron-monstera-bacterial-leaf-spot-aroids", + "philodendron-monstera-powdery-mildew", + "philodendron-monstera-anthracnose", + "philodendron-monstera-rust", + "philodendron-monstera-bacterial-leaf-spot", + "philodendron-monstera-blossom-end-rot", + "philodendron-monstera-herbicide-injury", + "philodendron-monstera-lesion-nematode", + "pothos-marble-queen-bacterial-leaf-spot-aroids", + "pothos-marble-queen-powdery-mildew", + "pothos-marble-queen-anthracnose", + "pothos-marble-queen-rust", + "pothos-marble-queen-bacterial-leaf-spot", + "pothos-marble-queen-blossom-end-rot", + "pothos-marble-queen-herbicide-injury", + "pothos-marble-queen-lesion-nematode", + "peace-lily-sensation-bacterial-leaf-spot-aroids", + "peace-lily-sensation-powdery-mildew", + "peace-lily-sensation-anthracnose", + "peace-lily-sensation-rust", + "peace-lily-sensation-bacterial-leaf-spot", + "peace-lily-sensation-blossom-end-rot", + "peace-lily-sensation-herbicide-injury", + "peace-lily-sensation-lesion-nematode", + "phalaenopsis-orchid-powdery-mildew", + "phalaenopsis-orchid-anthracnose", + "phalaenopsis-orchid-rust", + "phalaenopsis-orchid-bacterial-leaf-spot", + "phalaenopsis-orchid-blossom-end-rot", + "phalaenopsis-orchid-herbicide-injury", + "phalaenopsis-orchid-lesion-nematode", + "cattleya-orchid-powdery-mildew", + "cattleya-orchid-anthracnose", + "cattleya-orchid-rust", + "cattleya-orchid-bacterial-leaf-spot", + "cattleya-orchid-blossom-end-rot", + "cattleya-orchid-herbicide-injury", + "cattleya-orchid-lesion-nematode", + "dendrobium-orchid-powdery-mildew", + "dendrobium-orchid-anthracnose", + "dendrobium-orchid-rust", + "dendrobium-orchid-bacterial-leaf-spot", + "dendrobium-orchid-blossom-end-rot", + "dendrobium-orchid-herbicide-injury", + "dendrobium-orchid-lesion-nematode", + "oncidium-orchid-powdery-mildew", + "oncidium-orchid-anthracnose", + "oncidium-orchid-rust", + "oncidium-orchid-bacterial-leaf-spot", + "oncidium-orchid-blossom-end-rot", + "oncidium-orchid-herbicide-injury", + "oncidium-orchid-lesion-nematode", + "begonia-powdery-mildew", + "begonia-anthracnose", + "begonia-rust", + "begonia-bacterial-leaf-spot", + "begonia-blossom-end-rot", + "begonia-herbicide-injury", + "begonia-lesion-nematode", + "impatiens-powdery-mildew", + "impatiens-anthracnose", + "impatiens-rust", + "impatiens-bacterial-leaf-spot", + "impatiens-blossom-end-rot", + "impatiens-herbicide-injury", + "impatiens-lesion-nematode", + "geranium-powdery-mildew", + "geranium-anthracnose", + "geranium-rust", + "geranium-bacterial-leaf-spot", + "geranium-blossom-end-rot", + "geranium-herbicide-injury", + "geranium-lesion-nematode", + "cyclamen-powdery-mildew", + "cyclamen-anthracnose", + "cyclamen-rust", + "cyclamen-bacterial-leaf-spot", + "cyclamen-blossom-end-rot", + "cyclamen-herbicide-injury", + "cyclamen-lesion-nematode", + "african-violet-powdery-mildew", + "african-violet-anthracnose", + "african-violet-rust", + "african-violet-bacterial-leaf-spot", + "african-violet-blossom-end-rot", + "african-violet-herbicide-injury", + "african-violet-lesion-nematode", + "gloxinia-powdery-mildew", + "gloxinia-anthracnose", + "gloxinia-rust", + "gloxinia-bacterial-leaf-spot", + "gloxinia-blossom-end-rot", + "gloxinia-herbicide-injury", + "gloxinia-lesion-nematode", + "cucumber-horned-powdery-mildew-cucurbits", + "cucumber-horned-angular-leaf-spot-cucurbits", + "cucumber-horned-powdery-mildew", + "cucumber-horned-anthracnose", + "cucumber-horned-rust", + "cucumber-horned-bacterial-leaf-spot", + "cucumber-horned-blossom-end-rot", + "cucumber-horned-herbicide-injury", + "cucumber-horned-lesion-nematode", + "sweet-potato-leaf-powdery-mildew", + "sweet-potato-leaf-anthracnose", + "sweet-potato-leaf-rust", + "sweet-potato-leaf-bacterial-leaf-spot", + "sweet-potato-leaf-blossom-end-rot", + "sweet-potato-leaf-herbicide-injury", + "sweet-potato-leaf-lesion-nematode", + "ivy-english-powdery-mildew", + "ivy-english-anthracnose", + "ivy-english-rust", + "ivy-english-bacterial-leaf-spot", + "ivy-english-blossom-end-rot", + "ivy-english-herbicide-injury", + "ivy-english-lesion-nematode", + "ivy-swedish-powdery-mildew", + "ivy-swedish-anthracnose", + "ivy-swedish-rust", + "ivy-swedish-bacterial-leaf-spot", + "ivy-swedish-blossom-end-rot", + "ivy-swedish-herbicide-injury", + "ivy-swedish-lesion-nematode", + "banana-dwarf-powdery-mildew", + "banana-dwarf-anthracnose", + "banana-dwarf-rust", + "banana-dwarf-bacterial-leaf-spot", + "banana-dwarf-blossom-end-rot", + "banana-dwarf-herbicide-injury", + "banana-dwarf-lesion-nematode", + "mimosa-bacterial-blight-common-halo", + "mimosa-bean-rust", + "mimosa-powdery-mildew", + "mimosa-anthracnose", + "mimosa-rust", + "mimosa-bacterial-leaf-spot", + "mimosa-blossom-end-rot", + "mimosa-herbicide-injury", + "mimosa-lesion-nematode", + "kentucky-coffee-bacterial-blight-common-halo", + "kentucky-coffee-bean-rust", + "kentucky-coffee-powdery-mildew", + "kentucky-coffee-anthracnose", + "kentucky-coffee-rust", + "kentucky-coffee-bacterial-leaf-spot", + "kentucky-coffee-blossom-end-rot", + "kentucky-coffee-herbicide-injury", + "kentucky-coffee-lesion-nematode", + "redbud-bacterial-blight-common-halo", + "redbud-bean-rust", + "redbud-powdery-mildew", + "redbud-anthracnose", + "redbud-rust", + "redbud-bacterial-leaf-spot", + "redbud-blossom-end-rot", + "redbud-herbicide-injury", + "redbud-lesion-nematode", + "tulip-tree-powdery-mildew", + "tulip-tree-anthracnose", + "tulip-tree-rust", + "tulip-tree-bacterial-leaf-spot", + "tulip-tree-blossom-end-rot", + "tulip-tree-herbicide-injury", + "tulip-tree-lesion-nematode", + "sweetgum-powdery-mildew", + "sweetgum-anthracnose", + "sweetgum-rust", + "sweetgum-bacterial-leaf-spot", + "sweetgum-blossom-end-rot", + "sweetgum-herbicide-injury", + "sweetgum-lesion-nematode", + "crabapple-apple-scab", + "crabapple-cedar-apple-rust", + "crabapple-black-spot-rose", + "crabapple-powdery-mildew", + "crabapple-anthracnose", + "crabapple-rust", + "crabapple-bacterial-leaf-spot", + "crabapple-blossom-end-rot", + "crabapple-herbicide-injury", + "crabapple-lesion-nematode", + "serviceberry-apple-scab", + "serviceberry-cedar-apple-rust", + "serviceberry-black-spot-rose", + "serviceberry-powdery-mildew", + "serviceberry-anthracnose", + "serviceberry-rust", + "serviceberry-bacterial-leaf-spot", + "serviceberry-blossom-end-rot", + "serviceberry-herbicide-injury", + "serviceberry-lesion-nematode", + "chokecherry-apple-scab", + "chokecherry-cedar-apple-rust", + "chokecherry-black-spot-rose", + "chokecherry-powdery-mildew", + "chokecherry-anthracnose", + "chokecherry-rust", + "chokecherry-bacterial-leaf-spot", + "chokecherry-blossom-end-rot", + "chokecherry-herbicide-injury", + "chokecherry-lesion-nematode", + "buckeye-powdery-mildew", + "buckeye-anthracnose", + "buckeye-rust", + "buckeye-bacterial-leaf-spot", + "buckeye-blossom-end-rot", + "buckeye-herbicide-injury", + "buckeye-lesion-nematode", + "linden-powdery-mildew", + "linden-anthracnose", + "linden-rust", + "linden-bacterial-leaf-spot", + "linden-blossom-end-rot", + "linden-herbicide-injury", + "linden-lesion-nematode", + "ginkgo-powdery-mildew", + "ginkgo-anthracnose", + "ginkgo-rust", + "ginkgo-bacterial-leaf-spot", + "ginkgo-blossom-end-rot", + "ginkgo-herbicide-injury", + "ginkgo-lesion-nematode", + "ficus-microcarpa-powdery-mildew", + "ficus-microcarpa-anthracnose", + "ficus-microcarpa-rust", + "ficus-microcarpa-bacterial-leaf-spot", + "ficus-microcarpa-blossom-end-rot", + "ficus-microcarpa-herbicide-injury", + "ficus-microcarpa-lesion-nematode", + "schefflera-powdery-mildew", + "schefflera-anthracnose", + "schefflera-rust", + "schefflera-bacterial-leaf-spot", + "schefflera-blossom-end-rot", + "schefflera-herbicide-injury", + "schefflera-lesion-nematode", + "maranta-powdery-mildew", + "maranta-anthracnose", + "maranta-rust", + "maranta-bacterial-leaf-spot", + "maranta-blossom-end-rot", + "maranta-herbicide-injury", + "maranta-lesion-nematode", + "stromanthe-powdery-mildew", + "stromanthe-anthracnose", + "stromanthe-rust", + "stromanthe-bacterial-leaf-spot", + "stromanthe-blossom-end-rot", + "stromanthe-herbicide-injury", + "stromanthe-lesion-nematode", + "bok-choy-shanghai-downy-mildew-brassicas", + "bok-choy-shanghai-alternaria-leaf-spot-brassicas", + "bok-choy-shanghai-powdery-mildew", + "bok-choy-shanghai-anthracnose", + "bok-choy-shanghai-rust", + "bok-choy-shanghai-bacterial-leaf-spot", + "bok-choy-shanghai-blossom-end-rot", + "bok-choy-shanghai-herbicide-injury", + "bok-choy-shanghai-lesion-nematode", + "tatsoi-downy-mildew-brassicas", + "tatsoi-alternaria-leaf-spot-brassicas", + "tatsoi-powdery-mildew", + "tatsoi-anthracnose", + "tatsoi-rust", + "tatsoi-bacterial-leaf-spot", + "tatsoi-blossom-end-rot", + "tatsoi-herbicide-injury", + "tatsoi-lesion-nematode", + "mizuna-downy-mildew-brassicas", + "mizuna-alternaria-leaf-spot-brassicas", + "mizuna-powdery-mildew", + "mizuna-anthracnose", + "mizuna-rust", + "mizuna-bacterial-leaf-spot", + "mizuna-blossom-end-rot", + "mizuna-herbicide-injury", + "mizuna-lesion-nematode", + "kohlrabi-downy-mildew-brassicas", + "kohlrabi-alternaria-leaf-spot-brassicas", + "kohlrabi-powdery-mildew", + "kohlrabi-anthracnose", + "kohlrabi-rust", + "kohlrabi-bacterial-leaf-spot", + "kohlrabi-blossom-end-rot", + "kohlrabi-herbicide-injury", + "kohlrabi-lesion-nematode", + "rapini-downy-mildew-brassicas", + "rapini-alternaria-leaf-spot-brassicas", + "rapini-powdery-mildew", + "rapini-anthracnose", + "rapini-rust", + "rapini-bacterial-leaf-spot", + "rapini-blossom-end-rot", + "rapini-herbicide-injury", + "rapini-lesion-nematode", + "jicama-bacterial-blight-common-halo", + "jicama-bean-rust", + "jicama-powdery-mildew", + "jicama-anthracnose", + "jicama-rust", + "jicama-bacterial-leaf-spot", + "jicama-blossom-end-rot", + "jicama-herbicide-injury", + "jicama-lesion-nematode", + "adzuki-bean-bacterial-blight-common-halo", + "adzuki-bean-bean-rust", + "adzuki-bean-powdery-mildew", + "adzuki-bean-anthracnose", + "adzuki-bean-rust", + "adzuki-bean-bacterial-leaf-spot", + "adzuki-bean-blossom-end-rot", + "adzuki-bean-herbicide-injury", + "adzuki-bean-lesion-nematode", + "mung-bean-bacterial-blight-common-halo", + "mung-bean-bean-rust", + "mung-bean-powdery-mildew", + "mung-bean-anthracnose", + "mung-bean-rust", + "mung-bean-bacterial-leaf-spot", + "mung-bean-blossom-end-rot", + "mung-bean-herbicide-injury", + "mung-bean-lesion-nematode", + "garbanzo-bacterial-blight-common-halo", + "garbanzo-bean-rust", + "garbanzo-powdery-mildew", + "garbanzo-anthracnose", + "garbanzo-rust", + "garbanzo-bacterial-leaf-spot", + "garbanzo-blossom-end-rot", + "garbanzo-herbicide-injury", + "garbanzo-lesion-nematode", + "wiki-actinomycosis", + "wiki-african-cassava-mosaic", + "wiki-aggregate-sheath-spot", + "wiki-algal-disease", + "wiki-alligator-skin", + "wiki-almond-leaf-scorch", + "wiki-alternaria-black-spot", + "wiki-alternaria-cone-disorder", + "wiki-alternaria-diseases", + "wiki-alternaria-spot", + "wiki-american-hawthorn-rust", + "wiki-american-hop-latent", + "wiki-american-leaf-spot", + "wiki-anther-mold", + "wiki-anther-smut", + "wiki-antholysis", + "wiki-aphelenchoides", + "wiki-apple-chlorotic-leaf-spot", + "wiki-apple-flat-apple-disease", + "wiki-apple-flyspeck", + "wiki-apple-fruit-blotch", + "wiki-apple-green-crinkle", + "wiki-apple-joint-infection", + "wiki-apple-leaf-pucker", + "wiki-apple-necrotic-leaf-blotch", + "wiki-apple-rosette", + "wiki-apple-rough-skin", + "wiki-apple-rubbery-wood", + "wiki-apple-rust-mite", + "wiki-apple-scald", + "wiki-apple-silver-leaf", + "wiki-apple-sooty-blotch", + "wiki-apple-star-cracking", + "wiki-apple-stem-pitting", + "wiki-apple-storage-scald", + "wiki-apple-witches-broom", + "wiki-apricot-bare-twig", + "wiki-apricot-chlorotic-leaf-roll", + "wiki-apricot-deformation-mosaic", + "wiki-apricot-line-pattern", + "wiki-apricot-pucker-leaf", + "wiki-apricot-ring-pox", + "wiki-apricot-stone-pitting", + "wiki-arhar-mosaic", + "wiki-armillaria-root-disease", + "wiki-artichoke-curly-dwarf", + "wiki-artichoke-latent-virus", + "wiki-asparagus-1-virus", + "wiki-asparagus-2-virus", + "wiki-aster-yellows-of-carrot", + "wiki-asteroid-spot", + "wiki-avocado-black-streak", + "wiki-avocado-sunblotch", + "wiki-avocado-trunk-pitting", + "wiki-awka-disease", + "wiki-awl-nematode", + "wiki-bacterial-angular-leaf-spot", + "wiki-bacterial-black-spot", + "wiki-bacterial-blast", + "wiki-bacterial-brown-spot", + "wiki-bacterial-fasciation", + "wiki-bacterial-fruit-blotch", + "wiki-bacterial-leaf-scorch", + "wiki-bacterial-pocket", + "wiki-bacterial-pustule", + "wiki-bacterial-speck", + "wiki-bacterial-streak", + "wiki-bacterial-wetwood", + "wiki-banana-blood-disease", + "wiki-banana-bract-mosaic", + "wiki-banana-streak-virus", + "wiki-banana-virus-x", + "wiki-banded-sclerotial-disease", + "wiki-barley-covered-smut", + "wiki-barley-false-loose-smut", + "wiki-barley-loose-smut", + "wiki-barley-net-blotch", + "wiki-barley-scald", + "wiki-barley-spot-blotch", + "wiki-barley-stripe", + "wiki-bayoud", + "wiki-bean-common-mosaic", + "wiki-bean-curly-dwarf-mosaic", + "wiki-bean-golden-yellow-mosaic", + "wiki-beet-black-wood-vessel", + "wiki-beet-distortion-mosaic", + "wiki-beet-latent-rosette", + "wiki-beet-leaf-curl", + "wiki-beet-mosaic", + "wiki-beet-necrotic-yellow-vein", + "wiki-beet-savoy", + "wiki-beet-western-yellows", + "wiki-beet-yellow-net", + "wiki-beet-yellow-stunt", + "wiki-beet-yellow-vein", + "wiki-beet-yellows", + "wiki-belaat", + "wiki-bending-head", + "wiki-black-chaff", + "wiki-black-cross", + "wiki-black-currant-reversion", + "wiki-black-dot-disease", + "wiki-black-foot", + "wiki-black-head-mold", + "wiki-black-head-molds", + "wiki-black-horse", + "wiki-black-kernel", + "wiki-black-knot", + "wiki-black-leaf-streak", + "wiki-black-leg", + "wiki-black-pit", + "wiki-black-pod-disease", + "wiki-black-point", + "wiki-black-pox-of-apple", + "wiki-black-raspberry-streak", + "wiki-black-raspberry-witches-broom", + "wiki-black-root", + "wiki-black-scurf", + "wiki-black-seed-disease", + "wiki-black-smut", + "wiki-black-speck", + "wiki-black-streak", + "wiki-black-streaked-dwarf", + "wiki-black-vine-weevil", + "wiki-black-walnut", + "wiki-black-wood-vessel", + "wiki-blackberry-calico", + "wiki-blackberry-rosette", + "wiki-blackberry-rust", + "wiki-blackberry-sterility", + "wiki-blackleg", + "wiki-blackspot", + "wiki-blanks", + "wiki-blight", + "wiki-blight-leaf-spot", + "wiki-blister-spot-of-apple", + "wiki-blood-disease", + "wiki-blotch", + "wiki-blue-disease", + "wiki-blue-mold-of-apple", + "wiki-blueberry-necrotic-shock", + "wiki-blueberry-red-ringspot", + "wiki-blueberry-scorch", + "wiki-blueberry-shoestring", + "wiki-borro-sec", + "wiki-botrytis-gray-mold", + "wiki-botrytis-leaf-spot", + "wiki-bract-mosaic", + "wiki-bract-spot", + "wiki-bramble-yellow-mosaic", + "wiki-british-tar-spot", + "wiki-broad-bean-stain", + "wiki-broccoli-necrotic-yellows", + "wiki-brooks-fruit-spot-of-apple", + "wiki-brown-berry-disease", + "wiki-brown-blotch", + "wiki-brown-ring-of-roots", + "wiki-brown-root", + "wiki-brown-rust", + "wiki-browning-and-stem-break", + "wiki-brussels-sprout-leaf-spot", + "wiki-bud-and-flower-spot", + "wiki-bugtok", + "wiki-bunch-disease", + "wiki-bunt", + "wiki-bushy-stunt", + "wiki-cabbage-black-leaf-spot", + "wiki-cabbage-clubroot", + "wiki-cabbage-mosaic", + "wiki-cabbage-ring-spot", + "wiki-cabbage-yellows", + "wiki-cacao-swollen-shoot", + "wiki-cacao-yellow-mosaic", + "wiki-cadang-cadang", + "wiki-cane-and-leaf-rust", + "wiki-cane-botrytis", + "wiki-canker-of-apple", + "wiki-cantaloupe-monosporascus-collapse", + "wiki-carnation", + "wiki-carnation-etched-ring", + "wiki-carnation-latent", + "wiki-carnation-ring-spot", + "wiki-cassava-american-latent", + "wiki-cassava-ash", + "wiki-cassava-brown-streak-disease", + "wiki-cassava-common-mosaic", + "wiki-cassava-frog-skin", + "wiki-cassava-frogskin", + "wiki-cassava-symptomless-infections", + "wiki-cassava-vein-mosaic", + "wiki-catface", + "wiki-catkin-blast", + "wiki-cauliflower-mosaic", + "wiki-cedar-rust", + "wiki-cedar-hawthorn-rust", + "wiki-cedar-quince-rust", + "wiki-celery-western-blotch", + "wiki-ceratocystis-stain", + "wiki-cercoseptoria-leaf-spot", + "wiki-cercospora-spot", + "wiki-cherry-bark-disease", + "wiki-cherry-leaf-roll", + "wiki-cherry-leaf-spot", + "wiki-cherry-rasp-leaf", + "wiki-cherry-twisted-leaf", + "wiki-cherry-virus-a", + "wiki-chickpea-bushy-stunt", + "wiki-chickpea-distortion-mosaic", + "wiki-chickpea-filiform", + "wiki-chili-leaf-curl", + "wiki-chilling-injury-of-mango", + "wiki-chinese-cabbage-turnip-mosaic", + "wiki-chino-del-tomate", + "wiki-chlorotic-disease", + "wiki-chlorotic-leaf-roll", + "wiki-chlorotic-leaf-spot", + "wiki-chlorotic-streak", + "wiki-choke", + "wiki-chrysanthemum-aspermy", + "wiki-chrysanthemum-carlavirus", + "wiki-chrysanthemum-leaf-blotch", + "wiki-chrysanthemum-rosette", + "wiki-chrysanthemum-stunt", + "wiki-chrysomyxa-leaf-rust", + "wiki-cigar-end", + "wiki-cineraria-leaf-rust", + "wiki-cinnamon-leaf-spot", + "wiki-citrus-bud-mite", + "wiki-citrus-chlorotic-dwarf", + "wiki-citrus-cracky-bark", + "wiki-citrus-crinkly-leaf", + "wiki-citrus-exocortis", + "wiki-citrus-greening", + "wiki-citrus-impietratura", + "wiki-citrus-infectious-mottle", + "wiki-citrus-leaf-miner", + "wiki-citrus-leprosis", + "wiki-citrus-little-leaf", + "wiki-citrus-nematode", + "wiki-citrus-psorosis", + "wiki-citrus-ringspot", + "wiki-citrus-satsuma-dwarf", + "wiki-citrus-stubborn", + "wiki-citrus-tatting-leaf", + "wiki-citrus-tristeza", + "wiki-citrus-vein-enation", + "wiki-citrus-yellow-vein", + "wiki-cladosporium-leaf-spot", + "wiki-clover-phyllody", + "wiki-clover-wound-tumor", + "wiki-clover-yellow-mosaic", + "wiki-club-root-of-canola", + "wiki-coconut-cadang-cadang-viroid", + "wiki-coconut-foliar-decay", + "wiki-coconut-tinangaja", + "wiki-coffee-leaf-rust", + "wiki-coffee-ringspot", + "wiki-collapse", + "wiki-collar-crack", + "wiki-collenchyma", + "wiki-colorado-potato-beetle", + "wiki-common-bean-anthracnose", + "wiki-common-bean-golden-mosaic", + "wiki-common-bean-rust", + "wiki-common-bunt", + "wiki-common-leaf-spot", + "wiki-common-mosaic", + "wiki-common-rust", + "wiki-common-scab", + "wiki-common-smut", + "wiki-concentric-ring-leaf-spot", + "wiki-coral-spot", + "wiki-cordana-leaf-spot", + "wiki-corky-ring-spot", + "wiki-corky-ringspot", + "wiki-corn-anthracnose", + "wiki-corn-common-rust", + "wiki-corn-eyespot", + "wiki-corn-gray-leaf-spot", + "wiki-corn-head-smut", + "wiki-corn-smut", + "wiki-corticium-leaf-spot", + "wiki-coryneum-leaf-spot", + "wiki-cotton-aphid", + "wiki-cotton-leaf-blister", + "wiki-cotton-lint-contamination", + "wiki-cotton-pink-bollworm", + "wiki-cotton-rust", + "wiki-cottony-leak", + "wiki-covered-kernel-smut", + "wiki-covered-smut", + "wiki-cowpea-aphid-borne-mosaic", + "wiki-cowpea-mosaic", + "wiki-cracked-bark", + "wiki-cranberry-false-blossom", + "wiki-cranberry-leaf-spot", + "wiki-crinkle", + "wiki-crown-rust", + "wiki-crumbly-berries", + "wiki-crumbly-berry", + "wiki-crumple-leaf", + "wiki-cryptostictis-leaf-spot", + "wiki-cucumber-green-mottle-mosaic", + "wiki-cucumber-scab", + "wiki-cucumber-vein-yellowing", + "wiki-cucumber-wild-mosaic", + "wiki-curly-top-of-sugar-beet", + "wiki-cyathia-drop", + "wiki-cyclamen-stunt", + "wiki-cyclamen-yellows", + "wiki-cylindrosporium-leaf-spot", + "wiki-dactuliophora-leaf-spot", + "wiki-daffodil-fire", + "wiki-daffodil-leaf-scorch", + "wiki-daffodil-mosaic", + "wiki-daffodil-stripe", + "wiki-dahlia-mosaic", + "wiki-dahlia-ring-spot", + "wiki-dahlia-stunt", + "wiki-damping-off-fusarium", + "wiki-damping-off-of-apple", + "wiki-damping-off-pythium", + "wiki-damping-off-rhizoctonia", + "wiki-date-palm-bayoud-disease", + "wiki-date-palm-black-scorch", + "wiki-date-palm-diplodia-disease", + "wiki-datura-leaf-curl", + "wiki-datura-mosaic", + "wiki-datura-stramonium", + "wiki-dead-arm", + "wiki-decay", + "wiki-deformation-mosaic", + "wiki-diamond-spot", + "wiki-dianthus-mottle", + "wiki-dianthus-ringspot", + "wiki-diaprepes-root-weevil", + "wiki-dickeya", + "wiki-dieback-and-leaf-scorch", + "wiki-dilophospora-leaf-spot", + "wiki-diplodia-disease", + "wiki-diplodia-leaf-streak", + "wiki-dirty-root", + "wiki-discoloration", + "wiki-distortion-mosaic", + "wiki-dock-anthracnose", + "wiki-dogwood-anthracnose", + "wiki-dogwood-leaf-spot" ], - "totalFound": 1800 + "totalFound": 4350 } \ No newline at end of file diff --git a/apps/web/scripts/.flagged-content-review-needed.md b/apps/web/scripts/.flagged-content-review-needed.md new file mode 100644 index 0000000..2a453ea --- /dev/null +++ b/apps/web/scripts/.flagged-content-review-needed.md @@ -0,0 +1,11 @@ +# 🚩 Flagged Content Review — Nothing to Review + +Generated: 2026-06-06T21:02:03.301Z + +**No content has been flagged for review yet.** + +Flagged items will appear here once users flag content for manual review. + +--- + +_Report generated with min-flags=1_ diff --git a/apps/web/scripts/apply-flag-migration.ts b/apps/web/scripts/apply-flag-migration.ts new file mode 100644 index 0000000..74d195d --- /dev/null +++ b/apps/web/scripts/apply-flag-migration.ts @@ -0,0 +1,53 @@ +/** + * apply-flag-migration.ts + * + * Applies the flagged_content table migration to Turso. + * Run with: npx tsx scripts/apply-flag-migration.ts + */ + +import dotenv from "dotenv"; +import path from "node:path"; + +const envFile = + process.env.NODE_ENV === "production" ? "../.env.production" : "../.env.development"; +dotenv.config({ path: path.resolve(__dirname, envFile) }); + +import { createClient } from "@libsql/client"; + +async function main() { + const db = createClient({ + url: process.env.DATABASE_URL!, + authToken: process.env.DATABASE_TOKEN!, + }); + + console.log("Applying migration: create flagged_content table..."); + + await db.execute(` + CREATE TABLE IF NOT EXISTS flagged_content ( + id text PRIMARY KEY NOT NULL, + content_type text NOT NULL, + content_id text NOT NULL, + field_name text NOT NULL, + notes text DEFAULT '', + flag_count integer DEFAULT 1 NOT NULL, + created_at text DEFAULT (datetime('now')) NOT NULL, + updated_at text DEFAULT (datetime('now')) NOT NULL + ) + `); + + await db.execute(` + CREATE INDEX IF NOT EXISTS idx_flagged_content_type ON flagged_content (content_type) + `); + + await db.execute(` + CREATE INDEX IF NOT EXISTS idx_flagged_content_id ON flagged_content (content_id) + `); + + console.log("Migration applied successfully."); + db.close(); +} + +main().catch((err) => { + console.error("Migration failed:", err); + process.exit(1); +}); diff --git a/apps/web/scripts/check-progress.mjs b/apps/web/scripts/check-progress.mjs new file mode 100644 index 0000000..31a8ac7 --- /dev/null +++ b/apps/web/scripts/check-progress.mjs @@ -0,0 +1,19 @@ +import { createClient } from "@libsql/client"; +const c = createClient({ + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_TOKEN, +}); +const r = await c.execute("SELECT COUNT(*) as cnt FROM diseases"); +const r2 = await c.execute( + `SELECT SUM(CASE WHEN image_url IS NOT NULL AND image_url != '' THEN 1 ELSE 0 END) as has, SUM(CASE WHEN image_url IS NULL OR image_url = '' THEN 1 ELSE 0 END) as miss FROM diseases`, +); +const r3 = await c.execute( + `SELECT severity, COUNT(*) as total, SUM(CASE WHEN image_url IS NOT NULL AND image_url != '' THEN 1 ELSE 0 END) as has FROM diseases GROUP BY severity ORDER BY severity`, +); +console.log( + `Total: ${r.rows[0].cnt} | With images: ${r2.rows[0].has} | Missing: ${r2.rows[0].miss}`, +); +for (const row of r3.rows) { + console.log(` ${row.severity?.padEnd(10)}: ${row.has}/${row.total}`); +} +c.close(); diff --git a/apps/web/scripts/generate-flagged-report.ts b/apps/web/scripts/generate-flagged-report.ts new file mode 100644 index 0000000..bae8055 --- /dev/null +++ b/apps/web/scripts/generate-flagged-report.ts @@ -0,0 +1,379 @@ +/** + * generate-flagged-report.ts + * + * Reads all flagged content from the database and generates a pretty + * markdown report organized by content type. The report includes: + * - Summary table with counts per content type + * - Plant images flagged for review + * - Disease images flagged for review + * - Disease symptoms flagged for review + * - Disease causes flagged for review + * - Disease treatment steps flagged for review + * - Disease prevention tips flagged for review + * + * Usage: + * npx tsx scripts/generate-flagged-report.ts [--min-flags N] [--output path/to/report.md] + * + * Options: + * --min-flags Minimum flag count to include (default: 1) + * --output Output path (default: scripts/.flagged-content-review-needed.md) + */ + +import dotenv from "dotenv"; +import path from "node:path"; + +// Load DB config from .env.development (or .env.production if NODE_ENV=production) +const envFile = + process.env.NODE_ENV === "production" ? "../.env.production" : "../.env.development"; +dotenv.config({ path: path.resolve(__dirname, envFile) }); +import { createClient } from "@libsql/client"; +import fs from "node:fs"; + +// ─── Config ───────────────────────────────────────────────────────────────── + +const MIN_FLAGS = parseInt( + process.argv.find((a) => a.startsWith("--min-flags="))?.split("=")[1] ?? "1", + 10, +); +const OUTPUT_PATH = + process.argv.find((a) => a.startsWith("--output="))?.split("=")[1] ?? + path.join(__dirname, ".flagged-content-review-needed.md"); + +// ─── DB Connection ────────────────────────────────────────────────────────── + +const db = createClient({ + url: process.env.DATABASE_URL!, + authToken: process.env.DATABASE_TOKEN!, +}); + +// ─── Types ────────────────────────────────────────────────────────────────── + +interface FlaggedRow { + id: string; + content_type: string; + content_id: string; + field_name: string; + notes: string; + flag_count: number; + created_at: string; + updated_at: string; +} + +interface PlantRow { + id: string; + common_name: string; + scientific_name: string; + family: string; + image_url: string; +} + +interface DiseaseRow { + id: string; + name: string; + scientific_name: string; + plant_id: string; + image_url: string; +} + +// ─── Helpers ──────────────────────────────────────────────────────────────── + +const CONTENT_TYPE_LABELS: Record = { + plant_image: { + emoji: "🪴", + title: "Plant Images Flagged for Review", + description: "Plant images that users have flagged as potentially incorrect or low quality.", + }, + disease_image: { + emoji: "📸", + title: "Disease Images Flagged for Review", + description: + "Disease symptom images that users have flagged as potentially incorrect or misleading.", + }, + disease_symptoms: { + emoji: "⚠️", + title: "Disease Symptoms Flagged for Review", + description: "Symptom descriptions that users have flagged as potentially inaccurate.", + }, + disease_causes: { + emoji: "🔍", + title: "Disease Causes Flagged for Review", + description: + "Causes and contributing factors that users have flagged as potentially incorrect.", + }, + disease_treatment: { + emoji: "💊", + title: "Disease Treatment Steps Flagged for Review", + description: + "Treatment instructions that users have flagged as potentially incorrect or harmful.", + }, + disease_prevention: { + emoji: "🛡️", + title: "Disease Prevention Tips Flagged for Review", + description: "Prevention tips that users have flagged as potentially incorrect or misleading.", + }, +}; + +function formatDate(iso: string): string { + const d = new Date(iso); + return d.toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); +} + +// ─── Main ─────────────────────────────────────────────────────────────────── + +async function main() { + console.log(`📋 Generating flagged content report (min flags: ${MIN_FLAGS})...`); + + // Fetch flagged content + const flaggedRs = await db.execute({ + sql: "SELECT * FROM flagged_content WHERE flag_count >= ? ORDER BY content_type, flag_count DESC, updated_at DESC", + args: [MIN_FLAGS], + }); + const flaggedRows = flaggedRs.rows as unknown as FlaggedRow[]; + + if (flaggedRows.length === 0) { + const report = [ + "# 🚩 Flagged Content Review — Nothing to Review", + "", + `Generated: ${new Date().toISOString()}`, + "", + "**No content has been flagged for review yet.**", + "", + "Flagged items will appear here once users flag content for manual review.", + "", + "---", + "", + `_Report generated with min-flags=${MIN_FLAGS}_`, + "", + ].join("\n"); + + fs.writeFileSync(OUTPUT_PATH, report, "utf-8"); + console.log(`✅ Report written to ${OUTPUT_PATH} (no flagged items)`); + db.close(); + return; + } + + // Collect all unique plant and disease IDs + const plantIds = new Set(); + const diseaseIds = new Set(); + + for (const row of flaggedRows) { + if (row.content_type === "plant_image") { + plantIds.add(row.content_id); + } else { + diseaseIds.add(row.content_id); + } + } + + // Fetch plant names + const plantMap = new Map(); + if (plantIds.size > 0) { + const plantRs = await db.execute({ + sql: `SELECT id, common_name, scientific_name, family, image_url FROM plants WHERE id IN (${[...plantIds].map(() => "?").join(",")})`, + args: [...plantIds], + }); + for (const row of plantRs.rows as unknown as PlantRow[]) { + plantMap.set(row.id, row); + } + } + + // Fetch disease names + their plant references + const diseaseMap = new Map(); + if (diseaseIds.size > 0) { + const diseaseRs = await db.execute({ + sql: `SELECT id, name, scientific_name, plant_id, image_url FROM diseases WHERE id IN (${[...diseaseIds].map(() => "?").join(",")})`, + args: [...diseaseIds], + }); + for (const row of diseaseRs.rows as unknown as DiseaseRow[]) { + diseaseMap.set(row.id, row); + if (!plantMap.has(row.plant_id)) { + plantIds.add(row.plant_id); + } + } + // Fetch any missing plant references for diseases + if (plantIds.size > 0) { + const missingPlantIds = [...plantIds].filter((id) => !plantMap.has(id)); + if (missingPlantIds.length > 0) { + const plantRs = await db.execute({ + sql: `SELECT id, common_name, scientific_name, family, image_url FROM plants WHERE id IN (${missingPlantIds.map(() => "?").join(",")})`, + args: missingPlantIds, + }); + for (const row of plantRs.rows as unknown as PlantRow[]) { + plantMap.set(row.id, row); + } + } + } + } + + // Group by content type + const groups: Record = {}; + for (const row of flaggedRows) { + if (!groups[row.content_type]) groups[row.content_type] = []; + groups[row.content_type].push(row); + } + + // ─── Build Report ──────────────────────────────────────────────────────── + + const lines: string[] = []; + const totalFlags = flaggedRows.reduce((sum, r) => sum + r.flag_count, 0); + + lines.push("# 🚩 Flagged Content — Manual Review Needed"); + lines.push(""); + lines.push(`Generated: ${new Date().toISOString()}`); + lines.push(""); + lines.push( + flaggedRows.length === 1 + ? `**${flaggedRows.length} item** flagged for review (${totalFlags} total flags).` + : `**${flaggedRows.length} items** flagged for review (${totalFlags} total flags).`, + ); + lines.push(""); + lines.push("Most data in this knowledge base is not reviewed by humans. "); + lines.push("Items listed below have been flagged by users for manual review. "); + lines.push("Please review each item and take appropriate action."); + lines.push(""); + + // Summary table + lines.push("## 📊 Summary"); + lines.push(""); + lines.push("| Content Type | Count | Total Flags |"); + lines.push("|---|---|---|"); + const orderedTypes = [ + "plant_image", + "disease_image", + "disease_symptoms", + "disease_causes", + "disease_treatment", + "disease_prevention", + ]; + for (const type of orderedTypes) { + const items = groups[type]; + if (!items) continue; + const label = CONTENT_TYPE_LABELS[type]?.title ?? type; + const count = items.length; + const sumFlags = items.reduce((s, r) => s + r.flag_count, 0); + lines.push(`| ${label} | ${count} | ${sumFlags} |`); + } + lines.push(`| **Total** | **${flaggedRows.length}** | **${totalFlags}** |`); + lines.push(""); + lines.push("---"); + lines.push(""); + + // Detail sections per content type + for (const type of orderedTypes) { + const items = groups[type]; + if (!items) continue; + + const config = CONTENT_TYPE_LABELS[type]; + lines.push(`## ${config?.emoji ?? "📋"} ${config?.title ?? type}`); + lines.push(""); + lines.push(config?.description ?? ""); + lines.push(""); + lines.push(`**${items.length} item${items.length === 1 ? "" : "s"} flagged**`); + lines.push(""); + + for (const item of items) { + // Build label + let label = item.content_id; + let plantLabel = ""; + + if (type === "plant_image") { + const plant = plantMap.get(item.content_id); + if (plant) { + label = `${plant.common_name} (_${plant.scientific_name}_)`; + plantLabel = `${plant.family} family`; + } + } else { + const disease = diseaseMap.get(item.content_id); + if (disease) { + const plant = plantMap.get(disease.plant_id); + const plantName = plant?.common_name ?? disease.plant_id; + label = `${disease.name} (_${disease.scientific_name}_) on **${plantName}**`; + plantLabel = `Affects: ${plantName}`; + } + } + + const flagWord = item.flag_count === 1 ? "flag" : "flags"; + const firstFlagged = formatDate(item.created_at); + const lastFlagged = formatDate(item.updated_at); + + lines.push(`### ${label}`); + lines.push(""); + lines.push(`- **Field:** \`${item.field_name}\``); + lines.push(`- **Flags:** ${item.flag_count} ${flagWord}`); + lines.push(`- **First flagged:** ${firstFlagged}`); + lines.push(`- **Last flagged:** ${lastFlagged}`); + if (plantLabel) { + lines.push(`- **${plantLabel}**`); + } + if (item.notes) { + lines.push(`- **User notes:** ${item.notes}`); + } + + // Show the content data if we can fetch it + if (type === "plant_image") { + const plant = plantMap.get(item.content_id); + if (plant?.image_url) { + lines.push(""); + lines.push(` ![${plant.common_name}](${plant.image_url})`); + } + } else { + const disease = diseaseMap.get(item.content_id); + if (type === "disease_image" && disease?.image_url) { + lines.push(""); + lines.push(` ![${disease.name}](${disease.image_url})`); + } + } + + lines.push(""); + } + + lines.push("---"); + lines.push(""); + } + + // Footer + lines.push("## ℹ️ How This Works"); + lines.push(""); + lines.push("1. **Users** click the 🚩 Flag button on any content they believe needs review."); + lines.push("2. **The system** stores the flag in the database with a counter."); + lines.push( + "3. **This report** is generated by querying the database and formatting the results.", + ); + lines.push("4. **Reviewers** go through each item and take action (fix, update, or dismiss)."); + lines.push(""); + lines.push("### Taking Action"); + lines.push(""); + lines.push("After reviewing an item, you can clear its flags by running:"); + lines.push(""); + lines.push("```sql"); + lines.push("DELETE FROM flagged_content WHERE id = '';"); + lines.push("```"); + lines.push(""); + lines.push("Or clear all flags for a specific item by running:"); + lines.push(""); + lines.push("```sql"); + lines.push( + "UPDATE flagged_content SET flag_count = 0 WHERE content_id = '' AND field_name = '';", + ); + lines.push("```"); + lines.push(""); + lines.push("---"); + lines.push(""); + lines.push(`_Report generated with min-flags=${MIN_FLAGS}_`); + + // Write report + fs.writeFileSync(OUTPUT_PATH, lines.join("\n"), "utf-8"); + console.log(`✅ Report written to ${OUTPUT_PATH}`); + console.log(` ${flaggedRows.length} items, ${totalFlags} total flags`); + db.close(); +} + +main().catch((err) => { + console.error("❌ Failed to generate report:", err); + process.exit(1); +}); diff --git a/apps/web/scripts/scrape-training-dataset.ts b/apps/web/scripts/scrape-training-dataset.ts index 1cce92f..c7daf14 100644 --- a/apps/web/scripts/scrape-training-dataset.ts +++ b/apps/web/scripts/scrape-training-dataset.ts @@ -2,59 +2,113 @@ /** * scrape-training-dataset.ts * - * Collects a training dataset for fine-tuning by scraping DuckDuckGo image search. + * Collects a training dataset from DuckDuckGo, iNaturalist, and Wikimedia Commons. * - * Targets: - * - 200 images per disease class (93 diseases) - * - 400 images for the "healthy" class - * - Full resolution images stored in data/dataset/{class_id}/ + * Targets (tiered by plant type): + * - Core plants (houseplants + common garden): 100 images per disease + * - Full set (all 11,498 DB diseases): 10 images per disease + * - Healthy: 400 images * - * DuckDuckGo approach (no API key needed): - * 1. Fetch the main search page to extract a vqd (query) token - * 2. Use the vqd token to paginate through image results - * 3. Download each image to the dataset directory + * Sources (all free, no API keys): + * 1. DB image_url — existing images already found + * 2. DuckDuckGo — general web image search + * 3. iNaturalist — real-world plant observation photos + * 4. Wikimedia Commons — curated scientific/educational images * * Usage: cd apps/web && npx tsx scripts/scrape-training-dataset.ts - * - * Progress is tracked in data/dataset/.progress.json — interrupt and resume safely. + * Progress: data/dataset/.progress.json — interrupt and resume safely. */ import "dotenv/config"; -import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from "fs"; -import { resolve, extname, join } from "path"; +import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs"; +import { resolve, extname } from "path"; + +// Load .env.development for DB creds +const envPath = resolve(__dirname, "../.env.development"); +try { + const env = readFileSync(envPath, "utf-8"); + for (const line of env.split("\n")) { + const trimmed = line.trim(); + if (trimmed && !trimmed.startsWith("#")) { + const eqIdx = trimmed.indexOf("="); + if (eqIdx > 0) { + const key = trimmed.slice(0, eqIdx).trim(); + const val = trimmed.slice(eqIdx + 1).trim(); + if (!process.env[key]) process.env[key] = val; + } + } + } +} catch {} + +import { getDb, closeDb } from "@/lib/db/index"; +import { diseases } from "@/lib/db/schema"; // ─── Config ───────────────────────────────────────────────────────────────── -const DISEASES_JSON = resolve(__dirname, "../src/data/diseases.json"); -const PLANTS_JSON = resolve(__dirname, "../src/data/plants.json"); - const DATASET_DIR = resolve(__dirname, "../data/dataset"); const PROGRESS_FILE = resolve(DATASET_DIR, ".progress.json"); -/** Target images per disease class */ -const TARGET_PER_DISEASE = 200; +/** Target images per disease for CORE plants */ +const TARGET_CORE = 100; -/** Target images for the "healthy" class (2× normal) */ +/** Target images per disease for the FULL set */ +const TARGET_FULL = 10; + +/** Target images for the "healthy" class */ const TARGET_HEALTHY = 400; +/** Core plants that get higher image targets */ +const CORE_PLANTS = new Set([ + // Houseplants + "monstera", + "pothos", + "snake-plant", + "peace-lily", + "orchid", + "succulent", + "fiddle-leaf-fig", + "aloe-vera", + "cactus", + "fern", + // Garden plants + "tomato", + "basil", + "rose", + "pepper", + "strawberry", + "cucumber", + "squash", + "lettuce", + "spinach", + "cabbage", + "lavender", + "mint", + "jasmine", + "sunflower", + "daisy", + "zucchini", + "bean", + "eggplant", + "chili", + // General disease patterns + "general", +]); + /** Delay between DuckDuckGo search API calls (ms) */ const SEARCH_DELAY = 1500; /** Delay between image downloads (ms) */ -const DOWNLOAD_DELAY = 300; +const DOWNLOAD_DELAY = 100; /** Max concurrent downloads */ -const CONCURRENT_DOWNLOADS = 5; +const CONCURRENT_DOWNLOADS = 10; -/** Minimum image size in bytes to accept (reject tiny placeholders) */ +/** Minimum image size in bytes to accept */ const MIN_IMAGE_SIZE = 10_000; // 10KB /** Maximum image size in bytes */ const MAX_IMAGE_SIZE = 10 * 1024 * 1024; // 10MB -/** Allowed image content types */ -const ALLOWED_CONTENT_TYPES = ["image/jpeg", "image/jpg", "image/png", "image/webp", "image/gif"]; - /** Allowed file extensions */ const ALLOWED_EXTENSIONS = [".jpg", ".jpeg", ".png", ".webp"]; @@ -62,22 +116,16 @@ const ALLOWED_EXTENSIONS = [".jpg", ".jpeg", ".png", ".webp"]; const UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"; +/** Class ID for healthy plants */ +const HEALTHY_CLASS = "healthy"; + // ─── Types ────────────────────────────────────────────────────────────────── -interface DiseaseSeed { +interface DbDisease { id: string; plantId: string; name: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [key: string]: any; -} - -interface PlantSeed { - id: string; - commonName: string; - scientificName: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [key: string]: any; + imageUrl: string | null; } interface DuckDuckGoImageResult { @@ -93,10 +141,7 @@ interface ClassProgress { count: number; downloaded: number; failed: number; - skipped: number; - /** URLs we've already seen (to avoid duplicates) */ seenUrls: string[]; - /** Whether we've exhausted search results */ exhausted: boolean; } @@ -105,15 +150,27 @@ interface Progress { classes: Record; } -/** Class ID for healthy plants */ -const HEALTHY_CLASS = "healthy"; +// ─── DB Loading ────────────────────────────────────────────────────────────── + +/** + * Load all diseases from the database with their existing image URLs. + */ +async function loadDiseasesFromDb(): Promise { + const db = getDb(); + const rows = await db + .select({ + id: diseases.id, + plantId: diseases.plantId, + name: diseases.name, + imageUrl: diseases.imageUrl, + }) + .from(diseases) + .orderBy(diseases.id); + return rows; +} // ─── DuckDuckGo API ───────────────────────────────────────────────────────── -/** - * Extract the vqd token from DuckDuckGo's search page. - * Required for paginating image results. - */ async function getVqdToken(query: string): Promise { const url = `https://duckduckgo.com/?q=${encodeURIComponent(query)}&t=h_&iax=images&ia=images`; @@ -122,25 +179,15 @@ async function getVqdToken(query: string): Promise { signal: AbortSignal.timeout(15_000), }); - if (!res.ok) { - throw new Error(`Failed to get vqd token: ${res.status}`); - } + if (!res.ok) throw new Error(`Failed to get vqd token: ${res.status}`); const html = await res.text(); - - // Extract vqd token from the HTML - // Format: vqd='' or vqd="" const match = html.match(/vqd['"]?\s*[:=]\s*['"]([a-f0-9-]+)['"]/); - if (!match) { - throw new Error(`Could not extract vqd token from DuckDuckGo response for "${query}"`); - } + if (!match) throw new Error(`Could not extract vqd token for "${query}"`); return match[1]; } -/** - * Fetch a page of DuckDuckGo image results. - */ async function searchImagesDuckDuckGo( query: string, vqd: string, @@ -161,12 +208,9 @@ async function searchImagesDuckDuckGo( if (res.status === 429) { console.warn(" ⚠ Rate limited (429). Waiting 10s..."); await sleep(10_000); - return searchImagesDuckDuckGo(query, vqd, page); // Retry - } - if (res.status === 403) { - console.warn(" ⚠ Forbidden (403). Token may have expired."); - return []; // Token expired — no more pages + return searchImagesDuckDuckGo(query, vqd, page); } + if (res.status === 403) return []; throw new Error(`DuckDuckGo search failed: ${res.status}`); } @@ -174,11 +218,7 @@ async function searchImagesDuckDuckGo( return data.results ?? []; } -/** - * Search DuckDuckGo images, automatically paginating to collect up to `target` results. - * Returns unique image URLs. - */ -async function collectImages( +async function collectImagesDuckDuckGo( query: string, target: number, seenUrls: Set, @@ -188,27 +228,29 @@ async function collectImages( let exhausted = false; let consecutiveEmpty = 0; - // Get vqd token let vqd: string; try { vqd = await getVqdToken(query); } catch (err) { - console.warn(` ⚠ Failed to get vqd token: ${err instanceof Error ? err.message : "unknown"}`); + console.warn(` ⚠ DDG token failed: ${err instanceof Error ? err.message : "unknown"}`); return { urls: [], exhausted: true }; } - while (results.length < target) { + const MAX_PAGES = 5; + let lowNoveltyCount = 0; + + while (results.length < target && page <= MAX_PAGES) { await sleep(SEARCH_DELAY); let pageResults: DuckDuckGoImageResult[]; try { pageResults = await searchImagesDuckDuckGo(query, vqd, page); } catch (err) { - console.warn(` ⚠ Search error: ${err instanceof Error ? err.message : "unknown"}`); + console.warn(` ⚠ DDG error: ${err instanceof Error ? err.message : "unknown"}`); break; } - if (pageResults.length === 0) { + if (!pageResults || pageResults.length === 0) { consecutiveEmpty++; if (consecutiveEmpty >= 3) { exhausted = true; @@ -223,78 +265,160 @@ async function collectImages( for (const r of pageResults) { if (results.length >= target) break; - const imgUrl = r.image || r.url; - - // Skip if we've already seen this URL + if (!imgUrl || typeof imgUrl !== "string") continue; if (seenUrls.has(imgUrl)) continue; - - // Validate URL looks like an image - const ext = extname(new URL(imgUrl).pathname).toLowerCase(); - if (!ALLOWED_EXTENSIONS.includes(ext) && !ext) { - // No extension - still try, could be a CDN URL + try { + new URL(imgUrl); + } catch { + continue; } - seenUrls.add(imgUrl); results.push(imgUrl); newCount++; } - if (newCount === 0 && pageResults.every((r) => seenUrls.has(r.image || r.url))) { - // All results on this page were already seen - page++; - continue; + const newRatio = newCount / pageResults.length; + if (newRatio < 0.05) { + lowNoveltyCount++; + if (lowNoveltyCount >= 2) break; + } else { + lowNoveltyCount = 0; } - if (results.length < target) { - page++; - } + if (results.length < target) page++; } return { urls: results.slice(0, target), exhausted }; } +// ─── iNaturalist API ───────────────────────────────────────────────────────── + +async function searchImagesInaturalist( + query: string, + target: number, + seenUrls: Set, +): Promise<{ urls: string[]; exhausted: boolean }> { + const results: string[] = []; + const perPage = Math.min(target, 200); + + const apiUrl = + `https://api.inaturalist.org/v1/observations` + + `?q=${encodeURIComponent(query)}` + + `&photos_only=true` + + `&quality_grade=research` + + `&per_page=${perPage}` + + `&order_by=observed_on&order=desc`; + + try { + const res = await fetch(apiUrl, { + headers: { "User-Agent": UA, Accept: "application/json" }, + signal: AbortSignal.timeout(15_000), + }); + if (!res.ok) return { urls: [], exhausted: false }; + + const data = (await res.json()) as { + results: Array<{ photos: Array<{ url: string }> }>; + }; + + for (const obs of data.results ?? []) { + if (results.length >= target) break; + for (const photo of obs.photos ?? []) { + if (results.length >= target) break; + const url = photo.url; + if (!url || seenUrls.has(url)) continue; + const fullUrl = url.replace("/medium.", "/original."); + seenUrls.add(fullUrl); + results.push(fullUrl); + } + } + + return { urls: results, exhausted: results.length < target }; + } catch { + return { urls: results, exhausted: false }; + } +} + +// ─── Wikimedia Commons API ────────────────────────────────────────────────── + +async function searchImagesCommons( + query: string, + target: number, + seenUrls: Set, +): Promise<{ urls: string[]; exhausted: boolean }> { + const results: string[] = []; + let sroffset = 0; + + while (results.length < target) { + const params = new URLSearchParams({ + action: "query", + list: "search", + srsearch: query, + srnamespace: "6", + srlimit: "50", + sroffset: String(sroffset), + format: "json", + origin: "*", // server-side API call + }); + + const url = `https://commons.wikimedia.org/w/api.php?${params}`; + + try { + const res = await fetch(url, { + headers: { "User-Agent": UA }, + signal: AbortSignal.timeout(10_000), + }); + if (!res.ok) break; + + const data = (await res.json()) as { + query?: { search?: Array<{ title: string }> }; + continue?: { sroffset?: number }; + }; + + const hits = data.query?.search ?? []; + if (hits.length === 0) break; + + for (const hit of hits) { + if (results.length >= target) break; + const filename = hit.title.replace(/^File:/, ""); + const imgUrl = `https://commons.wikimedia.org/wiki/Special:FilePath/${encodeURIComponent(filename)}`; + if (seenUrls.has(imgUrl)) continue; + seenUrls.add(imgUrl); + results.push(imgUrl); + } + + sroffset = data.continue?.sroffset ?? sroffset + hits.length; + } catch { + break; + } + } + + return { urls: results, exhausted: results.length < target }; +} + // ─── Image Download ───────────────────────────────────────────────────────── -/** - * Download a single image from a URL to the target path. - * Returns true if successful, false otherwise. - */ async function downloadImage(url: string, destPath: string): Promise { try { const res = await fetch(url, { - headers: { "User-Agent": UA, Accept: "image/webp,image/png,image/jpeg" }, + headers: { "User-Agent": UA, Accept: "image/webp,image/png,image/jpeg,*/*" }, signal: AbortSignal.timeout(15_000), }); - if (!res.ok) return false; const contentType = res.headers.get("content-type") || ""; - const contentLength = parseInt(res.headers.get("content-length") || "0", 10); - - // Validate content type - if (!ALLOWED_CONTENT_TYPES.some((t) => contentType.includes(t))) { - return false; - } - - // Validate size - if (contentLength > 0 && contentLength < MIN_IMAGE_SIZE) return false; - if (contentLength > MAX_IMAGE_SIZE) return false; + if (contentType.includes("text/html")) return false; const buffer = Buffer.from(await res.arrayBuffer()); - - // Double-check actual buffer size if (buffer.length < MIN_IMAGE_SIZE) return false; if (buffer.length > MAX_IMAGE_SIZE) return false; - // Determine correct extension from content type or URL let ext = extname(new URL(url).pathname).toLowerCase(); if (!ALLOWED_EXTENSIONS.includes(ext)) { - // Map from content type if (contentType.includes("jpeg") || contentType.includes("jpg")) ext = ".jpg"; else if (contentType.includes("png")) ext = ".png"; else if (contentType.includes("webp")) ext = ".webp"; - else ext = ".jpg"; // Default + else ext = ".jpg"; } const filePath = destPath.replace(/\.\w+$/, ext); @@ -305,9 +429,6 @@ async function downloadImage(url: string, destPath: string): Promise { } } -/** - * Download multiple images concurrently, respecting a per-download delay. - */ async function downloadBatch( urls: string[], classDir: string, @@ -317,7 +438,6 @@ async function downloadBatch( let failed = 0; let index = startIndex; - // Process in chunks to control concurrency for (let i = 0; i < urls.length; i += CONCURRENT_DOWNLOADS) { const chunk = urls.slice(i, i + CONCURRENT_DOWNLOADS); @@ -325,16 +445,23 @@ async function downloadBatch( chunk.map(async (url) => { const paddedIndex = String(index).padStart(4, "0"); const destPath = resolve(classDir, `img_${paddedIndex}.jpg`); - const success = await downloadImage(url, destPath); await sleep(DOWNLOAD_DELAY); - return { success, index: index++ }; + return { success, index: index++, url: url.substring(0, 50) }; }), ); for (const r of results) { if (r.success) downloaded++; - else failed++; + else { + failed++; + if (failed % 20 === 1) console.log(` ⚠ Failed: ${r.url}...`); + } + } + + const total = downloaded + failed; + if (total % 30 === 0 || total === urls.length) { + console.log(` Progress: ${downloaded}/${urls.length} (${failed} failed)`); } } @@ -361,7 +488,6 @@ function getClassProgress(progress: Progress, classId: string): ClassProgress { count: 0, downloaded: 0, failed: 0, - skipped: 0, seenUrls: [], exhausted: false, }; @@ -369,26 +495,22 @@ function getClassProgress(progress: Progress, classId: string): ClassProgress { return progress.classes[classId]; } -// ─── Search Query Building ────────────────────────────────────────────────── +// ─── Query Building ───────────────────────────────────────────────────────── -function buildSearchQueries(disease: DiseaseSeed, plant: PlantSeed | null): string[] { - const name = disease.name; - const plantName = plant?.commonName || disease.plantId; - - return [ - `${name} ${plantName} leaf disease`, - `${plantName} ${name} symptoms`, - `${name} plant disease`, - `${plantName} diseased leaf`, - ]; +function buildSearchQueries(disease: DbDisease): string[] { + const name = disease.name || disease.id.replace(/-/g, " "); + const plant = disease.plantId.replace(/-/g, " "); + // Every query keeps the disease NAME to avoid noisy labels + return [`${name} ${plant} leaf disease`, `${plant} ${name} symptoms`, `${name} ${plant}`]; } -function buildHealthyQueries(plant: PlantSeed): string[] { +function buildHealthyQueries(plant: string): string[] { + const name = plant.replace(/-/g, " "); return [ - `healthy ${plant.commonName} leaf`, - `${plant.commonName} leaf closeup`, - `healthy ${plant.commonName} plant`, - `${plant.commonName} foliage`, + `healthy ${name} leaf`, + `${name} leaf closeup`, + `healthy ${name} plant`, + `${name} foliage`, ]; } @@ -400,64 +522,97 @@ async function collectClassImages( target: number, progress: Progress, classDir: string, + existingUrls: string[] = [], + fastMode = false, // Skip slow DuckDuckGo, use iNat + Commons only ): Promise { const cp = getClassProgress(progress, classId); const seenUrls = new Set(cp.seenUrls); if (cp.count >= target) { - console.log(` ✓ Already have ${cp.count}/${target} images`); + console.log(` ✓ Already have ${cp.count}/${target}`); return; } if (cp.exhausted) { - console.log(` ✓ Already exhausted search results (${cp.count}/${target} images)`); + console.log(` ✓ Exhausted (${cp.count}/${target})`); return; } mkdirSync(classDir, { recursive: true }); - const totalUrls: string[] = []; + const allUrls: string[] = []; let exhausted = false; - // Search with each query until we hit the target - for (const query of queries) { - if (totalUrls.length >= target) break; - - console.log(` Searching: "${query}"...`); - const result = await collectImages(query, target - totalUrls.length, seenUrls); - - totalUrls.push(...result.urls); - cp.seenUrls = Array.from(seenUrls); - - if (result.exhausted) { - exhausted = true; + // ── Source 0: Existing DB URLs ────────────────────────────────────────── + const freshDbUrls = existingUrls.filter((u) => !seenUrls.has(u)); + if (freshDbUrls.length > 0) { + console.log(` DB: ${freshDbUrls.length} existing URLs`); + for (const url of freshDbUrls) { + if (allUrls.length >= target) break; + seenUrls.add(url); + allUrls.push(url); } - - if (totalUrls.length >= target) break; } - if (totalUrls.length === 0) { + // ── Source 1: DuckDuckGo ────────────────────────────────────────────── + // Skip DDG in fast mode (full set — DDG is slowest source) + if (!fastMode && allUrls.length < target) { + for (const query of queries) { + if (allUrls.length >= target) break; + process.stdout.write(` DDG: "${query.substring(0, 40)}"... `); + const result = await collectImagesDuckDuckGo(query, target - allUrls.length, seenUrls); + allUrls.push(...result.urls); + if (result.exhausted) exhausted = true; + console.log(`${result.urls.length} new`); + if (allUrls.length >= target) break; + } + } + + // ── Source 2: iNaturalist ────────────────────────────────────────────── + if (allUrls.length < target) { + const primaryQuery = queries[0]; + console.log(` iNat: Searching...`); + const result = await searchImagesInaturalist(primaryQuery, target - allUrls.length, seenUrls); + allUrls.push(...result.urls); + if (result.exhausted) exhausted = true; + console.log(` iNat: ${result.urls.length} images`); + } + + // ── Source 3: Wikimedia Commons ──────────────────────────────────────── + if (allUrls.length < target) { + const primaryQuery = queries[0]; + console.log(` Commons: Searching...`); + const result = await searchImagesCommons(primaryQuery, target - allUrls.length, seenUrls); + allUrls.push(...result.urls); + if (result.exhausted) exhausted = true; + console.log(` Commons: ${result.urls.length} images`); + } + + if (allUrls.length === 0) { cp.exhausted = exhausted; saveProgress(progress); - console.log(` ✗ No images found for "${classId}"`); + console.log(` ✗ No images found`); return; } - console.log(` Found ${totalUrls.length} unique image URLs. Downloading...`); + // Save progress with seen URLs BEFORE downloading + cp.seenUrls = Array.from(seenUrls); + cp.exhausted = exhausted; + saveProgress(progress); - // Download the images - const { downloaded, failed } = await downloadBatch(totalUrls, classDir, cp.count); + console.log(` Downloading ${allUrls.length} images...`); + + const { downloaded, failed } = await downloadBatch(allUrls, classDir, cp.count); cp.count += downloaded; cp.downloaded += downloaded; cp.failed += failed; - cp.exhausted = exhausted; saveProgress(progress); const pct = Math.round((cp.count / target) * 100); console.log( - ` ${downloaded > 0 ? "✓" : "✗"} Got ${downloaded} images (${failed} failed). Total: ${cp.count}/${target} (${pct}%)`, + ` ${downloaded > 0 ? "✓" : "✗"} Got ${downloaded}/${allUrls.length} (${failed} failed). Total: ${cp.count}/${target} (${pct}%)`, ); } @@ -465,25 +620,18 @@ async function collectClassImages( async function main() { console.log("=".repeat(60)); - console.log("PLANT DISEASE DATASET COLLECTOR"); + console.log("PLANT DISEASE DATASET COLLECTOR — FULL DB"); console.log("=".repeat(60)); - // Load knowledge base - const diseases = JSON.parse(readFileSync(DISEASES_JSON, "utf-8")) as DiseaseSeed[]; - const plants = JSON.parse(readFileSync(PLANTS_JSON, "utf-8")) as PlantSeed[]; + // Load diseases from DB + console.log("\nLoading diseases from database..."); + const dbDiseases = await loadDiseasesFromDb(); + console.log(` ${dbDiseases.length} diseases loaded`); - const plantMap = new Map(); - for (const p of plants) { - plantMap.set(p.id, p); - } - - console.log(`\nLoaded ${diseases.length} diseases, ${plants.length} plants`); - console.log( - `Target: ${TARGET_PER_DISEASE} images/disease (×${diseases.length} = ${diseases.length * TARGET_PER_DISEASE})`, - ); - console.log(`Target: ${TARGET_HEALTHY} images for "healthy" class`); - console.log(`Output: ${DATASET_DIR}/`); - console.log(""); + const coreDiseases = dbDiseases.filter((d) => CORE_PLANTS.has(d.plantId)); + const fullDiseases = dbDiseases.filter((d) => !CORE_PLANTS.has(d.plantId)); + console.log(` Core plants: ${coreDiseases.length} diseases (target: ${TARGET_CORE})`); + console.log(` Full set: ${fullDiseases.length} diseases (target: ${TARGET_FULL})`); // Load progress mkdirSync(DATASET_DIR, { recursive: true }); @@ -491,28 +639,46 @@ async function main() { const startTime = Date.now(); - // ── Phase 1: Disease classes ────────────────────────────────────────────── - - console.log("─".repeat(60)); - console.log("PHASE 1: Disease Images"); - console.log("─".repeat(60)); - - for (let i = 0; i < diseases.length; i++) { - const disease = diseases[i]; - const plant = plantMap.get(disease.plantId) ?? null; - const classDir = resolve(DATASET_DIR, disease.id); - const queries = buildSearchQueries(disease, plant); - - const pct = Math.round((i / diseases.length) * 100); - console.log(`\n[${i + 1}/${diseases.length}] (${pct}%) ${disease.name} (${disease.id})`); - - await collectClassImages(disease.id, queries, TARGET_PER_DISEASE, progress, classDir); - } - - // ── Phase 2: Healthy class ──────────────────────────────────────────────── + // ── Phase 1: Core set ────────────────────────────────────────────────── console.log("\n" + "─".repeat(60)); - console.log("PHASE 2: Healthy Plant Images"); + console.log("PHASE 1: Core Diseases (100 images each)"); + console.log("─".repeat(60)); + + for (let i = 0; i < coreDiseases.length; i++) { + const d = coreDiseases[i]; + const classDir = resolve(DATASET_DIR, d.id); + const queries = buildSearchQueries(d); + const existingUrls = d.imageUrl ? [d.imageUrl] : []; + + const pct = Math.round((i / coreDiseases.length) * 100); + console.log(`\n[${i + 1}/${coreDiseases.length}] (${pct}%) ${d.name || d.id} (${d.plantId})`); + + await collectClassImages(d.id, queries, TARGET_CORE, progress, classDir, existingUrls); + } + + // ── Phase 2: Full set ────────────────────────────────────────────────── + + console.log("\n" + "─".repeat(60)); + console.log("PHASE 2: Full Disease Set (10 images each)"); + console.log("─".repeat(60)); + + for (let i = 0; i < fullDiseases.length; i++) { + const d = fullDiseases[i]; + const classDir = resolve(DATASET_DIR, d.id); + const queries = buildSearchQueries(d); + const existingUrls = d.imageUrl ? [d.imageUrl] : []; + + const pct = Math.round((i / fullDiseases.length) * 100); + console.log(`\n[${i + 1}/${fullDiseases.length}] (${pct}%) ${d.id} (${d.plantId})`); + + await collectClassImages(d.id, queries, TARGET_FULL, progress, classDir, existingUrls, true); + } + + // ── Phase 3: Healthy class ────────────────────────────────────────────── + + console.log("\n" + "─".repeat(60)); + console.log("PHASE 3: Healthy Plant Images"); console.log("─".repeat(60)); const healthyDir = resolve(DATASET_DIR, HEALTHY_CLASS); @@ -520,39 +686,50 @@ async function main() { const healthySeen = new Set(healthyCp.seenUrls); if (healthyCp.count >= TARGET_HEALTHY) { - console.log(`\n ✓ Already have ${healthyCp.count}/${TARGET_HEALTHY} healthy images`); + console.log(`\n ✓ Already have ${healthyCp.count}/${TARGET_HEALTHY}`); } else { - // Build a pool of healthy plant queries + // Collect all unique plants + const allPlants = [...new Set(dbDiseases.map((d) => d.plantId))]; const allHealthyQueries: string[] = []; - for (const plant of plants) { + for (const plant of allPlants) { allHealthyQueries.push(...buildHealthyQueries(plant)); } + const healthySources = [ + { name: "DDG", collector: collectImagesDuckDuckGo }, + { name: "iNat", collector: searchImagesInaturalist }, + { name: "Commons", collector: searchImagesCommons }, + ] as const; + const totalHealthyUrls: string[] = []; - let healthyExhausted = false; + let anyRemaining = false; - for (const query of allHealthyQueries) { + for (const source of healthySources) { if (totalHealthyUrls.length >= TARGET_HEALTHY) break; - if (healthyExhausted) break; + console.log(`\n Source: ${source.name}`); - console.log(`\n Searching: "${query}"...`); - const result = await collectImages( - query, - TARGET_HEALTHY - totalHealthyUrls.length, - healthySeen, - ); + for (const query of allHealthyQueries.slice(0, 20)) { + if (totalHealthyUrls.length >= TARGET_HEALTHY) break; - totalHealthyUrls.push(...result.urls); - - if (result.exhausted) { - healthyExhausted = true; + process.stdout.write(` "${query}"... `); + const result = await source.collector( + query, + TARGET_HEALTHY - totalHealthyUrls.length, + healthySeen, + ); + totalHealthyUrls.push(...result.urls); + if (!result.exhausted) anyRemaining = true; + console.log(`${result.urls.length} new`); } } healthyCp.seenUrls = Array.from(healthySeen); if (totalHealthyUrls.length > 0) { - console.log(`\n Found ${totalHealthyUrls.length} healthy image URLs. Downloading...`); + healthyCp.exhausted = !anyRemaining; + saveProgress(progress); + + console.log(`\n Downloading ${totalHealthyUrls.length} healthy images...`); const { downloaded, failed } = await downloadBatch( totalHealthyUrls, healthyDir, @@ -562,14 +739,12 @@ async function main() { healthyCp.count += downloaded; healthyCp.downloaded += downloaded; healthyCp.failed += failed; - healthyCp.exhausted = healthyExhausted; const pct = Math.round((healthyCp.count / TARGET_HEALTHY) * 100); console.log( - ` Got ${downloaded} images (${failed} failed). Total: ${healthyCp.count}/${TARGET_HEALTHY} (${pct}%)`, + ` Got ${downloaded} images. Total: ${healthyCp.count}/${TARGET_HEALTHY} (${pct}%)`, ); } else { - healthyCp.exhausted = true; console.log(` ✗ No healthy images found`); } @@ -580,76 +755,27 @@ async function main() { const elapsed = Math.round((Date.now() - startTime) / 1000); const mins = Math.floor(elapsed / 60); - const secs = elapsed % 60; + const hrs = Math.floor(mins / 60); let totalDownloaded = 0; let totalFailed = 0; - let totalTarget = 0; - - for (const [classId, cp] of Object.entries(progress.classes)) { + for (const [, cp] of Object.entries(progress.classes)) { totalDownloaded += cp.downloaded || 0; totalFailed += cp.failed || 0; - totalTarget += classId === HEALTHY_CLASS ? TARGET_HEALTHY : TARGET_PER_DISEASE; } - const totalSize = await getDatasetSize(); - const sizeGb = (totalSize / (1024 * 1024 * 1024)).toFixed(2); - console.log("\n" + "=".repeat(60)); console.log("COMPLETE"); console.log("=".repeat(60)); - console.log(` Time: ${mins}m ${secs}s`); + console.log(` Time: ${hrs}h ${mins % 60}m`); console.log(` Downloaded: ${totalDownloaded} images`); console.log(` Failed: ${totalFailed} images`); - console.log(` Target: ${totalTarget} images`); - console.log(` Dataset size: ${sizeGb} GB`); - console.log(` Dataset location: ${DATASET_DIR}/`); - console.log(""); - console.log("Next steps:"); - console.log(" 1. Run the fine-tuning script to train on this dataset"); - console.log(" 2. The fine-tuning script will resize to 160×160 and augment"); + console.log(` Dataset: ${DATASET_DIR}/`); + + await closeDb(); console.log("=".repeat(60)); } -/** - * Calculate total size of the dataset directory. - */ -async function getDatasetSize(): Promise { - let total = 0; - if (!existsSync(DATASET_DIR)) return 0; - - const entries = readdirSync(DATASET_DIR, { withFileTypes: true }); - - for (const entry of entries) { - if (!entry.name.startsWith(".")) { - const fullPath = resolve(DATASET_DIR, entry.name); - if (entry.isDirectory()) { - total += dirSize(fullPath); - } - } - } - - return total; -} - -function dirSize(dirPath: string): number { - let total = 0; - try { - const entries = readdirSync(dirPath, { withFileTypes: true }); - for (const entry of entries) { - const fullPath = join(dirPath, entry.name); - if (entry.isFile()) { - total += statSync(fullPath).size; - } else if (entry.isDirectory()) { - total += dirSize(fullPath); - } - } - } catch { - // skip errors - } - return total; -} - function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } diff --git a/apps/web/src/app/api/flag/report/route.ts b/apps/web/src/app/api/flag/report/route.ts new file mode 100644 index 0000000..b12fc6b --- /dev/null +++ b/apps/web/src/app/api/flag/report/route.ts @@ -0,0 +1,143 @@ +import { NextResponse } from "next/server"; +import { getDb } from "@/lib/db/index"; +import { flaggedContent, plants, diseases } from "@/lib/db/schema"; +import { inArray, sql } from "drizzle-orm"; + +/** + * GET /api/flag/report + * + * Returns all flagged content grouped by content type, with resolved + * plant/disease names for readability. Used by the generate-flagged-report script. + * + * Query params: + * minFlags - Optional minimum flag count to include (default: 1) + */ +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url); + const minFlags = parseInt(searchParams.get("minFlags") ?? "1", 10); + + const db = getDb(); + + // Get all flagged entries + const rows = await db + .select() + .from(flaggedContent) + .where(sql`flag_count >= ${minFlags}`) + .orderBy(flaggedContent.contentType, flaggedContent.flagCount); + + if (rows.length === 0) { + return NextResponse.json({ + total: 0, + groups: {}, + items: [], + }); + } + + // Resolve plant/disease names + const plantIds = new Set(); + const diseaseIds = new Set(); + + for (const row of rows) { + if (row.contentType === "plant_image") { + plantIds.add(row.contentId); + } else { + diseaseIds.add(row.contentId); + } + } + + // Fetch plant names + const plantMap = new Map(); + if (plantIds.size > 0) { + const plantRows = await db + .select({ id: plants.id, name: plants.commonName }) + .from(plants) + .where(inArray(plants.id, [...plantIds])); + for (const p of plantRows) { + plantMap.set(p.id, p.name); + } + } + + // Fetch disease names + their plant references + const diseaseMap = new Map(); + if (diseaseIds.size > 0) { + const diseaseRows = await db + .select({ + id: diseases.id, + name: diseases.name, + plantId: diseases.plantId, + }) + .from(diseases) + .where(inArray(diseases.id, [...diseaseIds])); + for (const d of diseaseRows) { + diseaseMap.set(d.id, { name: d.name, plantId: d.plantId }); + } + // Fetch plants for diseases that we don't already have + for (const d of diseaseRows) { + if (!plantMap.has(d.plantId)) { + plantIds.add(d.plantId); + } + } + if (plantIds.size > 0) { + const plantRows = await db + .select({ id: plants.id, name: plants.commonName }) + .from(plants) + .where(inArray(plants.id, [...plantIds])); + for (const p of plantRows) { + plantMap.set(p.id, p.name); + } + } + } + + // Group by content type + const groups: Record>> = {}; + for (const row of rows) { + const type = row.contentType; + if (!groups[type]) groups[type] = []; + + let label = row.contentId; + if (type === "plant_image") { + label = plantMap.get(row.contentId) ?? row.contentId; + } else { + const disease = diseaseMap.get(row.contentId); + if (disease) { + const plantName = plantMap.get(disease.plantId) ?? disease.plantId; + label = `${disease.name} (on ${plantName})`; + } + } + + groups[type].push({ + id: row.id, + contentType: row.contentType, + contentId: row.contentId, + fieldName: row.fieldName, + label, + notes: row.notes, + flagCount: row.flagCount, + createdAt: row.createdAt, + updatedAt: row.updatedAt, + }); + } + + return NextResponse.json({ + total: rows.length, + groups, + items: rows.map((row) => ({ + id: row.id, + contentType: row.contentType, + contentId: row.contentId, + fieldName: row.fieldName, + notes: row.notes, + flagCount: row.flagCount, + createdAt: row.createdAt, + updatedAt: row.updatedAt, + })), + }); + } catch (err) { + console.error("[Flag Report] Error fetching flagged content:", err); + return NextResponse.json( + { error: "Internal Server Error", message: "Failed to fetch flagged content", status: 500 }, + { status: 500 }, + ); + } +} diff --git a/apps/web/src/app/api/flag/route.ts b/apps/web/src/app/api/flag/route.ts new file mode 100644 index 0000000..c25ab99 --- /dev/null +++ b/apps/web/src/app/api/flag/route.ts @@ -0,0 +1,147 @@ +import { NextRequest, NextResponse } from "next/server"; +import { eq, and } from "drizzle-orm"; +import { getDb } from "@/lib/db/index"; +import { flaggedContent } from "@/lib/db/schema"; +import { v4 as uuidv4 } from "uuid"; + +/** + * Content types that can be flagged for manual review. + */ +const VALID_CONTENT_TYPES = [ + "plant_image", + "disease_image", + "disease_symptoms", + "disease_causes", + "disease_treatment", + "disease_prevention", +] as const; + +type FlagContentType = (typeof VALID_CONTENT_TYPES)[number]; + +interface FlagRequestBody { + contentType: FlagContentType; + contentId: string; + fieldName: string; + notes?: string; +} + +/** + * POST /api/flag + * + * Flag content for manual review. If the same content_type + content_id + field_name + * combination already exists, increments the flag_count. Otherwise creates a new entry. + * + * Body: + * contentType - Type of content being flagged + * contentId - The ID of the plant or disease + * fieldName - The specific field name (e.g., "image", "symptoms") + * notes - Optional notes/reason for flagging + */ +export async function POST(request: NextRequest) { + try { + const body: FlagRequestBody = await request.json(); + + // ── Validate required fields ── + + if (!body.contentType || !VALID_CONTENT_TYPES.includes(body.contentType)) { + return NextResponse.json( + { + error: "Bad Request", + message: `Invalid contentType. Must be one of: ${VALID_CONTENT_TYPES.join(", ")}`, + status: 400, + }, + { status: 400 }, + ); + } + + if ( + !body.contentId || + typeof body.contentId !== "string" || + body.contentId.trim().length === 0 + ) { + return NextResponse.json( + { error: "Bad Request", message: "contentId is required", status: 400 }, + { status: 400 }, + ); + } + + if ( + !body.fieldName || + typeof body.fieldName !== "string" || + body.fieldName.trim().length === 0 + ) { + return NextResponse.json( + { error: "Bad Request", message: "fieldName is required", status: 400 }, + { status: 400 }, + ); + } + + const db = getDb(); + + // ── Check if this item was already flagged ── + + const existing = await db + .select() + .from(flaggedContent) + .where( + and( + eq(flaggedContent.contentType, body.contentType), + eq(flaggedContent.contentId, body.contentId), + eq(flaggedContent.fieldName, body.fieldName), + ), + ) + .limit(1); + + if (existing.length > 0) { + // Increment flag count and update timestamp + const current = existing[0]; + await db + .update(flaggedContent) + .set({ + flagCount: (current.flagCount ?? 0) + 1, + updatedAt: new Date().toISOString(), + ...(body.notes ? { notes: body.notes } : {}), + }) + .where(eq(flaggedContent.id, current.id)); + + return NextResponse.json({ + success: true, + action: "incremented", + flagCount: (current.flagCount ?? 0) + 1, + message: "Flag count incremented. Thank you for your review input.", + }); + } + + // ── Create new flag entry ── + + const id = uuidv4(); + await db.insert(flaggedContent).values({ + id, + contentType: body.contentType, + contentId: body.contentId, + fieldName: body.fieldName, + notes: body.notes ?? "", + flagCount: 1, + }); + + console.log( + `[Flag] New flag: type=${body.contentType} id=${body.contentId} field=${body.fieldName}`, + ); + + return NextResponse.json( + { + success: true, + action: "created", + flagCount: 1, + message: "Content flagged for manual review. Thank you!", + }, + { status: 201 }, + ); + } catch (err) { + console.error("[Flag] Error flagging content:", err); + return NextResponse.json( + { error: "Internal Server Error", message: "Failed to flag content", status: 500 }, + { status: 500 }, + ); + } +} diff --git a/apps/web/src/app/browse/[plantId]/DiseaseCards.tsx b/apps/web/src/app/browse/[plantId]/DiseaseCards.tsx index 358d349..9d6be50 100644 --- a/apps/web/src/app/browse/[plantId]/DiseaseCards.tsx +++ b/apps/web/src/app/browse/[plantId]/DiseaseCards.tsx @@ -3,6 +3,7 @@ import { useState, useCallback, useMemo } from "react"; import type { Disease, CausalAgentType, Prevalence, Severity } from "@/lib/types"; import ImageLightbox from "@/components/ImageLightbox"; +import FlagButton from "@/components/FlagButton"; // ─── Severity badge ─── @@ -86,7 +87,7 @@ function DiseaseCard({ {/* Disease image or placeholder */} -
+
{disease.imageUrl ? (
+ {/* Flag button for disease image */} +
+ +

{disease.description} @@ -137,9 +148,18 @@ function DiseaseCard({

{/* Symptoms */}
-

- Symptoms -

+
+

+ Symptoms +

+ +
    {disease.symptoms.map((symptom, i) => (
  • -

    - Causes -

    +
    +

    + Causes +

    + +
      {disease.causes.map((cause, i) => (
    • -

      - Treatment Steps -

      +
      +

      + Treatment Steps +

      + +
        {disease.treatment.map((step, i) => (
      1. @@ -187,9 +225,18 @@ function DiseaseCard({ {/* Prevention Tips */}
        -

        - Prevention Tips -

        +
        +

        + Prevention Tips +

        + +
          {disease.prevention.map((tip, i) => (
        • ; @@ -114,6 +115,7 @@ export default async function PlantDetailPage({ params }: Props) {
        )} +
diff --git a/apps/web/src/components/DiseaseCard.tsx b/apps/web/src/components/DiseaseCard.tsx index 6b4327e..f0aab85 100644 --- a/apps/web/src/components/DiseaseCard.tsx +++ b/apps/web/src/components/DiseaseCard.tsx @@ -6,6 +6,7 @@ import ConfidenceBadge, { getConfidenceColors } from "@/components/ConfidenceBad import SymptomChecker from "@/components/SymptomChecker"; import TreatmentTimeline, { treatmentStepsWithUrgency } from "@/components/TreatmentTimeline"; import LookalikeWarning from "@/components/LookalikeWarning"; +import FlagButton from "@/components/FlagButton"; import { getLookalikeDiseases } from "@/lib/api/diseases"; /** @@ -45,15 +46,18 @@ export default function DiseaseCard({
{/* Primary diagnosis ribbon */} {isPrimary && ( -
+
@@ -71,13 +75,16 @@ export default function DiseaseCard({ >
{/* Rank / causal agent icon */} -
+ `} + > {rank}
@@ -93,9 +100,7 @@ export default function DiseaseCard({

{disease.scientificName}

-

- {summary} -

+

{summary}

{/* Expand/collapse chevron */} @@ -105,7 +110,11 @@ export default function DiseaseCard({ fill="currentColor" aria-hidden="true" > - +
@@ -133,17 +142,47 @@ export default function DiseaseCard({ {/* Symptom checker */}
+
+

+ Symptom Checker +

+ +
{/* Causes */}
-

- - Causes & Contributing Factors -

+
+

+ + Causes & Contributing Factors +

+ +
    {disease.causes.map((cause, i) => (
  • @@ -156,12 +195,30 @@ export default function DiseaseCard({ {/* Treatment timeline */}
    -

    - - Treatment Plan -

    +
    +

    + + Treatment Plan +

    + +
    -

    - - Prevention Tips -

    +
    +

    + + Prevention Tips +

    + +
      {disease.prevention.map((tip, i) => (
    • @@ -187,9 +262,7 @@ export default function DiseaseCard({
    {/* Lookalike warnings */} - {lookalikes.length > 0 && ( - - )} + {lookalikes.length > 0 && } {/* Feedback buttons */}
    @@ -203,9 +276,10 @@ export default function DiseaseCard({ className={` inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium transition-colors - ${feedback === "yes" - ? "bg-leaf-green-100 dark:bg-leaf-green-900/50 text-leaf-green-700 dark:text-leaf-green-300 ring-1 ring-leaf-green-300 dark:ring-leaf-green-700" - : "bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700" + ${ + feedback === "yes" + ? "bg-leaf-green-100 dark:bg-leaf-green-900/50 text-leaf-green-700 dark:text-leaf-green-300 ring-1 ring-leaf-green-300 dark:ring-leaf-green-700" + : "bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700" } `} aria-pressed={feedback === "yes"} @@ -221,9 +295,10 @@ export default function DiseaseCard({ className={` inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium transition-colors - ${feedback === "no" - ? "bg-red-100 dark:bg-red-900/50 text-red-700 dark:text-red-300 ring-1 ring-red-300 dark:ring-red-700" - : "bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700" + ${ + feedback === "no" + ? "bg-red-100 dark:bg-red-900/50 text-red-700 dark:text-red-300 ring-1 ring-red-300 dark:ring-red-700" + : "bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700" } `} aria-pressed={feedback === "no"} diff --git a/apps/web/src/components/FlagButton.tsx b/apps/web/src/components/FlagButton.tsx new file mode 100644 index 0000000..bf44037 --- /dev/null +++ b/apps/web/src/components/FlagButton.tsx @@ -0,0 +1,178 @@ +"use client"; + +import { useState, useCallback } from "react"; + +/** + * Content types that can be flagged for manual review. + */ +export type FlagContentType = + | "plant_image" + | "disease_image" + | "disease_symptoms" + | "disease_causes" + | "disease_treatment" + | "disease_prevention"; + +interface FlagButtonProps { + /** Type of content being flagged */ + contentType: FlagContentType; + /** The ID of the plant or disease */ + contentId: string; + /** The specific field name (e.g., "image", "symptoms", "causes", "treatment", "prevention") */ + fieldName: string; + /** Optional human-readable label for display (e.g., "This plant image") */ + label?: string; + /** Optional notes/reason pre-filled for flagging */ + notes?: string; + /** Small variant for inline use */ + small?: boolean; + /** Optional class name override */ + className?: string; +} + +/** + * FlagButton — a small button that lets users flag content for manual review. + * + * When clicked, it POSTs to /api/flag which either creates or increments + * a flag count in the flagged_content table. + * + * Shows visual feedback: "Flagged!" toast-like state for a few seconds. + */ +export default function FlagButton({ + contentType, + contentId, + fieldName, + label, + small = false, + className = "", +}: FlagButtonProps) { + const [state, setState] = useState<"idle" | "loading" | "flagged" | "error">("idle"); + const [flagCount, setFlagCount] = useState(0); + const [errorMsg, setErrorMsg] = useState(""); + + const handleFlag = useCallback(async () => { + if (state === "loading" || state === "flagged") return; + + setState("loading"); + setErrorMsg(""); + + try { + const res = await fetch("/api/flag", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ contentType, contentId, fieldName }), + }); + + if (!res.ok) { + const data = await res.json().catch(() => ({ message: "Failed to flag content" })); + throw new Error(data.message || "Failed to flag content"); + } + + const data = await res.json(); + setFlagCount(data.flagCount ?? 1); + setState("flagged"); + + // Reset back to idle after a moment so user can flag again if needed + setTimeout(() => { + setState("idle"); + }, 3000); + } catch (err) { + setErrorMsg(err instanceof Error ? err.message : "Failed to flag"); + setState("error"); + + setTimeout(() => { + setState("idle"); + setErrorMsg(""); + }, 3000); + } + }, [contentType, contentId, fieldName, state]); + + // ─── Button state styles ──────────────────────────────────────────────────── + + const baseClasses = small + ? "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs font-medium transition-all" + : "inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition-all"; + + const idleClasses = + "text-zinc-400 dark:text-zinc-500 hover:text-amber-600 dark:hover:text-amber-400 hover:bg-amber-50 dark:hover:bg-amber-950/30 border border-transparent hover:border-amber-200 dark:hover:border-amber-800"; + + const loadingClasses = "text-zinc-300 dark:text-zinc-600 cursor-wait"; + + const flaggedClasses = + "text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-950/40 border border-amber-200 dark:border-amber-700"; + + const errorClasses = + "text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-950/40 border border-red-200 dark:border-red-800"; + + const stateClasses = + state === "loading" + ? loadingClasses + : state === "flagged" + ? flaggedClasses + : state === "error" + ? errorClasses + : idleClasses; + + return ( + + ); +} diff --git a/apps/web/src/components/FlagPlantImage.tsx b/apps/web/src/components/FlagPlantImage.tsx new file mode 100644 index 0000000..3770a40 --- /dev/null +++ b/apps/web/src/components/FlagPlantImage.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { useCallback } from "react"; +import FlagButton from "@/components/FlagButton"; + +/** + * Client component wrapper to add a flag button for plant images + * on the detail page (which is a server component). + */ +export default function FlagPlantImage({ plantId }: { plantId: string }) { + const handleClick = useCallback((e: React.MouseEvent) => { + e.stopPropagation(); + }, []); + + return ( +
    + +
    + ); +} diff --git a/apps/web/src/components/PlantCard.tsx b/apps/web/src/components/PlantCard.tsx index 9562daa..0e70198 100644 --- a/apps/web/src/components/PlantCard.tsx +++ b/apps/web/src/components/PlantCard.tsx @@ -1,5 +1,7 @@ import Image from "next/image"; import Link from "next/link"; +import FlagButton from "@/components/FlagButton"; +import { useCallback } from "react"; export interface PlantCardData { id: string; @@ -23,6 +25,11 @@ interface PlantCardProps { * Used on the homepage featured section and browse grid. */ export default function PlantCard({ plant, showDiseaseCount = true }: PlantCardProps) { + const handleFlagClick = useCallback((e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + }, []); + return (
    )} + {/* Flag button overlay at bottom-right of image */} +
    + +
diff --git a/apps/web/src/lib/db/index.ts b/apps/web/src/lib/db/index.ts index 1f48502..84be65a 100644 --- a/apps/web/src/lib/db/index.ts +++ b/apps/web/src/lib/db/index.ts @@ -10,7 +10,14 @@ import { drizzle, type LibSQLDatabase } from "drizzle-orm/libsql"; import { createClient } from "@libsql/client"; import * as schema from "./schema"; -export type { PlantRow, PlantInsert, DiseaseRow, DiseaseInsert } from "./schema"; +export type { + PlantRow, + PlantInsert, + DiseaseRow, + DiseaseInsert, + FlaggedContentRow, + FlaggedContentInsert, +} from "./schema"; export { schema }; diff --git a/apps/web/src/lib/db/schema.ts b/apps/web/src/lib/db/schema.ts index 2216eda..7b4fe42 100644 --- a/apps/web/src/lib/db/schema.ts +++ b/apps/web/src/lib/db/schema.ts @@ -113,6 +113,51 @@ export const plantViews = sqliteTable( }), ); +// ─── Flagged Content Table ───────────────────────────────────────────────── + +/** + * Stores user-flagged content for manual review. + * content_type: what kind of content is flagged + * content_id: the ID of the plant or disease + * field_name: specific field being flagged (e.g., "image", "symptoms", "causes", "treatment", "prevention") + * flag_count: number of times this item has been flagged + */ +export const flaggedContent = sqliteTable( + "flagged_content", + { + id: text("id").primaryKey(), + contentType: text("content_type", { + enum: [ + "plant_image", + "disease_image", + "disease_symptoms", + "disease_causes", + "disease_treatment", + "disease_prevention", + ], + }).notNull(), + contentId: text("content_id").notNull(), + fieldName: text("field_name").notNull(), + notes: text("notes").default(""), + flagCount: integer("flag_count").notNull().default(1), + createdAt: text("created_at") + .notNull() + .default(sql`(datetime('now'))`), + updatedAt: text("updated_at") + .notNull() + .default(sql`(datetime('now'))`), + }, + (table) => ({ + contentTypeIdx: index("idx_flagged_content_type").on(table.contentType), + contentIdIdx: index("idx_flagged_content_id").on(table.contentId), + }), +); + +// ─── Type helpers ──────────────────────────────────────────────────────────── + +export type FlaggedContentRow = typeof flaggedContent.$inferSelect; +export type FlaggedContentInsert = typeof flaggedContent.$inferInsert; + // ─── Relation Inference ────────────────────────────────────────────────────── export const plantsRelations = {};