diff --git a/src/main/java/org/ecocean/api/AgentSkill.java b/src/main/java/org/ecocean/api/AgentSkill.java index aa8680372a..866d65b8a2 100644 --- a/src/main/java/org/ecocean/api/AgentSkill.java +++ b/src/main/java/org/ecocean/api/AgentSkill.java @@ -32,6 +32,7 @@ public class AgentSkill extends ApiBase { m.put("find-misfiled-sightings", "find-misfiled-sightings.md"); m.put("how-good-is-our-matching", "how-good-is-our-matching.md"); m.put("review-id-problems", "review-id-problems.md"); + m.put("inat-to-wildbook-import", "inat-to-wildbook-import.md"); SKILL_RESOURCES = Collections.unmodifiableMap(m); } diff --git a/src/main/resources/agent-skills/inat-to-wildbook-import.md b/src/main/resources/agent-skills/inat-to-wildbook-import.md new file mode 100644 index 0000000000..29a2291337 --- /dev/null +++ b/src/main/resources/agent-skills/inat-to-wildbook-import.md @@ -0,0 +1,66 @@ +--- +name: inat-to-wildbook-import +description: Pull recent iNaturalist sightings of your species, curate them, and prepare them for bulk import into Wildbook. +--- + +# Get iNaturalist sightings into Wildbook + +## When to use this +Use this when the person says things like "get recent iNaturalist observations of my species +ready for Wildbook", "pull last month's jaguar sightings from the Pantanal so I can import them", +or "download weedy seadragon photos from iNaturalist for our catalog." + +## What it does, in plain terms +It downloads recent, wild, photographed sightings of the species you name from iNaturalist, keeps +only the ones suitable for photo identification, downloads the photos, and writes a Wildbook +bulk-import spreadsheet plus a folder of photos. It can also make a simple web page for reviewing +the sightings and unchecking any you don't want before import. It only prepares files — you do the +actual import in Wildbook, and you decide what to keep. + +## What you'll need +Python 3.6 or newer (standard library only; the Pillow package is needed only if you want animated +GIFs handled). The species name(s), and optionally a place and a number of days back. The Wildbook +`locationID` and `submitterID` you want stamped on the encounters. No iNaturalist account and no +Wildbook token are required — this uses the public iNaturalist API and hands the finished files to +Wildbook's Bulk Import page. + +## Where the tool lives +The tool is the public, MIT-licensed repository +`https://github.com/WildMeOrg/inat-download-recent-species-sightings`, pinned to release `v1.0.0`. +Fetch that release — either download `inat-download-new-species-sightings.py` from the `v1.0.0` +tag, or clone the repo and check out `v1.0.0`. Always use the pinned release so results stay +consistent. + +## How to do it +1. Get the tool at the pinned release: + `git clone https://github.com/WildMeOrg/inat-download-recent-species-sightings && cd inat-download-recent-species-sightings && git checkout v1.0.0` + (or download `inat-download-new-species-sightings.py` from the `v1.0.0` tag). +2. Run it for the person's species and scope. Example: + `python3 inat-download-new-species-sightings.py --species "Panthera onca" --days 30 --place "Mato Grosso" --use-locationID "MatoGrosso" --use-submitterID "their_wildbook_username" --html-review --output ./inat_data` + Use `--social-split-observations` for social species where several animals can share one + observation. Drop `--html-review` to write the CSV directly with no review page. +3. If you made the review page, open it and help the person uncheck low-quality or unlicensed + sightings; the page keeps good ones checked and sorted to the top. Export the curated CSV. +4. Hand off for import: tell the person to open Wildbook's **Bulk Import** page, upload the + `photos/` folder, then upload the CSV. Every row is marked `unapproved` so their team verifies + before anything enters analyses. +5. Each row carries `Encounter.otherCatalogNumbers` set to `iNaturalist:`. This is + the back-reference that lets Wildbook recognise a sighting that was already imported, so keep it + in the spreadsheet. + +## How to report results +Speak plainly. Say, for example, "I found 47 jaguar sightings from the Pantanal in the last 30 +days; 39 have open licenses and clear photos and are ready to import." Tell the person where the +CSV and `photos/` folder are, how many rows the spreadsheet has, and the exact next step (upload +the photos then the CSV on Wildbook's Bulk Import page). Never say anything was imported — you only +prepared the files. + +## Cautions +Respect iNaturalist licenses: sightings whose photos have no open license are flagged and left +unchecked — do not import them without the owner's permission. The tool is polite to iNaturalist's +servers (about one request per second); large pulls take a few minutes. Everything is stamped +`unapproved` for the team's own review. This skill cannot import for you and cannot change anything +in Wildbook — the person does the upload. + +## Additional references +- Tool source (MIT): https://github.com/WildMeOrg/inat-download-recent-species-sightings (release `v1.0.0`) diff --git a/src/main/resources/agent-skills/index.md b/src/main/resources/agent-skills/index.md index 35d464eeef..f0f54ed037 100644 --- a/src/main/resources/agent-skills/index.md +++ b/src/main/resources/agent-skills/index.md @@ -1,17 +1,19 @@ -# Wildbook Catalog Helper — Toolbox +# Wildbook Helper — Toolbox -These tools help you check and tidy up your animal photo-ID catalog: spot the same animal recorded -twice, find sightings filed under the wrong animal, and judge how reliable the automatic matching -is. Everything here is **read-only** — the tools only ever suggest; you make the changes in Wildbook. +These tools help you work with your animal photo-ID catalog in two ways: **check and tidy** the +catalog you already have, and **get new sightings into** it. Each tool's page tells your assistant +exactly what to do; you review and make the final decisions in Wildbook. ## What you'll need -A short-lived access token from Wildbook. In Wildbook, open your account menu and choose -**API Access** to create one, then paste **only that token** to your assistant — never your username -or password. The token has an expiration date that may vary by Wildbook; create a fresh one when it stops working. -Full technical detail is in the **api-reference** page (fetch `/api/v3/agent-skill/api-reference`). +Most tools here need a short-lived access token from Wildbook. In Wildbook, open your account menu +and choose **API Access** to create one, then paste **only that token** to your assistant — never +your username or password. The token has an expiration date that may vary by Wildbook; create a +fresh one when it stops working. Full technical detail is in the **api-reference** page (fetch +`/api/v3/agent-skill/api-reference`). The import-prep tools below are the exception — they need no +token, because they only prepare files you upload yourself. -## The toolbox +## Check and tidy your catalog (read-only — the tools only suggest; you make the changes in Wildbook) | Tool | Use this when you want to… | Fetch | |---|---|---| @@ -20,13 +22,22 @@ Full technical detail is in the **api-reference** page (fetch `/api/v3/agent-ski | how-good-is-our-matching | understand how reliable the automatic matching is for a species or site | `/api/v3/agent-skill/how-good-is-our-matching` | | review-id-problems | go through suspected ID problems photo-by-photo and build a to-do list | `/api/v3/agent-skill/review-id-problems` | +## Get sightings into Wildbook (import prep — no token needed) + +| Tool | Use this when you want to… | Fetch | +|---|---|---| +| inat-to-wildbook-import | pull recent iNaturalist sightings of your species and prepare them for bulk import | `/api/v3/agent-skill/inat-to-wildbook-import` | + ## How this works -When you describe one of the tasks above to your AI assistant, it fetches that tool's page and follows the steps there. Each page tells the assistant exactly which catalog information to look up and how to show you what it finds — so you can review and decide. +When you describe one of the tasks above to your AI assistant, it fetches that tool's page and +follows the steps there. Each page tells the assistant exactly what to look up or run and how to +show you what it finds — so you can review and decide. ## Additional references -These tools are only a subset of the types of data management and scientific analysis tasks you can use this API and Wildbook. For more information about Wildbook, see these resources if needed: +These tools are only a subset of the data management and scientific analysis tasks you can do with +this API and Wildbook. For more information about Wildbook, see: - [Wildbook Documentation](https://wildbook.docs.wildme.org/) - [Wildbook Community](https://community.wildme.org/) - [How I AI by Wildbook User Dr. Simon Pierce](https://github.com/simonjpierce/how-i-ai) diff --git a/src/test/java/org/ecocean/api/AgentSkillContentTest.java b/src/test/java/org/ecocean/api/AgentSkillContentTest.java index e24e7b231e..58dd22a366 100644 --- a/src/test/java/org/ecocean/api/AgentSkillContentTest.java +++ b/src/test/java/org/ecocean/api/AgentSkillContentTest.java @@ -166,9 +166,33 @@ static void assertSkillStructure(String stem) { assertTrue(index.contains(n), "index toolbox must list " + n); assertTrue(index.contains("api-reference"), "index must reference api-reference"); // (c) the map's analytical keys are exactly those four (api-reference is the only extra) + assertTrue(AgentSkill.SKILL_RESOURCES.containsKey("inat-to-wildbook-import"), + "the import-prep skill must be registered"); java.util.Set keys = new java.util.HashSet<>(AgentSkill.SKILL_RESOURCES.keySet()); keys.remove("api-reference"); + keys.remove("inat-to-wildbook-import"); assertEquals(new java.util.HashSet<>(java.util.Arrays.asList(analytical)), keys, "the analytical skills in the map must be exactly the four listed in the index"); } + + @Test void inat_to_wildbook_import_is_well_formed() { + String md = load("/agent-skills/inat-to-wildbook-import.md"); + assertFalse(md.isEmpty(), "inat-to-wildbook-import must be non-empty"); + assertTrue(md.contains("name: inat-to-wildbook-import"), + "frontmatter name must equal the file stem"); + for (String s : REQUIRED_SECTIONS) + assertTrue(md.contains(s), "import skill must contain section " + s); + assertTrue(md.contains("github.com/WildMeOrg/inat-download-recent-species-sightings"), + "must point at the public repo"); + assertTrue(md.contains("v1.0.0"), "must pin to the released tag"); + assertTrue(md.contains("Encounter.otherCatalogNumbers"), + "must name the dedup back-reference column"); + assertTrue(md.toLowerCase().contains("bulk import"), + "must hand off to the Wildbook Bulk Import UI"); + assertNoLeak(md); + assertNoJargon(userFacingSections(md)); + // it is an import-prep skill, so it must NOT be forced through the read-only template + assertTrue(load("/agent-skills/index.md").contains("inat-to-wildbook-import"), + "root index must list the import skill"); + } }