commit 1c4d0fb8affcdfced996be9170b6badf83be019f Author: Owen Date: Fri Dec 13 22:03:26 2024 +0100 initial commit diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f58f4cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +plantid_discord_bot-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..5e4efc2 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# PlantIdDiscordBot diff --git a/config/config.exs b/config/config.exs new file mode 100644 index 0000000..d1186fe --- /dev/null +++ b/config/config.exs @@ -0,0 +1,3 @@ +import Config + +import_config "#{config_env()}.exs" diff --git a/config/dev.exs b/config/dev.exs new file mode 100644 index 0000000..d185989 --- /dev/null +++ b/config/dev.exs @@ -0,0 +1,13 @@ +import Config + +config :plantid_discord_bot, + guild_ids: [1_002_507_312_159_797_318], + start_time: DateTime.utc_now(), + plantnet_api_key: System.get_env("PLANTNET_API_KEY"), + plantnet_api_base_url: "https://my-api.plantnet.org/v2", + image_folder: "priv/static", + fileserver_url: "http://localhost:4321", + port: 4321, + source: "https://github.com/TheRealOwenRees/plantID_discordbot", + invite: + "https://discord.com/api/oauth2/authorize?client_id=948227126094598204&permissions=19520&scope=bot" diff --git a/config/prod.exs b/config/prod.exs new file mode 100644 index 0000000..f3923df --- /dev/null +++ b/config/prod.exs @@ -0,0 +1,13 @@ +import Config + +config :plantid_discord_bot, + guild_ids: [], + start_time: DateTime.utc_now(), + plantnet_api_key: System.get_env("PLANTNET_API_KEY"), + plantnet_api_base_url: "https://my-api.plantnet.org/v2", + image_folder: "priv/static", + fileserver_url: "http://localhost:4321", + port: 4321, + source: "https://github.com/TheRealOwenRees/plantID_discordbot", + invite: + "https://discord.com/api/oauth2/authorize?client_id=948227126094598204&permissions=19520&scope=bot" diff --git a/config/runtime.exs b/config/runtime.exs new file mode 100644 index 0000000..0853604 --- /dev/null +++ b/config/runtime.exs @@ -0,0 +1,21 @@ +import Config + +config :plantid_discord_bot, + guild_ids: [1_002_507_312_159_797_318], + start_time: DateTime.utc_now(), + plantnet_api_key: System.get_env("PLANTNET_API_KEY"), + plantnet_api_base_url: "https://my-api.plantnet.org/v2", + image_folder: "priv/static", + fileserver_url: "http://localhost:4321", + port: 4321, + source: "https://github.com/TheRealOwenRees/plantID_discordbot", + invite: + "https://discord.com/api/oauth2/authorize?client_id=948227126094598204&permissions=19520&scope=bot" + +config :nostrum, + token: System.get_env("DISCORD_TOKEN"), + ffmpeg: nil + +config :logger, :console, + formate: "$time $metadata[$level] $message\n", + level: :info diff --git a/config/test.exs b/config/test.exs new file mode 100644 index 0000000..d185989 --- /dev/null +++ b/config/test.exs @@ -0,0 +1,13 @@ +import Config + +config :plantid_discord_bot, + guild_ids: [1_002_507_312_159_797_318], + start_time: DateTime.utc_now(), + plantnet_api_key: System.get_env("PLANTNET_API_KEY"), + plantnet_api_base_url: "https://my-api.plantnet.org/v2", + image_folder: "priv/static", + fileserver_url: "http://localhost:4321", + port: 4321, + source: "https://github.com/TheRealOwenRees/plantID_discordbot", + invite: + "https://discord.com/api/oauth2/authorize?client_id=948227126094598204&permissions=19520&scope=bot" diff --git a/lib/plantid_discord_bot.ex b/lib/plantid_discord_bot.ex new file mode 100644 index 0000000..63762f1 --- /dev/null +++ b/lib/plantid_discord_bot.ex @@ -0,0 +1,18 @@ +defmodule PlantIdDiscordBot do + @moduledoc """ + Documentation for `PlantidDiscordBot`. + """ + + @doc """ + Hello world. + + ## Examples + + iex> PlantidDiscordBot.hello() + :world + + """ + def hello do + :world + end +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..2acf03d --- /dev/null +++ b/mix.exs @@ -0,0 +1,31 @@ +defmodule PlantidDiscordBot.MixProject do + use Mix.Project + + def project do + [ + app: :plantid_discord_bot, + version: "0.1.0", + elixir: "~> 1.16", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + {:nostrum, "~> 0.10"}, + {:httpoison, "~> 2.2"}, + {:image, "~> 0.55"}, + {:jason, "~> 1.4"}, + {:plug_cowboy, "~> 2.7"} + ] + end +end diff --git a/mix.lock b/mix.lock new file mode 100644 index 0000000..3ef3a71 --- /dev/null +++ b/mix.lock @@ -0,0 +1,32 @@ +%{ + "castle": {:hex, :castle, "0.3.0", "47b1a550b2348a6d7e60e43ded1df19dca601ed21ef6f267c3dbb1b3a301fbf5", [:mix], [{:forecastle, "~> 0.1.0", [hex: :forecastle, repo: "hexpm", optional: false]}], "hexpm", "dbdc1c171520c4591101938a3d342dec70d36b7f5b102a5c138098581e35fcef"}, + "castore": {:hex, :castore, "1.0.10", "43bbeeac820f16c89f79721af1b3e092399b3a1ecc8df1a472738fd853574911", [:mix], [], "hexpm", "1b0b7ea14d889d9ea21202c43a4fa015eb913021cb535e8ed91946f4b77a8848"}, + "cc_precompiler": {:hex, :cc_precompiler, "0.1.10", "47c9c08d8869cf09b41da36538f62bc1abd3e19e41701c2cea2675b53c704258", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f6e046254e53cd6b41c6bacd70ae728011aa82b2742a80d6e2214855c6e06b22"}, + "certifi": {:hex, :certifi, "2.13.0", "e52be248590050b2dd33b0bb274b56678f9068e67805dca8aa8b1ccdb016bbf6", [:rebar3], [], "hexpm", "8f3d9533a0f06070afdfd5d596b32e21c6580667a492891851b0e2737bc507a1"}, + "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, + "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"}, + "forecastle": {:hex, :forecastle, "0.1.2", "f8dab08962c7a33010ebd39182513129f17b8814aa16fa453ddd536040882daf", [:mix], [], "hexpm", "8efaeb2e7d0fa24c605605e42562e2dbb0ffd11dc1dd99ef77d78884536ce501"}, + "gun": {:hex, :gun, "2.1.0", "b4e4cbbf3026d21981c447e9e7ca856766046eff693720ba43114d7f5de36e87", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "52fc7fc246bfc3b00e01aea1c2854c70a366348574ab50c57dfe796d24a0101d"}, + "hackney": {:hex, :hackney, "1.17.1", "08463f93d2cc1a03817bf28d8dae6021543f773bd436c9377047224856c4422c", [:rebar3], [{:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "~> 3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "d2cba9e3c8103ad0320623e9f1c33e8d378a15eaabe2ee8ae441898f3d35a18c"}, + "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "image": {:hex, :image, "0.55.2", "f21b5341ee05dfe2e0f649c34c6335cbce44be55e3ce3ced404ac008bef6c335", [:mix], [{:bumblebee, "~> 0.3", [hex: :bumblebee, repo: "hexpm", optional: true]}, {:evision, "~> 0.1.33 or ~> 0.2", [hex: :evision, repo: "hexpm", optional: true]}, {:exla, "~> 0.5", [hex: :exla, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:kino, "~> 0.13", [hex: :kino, repo: "hexpm", optional: true]}, {:nx, "~> 0.7", [hex: :nx, repo: "hexpm", optional: true]}, {:nx_image, "~> 0.1", [hex: :nx_image, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.1 or ~> 3.2 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: true]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: true]}, {:rustler, "> 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:scholar, "~> 0.3", [hex: :scholar, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}, {:vix, "~> 0.23", [hex: :vix, repo: "hexpm", optional: false]}], "hexpm", "aa126e45b514810d1af89eded505ed3e523acefbb005f6220f8fbc1955904607"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, + "nostrum": {:hex, :nostrum, "0.10.0", "c54395970ee630cf577472f13baad1fb8eb02b7cd48868bc62b8a8a153d62cde", [:mix], [{:castle, "~> 0.3.0", [hex: :castle, repo: "hexpm", optional: false]}, {:certifi, "~> 2.13", [hex: :certifi, repo: "hexpm", optional: false]}, {:ezstd, "~> 1.1", [hex: :ezstd, repo: "hexpm", optional: true]}, {:gun, "~> 2.0", [hex: :gun, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm", "dd507bcd7c9bd7a5ec6ee69f9207f8101603caaedd14b204d3be3842d95be948"}, + "parse_trans": {:hex, :parse_trans, "3.4.2", "c352ddc1a0d5e54f9b1654d45f9c432eef76f9cea371c55ddff769ef688fdb74", [:rebar3], [], "hexpm", "4c25347de3b7c35732d32e69ab43d1ceee0beae3f3b3ade1b59cbd3dd224d9ca"}, + "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.2", "fdadb973799ae691bf9ecad99125b16625b1c6039999da5fe544d99218e662e4", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "245d8a11ee2306094840c000e8816f0cbed69a23fc0ac2bcf8d7835ae019bb2f"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, + "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, + "vix": {:hex, :vix, "0.31.1", "2b1d379393060ee8e4e1f1c9a621811c4091d8f063221c1ff24a41a4f0c97edc", [:make, :mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "766856b52bec222cb5fd301f645a7a9869b61e0ec6e87dc0789ae9657356a8ea"}, +} diff --git a/test/plantid_discord_bot_test.exs b/test/plantid_discord_bot_test.exs new file mode 100644 index 0000000..c99204b --- /dev/null +++ b/test/plantid_discord_bot_test.exs @@ -0,0 +1,8 @@ +defmodule PlantIdDiscordBotTest do + use ExUnit.Case + doctest PlantIdDiscordBot + + test "greets the world" do + assert PlantIdDiscordBot.hello() == :world + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..d816db0 --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1,143 @@ +ExUnit.start() + +defmodule PlantNetFixtures do + def raw_response, do: plantnet_raw_response + def parsed_response, do: plantnet_parsed_response +end + +plantnet_raw_response = + "{\"query\":{\"project\":\"all\",\"images\":[\"https://upload.wikimedia.org/wikipedia/commons/f/ff/Prunus_cerasifera_A.jpg\",\"https://le-jardin-de-pascal.com/2195113-large_default/prunus-cerasifera-atropurpurea-prunier-myrobolan-nigra.jpg\"],\"organs\":[\"auto\",\"auto\"],\"includeRelatedImages\":false,\"noReject\":false},\"language\":\"en\",\"preferedReferential\":\"k-world-flora\",\"bestMatch\":\"Prunus cerasifera Ehrh.\",\"results\":[{\"score\":0.87871,\"species\":{\"scientificNameWithoutAuthor\":\"Prunus cerasifera\",\"scientificNameAuthorship\":\"Ehrh.\",\"genus\":{\"scientificNameWithoutAuthor\":\"Prunus\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Prunus\"},\"family\":{\"scientificNameWithoutAuthor\":\"Rosaceae\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Rosaceae\"},\"commonNames\":[\"Cherry plum, myrobalan\",\"Cherry Plum\",\"Purple-leaf Plum\"],\"scientificName\":\"Prunus cerasifera Ehrh.\"},\"gbif\":{\"id\":\"3021730\"},\"powo\":{\"id\":\"729568-1\"},\"iucn\":{\"id\":\"172162\",\"category\":\"DD\"}},{\"score\":0.31668,\"species\":{\"scientificNameWithoutAuthor\":\"Prunus × cistena\",\"scientificNameAuthorship\":\"N.E.Hansen ex Koehne\",\"genus\":{\"scientificNameWithoutAuthor\":\"Prunus\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Prunus\"},\"family\":{\"scientificNameWithoutAuthor\":\"Rosaceae\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Rosaceae\"},\"commonNames\":[\"Dwarf red-leaf plum\",\"Purple-leaf sand cherry\",\"Purple-leaved sand cherry\"],\"scientificName\":\"Prunus × cistena N.E.Hansen ex Koehne\"},\"gbif\":{\"id\":\"3022465\"},\"powo\":{\"id\":\"2959315-4\"}},{\"score\":0.01801,\"species\":{\"scientificNameWithoutAuthor\":\"Prunus sargentii\",\"scientificNameAuthorship\":\"Rehder\",\"genus\":{\"scientificNameWithoutAuthor\":\"Prunus\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Prunus\"},\"family\":{\"scientificNameWithoutAuthor\":\"Rosaceae\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Rosaceae\"},\"commonNames\":[\"Sargent's cherry\",\"Northern Japanese hill cherry\",\"Sargent’s cherry\"],\"scientificName\":\"Prunus sargentii Rehder\"},\"gbif\":{\"id\":\"3020955\"},\"powo\":{\"id\":\"730239-1\"},\"iucn\":{\"id\":\"64127603\",\"category\":\"LC\"}},{\"score\":0.00896,\"species\":{\"scientificNameWithoutAuthor\":\"Prunus × yedoensis\",\"scientificNameAuthorship\":\"Matsum.\",\"genus\":{\"scientificNameWithoutAuthor\":\"Prunus\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Prunus\"},\"family\":{\"scientificNameWithoutAuthor\":\"Rosaceae\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Rosaceae\"},\"commonNames\":[\"Yoshino cherry\",\"Hybrid cherry\",\"Korean flowering cherry\"],\"scientificName\":\"Prunus × yedoensis Matsum.\"},\"gbif\":{\"id\":\"3021335\"},\"powo\":{\"id\":\"30119904-2\"}},{\"score\":0.00518,\"species\":{\"scientificNameWithoutAuthor\":\"Prunus serrulata\",\"scientificNameAuthorship\":\"Lindl.\",\"genus\":{\"scientificNameWithoutAuthor\":\"Prunus\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Prunus\"},\"family\":{\"scientificNameWithoutAuthor\":\"Rosaceae\",\"scientificNameAuthorship\":\"\",\"scientificName\":\"Rosaceae\"},\"commonNames\":[\"Japanese flowering cherry\",\"Japanese flowering cherry Kwanzan\",\"Tibetan Cherry\"],\"scientificName\":\"Prunus serrulata Lindl.\"},\"gbif\":{\"id\":\"3022609\"},\"powo\":{\"id\":\"730268-1\"},\"iucn\":{\"id\":\"217170511\",\"category\":\"LC\"}}],\"version\":\"2024-11-19 (7.3)\",\"remainingIdentificationRequests\":488}" + +plantnet_parsed_response = [ + %{ + "gbif" => %{"id" => "3021730"}, + "gbif_url" => "https://www.gbif.org/species/3021730", + "iucn" => %{"category" => "DD", "id" => "172162"}, + "pfaf_url" => "https://pfaf.org/user/Plant.aspx?LatinName=/Prunus+cerasifera", + "powo" => %{"id" => "729568-1"}, + "powo_url" => "https://powo.science.kew.org/taxon/729568-1", + "score" => 0.87871, + "species" => %{ + "commonNames" => ["Cherry plum, myrobalan", "Cherry Plum", "Purple-leaf Plum"], + "family" => %{ + "scientificName" => "Rosaceae", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Rosaceae" + }, + "genus" => %{ + "scientificName" => "Prunus", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Prunus" + }, + "scientificName" => "Prunus cerasifera Ehrh.", + "scientificNameAuthorship" => "Ehrh.", + "scientificNameWithoutAuthor" => "Prunus cerasifera" + } + }, + %{ + "gbif" => %{"id" => "3022465"}, + "gbif_url" => "https://www.gbif.org/species/3022465", + "pfaf_url" => "https://pfaf.org/user/Plant.aspx?LatinName=/Prunus+×+cistena", + "powo" => %{"id" => "2959315-4"}, + "powo_url" => "https://powo.science.kew.org/taxon/2959315-4", + "score" => 0.31668, + "species" => %{ + "commonNames" => [ + "Dwarf red-leaf plum", + "Purple-leaf sand cherry", + "Purple-leaved sand cherry" + ], + "family" => %{ + "scientificName" => "Rosaceae", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Rosaceae" + }, + "genus" => %{ + "scientificName" => "Prunus", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Prunus" + }, + "scientificName" => "Prunus × cistena N.E.Hansen ex Koehne", + "scientificNameAuthorship" => "N.E.Hansen ex Koehne", + "scientificNameWithoutAuthor" => "Prunus × cistena" + } + }, + %{ + "gbif" => %{"id" => "3020955"}, + "gbif_url" => "https://www.gbif.org/species/3020955", + "iucn" => %{"category" => "LC", "id" => "64127603"}, + "pfaf_url" => "https://pfaf.org/user/Plant.aspx?LatinName=/Prunus+sargentii", + "powo" => %{"id" => "730239-1"}, + "powo_url" => "https://powo.science.kew.org/taxon/730239-1", + "score" => 0.01801, + "species" => %{ + "commonNames" => ["Sargent's cherry", "Northern Japanese hill cherry", "Sargent’s cherry"], + "family" => %{ + "scientificName" => "Rosaceae", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Rosaceae" + }, + "genus" => %{ + "scientificName" => "Prunus", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Prunus" + }, + "scientificName" => "Prunus sargentii Rehder", + "scientificNameAuthorship" => "Rehder", + "scientificNameWithoutAuthor" => "Prunus sargentii" + } + }, + %{ + "gbif" => %{"id" => "3021335"}, + "gbif_url" => "https://www.gbif.org/species/3021335", + "pfaf_url" => "https://pfaf.org/user/Plant.aspx?LatinName=/Prunus+×+yedoensis", + "powo" => %{"id" => "30119904-2"}, + "powo_url" => "https://powo.science.kew.org/taxon/30119904-2", + "score" => 0.00896, + "species" => %{ + "commonNames" => ["Yoshino cherry", "Hybrid cherry", "Korean flowering cherry"], + "family" => %{ + "scientificName" => "Rosaceae", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Rosaceae" + }, + "genus" => %{ + "scientificName" => "Prunus", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Prunus" + }, + "scientificName" => "Prunus × yedoensis Matsum.", + "scientificNameAuthorship" => "Matsum.", + "scientificNameWithoutAuthor" => "Prunus × yedoensis" + } + }, + %{ + "gbif" => %{"id" => "3022609"}, + "gbif_url" => "https://www.gbif.org/species/3022609", + "iucn" => %{"category" => "LC", "id" => "217170511"}, + "pfaf_url" => "https://pfaf.org/user/Plant.aspx?LatinName=/Prunus+serrulata", + "powo" => %{"id" => "730268-1"}, + "powo_url" => "https://powo.science.kew.org/taxon/730268-1", + "score" => 0.00518, + "species" => %{ + "commonNames" => [ + "Japanese flowering cherry", + "Japanese flowering cherry Kwanzan", + "Tibetan Cherry" + ], + "family" => %{ + "scientificName" => "Rosaceae", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Rosaceae" + }, + "genus" => %{ + "scientificName" => "Prunus", + "scientificNameAuthorship" => "", + "scientificNameWithoutAuthor" => "Prunus" + }, + "scientificName" => "Prunus serrulata Lindl.", + "scientificNameAuthorship" => "Lindl.", + "scientificNameWithoutAuthor" => "Prunus serrulata" + } + } +]