Add level

This commit is contained in:
Samuel Ortion 2022-05-26 16:14:55 +02:00
parent a760e2fabc
commit 3e80e68da7
7 changed files with 238 additions and 18 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
venv
config.py
__pycache__
data/
src_audio/

31
app.py
View File

@ -62,17 +62,29 @@ def home():
@app.route("/signup", methods=["GET", "POST"])
def signup():
if request.method == "POST":
message = ""
username = request.form['username']
if username == "":
message += gettext("Username empty. Try to find one.")
email = request.form['email']
if email == "":
message += gettext("Email empty. Please give me one.")
password = request.form['password']
registered_user = User.query.filter_by(user_name=username).first()
if registered_user is None:
if password == "":
message += gettext("You should not use an empty password")
registered_user_by_username = User.query.filter_by(user_name=username).first()
registered_user_by_email = User.query.filter_by(user_email=email).first()
if registered_user_by_username is None and registered_user_by_email is None:
password_hash = generate_password_hash(password)
registered_user = User(user_name=username, user_email=email, user_password=password_hash)
db.session.add(registered_user)
db.session.commit()
else:
return render_template("auth/signup.html", message="Username already used. Try with an other.")
if not registered_user_by_email is None:
message += gettext("Email already used by a user.")
else:
message += gettext("Username already used by a user.")
return render_template("auth/signup.html", message=message)
return redirect(url_for("login"))
elif request.method == "GET":
return render_template("auth/signup.html")
@ -109,9 +121,16 @@ def game():
@app.route("/game/new")
def new_game():
question = Game.new_question()
session["question"] = question
return render_template("game/question.html", question=question)
if not "username" in session:
return redirect(url_for('login'))
user = User.query.filter_by(user_name = session['username']).first()
if user is None:
return redirect(url_for('login'))
else:
level = str(user.user_level)
question = Game.new_question(level)
session["question"] = question
return render_template("game/question.html", question=question)
@app.route("/game/answer", methods=["POST", "GET"])
def game_answer():

View File

@ -0,0 +1,120 @@
{
"1": [
"Buse variable",
"Merle noir",
"Pic vert",
"Rougegorge familier",
"Mouette rieuse",
"Canard colvert",
"Pinson des arbres",
"Moineau domestique",
"Pie bavarde",
"Corneille noire",
"Faisan de Colchide"
],
"2": [
"Grive draine",
"Grande Aigrette",
"Grand Cormoran",
"Foulque macroule",
"Hirondelle rustique",
"Fauvette grisette",
"Troglodyte mignon",
"Bergeronnette grise",
"Choucas des tours",
"Pigeon ramier",
"Rougequeue noir",
"Tourterelle turque"
],
"3": [
"Aigrette garzette",
"Grive litorne",
"Accenteur mouchet",
"Bernache du Canada",
"Pipit farlouse",
"Tourterelle des bois",
"Sittelle torchepot",
"Alouette des champs",
"Coucou gris",
"Corbeau freux",
"Martinet noir",
"Bruant zizi"
],
"4": [
"Grimpereau des jardins",
"Grive musicienne",
"Bruant jaune",
"Bergeronnette des ruisseaux",
"Sterne pierregarin",
"Bruant des roseaux",
"Milan noir",
"Grand Corbeau",
"Fuligule morillon"
],
"5": [
"Gobemouche gris",
"Cigogne blanche",
"Alouette lulu",
"Grive mauvis",
"Tarin des aulnes",
"Chouette hulotte",
"Traquet motteux",
"Milan royal",
"Monticole bleu",
"Canard chipeau"
],
"6": [
"Fuligule milouin",
"Chevalier guignette",
"Bouscarle de Cetti",
"Tadorne de Belon",
"Cisticole des joncs",
"Pic noir",
"Nette rousse",
"Petit Gravelot",
"Fauvette des jardins",
"Serin cini"
],
"7": [
"Pic mar",
"Perdrix grise",
"Pinson du Nord",
"Bruant proyer",
"Phragmite des joncs",
"Rousserolle effarvatte",
"Pouillot fitis",
"Faucon hobereau"
],
"8": [
"Fauvette pitchou",
"Busard des roseaux",
"Canard mandarin",
"Spatule blanche",
"Bernache nonnette",
"Torcol fourmilier",
"Effraie des clochers",
"Sittelle corse",
"Perdrix rouge",
"Hirondelle de rochers",
"Hirondelle de rivage"
],
"9": [
"Moineau friquet",
"Bernache cravant",
"Plongeon imbrin",
"Fuligule nyroca",
"Pigeon colombin",
"Grimpereau des bois"
],
"10": [
"Petit-duc scops",
"Chevalier sylvain",
"Chevalier gambette",
"Pipit spioncelle",
"Canard souchet",
"Accenteur alpin",
"Sterne naine",
"Chevalier aboyeur",
"Gobemouche noir"
]
}

