#!/usr/bin/python3.10 # -*- coding: utf-8 -*- """************************ AnkIdentification - A project to improve your plant identifcation skills through Anki. Aurélien VALENTIN - from 06/11/2022 to 29/12/2022 ************************""" # Default parameters, feel free to change them as you want. NB_SPECIES = ( 50 # Number of species wanted by the user. Can't exceed 100 with the GBIF method. ) LANGUAGE = "fr" # Please choose "fr" or "en" to get respectively French or English vernacular names. SPECIE_LIST_PATH_IF_GBIF_METHOD = "" # A csv file from https://identify.plantnet.org/prediction. Only if you've chosen the GBIF method. MY_OWN_LIST_PATH = "" # A txt file with one specie by line. Be careful to write the scientific name used in Pl@ntNet and change NB_SPECIES if needed. MAX_NB_OF_LINKS_BY_TYPE_AND_BY_SPECIES = 100 # The code will accumulate links of pictures of leaves, flower, fruits and barks of eache species. # The most photos you want, the most diversified your learning will be, but the longer it will take to load... # Importation and other initialisations import json, sys import genanki # https://github.com/kerrickstaley/genanki.git from random import shuffle dict_common_plants = {} with open("_dict_species.json", "r") as fpi: dict_common_names = json.load(fpi) # From the 3-1 and 3-2 supplementary codes # Definition of the progressbar function, from https://gist.github.com/ChesterChowWOV/2b35c551b339adbf459363322aac5b4b def progressbar(it, prefix="", size=60, file=sys.stdout): count = len(it) def show(j): x = int(size * j / count) file.write( "{}[{}{}] {}/{} {}%\r".format( prefix, "█" * x, "." * (size - x), j, count, round(j / count * 100, 2) ) ) file.flush() show(0) for i, item in enumerate(it): yield item show(i + 1) file.write("\n") file.flush() """************************ Step 1 : Listing the most common species (if without a manual list or a GBIF file). ************************""" if SPECIE_LIST_PATH_IF_GBIF_METHOD == MY_OWN_LIST_PATH: print("Listing the most common species") # Loading of the whole list with open("_dict_species_by_rarety.json") as fpi: dict_plants_sorted = json.load(fpi) # From the first supplementary code # Writing of the user's list with open("Selected_species.txt", "w") as fpo: for species in list(dict_plants_sorted.keys())[:NB_SPECIES]: fpo.write(species + "\n") """************************ Step 2 : Parsing data for each species. ************************""" # Initialisation of the dictionary (and addition of the family) from a file from the step 1... if SPECIE_LIST_PATH_IF_GBIF_METHOD == "": with open("_dict_classification.json", "r") as fpi: dict_classification = json.load(fpi) # From the second supplementary code try: fpi = open(MY_OWN_LIST_PATH) except: fpi = open("Selected_species.txt") for line in progressbar(fpi.readlines(), "Adding families", 40): specie = line.split(" ")[0] + " " + line.split(" ")[1].lower().strip() dict_common_plants[specie] = { "Occurrence": {"leaf": 0, "flower": 0, "fruit": 0, "bark": 0} } try: dict_common_plants[specie]["Family"] = dict_classification[specie] except: dict_common_plants[specie]["Family"] = "Family not found" dict_common_plants[specie]["Links"] = { "leaf": "", "flower": "", "fruit": "", "bark": "", } dict_common_plants[specie]["Authors"] = { "leaf": "", "flower": "", "fruit": "", "bark": "", } # ...or from a GBIF file from here : https://identify.plantnet.org/prediction else: with open(SPECIE_LIST_PATH_IF_GBIF_METHOD) as fpi: fpi.readline() for line in progressbar(fpi.readlines(), "Adding families", 40): specie = ( line.split(",")[1].split(" ")[0] + " " + line.split(",")[1].split(" ")[1] ) dict_common_plants[specie] = { "Occurrence": {"leaf": 0, "flower": 0, "fruit": 0, "bark": 0} } dict_common_plants[specie]["Family"] = line.split(",")[2] dict_common_plants[specie]["Links"] = { "leaf": "", "flower": "", "fruit": "", "bark": "", } dict_common_plants[specie]["Authors"] = { "leaf": "", "flower": "", "fruit": "", "bark": "", } # Addition of vernacular name(s) for specie in progressbar(dict_common_plants.keys(), "Adding common names", 40): try: dict_common_plants[specie]["Common names"] = dict_common_names[specie][LANGUAGE] except: dict_common_plants[specie]["Common names"] = "No common name found." # Addition of photo links and author names with open("multimedia.txt", encoding="utf-8") as fpi: fpi.readline() for line in progressbar(fpi.readlines(), "Adding links and common names", 40): line_split = line.split("\t") specie = line_split[5].split(" ")[0] + " " + line_split[5].split(" ")[1] link = line_split[3].strip(" ").split("o/")[1] type = line_split[5].split(":")[1].strip(" ") author = line_split[len(line_split) - 1].strip() if specie in dict_common_plants.keys() and type in [ "leaf", "flower", "fruit", "bark", ]: if dict_common_plants[specie]["Occurrence"][type] == 0: dict_common_plants[specie]["Links"][type] += link dict_common_plants[specie]["Authors"][type] += author dict_common_plants[specie]["Occurrence"][type] += 1 elif ( dict_common_plants[specie]["Occurrence"][type] < MAX_NB_OF_LINKS_BY_TYPE_AND_BY_SPECIES + 1 ): dict_common_plants[specie]["Links"][type] += "," + link dict_common_plants[specie]["Authors"][type] += "," + author dict_common_plants[specie]["Occurrence"][type] += 1 """************************ Step 3 : Generation of the Anki deck. ************************""" print("Preparing the Anki deck") # Definition of the Anki card model my_model = genanki.Model( 1091735104, "Model for AnkIdentification", fields=[ {"name": "Name"}, {"name": "Common names"}, {"name": "Family"}, {"name": "Leaf"}, {"name": "Flower"}, {"name": "Fruit"}, {"name": "Bark"}, {"name": "Leaf authors"}, {"name": "Flower authors"}, {"name": "Fruit authors"}, {"name": "Bark authors"}, ], templates=[ { "name": "Card 1", "qfmt": """
""", "afmt": """

{{Name}}


{{Family}}
{{Common names}}
{{FrontSide}}""", "bfont": "Arial" #'Styles': ".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}" }, ], css=".card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n", ) # Creation of the deck my_deck = genanki.Deck(2059400110, "AnkIdentifaction") # Randomization of the species order species_shuffled = list(dict_common_plants.keys()) shuffle(species_shuffled) # Generation of all notes for specie in progressbar(species_shuffled, "Creating notes", 40): dict_specie = dict_common_plants[specie] my_note = genanki.Note( model=my_model, fields=[ specie, dict_specie["Common names"], dict_specie["Family"], dict_specie["Links"]["leaf"], dict_specie["Links"]["flower"], dict_specie["Links"]["fruit"], dict_specie["Links"]["bark"], dict_specie["Authors"]["leaf"], dict_specie["Authors"]["flower"], dict_specie["Authors"]["fruit"], dict_specie["Authors"]["bark"], ], tags=["AnkIdentification::" + dict_specie["Family"]], ) my_deck.add_note(my_note) # Creation of the final file print("Almost done!") genanki.Package(my_deck).write_to_file("AnkIdentification.apkg") print("Enjoy ^^")