...
 
Commits (15)
*~
db
db/
external*
photos
debian
photos/
debian/
__pycache__/
test.*
[global]
server.socket_port = 8901
log.screen = False
[/]
tools.staticdir.root = "/home/georgesk/developpement/photodb/photodb-1.5"
[/static]
tools.staticdir.on = True
tools.staticdir.dir = "static"
#!/usr/bin/python3
import sys, csv, re, datetime
import sqlite3
encodingList=[
"utf-8",
"latin1",
"dos",
"cp437",
]
secondNamePattern=re.compile(r"^nom$", re.I)
firstNamePattern=re.compile(r"^pr[eé]nom$", re.I)
connection=None # connection to a sqlite3 database
def find_encoding(f, encodings=encodingList):
"""
finds the encoding of a text file
"""
for e in encodings:
try:
with open(f,encoding=e) as infile:
s=infile.read()
return e
except:
pass
return None
def getReader(csvfile):
"""
makes a DictReader from the file f, with the given encoding.
This Dictrader must have one field with name matched by secondNamePattern
and another one with name matched by firstNamePattern
@param csvfile an open string stream
@return a Dictreader, and the names of fields for the surname and
the given name
"""
reader=None
for delimiter in (";", ",", "\t",):
csvfile.seek(0)
reader = csv.DictReader(csvfile, delimiter=delimiter)
fields2=[f for f in reader.fieldnames if secondNamePattern.match(f)]
fields1=[f for f in reader.fieldnames if firstNamePattern.match(f)]
if (len(fields2), len(fields1)) == (1, 1):
return reader, fields2[0], fields1[0]
return reader, "", ""
def addToDb(row, field2, field1, verbose=False):
"""
adds surname and given name records to the database.
"""
date=datetime.datetime.utcnow().isoformat(sep=' ', timespec='seconds')
c = connection.cursor()
surname=row[field2]
givenname=row[field1]
c.execute("select * from person where surname=:surname and givenname=:givenname",
{"surname": surname, "givenname": givenname})
if c.fetchone()==None:
## the key surname + givenname does not yet exist !
print("+",end="")
sys.stdout.flush()
c.execute("INSERT INTO person (surname, givenname, date) VALUES (?,?,?)",
(surname, givenname, date))
connection.commit()
return 1
else:
if verbose:
print("-",end="")
sys.stdout.flush()
return 0
if __name__=="__main__":
infile=sys.argv[1]
try:
outfile=sys.argv[2]
except:
outfile="db/names.db"
connection = sqlite3.connect(outfile)
c = connection.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS person
(surname text, givenname text, photo text, date text)''')
connection.commit()
encoding=find_encoding(infile)
written=0
with open(infile, encoding=encoding) as csvfile:
reader, field2, field1 = getReader(csvfile)
for r in reader:
written=written + addToDb(r, field2, field1, verbose=True)
print ("\n{} ==>{}\nwritten {} records".format(infile,outfile,written))
photodb (2.0-1) unstable; urgency=medium
* complete rewrite to django
-- Georges Khaznadar <georgesk@debian.org> Fri, 22 Jun 2018 18:54:40 +0200
photodb (1.5-1) UNRELEASED; urgency=medium
* complete rewrite to use cherrypy
......
#!/usr/bin/env python3
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "photodb.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
# The above import may fail for some other reason. Ensure that the
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
execute_from_command_line(sys.argv)
"""
Django settings for photodb project.
Generated by 'django-admin startproject' using Django 1.11.13.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'a0gse8(@w8*1gfzzkgvfjg925s1#kv(f#2mi-_mz$yf_!c76a7'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['127.0.0.1',]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pose',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'photodb.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'photodb.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db', 'names.db'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
'min_length': 7,
},
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'fr-fr'
TIME_ZONE = 'Europe/Paris'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL = '/photos/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'photos')
"""photodb URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from django.contrib import admin
from django.conf.urls.static import static
from .settings import MEDIA_URL, MEDIA_ROOT
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('pose.urls')),
] + static(MEDIA_URL, document_root=MEDIA_ROOT)
"""
WSGI config for photodb project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "photodb.settings")
application = get_wsgi_application()
#!/bin/sh
user=$(id -un)
if [ "$user" = "www-data" ]; then
cd /var/lib/photodb
exec python3 webretouche.py
else
sudo su www-data --shell /bin/sh --command "$0"
fi
from django.contrib import admin
from .models import Person
admin.site.register(Person)
from django.apps import AppConfig
class PoseConfig(AppConfig):
name = 'pose'
from django import forms
class ImportCsvForm(forms.Form):
fname = forms.FileField(label="Choisir un fichier")
# -*- coding: utf-8 -*-
# Generated by Django 1.11.13 on 2018-06-20 09:46
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Person',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('firstName', models.CharField(max_length=30)),
('lastName', models.CharField(max_length=30)),
('photo', models.ImageField(blank=True, null=True, upload_to='')),
('modifDate', models.DateTimeField(blank=True, null=True)),
('level', models.IntegerField(blank=True, choices=[(4, 'Seconde'), (5, 'Première'), (6, 'Terminale'), (7, 'Supérieur1'), (8, 'Supérieur2')], null=True)),
('className', models.CharField(blank=True, max_length=10, null=True)),
],
),
migrations.AlterUniqueTogether(
name='person',
unique_together=set([('firstName', 'lastName')]),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11.13 on 2018-06-21 21:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pose', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Export',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('directory', models.CharField(max_length=30)),
('modifDate', models.DateTimeField(blank=True, null=True)),
('flavor', models.IntegerField(blank=True, choices=[(1, 'Pronote'), (2, 'Intendance'), (3, 'Trombinoscope')], null=True)),
('comment', models.TextField()),
],
),
]
from django.db import models
LEVELS = (
(4, 'Seconde'),
(5, 'Première'),
(6, 'Terminale'),
(7, 'Supérieur1'),
(8, 'Supérieur2'),
)
class Person(models.Model):
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=30)
photo = models.ImageField(blank=True, null=True)
modifDate = models.DateTimeField(blank=True, null=True)
level = models.IntegerField(choices=LEVELS, blank=True, null=True)
className = models.CharField(max_length=10, blank=True, null=True)
class Meta:
unique_together = (("firstName", "lastName"),)
def __str__(self):
return "{f} {l}".format(f=self.firstName, l=self.lastName)
EXPORTFLAVORS =(
(1,'Pronote'),
(2,'Intendance'),
(3,'Trombinoscope'),
)
class Export(models.Model):
directory = models.CharField(max_length=30)
modifDate = models.DateTimeField(blank=True, null=True)
flavor = models.IntegerField(choices=EXPORTFLAVORS, blank=True, null=True)
comment = models.TextField()
def __str__(self):
return self.directory
jQuery(document).ready(function () {
$("#loading").hide();
});
function showLoading(){
$("#loading").show();
return true;
}
......@@ -67,3 +67,50 @@
color: black;
}
#footer h1, h2, h3, ul, li {
display: inline-block;
}
#footer li a {
background: #79aec8;
color: white;
border-radius: 4px;
padding: 0px 4px;
}
#footer {
padding: 0.5em;
border: 1px gray solid;
border-radius: 0.5em;
}
#loading {
background: rgba(0,0,0,0.5);
z-index: 100;
width: 100%;
height:100%;
display: none;
position: fixed;
top: 0px;
left: 0px;
}
#loading img{
position: relative;
width: 150px;
height: 150px;
display: block;
margin: 150px auto;
}
dd {
margin-left: 1em;
}
.vignette {
display: inline-block;
}
.vignette img {
width: 8em;
}
......@@ -40,7 +40,6 @@ jQuery(document).ready(function () {
$.getJSON("/chercheNom", term, callback);
},
// effacer le prénom pendant qu'on bricole le nom !
// et aussi : remttre en saisie de vidéo
search: function( event, ui ) {$("#prenom").val("")},
change: function( event, ui ) {$("#prenom").val("");},
});
......@@ -64,6 +63,7 @@ function findFace(){
photo: photodata,
nom: $("#nom").val(),
prenom: $("#prenom").val(),
csrfmiddlewaretoken: $("#csrf").val(),
}).done(function(data){
if (data.status){
face.attr({
......@@ -106,6 +106,7 @@ function envoyer(){
prenom: prenom,
nom: nom,
photo: photodata,
csrfmiddlewaretoken: $("#csrf").val(),
},
}).done(
function(data){
......
{% load static %}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Importation de données d'élèves</title>
<script src="{% static 'jquery.js' %}" type="text/javascript"></script>
<link rel="stylesheet" href="{% static 'jquery-ui-themes/smoothness/jquery-ui.css' %}"/>
<script src="{% static 'jquery-ui/jquery-ui.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% static 'importeCSV.js' %}"></script>
<link rel="stylesheet" href="{% static 'portrait.css' %}" type="text/css"/>
<link rel="stylesheet" type="text/css" href="{% static '/admin/css/base.css' %}" />
</head>
<body>
<form method="post" action="" enctype="multipart/form-data" onsubmit="return showLoading()">
<fieldset>
<legend>Fichier de type CSV</legend>
{% csrf_token %}
<table>
{{form.as_table}}
<tr><td colspan="2" style="text-align: center;"><input type="submit" value="Importer"/></td></tr>
</table>
</fieldset>
</form>
<h1>Importation d'élèves</h1>
<dl>
<dt>Fichier traité :</dt>
<dd>{{fname}}</dd>
{% if ok %}
<dt>Colonnes prises en considération :</dt>
<dd>{{okFields}}</dd>
<dt>Nombre d'ajouts dans la base de données :</dt>
<dd>{{created}}</dd>
<dt>Nombre de mises à jour dans la base de données :</dt>
<dd>{{updated}}</dd>
{% endif %}
</dl>
<div id="footer">
<h3>Liens :</h3>
<ul>
<li><a href="/">Retour à la page d'accueil</a></li>
</ul>
</div>
<div id="loading">
<img src="{% static 'loading.gif' %}" alt="loading"/>
</div>
</body>
</html>
<!--
Local Variables:
mode: nxml
End:
-->
{% load static %}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Saisie de portrait</title>
<script src="/static/jquery.js" type="text/javascript"></script>
<link rel="stylesheet" href="/static/jquery-ui-themes/smoothness/jquery-ui.css"/>
<script src="/static/jquery-ui/jquery-ui.js" type="text/javascript"></script>
<script type="text/javascript" src="/static/portrait.js"></script>
<link rel="stylesheet" href="/static/portrait.css" type="text/css"/>
<script src="{% static 'jquery.js' %}" type="text/javascript"></script>
<link rel="stylesheet" href="{% static 'jquery-ui-themes/smoothness/jquery-ui.css' %}"/>
<script src="{% static 'jquery-ui/jquery-ui.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% static 'portrait.js' %}"></script>
<link rel="stylesheet" href="{% static 'portrait.css' %}" type="text/css"/>
</head>
<body>
<body>
<input type="hidden" id="csrf" value="{{csrf_token}}"/>
<div id="maincontent">
<form id="theform" action="#" method="post" onsubmit="return envoyer();">
<h3>Portrait</h3>
......@@ -56,6 +58,12 @@
<video id="webcam" autoplay ></video>
</div>
</div>
<div id="footer">
<h3>Liens :</h3>
<ul>
<li><a href="/importeCSV">Importation depuis un fichier CSV</a></li>
</ul>
</div>
<div id="dialog"></div>
</body>
</html>
......
{% load static %}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Export pour Pronote</title>
<script src="{% static 'jquery.js' %}" type="text/javascript"></script>
<link rel="stylesheet" href="{% static 'jquery-ui-themes/smoothness/jquery-ui.css' %}"/>
<script src="{% static 'jquery-ui/jquery-ui.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% static 'importeCSV.js' %}"></script>
<link rel="stylesheet" href="{% static 'portrait.css' %}" type="text/css"/>
<link rel="stylesheet" type="text/css" href="{% static '/admin/css/base.css' %}" />
</head>
<body>
{{grrr}}
<div id="footer">
<h3>Liens :</h3>
<ul>
<li>Photos exportées dans le dossier <b>{{destdir}}</b></li>
<li><a href="/">Retour à la page d'accueil</a></li>
</ul>
</div>
<div id="loading">
<img src="{% static 'loading.gif' %}" alt="loading"/>
</div>
<div id="vignettes">
{% for v in vignettes %}
<div class="vignette">
<img src="{{v.url}}" alt="{{v.prenom}} {{v.nom}}"/> <br/>
{{v.prenom}} <b>{{v.nom}}</b>
</div>
{% endfor %}
</div>
</body>
</html>
<!--
Local Variables:
mode: nxml
End:
-->
from django.test import TestCase
# Create your tests here.
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^encadre$', views.encadre, name='encadre'),
url(r'^envoi$', views.envoi, name='envoi'),
url(r'^chercheNom$', views.chercheNom, name='chercheNom'),
url(r'^cherchePrenom$', views.cherchePrenom, name='cherchePrenom'),
url(r'^importeCSV$', views.importeCSV, name='importeCSV'),
url(r'^pourPronote$', views.pourPronote, name='pourPronote'),
]
This diff is collapsed.
This diff is collapsed.
#!/bin/sh
# create or update a database for photodb
# check the existence of a previous database
db=/var/lib/photodb/db/names.db
version=1.4
if [ -f $db ] && [ $(echo "PRAGMA integrity_check;"| sqlite3 $db) = "ok" ]; then
foundVersion=$(echo "select version from version" | sqlite3 $db)
echo "The version number of $db is $version"
else
echo "$db must be created"
mkdir -p $(dirname $db)
sqlite3 $db <<EOF
CREATE TABLE person (surname text, givenname text, photo text, date text);
CREATE TABLE version (version text);
INSERT INTO version VALUES ('$version');
EOF
fi
#!/usr/bin/python3
"""
A small web service based on cherrypy and opencv, which allow one
to normalize photos of faces
"""
import os, sys, cherrypy, sqlite3, re, uuid, base64
from io import BytesIO
from datetime import datetime
thisdir=os.path.dirname(__file__)
sys.path.insert(0, thisdir)
staticdir=os.path.join(thisdir,"static")
db=os.path.join(thisdir,'db','names.db')
jpgPrefix=b'data:image/jpeg;base64,'
from autoretouche import jpgPrefix, FaceImage
def protect(s):
"""
prepare a name to be compatible with every file system
@ a string with no spaces, no diacritics, etc.
"""
return re.sub(r'[^A-Za-z0-9_\-]','_',s)
def nommage(nom, prenom):
"""
return a unique file name based on two strings
@param nom surname
@param prenom given name
@return a unique filename
"""
result=protect(nom)+'_'+protect(prenom)
result=result[:20]+'_'+str(uuid.uuid1())+'.jpg'
return result
def staticFile(path):
"""
@return the content of a file in the static/ directory
"""
return open(os.path.join(staticdir, path)).read()
def timestamp():
"""
@return a UTC time stamp
"""
return datetime.utcnow().isoformat(sep=" ", timespec="seconds")
class Retouche(object):
@cherrypy.expose
def index(self):
return staticFile("portrait.html")
@cherrypy.expose
def test(self):
return staticFile("test.html")
@cherrypy.expose
@cherrypy.tools.json_out()
def chercheNom(self, term=None):
"""
search the database in order to make an autocompletion
on the First Name field
"""
if term is None:
return []
result=[]
c = sqlite3.connect(db).cursor()
for row in c.execute("SELECT surname FROM person where surname like '%{}%'".format(term)):
result.append(row[0])
return result
@cherrypy.expose
@cherrypy.tools.json_out()
def cherchePrenom(self, **kw):
"""
search the database in order to make an autocompletion
on the Second Name field
"""
if 'nom' not in kw or 'prenom' not in kw:
return []
result=[]
c = sqlite3.connect(db).cursor()
for row in c.execute("SELECT givenname FROM person WHERE surname = '{nom}' and givenname LIKE '{prenom}%'".format(**kw)):
result.append(row[0])
return result
@cherrypy.expose
@cherrypy.tools.json_out()
def envoi(self, **kw):
"""
callback page to deal with first and second name, plus an image
@param kw dictionary of named parameters, with mandatory keys:
nom, prenom, photo
@return dictionary with those keys: status and message; when
status is not "ko", two other keys are given: fname and base64
"""
keys=('nom','prenom','photo')
# give an error message when one parameter is missing or empty
missingKeys=[k for k in keys if k not in kw]
missingVals=[k for k in kw if not kw[k]]
if missingKeys + missingVals:
return {
"status": "ko",
"message": "appel erroné, paramètres incorrects: {l}".format(l=",".join(missingKeys + missingVals)),
}
fi = FaceImage(kw['photo'].encode("utf-8"))
#### default return components, when no face is detected ####
status="malretouche"
fname=""
base64=fi.toDataUrl
message="""<p>Le système détecte mal le visage à recadrer.</p>
<p>Veuillez refaire la photo.</p>
"""
if fi.ok:
# a face was detected, good!
fname=nommage(kw['nom'],kw['prenom'])
fi.saveAs(os.path.join(thisdir,'photos',fname))
conn=sqlite3.connect(db)
c = conn.cursor()
rows=list(c.execute("""
SELECT photo FROM person
WHERE surname = '{nom}' and givenname = '{prenom}'
""".format(**kw)))
if not rows:
# the user does not exist so far: create a new entry
status="nouveau"
message="""
<p>Nouvel enregistrement créé pour {nom} {prenom}</p>
""".format(**kw)
c.execute("""
INSERT INTO person (surname, givenname, photo, date)
VALUES ('{nom}','{prenom}','{fname}','{date}')
""".format(fname=fname,date=timestamp(),**kw))
conn.commit()
else:
photo=rows[0][0]
# the user already exists, make an update
status="ok"
message="""
<p>Enregistrement de la photo effectué pour {nom} {prenom}</p>
""".format(**kw)
if photo: # erase an earlier photo file
moremessage="<p>L'ancienne photo n'existait pas : erreur ?</p>"
try:
os.unlink(os.path.join(thisdir,'photos',photo))
moremessage="<p>L'ancienne photo a été effacée</p>"
except:
pass
message+=moremessage
# the update is made in either case, even if there was no photo
c.execute("""
UPDATE person SET photo='{fname}', date='{date}'
WHERE surname = '{nom}' and givenname = '{prenom}'
""".format(fname=fname,date=timestamp(),**kw))
conn.commit()
# in any case, return status, fname, base64 message
return {
"statut": "ok",
"fname": fname,
"base64": fi.toDataUrl,
"message": message,
}
@cherrypy.expose
@cherrypy.tools.json_out()
def encadre(self, **kw):
"""
callback page to get the rectangle of a recognized face, if any
@param kw the keywords with keys "photo", "nom", "prenom"
which yields a dataURL encoded JPG image
"""
fi = FaceImage(kw['photo'].encode("utf-8"))
c = sqlite3.connect(db).cursor()
rows=list(c.execute("SELECT photo FROM person where surname = '{nom}' and givenname = '{prenom}'".format(**kw)))
message=""
oldimage=""
if not rows:
message="Inconnu(e) dans la base"
cssclass="red"
else:
message="Trouvé(e) dans la base"
cssclass="green"
photo=rows[0][0]
if photo:
photo=open(os.path.join(thisdir,"photos",photo),'rb').read()
photo=jpgPrefix+base64.b64encode(photo)
oldimage=photo.decode("ascii")
message="Trouvé(e) avec la photo"
cssclass="orange"
return {
"status": fi.ok,
"rect": fi.cropRect,
"message": message,
"oldimage": oldimage,
"cssclass": cssclass,
}
@cherrypy.expose
@cherrypy.tools.json_out()
def retouche(self, data=None):
"""
@param data should be an url-encoded JPG image
(magic bytes: 'data:image/jpeg;base64,')
@return a JSON response, with status => "OK" when a face was recognized
then imgdata => an url-encoded JPG image. If the status is something
else, an anonymous image is loaded in imgdata.
"""
if data is None:
with open("nobody.jpg", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
data=jpgPrefix+encoded_string
else:
data=data.encode("utf-8") # to bytes
fi = FaceImage(data)
status = "OK" if fi.ok else "Face auto-detection failed"
return {
"status": status,
"imgdata": fi.toDataUrl,
}
if __name__=="__main__":
print("service dans quelques secondes à http://localhost:8901")
cherrypy.quickstart(Retouche(),'/','cherryApp.conf')