Commit f63453d5 authored by Sylvain Coulange's avatar Sylvain Coulange
Browse files

suite mise à jour player

parent 3273cbff
......@@ -7,11 +7,14 @@ from .models import Serie
from .text2speech import lambda_handler
from users.views import saveTraceSynthVoc
from users.models import SynthVocRecord
from users.models import SynthVocRecord, User
from user_agents import parse
from django.db.models import Q
import subprocess, json, os, tempfile
### Chargement de la base de données
dbFile = '../db/db_phonographe.json'
dbPhonographe = {}
......@@ -108,20 +111,11 @@ def openPlayerHome(request):
updateTimeStr = updateTime()
return render(request, 'playerHome.html', {'updateTime': updateTimeStr, 'titrePage': 'phonoplayer'})
from django.core import serializers
def getSeries(request):
series = Serie.objects.all()
seriesMainInfo = []
for s in series:
seriesMainInfo.append({
"code":s.code,
"nom":s.nom,
"auteurIm":s.auteur.profile.image.url,
"auteur":s.auteur.username,
"description":s.description,
"dateCreation":s.dateCreation.strftime("%Y/%m/%d"),
"dateModification":s.dateModification.strftime("%Y/%m/%d %H:%M")
})
return JsonResponse({ "series":seriesMainInfo })
return JsonResponse({"users": serializers.serialize('json', User.objects.all(), fields=("id","username")),
"series":serializers.serialize('json', Serie.objects.all(), fields=('code','nom','auteur','description','dateCreation','dateModification'))})
def infoSerie(request, pk):
s = Serie.objects.filter(code=pk).first()
......
......@@ -53,7 +53,6 @@ urlpatterns = [
path('player/', clavier_views.openPlayerHome, name='home'),
path('player/getSeries/', csrf_exempt(clavier_views.getSeries), name='getSeries'),
#path('player/serie-<str:pk>', clavier_views.SerieDetailView.as_view(), name='serie-page'),
path('player/serie-<str:pk>/info', clavier_views.infoSerie, name='serie-info'),
path('player/serie-<str:pk>/play', clavier_views.openPlayerPhono, name='serie-play'),
path('player/serie-<str:pk>/edit', user_views.editSerie, name='serie-edit'),
......
......@@ -455,6 +455,7 @@ function makeSerieMots(){
"code" : document.getElementById('code').value,
"description" : document.getElementById('description').value,
"auteur" : document.getElementById('auteur').value,
"dateCreation": document.getElementById('dateCreation').value,
"panneau" : "",
"fidel" : "",
......@@ -572,7 +573,7 @@ async function saveSerie(thisSerie, confirm=false) {
// ON EMBALLE TOUT ÇA
var colis = {
serie: thisSerie,
serieOrigin: serie.code,
serieOrigin: serie["code"],
updateExisting: false
}
......
......@@ -104,11 +104,17 @@ function recupPhon(identifiant) {
var repDiv = document.getElementById(ligneCible)
var newCarte = document.createElement('div')
newCarte.classList = "carte " + rectId;// on garde rectId, pour connaître le phonème mais sans appeler les styles de phonochromie-alem.css
newCarte.classList = "carte " + phonId + " noTextClip";// on garde rectId, pour connaître le phonème mais sans appeler les styles de phonochromie-alem.css
newCarte.draggable = true
if (!identifiant.match(/espace/)) { newCarte.style.backgroundImage = "url('/static/cartes/"+ famille +"/"+ phonId + ".jpg')"}
if (!identifiant.match(/espace/)) {
var newCarteIn = document.createElement('div')
newCarteIn.classList = "carteIn"
newCarteIn.style.backgroundImage = `url('../../../media/phonocartes/do_${famille}/${phonId}.png')`; //"url('/static/cartes/"+ famille +"/"+ phonId + ".jpg')"}
newCarte.appendChild(newCarteIn)
}
newCarte.addEventListener("click", function(e) {
var tgt = e.target
var tgt = e.target.parentElement;
playEffect("delete")
tgt.remove()
saveTrace(`del ${famille} ${rectId}`)
......@@ -176,11 +182,11 @@ function loadNext() {
saveTrace(`next ${mots[cptitem]["motGenerique"]}`)
rep.innerHTML = ""
if (audioMode) {
currentAudio = mots[cptitem]["audio"]
currentAudio = mots[cptitem]["audio"] || mots[cptitem]['audioDeb']
playAudio()
}
if (videoMode) {
currentVideo = mots[cptitem]["video"]
currentVideo = mots[cptitem]["video"] || mots[cptitem]['videoDeb']
document.getElementById('videoSrc').src = '../../media/video-uploads/'+currentVideo
document.getElementById('video').load()
playVideo()
......@@ -202,23 +208,69 @@ function loadNext() {
function checkAnswer() {
var mot = mots[cptitem-1]
var phono = mot["phono"] // cptitem-1 parce qu'on a déjà incrémenté cptitem lors de loadNext()
var erreur = false
var erreur = true;
for (i=0; i<rep.children.length; i++) {
var repphon = rep.children[i].classList[1].replace("rect","phon")
if (repphon != phono[i]) {
erreur = true
// console.log(`ERREUR ${repphon} attendu: ${phono[i]}`)
playEffect('wrong')
rep.children[i].classList.add("wrongPhon")
saveTrace(`erreur ${repphon} attendu: ${phono[i]}`)
}
myrep = [];
rep.childNodes.forEach((el) => { myrep.push(el.classList[1].replace("rect","phon")) })
console.log("myrep:",myrep)
if (!Array.isArray(phono[0])) {
// Si premier élément n'est pas isArray, c'est qu'il y a qu'une phono enregistrée (ancienne série), dans ce cas on reformatte en liste de phono [ ["a","b"] ]
phono = [ phono ];
}
if (rep.children.length != phono.length) {
erreur = true
// console.log("ERREUR nb phonèmes")
playEffect('wrong')
saveTrace(`erreur nb phon ${rep.children.length} attendu:${phono.length}`)
comps = [];
phono.forEach( (ref) => {
// pour chaque phono de référence possible
var comp = compareRepRef(myrep,ref);
var newComp = {
"comp": comp,
"nbok": comp.filter(item => item.type==="OK").length,
"correct": comp.filter(item => item.type==="OK").length > 0 && comp.filter(item => item.type==="OK").length == comp.length && comp.filter(item => item.type==="OK").length == ref.length
}
comps.push(newComp)
})
comps.sort((a, b) => { return b.nbok - a.nbok; }); // on met la réponse la plus proche en première (nbok plus grand)
console.log(comps)
comps.forEach( comp => { if (comp.correct) erreur=false })
// COLORATION DES CARTES
for (i=0; i<comps[0].comp.length; i++) {
if (comps[0].comp[i].type == "SUB") rep.childNodes[i].classList.add("subPhon")
else if (comps[0].comp[i].type == "INS") {
rep.childNodes[i].classList.add("insPhon")
} else if (comps[0].comp[i].type == "DEL") {
var newCarte = document.createElement('div')
newCarte.classList = "carte phon_inconnu delPhon noTextClip";// on garde rectId, pour connaître le phonème mais sans appeler les styles de phonochromie-alem.css
newCarte.draggable = true
var newCarteIn = document.createElement('div')
newCarteIn.classList = "carteIn"
newCarteIn.style.backgroundImage = `url('../../../media/phonocartes/do_bouches/phon_inconnu.png')`;
newCarte.appendChild(newCarteIn)
newCarte.addEventListener("click", function(e) {
var tgt = e.target.parentElement;
playEffect("delete")
tgt.remove()
})
newCarte.addEventListener('dragstart', () => {
newCarte.classList.add('dragging')
})
newCarte.addEventListener('dragend', () => {
newCarte.classList.remove('dragging')
let listCartes = []
for (i=0; i<repDiv.children.length; i++) listCartes.push(Array.from(repDiv.children[i].classList).join("."))
// saveTrace(`drag to ${listCartes.join(' ')}`)
})
if (i<=rep.childNodes.length) rep.insertBefore(newCarte, rep.childNodes[i])
else rep.appendChild(newCarte);
}
//else if (comps[0].comp[i].type == "OK") rep.childNodes[i].classList.add("correctPhon")
}
if (!erreur) {
......@@ -226,7 +278,122 @@ function checkAnswer() {
setTimeout(playAudio_R(), 2000)
getBravo(mot)
saveTrace('correct')
} else {
playEffect('wrong')
}
// for (i=0; i<rep.children.length; i++) {
// var repphon = rep.children[i].classList[1].replace("rect","phon")
// if (repphon != phono[i]) {
// erreur = true
// // console.log(`ERREUR ${repphon} attendu: ${phono[i]}`)
// playEffect('wrong')
// rep.children[i].classList.add("wrongPhon")
// saveTrace(`erreur ${repphon} attendu: ${phono[i]}`)
// }
// }
// if (rep.children.length != phono.length) {
// erreur = true
// // console.log("ERREUR nb phonèmes")
// playEffect('wrong')
// saveTrace(`erreur nb phon ${rep.children.length} attendu:${phono.length}`)
// }
// if (!erreur) {
// playEffect("correct")
// setTimeout(playAudio_R(), 2000)
// getBravo(mot)
// saveTrace('correct')
// }
}
function compareRepRef(myrep, ref) {
// inspiré du script python pour calculer le WER https://github.com/imalic3/python-word-error-rate/blob/master/word_error_rate.py
// PREPARATION
// On commence par faire une table au format suivant :
// (r e p)
//
// 0 1 2 3
// (r 1 0 0 0
// e 2 0 0 0
// f) 3 0 0 0
var d = [...Array(ref.length+1).keys()];
d.forEach((row) => { d[row] = [...Array(myrep.length+1).keys()] })
for (i=0; i<d.length; i++) {
for (j=0; j<d[i].length; j++) {
if (i == 0) d[0][j] = j
else if (j == 0) d[i][0] = i
else d[i][j] = 0
}
}
// REMPLISSAGE
// on compare chaque item de myrep avec ref, si == alors on récupère la valeur d[i-1][j-1], sinon on récupère le minimum entre ( d[i-1][j-1]+1 ; d[i][j-1]+1 ; d[i-1][j]+1 )
for (i=1; i<ref.length+1; i++) {
for (j=1; j<myrep.length+1; j++) {
if (ref[i-1] == myrep[j-1]) d[i][j] = d[i-1][j-1]
else {
substitution = d[i - 1][j - 1] + 1
insertion = d[i][j - 1] + 1
deletion = d[i - 1][j] + 1
d[i][j] = Math.min(substitution, insertion, deletion)
}
}
}
// RÉCUPÉRATION DES INS DEL SUB
// comparer les derniers items de myrep et ref, si pas == alors minimum entre ( d[i-1][j-1]+1 (SUB) ; d[i][j-1]+1 (INS) ; d[i-1][j]+1 (DEL) )
x = ref.length
y = myrep.length
resultat = []
while (true) {
if (x == 0 && y == 0) break // FIN
if (y == 0 && x>0) {
x = x - 1
resultat.push({ "item":ref[x], "type":"DEL" })
} else if (x == 0 && y>0) {
y = y - 1
resultat.push({ "item":myrep[y], "type":"INS" })
} else if (ref[x-1] == myrep[y-1]) {
// IDENTIQUE: BONNE RÉPONSE
x = x - 1
y = y - 1
resultat.push({ "item":myrep[y], "type":"OK" })
} else if (d[x][y] == d[x-1][y-1]+1) {
// SUBSTITUTION
x = x - 1
y = y - 1
resultat.push({ "item":myrep[y], "type":"SUB", "ref":ref[x] })
} else if (d[x][y] == d[x - 1][y] + 1) {
// DELETION
x = x - 1
resultat.push({ "item":ref[x], "type":"DEL" })
} else if (d[x][y] == d[x][y - 1] + 1) {
// INSERTION
y = y - 1
resultat.push({ "item":myrep[y], "type":"INS" })
} else {
console.log('We got an error.')
break
}
}
resultat = resultat.reverse()
// Si il y a des insertions avant le début du mot, ils ne rentrent pas dans le tableau donc contrôle supplémentaire
return resultat
}
......
......@@ -17,25 +17,49 @@ async function getSeries() {
// ENVOI
const response = await fetch('/player/getSeries/', options);
const data = await response.json();
console.log(data);
var series = JSON.parse(data.series);
var users = JSON.parse(data.users);
console.log(series);
console.log(users);
document.getElementById('nbSeries').innerHTML = series.length;
document.getElementById('nbSeries').innerHTML = data.series.length;
var myusers = {};
for (i=0; i<users.length; i++){
myusers[users[i].pk] = users[i].fields.username;
}
for (i=0; i<data.series.length; i++){
for (i=0; i<series.length; i++){
document.getElementById("tbody").innerHTML += `
<tr style="cursor: pointer;" onclick="getModalSerieInfo('${data.series[i].code}')">
<th scope="row">${data.series[i].code}</th>
<td>${data.series[i].nom}</td>
<td><img class="rounded-circle serieAuteurImage" src="${data.series[i].auteurIm}"> ${data.series[i].auteur}</td>
<td>${data.series[i].description}</a></td>
<td>${data.series[i].dateCreation}</td>
<td>${data.series[i].dateModification}</td>
<tr style="cursor: pointer;" onclick="getModalSerieInfo('${series[i].fields.code}')">
<th scope="row">${series[i].fields.code}</th>
<td>${series[i].fields.nom}</td>
<td>${ myusers[series[i].fields.auteur] }</td>
<td>${series[i].fields.description}</a></td>
<td>${ formatDate(series[i].fields.dateCreation) }</td>
<td>${ formatDate(series[i].fields.dateModification) }</td>
</tr>`
// <img class="rounded-circle serieAuteurImage" src="${ users[series[i].fields.auteur] }">
}
$('#loader').hide();
$('#seriesTable').DataTable();
}
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('/')+" "+d.getHours()+":"+d.getMinutes();
}
//////////////////////////////////////
////////// PARAMÉTRAGE POPUP /////////
////////// POUR COPIER TEXTE /////////
......@@ -46,7 +70,6 @@ var modal = document.getElementById("modalSerieInfo")
// Fonction pour ouvrir le PopUp
function getModalSerieInfo(code) {
document.getElementById('modalSerieInfoNom').innerHTML = "...";
modal.style.display = "block";
getSerieInfo(code);
}
function closeModalSerieInfo() {
......@@ -83,6 +106,7 @@ async function getSerieInfo(code) {
document.getElementById('modalUrl').innerHTML = "https://phonographe.alem-app.fr/player/serie-"+ data.serieInfo.code +"/play";
document.getElementById('modalBtnPlay').href = window.location.href + "serie-"+ data.serieInfo.code +"/play";
document.getElementById('modalBtnEdit').href = window.location.href + "serie-"+ data.serieInfo.code +"/edit";
modal.style.display = "block";
}
......
......@@ -155,6 +155,26 @@
color: black;
}
.carte {
width: var(--carteWidth);
height: var(--carteHeight);
border: solid 1px black;
border-radius: 5px;
display: inline-block;
position: relative;
margin: 2px;
cursor: grab;
}
.carteIn {
position:absolute;
width:100%;
height:100%;
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
}
.carte {
width: var(--carteWidth);
height: var(--carteHeight);
......@@ -202,6 +222,18 @@
.wrongPhon {
border: solid 4px red;
}
.correctPhon {
border: solid 4px green;
}
.subPhon {
border: solid 4px orange;
}
.insPhon {
border: solid 4px red;
}
.delPhon {
border: dotted white;
}
.playerClavierPhono {
/* max-width: 1000px; */
......
......@@ -20,9 +20,6 @@
<div>
<h2><span id="nbSeries">...</span> <span id="sp_playerHomeListSeriesTitle" class="langspan"></span></h2>
</div>
<!-- <div >
<a href="{% url 'createSerie' %}" style="color:black;text-decoration: none;"><button type="button" class="btn btn-outline-dark"><i class="fa fa-plus-square"></i> Créer une série</button></a>
</div> -->
</div>
<div class="listSeries">
<table class="table table-hover" id="seriesTable" data-order='[[ 4, "desc"]]' data-page-length='30'>
......
......@@ -24,7 +24,7 @@
var video = sc.videoDeb;
var synthvoc = sc.syntheseVocale;
var panneauPartiel = sc.panneauPartiel;
var phonActifs = sc.phonVisibles;
var phonActifs = JSON.parse(sc.phonVisibles);
panneauPartiel = (panneauPartiel==1) ? true : false
synthvoc = (synthvoc==1) ? true : false
let videoMode = false
......
......@@ -210,53 +210,71 @@ def saveSerie(request):
colis = json.loads(request.body)
s = colis['serie']
serieOrigin = colis['serieOrigin']
updateExisting = True #colis['updateExisting']
saveIt = False
print("demande saveSerie",s['code'], serieOrigin)
# Récupère la série existante avec le nom d'origine (dans le cas où on a changé le code, il faut pouvoir updater la série d'origine et pas en créer une nouvelle)
existingSerie = Serie.objects.filter(code=serieOrigin).first()
if existingSerie!="":
if updateExisting:
print("s:",s)
print("existingSerie:",existingSerie)
if existingSerie:
# Si on a bien une série avec ce nom (d'origine) dans la base
if s['dateCreation'] == existingSerie.dateCreation.strftime("%Y-%m-%d %H:%M:%S"):
# Si cette série a bien la même date de création que la série envoyée par le client... c'est que c'est bien la série à updater
if s['code'] != serieOrigin:
# Si le code a changé entre sérieOrigine et série actuelle : Check si une série existe déjà avec le nouveau nom
withNewName = Serie.objects.filter(code=serieOrigin).first()
if withNewName:
print("serie already exists with this new name!")
data = {
'msg': "Une autre série du même nom existe déjà ! Choisissez un autre code de série.",
'saved': False
}
return JsonResponse(data)
print("OK edit existing serie", existingSerie.code, ' (', serieOrigin, ')')
saveIt = True
newSerie = existingSerie
print("OK edit serie", existingSerie.code, ' (', serieOrigin, ')')
targetSerie = existingSerie
else :
print("Série existante: demande édition série", existingSerie.code, ' (', serieOrigin, ')')
# Sinon c'est que le client a mis un nom déjà existant dans une autre série : donc STOP
print("serie exists with other creation date!")
data = {
'alreadyExists': True,
'msg': "Une autre série du même nom existe déjà ! Choisissez un autre code de série.",
'saved': False
}
return JsonResponse(data)
else:
saveIt = True
newSerie = Serie()
print("OK create serie", s['code'], serieOrigin)
targetSerie = Serie()
print("OK create new serie", s['code'], serieOrigin)
if saveIt:
newSerie.nom = s["nom"]
newSerie.code = s["code"]
newSerie.description = s["description"]
newSerie.auteur = User.objects.filter(username=s["auteur"]).first()
newSerie.audioDeb = s["audioDeb"]
newSerie.imageDeb = s["imageDeb"]
newSerie.videoDeb = s["videoDeb"]
newSerie.graphieDeb = s["graphieDeb"]
targetSerie.nom = s["nom"]
targetSerie.code = s["code"]
targetSerie.description = s["description"]
targetSerie.auteur = User.objects.filter(username=s["auteur"]).first()
targetSerie.audioDeb = s["audioDeb"]
targetSerie.imageDeb = s["imageDeb"]
targetSerie.videoDeb = s["videoDeb"]
targetSerie.graphieDeb = s["graphieDeb"]
newSerie.audioFin = s["audioFin"]
newSerie.imageFin = s["imageFin"]
newSerie.videoFin = s["videoFin"]
newSerie.graphieFin = s["graphieFin"]
newSerie.phonoFin = s["phonoFin"]
targetSerie.audioFin = s["audioFin"]
targetSerie.imageFin = s["imageFin"]
targetSerie.videoFin = s["videoFin"]
targetSerie.graphieFin = s["graphieFin"]
targetSerie.phonoFin = s["phonoFin"]
newSerie.syntheseVocale = s["syntheseVocale"]
newSerie.panneauPartiel = s["panneauPartiel"]
newSerie.phonVisibles = s["phonVisibles"]
targetSerie.syntheseVocale = s["syntheseVocale"]
targetSerie.panneauPartiel = s["panneauPartiel"]
targetSerie.phonVisibles = s["phonVisibles"]
newSerie.mots = json.dumps(s["mots"])
targetSerie.mots = json.dumps(s["mots"])
newSerie.save()
targetSerie.save()
print("saveSerie",s['code'], serieOrigin)
data = {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment