Upload main files

This commit is contained in:
Darmstadtium 2022-12-29 18:43:40 +01:00
parent 700535092a
commit 7ea5c0c9d7
3 changed files with 357 additions and 0 deletions

1
_dict_species.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

355
main.py Normal file
View File

@ -0,0 +1,355 @@
#!/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 = 100 # 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.
# 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] < 101:
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': """<style>
.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
body{
margin:0;
}
input{
position:absolute;top:0;left:0;
}
#fullscreen{
position:fixed;
top:0;bottom:0;
left:0;right:0;
background-color:rgba(0,0,0,0.7);
display:none;
}
#fImg{
position:absolute;
top:0;
bottom:0;left:0;right:0;
margin:auto;
max-width:100%;
max-height:100%;
}
#container{
display: flex;
width: 100vw;
height: 98vh;
padding: 1vh 0 1vh 0vh;
flex-wrap: wrap;
background-color:black;
}
td{
border: 1px solid;
}
#container>img {
width: 49%;
height:49%;
padding:1px;
object-fit: contain;
}
.half{
display: block;
height: 35vh;
}
</style>
<input type="button" id="qButton" value="" onclick="qSwitch()">
<div id="fullscreen"><img id="fImg"/></div>
<div id=container></div>
<script>
//once
if(typeof o=='undefined'){
var o={};
var quality=3;
var prevName='';
var isRecto=true;
var qTab=["s","m","o","a"];
var qTab2=["150x150","600x600","Original","Automatic"];
var lastRelease=0;
var lastPress=0;
//Quality switcher
function qSwitch(){
quality=(quality+1)%4;
for (const k in o) {
chgImg(o[k],0);
qButton.value=qTab2[quality];
}
}
//fullscreen
function fullscreenImg(img){
fImg.src='https://bs.plantnet.org/image/o/'+img.t[img.i];
fImg.title="Author :\\n"+img.a[img.i];
fullscreen.style.display='block';
}
function deFullscreenImg(){
fImg.src="";
fullscreen.style.display='none';
}
//click handling
function mDown(e){
setTimeout(function(){
if(Date.now()-lastRelease>=500){
chgImg(e.target,-1);
}
},500);
lastPress=Date.now();
}
function mUp(e){
if(e.button==0){
if(Date.now()-lastPress<500){
chgImg(e.target,1);
}
}else if(e.button==2){
if(Date.now()-lastPress<500){
fullscreenImg(e.target);
}
}
lastRelease=Date.now();
}
function chgImg(img,n){
img.i=(img.i+n)%img.t.length;
if(img.i<0){img.i=img.t.length-1;}
img.title="Author :\\n"+img.a[img.i];
if(qTab[quality]!='a'){
img.srcset='';
img.src='https://bs.plantnet.org/image/'+qTab[quality]+'/'+img.t[img.i];
}else{
img.srcset='https://bs.plantnet.org/image/s/'+img.t[img.i]+' 600w,'+'https://bs.plantnet.org/image/m/'+img.t[img.i]+' 2400w,'+'https://bs.plantnet.org/image/o/'+img.t[img.i]+' 4000w';
}
if(img.complete==true){
img.style.opacity=1;
}else{
img.style.opacity=0.5;
}
}
function imgLoad(e){
e.target.style.opacity=1;
}
//main show
function prepImg(list,author,id){
if(isRecto){
img=document.createElement('img');
img.t=list.replace(/<[^>]*>?/gm,'').split(',');
img.a=author.replace(/<[^>]*>?/gm,'').split(',');
img.i=Math.floor(Math.random()*img.t.length);
chgImg(img,0);
img.addEventListener('mousedown',mDown);
img.addEventListener('mouseup',mUp);
img.addEventListener('contextmenu',function(e){e.preventDefault();});
img.addEventListener('load',imgLoad);
o[id]=img;
}
container.appendChild(o[id]);
}
}
//init objects (mist be re-done because recto/verso reload)
var fImg=document.getElementById('fImg');
var fullscreen=document.getElementById('fullscreen');
var qButton=document.getElementById('qButton');
var container=document.getElementById('container');
fullscreen.addEventListener('click',deFullscreenImg);
//recto or verso ?
if(prevName=='{{Name}}'){
isRecto=!isRecto;
}else{
isRecto=true;
}
prevName="{{Name}}";
if(isRecto){
qButton.value=qTab2[quality];
}else{
container.style.height="55vh";
qButton.style.display='none';
}
prepImg("{{Leaf}}","{{Leaf authors}}",'Leaf');
prepImg("{{Flower}}","{{Flower authors}}",'Flower');
prepImg("{{Fruit}}","{{Fruit authors}}",'Fruit');
prepImg("{{Bark}}","{{Bark authors}}",'Bark');
</script>""",
'afmt': """<div class="half">
<h1><i>{{Name}}</i></h1>
<br>
<b><i>{{Family}}</i></b>
<br>
{{Common names}}
</div>
{{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 ^^")