mirror of
https://github.com/augustin64/projet-tipe
synced 2025-04-22 13:23:53 +02:00
Add webserver
This commit is contained in:
parent
b93d1475e0
commit
1d4b56a14f
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
**/a.out
|
||||
.cache/*
|
||||
.test-cache/*
|
||||
**/__pycache__
|
71
src/webserver/app.py
Normal file
71
src/webserver/app.py
Normal file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/python3
|
||||
from flask import Flask, render_template, request
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
MAGIC_NUMBER = 2051
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("index.html")
|
||||
|
||||
@app.route("/mnist")
|
||||
def mnist():
|
||||
return render_template("mnist.html")
|
||||
|
||||
@app.route("/post", methods=["POST"])
|
||||
def post_json_handler():
|
||||
"""
|
||||
Gère les requêtes POST
|
||||
"""
|
||||
if request.is_json:
|
||||
content = request.get_json()
|
||||
req_type = content["type"]
|
||||
if req_type == "prediction":
|
||||
dataset = content["dataset"]
|
||||
image = content["data"]
|
||||
if dataset == "mnist":
|
||||
return recognize_mnist(image)
|
||||
return {"status": "404"}
|
||||
|
||||
|
||||
def recognize_mnist(image):
|
||||
"""Appelle le programme C reconnaissant les images"""
|
||||
# Créer le fichier binaire
|
||||
write_image_to_binary(image, ".cache/image.bin")
|
||||
|
||||
try:
|
||||
return {"status": 200, "data":
|
||||
json.loads(subprocess.check_output([
|
||||
'out/main',
|
||||
'recognize',
|
||||
'--modele', '.cache/reseau.bin',
|
||||
'--in', '.cache/image.bin',
|
||||
'--out', 'json'
|
||||
]))["0"]}
|
||||
except subprocess.CalledProcessError:
|
||||
return {
|
||||
"status": 500,
|
||||
"data": "Internal Server Error"
|
||||
}
|
||||
|
||||
def write_image_to_binary(image, filepath):
|
||||
byteorder = "big"
|
||||
|
||||
bytes_ = MAGIC_NUMBER.to_bytes(4, byteorder=byteorder)
|
||||
bytes_ += (1).to_bytes(4, byteorder=byteorder)
|
||||
bytes_ += len(image).to_bytes(4, byteorder=byteorder)
|
||||
bytes_ += len(image[0]).to_bytes(4, byteorder=byteorder)
|
||||
for row in image:
|
||||
for nb in row:
|
||||
bytes_ += int(nb).to_bytes(1, byteorder=byteorder)
|
||||
|
||||
with open(filepath, "wb") as f:
|
||||
f.write(bytes_)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, host='0.0.0.0')
|
169
src/webserver/static/script.js
Normal file
169
src/webserver/static/script.js
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
Le code concernant l'entrée par l'utilisateur d'un nombre a été adapté depuis le code suivant: (License MIT)
|
||||
https://github.com/maneprajakta/Digit_Recognition_Web_App/blob/master/js/main.js
|
||||
|
||||
On été rajoutées les fonctions permettant de communiquer avec le serveur
|
||||
*/
|
||||
// Variables globales
|
||||
var canvas;
|
||||
var ctx;
|
||||
var touchX;
|
||||
var touchY;
|
||||
var mouseX;
|
||||
var mouseY;
|
||||
var mouseDown = 0;
|
||||
|
||||
function init() {
|
||||
canvas = document.getElementById('digit-canvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.fillStyle = "black";
|
||||
// Créer une zone de dessin
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
if(ctx)
|
||||
{
|
||||
canvas.addEventListener('mousedown', s_mouseDown, false);
|
||||
canvas.addEventListener('mousemove', s_mouseMove, false);
|
||||
window.addEventListener('mouseup', s_mouseUp, false);
|
||||
document.getElementById('clear').addEventListener("click", clear);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function draw(ctx, x, y, isDown) {
|
||||
// isDown représente le fait que le chemin ait déjà commencé ou non
|
||||
// On ne dessine donc ue si le "stylo" est déjà posé
|
||||
if (isDown) {
|
||||
ctx.beginPath();
|
||||
// On choisit les options suivantes:
|
||||
ctx.strokeStyle = "white";
|
||||
ctx.lineWidth = "10";
|
||||
ctx.lineJoin = "round";
|
||||
ctx.lineCap = "round";
|
||||
ctx.moveTo(lastX, lastY);
|
||||
ctx.lineTo(x, y);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
|
||||
// Mouse moves
|
||||
function s_mouseDown() {
|
||||
mouseDown = 1;
|
||||
draw(ctx, mouseX, mouseY, false);
|
||||
}
|
||||
|
||||
function s_mouseUp() {
|
||||
mouseDown = 0;
|
||||
}
|
||||
|
||||
function s_mouseMove(e) {
|
||||
// Si la souris bouge et est cliquée, on souhaite dessiner un trait
|
||||
getMousePos(e);
|
||||
if (mouseDown == 1) {
|
||||
draw(ctx, mouseX, mouseY, true);
|
||||
}
|
||||
}
|
||||
|
||||
function getMousePos(e) {
|
||||
if (e.offsetX) {
|
||||
mouseX = e.offsetX;
|
||||
mouseY = e.offsetY;
|
||||
} else if (e.layerX) {
|
||||
mouseX = e.layerX;
|
||||
mouseY = e.layerY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function clear() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function sendJSON(data,callback){
|
||||
// Creating a XHR object
|
||||
let xhr = new XMLHttpRequest();
|
||||
let url = "post";
|
||||
|
||||
// open a connection
|
||||
xhr.open("POST", url, true);
|
||||
|
||||
// Set the request header i.e. which type of content you are sending
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
// Create a state change callback
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
|
||||
// Print received data from server
|
||||
callback(this.responseText);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Converting JSON data to string
|
||||
var data = JSON.stringify(data);
|
||||
|
||||
// Sending data with the request
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
|
||||
function getPrediction() {
|
||||
let totalWidth = 280;
|
||||
let totalHeight = 280;
|
||||
let curWidth = 0;
|
||||
let curHeight = 0;
|
||||
let stepSize = 10;
|
||||
|
||||
let tableau = [];
|
||||
let tmp_tableau = [];
|
||||
|
||||
while (curWidth < totalWidth) {
|
||||
curHeight = 0;
|
||||
tmp_tableau = [];
|
||||
while (curHeight < totalHeight) {
|
||||
data = ctx.getImageData(curWidth, curHeight, stepSize, stepSize);
|
||||
size = data.width * data.height;
|
||||
density = 0;
|
||||
|
||||
for (let i=0;i < size;i++) {
|
||||
density += (data.data[i*4]+data.data[i*4+1]+data.data[i*4+2])/3;
|
||||
}
|
||||
density = density*1.0 / size;
|
||||
|
||||
tmp_tableau.push(density);
|
||||
curHeight += stepSize;
|
||||
}
|
||||
curWidth += stepSize;
|
||||
tableau.push(tmp_tableau);
|
||||
}
|
||||
|
||||
return sendJSON({
|
||||
"type": "prediction",
|
||||
"dataset": "mnist",
|
||||
"data": tableau
|
||||
}, (data) => {
|
||||
data = JSON.parse(data);
|
||||
if (data["status"] != 200) {
|
||||
document.getElementById("result").innerHTML = "500 Internal Server Error";
|
||||
} else {
|
||||
let resultat = document.getElementById("result");
|
||||
resultat.innerHTML = "Résultat:";
|
||||
let dict = {};
|
||||
let i = 0;
|
||||
data["data"].map((e) => { dict[e] = i; i++; });
|
||||
let res = Object.keys(dict).sort().reverse();
|
||||
for (let j=0; j < res.length; j++) {
|
||||
resultat.innerHTML += "<br/>"+dict[res[j]]+" : "+res[j];
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
4
src/webserver/static/style.css
Normal file
4
src/webserver/static/style.css
Normal file
@ -0,0 +1,4 @@
|
||||
#digit-canvas {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 5px;
|
||||
}
|
12
src/webserver/templates/index.html
Normal file
12
src/webserver/templates/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Home page<</title>
|
||||
<link href="{{ url_for('static',filename='style.css') }}" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<a href="/mnist">MNIST</a>
|
||||
</body>
|
||||
</html>
|
17
src/webserver/templates/mnist.html
Normal file
17
src/webserver/templates/mnist.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>MNIST interaction</title>
|
||||
<link href="{{ url_for('static',filename='style.css') }}" rel="stylesheet">
|
||||
<script src="{{ url_for('static',filename='script.js') }}"></script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<div id="maincard">
|
||||
<canvas id="digit-canvas" width="280" height="280"></canvas><br/>
|
||||
<button id="clear">Clear</button>
|
||||
<button id="predict" onclick="getPrediction()">Prédire</button>
|
||||
</div><br/>
|
||||
<div id="result"></div>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user