22
game.py
View File

@ -1,31 +1,33 @@
import random
import os
from glob import glob
import json
bird_species_folders = list(map(os.path.basename, glob("static/data/src_audio/*")))
with open("./data/level_species_cleaned.json", "r") as f:
LEVEL_SPECIES_LIST = json.load(f)
format_name = lambda folder_name : folder_name.replace('_', ' ')
to_folder_name = lambda species_name : species_name.replace(' ', '_').replace('\'', '').lower()
def get_proposals(question_species_name, n):
def get_proposals(question_species_name, available_species, n):
proposals = [question_species_name]
for i in range(n):
proposition = format_name(random.choice(bird_species_folders))
proposition = random.choice(available_species)
while proposition == question_species_name:
proposition = format_name(random.choice(bird_species_folders))
proposition = random.choice(available_species)
proposals.append(proposition)
random.shuffle(proposals)
return proposals
def new_question():
question_species_folder = random.choice(bird_species_folders)
question_species_name = format_name(question_species_folder)
print(question_species_folder)
def new_question(level):
available_species = LEVEL_SPECIES_LIST[level]
question_species_name = random.choice(available_species)
question_species_folder = to_folder_name(question_species_name)
question = {}
audio_paths = list(map(os.path.basename, glob(f"static/data/src_audio/{question_species_folder}/*.mp3")))
print(audio_paths)
audio_path = random.choice(audio_paths)
question["species"] = question_species_name
question["species_folder"] = question_species_folder
question["audio_path"] = audio_path
question["proposals"] = get_proposals(question_species_name, 5)
question["proposals"] = get_proposals(question_species_name, available_species, 5)
return question

View File

@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block content %}
<audio src="/static/data/src_audio/{{ question['species_folder'] }}/{{ question['audio_path'] }}" controls></audio>
<audio src="/static/data/src_audio/{{ question['species_folder'] }}/{{ question['audio_path'] }}" controls autoplay></audio>
<form action="/game/answer" method="POST">
<select name="answer" id="answer">
{% for item in question['proposals'] %}

33
utils/convert_levels.py Normal file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env python3
"""Update levels species folowing the folder names"""
import json
import glob
import os
SPECIES_FOLDER_NAMES = list(map(os.path.basename, glob.glob("./static/data/src_audio/*")))
def filter(species, condition):
keeped = []
for name in species:
if condition(name):
keeped.append(name)
return keeped
def only_matched_folder(species_name):
folder_like_name = species_name.replace(' ', '_').replace('\'', '')
folder_like_name = folder_like_name.lower()
return folder_like_name in SPECIES_FOLDER_NAMES
def main():
with open("./data/level_species.json", "r") as f:
data = json.load(f)
for level in data:
species_list = data[level]
species_list = filter(species_list, only_matched_folder)
data[level] = species_list
with open("./data/level_species_cleaned.json", "w") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
if __name__ == "__main__":
main()

46
utils/generate_levels.py Normal file
View File

@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Generate species list for each levels"""
import os
import glob
import json
import math
LEVELS = 10
def load_species_sightings(file):
species_sightings = {}
with open(file, "r") as f:
data = json.load(f)
sightings = data['data']['sightings']
counter = 0
for sighting in sightings:
species = sighting["species"]["name"]
if species in species_sightings:
species_sightings[species] += 1
else:
species_sightings[species] = 1
counter += 1
for species in species_sightings:
species_sightings[species] /= counter * 0.01
return species_sightings
def split_species_list(species_sightings):
level_lists = { level: [] for level in range(1, LEVELS + 1)}
species_sorted = sorted(species_sightings, key = lambda species: -species_sightings[species])
species_number = len(species_sorted)
species_per_level = species_number // LEVELS
species_splitted = [species_sorted[i:i+species_per_level] for i in range(0, species_number, species_per_level)]
for level in range(1, LEVELS + 1):
level_lists[level] = species_splitted[level - 1]
return level_lists
def main():
file = "./data/export_26052022_150619.json"
species_frequency = load_species_sightings(file)
level_species = split_species_list(species_frequency)
with open("./data/level_species.json", "w") as f:
json.dump(level_species, f, ensure_ascii=False, indent=4)
if __name__ == "__main__":
main()