mirror of
https://github.com/TheRealOwenRees/plantid-discord-bot.git
synced 2026-07-23 12:36:58 +00:00
follow up messages, separation of identification functions
This commit is contained in:
+3
-1
@@ -2,6 +2,8 @@ import Config
|
|||||||
|
|
||||||
config :plantid_discord_bot,
|
config :plantid_discord_bot,
|
||||||
image_path: "priv/static",
|
image_path: "priv/static",
|
||||||
plantnet_api_base_url: "https://my-api.plantnet.org/v2"
|
plantnet_api_base_url: "https://my-api.plantnet.org/v2",
|
||||||
|
score_threshold: 0.3,
|
||||||
|
max_results: 5
|
||||||
|
|
||||||
import_config "#{config_env()}.exs"
|
import_config "#{config_env()}.exs"
|
||||||
|
|||||||
@@ -3,15 +3,16 @@ defmodule PlantIdDiscordBot.Cog.PlantNet do
|
|||||||
alias PlantIdDiscordBot.RateLimiter
|
alias PlantIdDiscordBot.RateLimiter
|
||||||
alias PlantIdDiscordBot.PlantNet.Parser
|
alias PlantIdDiscordBot.PlantNet.Parser
|
||||||
alias PlantIdDiscordBot.FileServer.File
|
alias PlantIdDiscordBot.FileServer.File
|
||||||
|
alias Nostrum.Api
|
||||||
|
|
||||||
@api Application.compile_env(:plantid_discord_bot, :api)
|
@api Application.compile_env(:plantid_discord_bot, :api)
|
||||||
@plantnet_api_base_url Application.compile_env(:plantid_discord_bot, :plantnet_api_base_url)
|
@plantnet_api_base_url Application.compile_env(:plantid_discord_bot, :plantnet_api_base_url)
|
||||||
|
@plantnet_api_key Application.compile_env(:plantid_discord_bot, :plantnet_api_key)
|
||||||
# TEMP: Mock data
|
@score_threshold Application.compile_env(:plantid_discord_bot, :score_threshold)
|
||||||
@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}"
|
@max_results Application.compile_env(:plantid_discord_bot, :max_results)
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
ID a plant from up to 5 images of organs.
|
Process /id application command.
|
||||||
"""
|
"""
|
||||||
def id(interaction) do
|
def id(interaction) do
|
||||||
case RateLimiter.check_limit(interaction.guild_id) do
|
case RateLimiter.check_limit(interaction.guild_id) do
|
||||||
@@ -30,41 +31,75 @@ defmodule PlantIdDiscordBot.Cog.PlantNet do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp do_identification(interaction) do
|
defp do_identification(interaction) do
|
||||||
|
@api.create_interaction_response(interaction, %{
|
||||||
|
type: 5,
|
||||||
|
data: %{
|
||||||
|
content: "Processing..."
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
attachment_urls = get_attachment_urls(interaction)
|
attachment_urls = get_attachment_urls(interaction)
|
||||||
original_images = get_original_images(attachment_urls)
|
original_images = get_original_images(attachment_urls)
|
||||||
|
|
||||||
# TODO return image filename list as a list of images to delete
|
# FUNCTION return image filename list as a list of images to delete
|
||||||
saved_images =
|
saved_images =
|
||||||
try do
|
try do
|
||||||
File.download_and_save_files!(attachment_urls)
|
File.download_and_save_files!(attachment_urls)
|
||||||
rescue
|
rescue
|
||||||
e ->
|
e ->
|
||||||
@api.create_interaction_response(interaction, %{
|
Api.create_followup_message(interaction.application_id, interaction.token, %{
|
||||||
type: 4,
|
content: e.message
|
||||||
data: %{
|
|
||||||
content: e.message
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
IO.inspect(saved_images)
|
IO.inspect(saved_images)
|
||||||
|
|
||||||
# TODO call PlantNet API and get response, with error handling
|
# TODO use actual image data
|
||||||
|
image1 =
|
||||||
|
"https://upload.wikimedia.org/wikipedia/commons/f/ff/Prunus_cerasifera_A.jpg"
|
||||||
|
|
||||||
# TODO pass this response to the parser as below, with error handling
|
image2 =
|
||||||
|
"https://le-jardin-de-pascal.com/2195113-large_default/prunus-cerasifera-atropurpurea-prunier-myrobolan-nigra.jpg"
|
||||||
|
|
||||||
# temp data
|
images = [image1, image2]
|
||||||
response_message = Parser.parse(@plantnet_raw_response)
|
|
||||||
|
|
||||||
# TODO increase on success (failed id or otherwise)
|
query_uri = build_query_uri(images)
|
||||||
# RateLimiter.increase_counter(guild_id)
|
|
||||||
|
case HTTPoison.get(query_uri) do
|
||||||
|
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
|
||||||
|
response_message = Parser.parse(body)
|
||||||
|
# RateLimiter.increase_counter(guild_id)
|
||||||
|
Api.create_followup_message(interaction.application_id, interaction.token, %{
|
||||||
|
content: response_message
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, %HTTPoison.Response{status_code: 400}} ->
|
||||||
|
# TODO add logger
|
||||||
|
Api.create_followup_message(interaction.application_id, interaction.token, %{
|
||||||
|
content: "Bad Request"
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, %HTTPoison.Response{status_code: 404}} ->
|
||||||
|
# TODO add logger
|
||||||
|
# RateLimiter.increase_counter(guild_id)
|
||||||
|
Api.create_followup_message(interaction.application_id, interaction.token, %{
|
||||||
|
content: "Species Not Found"
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, %HTTPoison.Response{status_code: 429}} ->
|
||||||
|
# TODO add logger
|
||||||
|
Api.create_followup_message(interaction.application_id, interaction.token, %{
|
||||||
|
content: "Too Many Requests"
|
||||||
|
})
|
||||||
|
|
||||||
|
{_, _} ->
|
||||||
|
# TODO add logger
|
||||||
|
Api.create_followup_message(interaction.application_id, interaction.token, %{
|
||||||
|
content: "Internal Server Error"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
# TODO delete saved images
|
# TODO delete saved images
|
||||||
|
|
||||||
@api.create_interaction_response(interaction, %{
|
|
||||||
type: 4,
|
|
||||||
data: %{content: response_message <> "\n#{original_images}"}
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_attachment_urls(interaction) do
|
defp get_attachment_urls(interaction) do
|
||||||
@@ -75,4 +110,18 @@ defmodule PlantIdDiscordBot.Cog.PlantNet do
|
|||||||
|
|
||||||
@spec get_original_images([String.t()]) :: String.t()
|
@spec get_original_images([String.t()]) :: String.t()
|
||||||
defp get_original_images(attachment_urls), do: Enum.join(attachment_urls, "\n")
|
defp get_original_images(attachment_urls), do: Enum.join(attachment_urls, "\n")
|
||||||
|
|
||||||
|
@spec build_query_uri([String.t()]) :: String.t()
|
||||||
|
defp build_query_uri(image_filenames) do
|
||||||
|
identify_api_url = "#{@plantnet_api_base_url}/identify/all?api-key=#{@plantnet_api_key}"
|
||||||
|
|
||||||
|
query_uri =
|
||||||
|
URI.append_query(
|
||||||
|
URI.parse(identify_api_url),
|
||||||
|
"images=#{Enum.join(image_filenames, "&images=")}"
|
||||||
|
)
|
||||||
|
|> URI.append_query("nb-results=#{@max_results}")
|
||||||
|
|> URI.append_query("type=kt")
|
||||||
|
|> URI.to_string()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ defmodule PlantIdDiscordBot.FileServer.File do
|
|||||||
|> File.read()
|
|> File.read()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec delete_file!(String.t()) :: :ok
|
||||||
|
def delete_file!(filename) do
|
||||||
|
File.rm!(Path.join(@image_path, filename))
|
||||||
|
end
|
||||||
|
|
||||||
@spec download_file!(String.t()) :: binary
|
@spec download_file!(String.t()) :: binary
|
||||||
defp download_file!(url) do
|
defp download_file!(url) do
|
||||||
HTTPoison.get!(url)
|
HTTPoison.get!(url)
|
||||||
|
|||||||
Reference in New Issue
Block a user