This commit is contained in:
Jetson
2023-01-10 01:52:32 +08:00
commit 77ea4bb6a0
17 changed files with 557 additions and 0 deletions

100
frontend/index.html Normal file
View File

@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Minified version -->
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
<title>Automated Garbage Segregation</title>
<style>
body {
grid-template-columns: 1fr min(75rem, 90%) 1fr;
}
body, html {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#main {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 1fr 2fr;
}
#main > div {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
</style>
</head>
<body>
<div id="main" v-scope @mounted="mounted()" @unmounted="unmounted()">
<div id="image">
<img v-if="state =='put'" :src="placeholder" alt="placeholder">
<img v-else-if="state =='camera'" :src="loader" alt="loader">
<img v-else :src="imageUrl" alt="item">
</div>
<div id="status">
<h1>{{ status }}</h1>
</div>
</div>
<script src="https://unpkg.com/petite-vue@0.2.2/dist/petite-vue.iife.js"></script>
<script>
let app = PetiteVue.createApp({
intervalId: -1,
pollingInterval: 500,
placeholder: "/static/scroll-down.gif",
loader: "/static/loader.gif",
imageUrl: "/photo",
type: "未知",
state: "put",
get status() {
let data = {
"put": "請放置垃圾",
"camera": "拍照中,請勿移動",
"identify": "辨識中",
"identified": this.type,
}
return data[this.state];
},
mounted() {
console.log("mounted");
if (this.intervalId < 0) this.intervalId = setInterval(() => { this.polling(); }, this.pollingInterval);
},
unmounted() {
console.log("unmounted");
if (this.intervalId >= 0) {
clearInterval(this.intervalId);
}
},
update(data) {
let state = data.state;
if (state == "identified") this.type = data.type;
this.state = state;
if (state == "identify") this.imageUrl = `/photo?${Date.now()}`
},
async polling() {
let res, data;
try {
res = await fetch("/poll");
data = await res.json();
} catch (error) {
console.error(error);
return;
}
this.update(data);
}
});
app.mount("#main");
</script>
</body>
</html>

72
frontend/server.py Normal file
View File

@@ -0,0 +1,72 @@
import os
from flask import Blueprint, Flask, render_template, jsonify, send_file, request
image_path = "/tmp/photo.jpg"
state = "put"
trash_type = ""
api = Blueprint('api', __name__)
# 放下垃圾
@api.route("/putdown")
def putdown():
global state
state = "camera"
return "ok"
# 拍好照
@api.route("/pic")
def pic():
global state
state = "identify"
return "ok"
# 辨識好
@api.route("/result")
def result():
global state, trash_type
trash = request.args.get("type")
if not trash:
return "sad", 400
trash_type = trash
state = "identified"
return "ok"
# 準備好下一個
@api.route("/ready")
def ready():
global state
state = "put"
return "ok"
app = Flask(__name__)
app.register_blueprint(api, url_prefix="/api")
@app.route("/")
def index():
return send_file("index.html")
@app.route("/poll")
def poll():
data = {
"state": state
}
if state == "identified":
data.update({"type": trash_type})
return jsonify(data)
@app.route("/photo")
def photo():
return send_file(image_path)
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)

BIN
frontend/static/loader.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
frontend/static/photo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB