diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..67dd241 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM python +COPY ./certs /certs + +COPY ./ /app +RUN pip install -r /app/requirements.txt + +CMD python /app/run.py \ No newline at end of file diff --git a/application/__init__.py b/application/__init__.py new file mode 100644 index 0000000..cd21050 --- /dev/null +++ b/application/__init__.py @@ -0,0 +1,20 @@ +from flask import Flask, request, g, render_template +from flask_restful import Resource, reqparse +from flask_restful_swagger_3 import Api +from flask_cors import CORS +import os +from json import dumps +import application.endpoints as endpoints +import application.config as config +from flask_sqlalchemy import SQLAlchemy + +app = Flask(__name__) +api = Api(app, version='1', contact={"name":""}, license={"name":"Online Dienst Dokumentation"}, api_spec_url='/api/swagger') + +api.add_resource(endpoints.Recipe,'/api/v1/recipe/') + +@app.route("/") +def index(): + """serve the ui""" + return render_template("index.html") + \ No newline at end of file diff --git a/application/__pycache__/__init__.cpython-37.pyc b/application/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000..d0d9cf5 Binary files /dev/null and b/application/__pycache__/__init__.cpython-37.pyc differ diff --git a/application/__pycache__/app.cpython-37.pyc b/application/__pycache__/app.cpython-37.pyc new file mode 100644 index 0000000..eb08c4c Binary files /dev/null and b/application/__pycache__/app.cpython-37.pyc differ diff --git a/application/__pycache__/config.cpython-37.pyc b/application/__pycache__/config.cpython-37.pyc new file mode 100644 index 0000000..488e64a Binary files /dev/null and b/application/__pycache__/config.cpython-37.pyc differ diff --git a/application/__pycache__/db.cpython-37.pyc b/application/__pycache__/db.cpython-37.pyc new file mode 100644 index 0000000..43d69f5 Binary files /dev/null and b/application/__pycache__/db.cpython-37.pyc differ diff --git a/application/__pycache__/endpoints.cpython-37.pyc b/application/__pycache__/endpoints.cpython-37.pyc new file mode 100644 index 0000000..c9bebe7 Binary files /dev/null and b/application/__pycache__/endpoints.cpython-37.pyc differ diff --git a/application/config.py b/application/config.py new file mode 100644 index 0000000..6c2c8da --- /dev/null +++ b/application/config.py @@ -0,0 +1,2 @@ + +debug = True diff --git a/application/db.py b/application/db.py new file mode 100644 index 0000000..22d21dc --- /dev/null +++ b/application/db.py @@ -0,0 +1,76 @@ +import sqlalchemy as db +from sqlalchemy import Column, String, Integer, Numeric, Table, DateTime, ARRAY, ForeignKey, create_engine, LargeBinary, Enum, Text +from sqlalchemy.orm import sessionmaker, relationship, column_property +from datetime import datetime +from sqlalchemy.ext.declarative import declarative_base +import enum +from flask_sqlalchemy import SQLAlchemy +from flask import Flask + +engine = db.create_engine('sqlite:///./test.sqlite', echo=False) +connection = engine.connect() +Base = declarative_base() +Session = sessionmaker(bind=engine) + +# https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html#association-object +class Link(Base): + __tablename__ = 'link' + recipe_id = Column(Integer, ForeignKey('recipe.recipe_id'), primary_key=True) + ingredient_id = Column(Integer, ForeignKey('ingredient.ingredient_id'), primary_key=True) + ingredient_amount = Column('ingredient_amount', Text) + ingredient_amount_mu = Column('ingredient_amount_mu', Text) # measurement unit + + recipe = relationship("Recipe", back_populates="ingredient") + ingredient = relationship("Ingredient", back_populates="recipe") + + def ingredients(self): + return self.ingredient.name + +class Recipe(Base): + __tablename__ = "recipe" + recipe_id = Column('recipe_id', Integer, primary_key=True, autoincrement=True) + name = Column('name', Text) + instructions = Column('instructions', Text) + url = Column('url', Text) + img = Column('img', LargeBinary) + ingredient = relationship("Link", back_populates="recipe") + + def ingredients(self): + l = [] + for i in self.ingredient: + l.append(i.ingredients()) + return l + + def ingredientDict(self): + l = {} + for i in self.ingredient: + l[i.ingredients()] = [i.ingredient_amount, i.ingredient_amount_mu] + return l + + def serialize(self): + ingredients = [] + + if self.img is not None: + img = self.img.decode('utf-8') + else: + img = None + + data = { + "recipe_id": self.recipe_id, + "name":self.name, + "instructions":self.instructions, + "url": self.url, + "img": img, + "ingredients": self.ingredient.ingredient + + } + return data + +class Ingredient(Base): + __tablename__ = "ingredient" + ingredient_id = Column('ingredient_id', Integer, primary_key=True) + name = Column('name', Text) + recipe = relationship("Link", back_populates="ingredient") + + +Base.metadata.create_all(engine) diff --git a/application/endpoints.py b/application/endpoints.py new file mode 100644 index 0000000..8f99644 --- /dev/null +++ b/application/endpoints.py @@ -0,0 +1,23 @@ +from flask_restful import Resource, reqparse +import flask +import requests +import application.config as config +import json +import base64 +from application.db import Session, Recipe, Ingredient + +class Recipe(Resource): + def get(self): + """ """ + try: + parser = reqparse.RequestParser() + parser.add_argument('useFace', type=bool, required=False) + args = parser.parse_args() + + session = Session() + + return flask.make_response(flask.jsonify({'data': args}), 200) + except Exception as e: + print("error: -", e) + return flask.make_response(flask.jsonify({'error': str(e)}), 400) + diff --git a/application/static/coms.js b/application/static/coms.js new file mode 100644 index 0000000..85c6b9f --- /dev/null +++ b/application/static/coms.js @@ -0,0 +1,46 @@ +function getJSON(url, callback, fallback) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'json'; + xhr.onload = function () { + var status = xhr.status; + if (status < 400) { + callback(null, xhr.response); + } else { + fallback(); + } + }; + xhr.send(); +}; + +function putJSON(url, data, callback, fallback) { + var xhr = new XMLHttpRequest(); + xhr.open('PUT', url, true); + xhr.responseType = 'json'; + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.onload = function () { + var status = xhr.status; + if (status < 400) { + callback(null, xhr.response); + } else { + fallback(); + } + }; + xhr.send(data); +}; + +function postJSON(url, data, callback, fallback) { + var xhr = new XMLHttpRequest(); + xhr.open('POST', url, true); + xhr.responseType = 'json'; + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.onload = function () { + var status = xhr.status; + if (status < 400) { + callback(null, xhr.response); + } else { + fallback(); + } + }; + xhr.send(data); +}; \ No newline at end of file diff --git a/application/static/main.css b/application/static/main.css new file mode 100644 index 0000000..da21677 --- /dev/null +++ b/application/static/main.css @@ -0,0 +1,86 @@ +#list{ + position: absolute; + right: 0; + top:0; + width: 20rem; + min-height: 100%; + +} + +#switch{ + width: 25rem; + height: 5rem; + position: relative; + top: 0; + left: -50%; + +} +.navButton{ + padding-left: 1rem; + padding-right: 1rem; + margin-right: 0.5rem; +} +#main{ + width: 65rem; + height: 38rem; + position: relative; + top: 10rem; + left: -50%; + display: block; + padding: 0; +} + +.listIMG{ + width: 5rem; + float: left; +} + +.navi{ + margin-left: 1.5rem; +} + +.personalInfo{ + float: right; + width: 9rem; + margin:0; + padding:0; +} +.card{ + margin-top:1rem; +} +.card-text{ + padding: 0; + height: 0; +} + +#middle-left{ + float: left; +} +#middle-right{ + float:right; +} +.middle{ + padding: 2rem ; + margin: 0 !important; + height: 100%; + width: 45%; + display: block; +} + +#image-left{ + width:100%; + +} +#image-right{ + width:100%; + +} + +.heroInfo{ + +} + +.middle-controls{ + margin-left: 1rem; + margin-top: 1rem; +} \ No newline at end of file diff --git a/application/static/main.js b/application/static/main.js new file mode 100644 index 0000000..57c847f --- /dev/null +++ b/application/static/main.js @@ -0,0 +1,152 @@ + +rootKontext = "" +selected = null +var ml = document.getElementById('middle-left'); +var mr = document.getElementById('middle-right'); +personData = {} + +/** + * Retrieves input data from a form and returns it as a JSON object. + * @param {HTMLFormControlsCollection} elements the form elements + * @return {Object} form data as an object literal + */ +const formToJSON = elements => [].reduce.call(elements, (data, element) => { + data[element.name] = element.value; + return data; + }, {}); + +function focusNav(id) { + focusedID = id; + $(id).addClass('btn-primary').siblings().removeClass('btn-primary') + //$(id).removeClass('active').siblings().removeClass('active') +} + +function focusPerson(id) { + selected = id; + $("#person" + id).removeClass('border-light').siblings().addClass('border-light') + $("#person" + id).addClass('border-success').siblings().removeClass('border-success') + renderPersonRight() +} + +function loadPersonList(data) { + console.log(data) + data = data["data"] + let el = document.getElementById('list'); + data.forEach(function (item) { + string = ` +
+
+

${item["fname"]} ${item["lname"]}

+
${item["timestamp"]}
+ +

+ +

+ Gender: ${item["gender"]}
+ YoB: ${item["yob"]}
+ Available FP: ${item["fingerprints"].length}
+ +
+ +

+
+
+ ` + el.innerHTML += string; + }) +} + +function snapShot(){ + postJSON(rootKontext + "/api/v1/camera/", {}, + function (error, data) { + document.getElementById('image-left').src = rootKontext + "/api/v1/camera/still"; + }, + null + ); +} + +function renderPersonRight(data){ + string = ` + + +

+ Gender: ${data["gender"]}
+ YoB: ${data["yob"]}
+ Available FP: ${data["fingerprints"].length}
+

Score: ${data["matching_score"]}

+ + + ` + mr.innerHTML = string; +} + +function enrole(){ + data = {} + data["fname"] = document.getElementById("personform")["fname"].value + data["lname"] = document.getElementById("personform")["lname"].value + data["gender"] = document.getElementById("personform")["gender"].value + data["yob"] = document.getElementById("personform")["yob"].value + data = {"person": data} + console.log(data) + postJSON(rootKontext + "/api/v1/person/", JSON.stringify(data), + function(){ + location.reload() + }, + null + ) +} + +function identify(){ + snapShot() + getJSON(rootKontext + "/api/v1/person/?useFace=True", + function (error, data) { + data = data["data"] + renderPersonRight(data) + $("#middle-right").removeClass("border-danger").addClass("boarder-success") + }, + function(){ + $("#middle-right").removeClass("border-success").addClass("border-danger") + } + ); +} + +function validate(){ + snapShot() + getJSON(rootKontext + "/api/v1/person/" + selected + "?useFace=True", + function (error, data) { + data = data["data"] + renderPersonRight(data) + $("#middle-right").removeClass("border-danger").addClass("border-success") + }, + function(){ + mr.innerHTML="

Please select a person
from the list, which you want to use for validation

" + $("#middle-right").removeClass("border-success").addClass("border-danger") + } + ); +} + +function loadStream() { + string = ` + + ` + ml.innerHTML += string; + + string = ` + + ` + mr.innerHTML += string; +} + +function loadData() { + getJSON(rootKontext + "/api/v1/person/", + function (error, data) { + ml = document.getElementById('middle-left'); + mr = document.getElementById('middle-right'); + personData = data + loadPersonList(data) + renderIdentify() + }, + null + ); +} + diff --git a/application/static/render.js b/application/static/render.js new file mode 100644 index 0000000..c75f940 --- /dev/null +++ b/application/static/render.js @@ -0,0 +1,61 @@ +function clearMiddle(){ + ml.innerHTML = "" + mr.innerHTML = "" +} + +function renderValidate(){ + clearMiddle() + string = ` + + + + + ` + ml.innerHTML = string; + $("#middle-right").removeClass("border-danger").removeClass("border-success") +} + +function renderChange(){ + clearMiddle() + $("#middle-right").removeClass("border-danger").removeClass("border-success") + console.log("change") + +} +function renderEnrole(){ + clearMiddle() + string = ` + + + + + ` + ml.innerHTML = string; + + string2 = ` +
+
+
+
+
+ +
+ + ` + mr.innerHTML = string2; + $("#middle-right").removeClass("border-danger").removeClass("border-success") +} +function renderIdentify(){ + clearMiddle() + string = ` + + + + + ` + ml.innerHTML = string; + $("#middle-right").removeClass("border-danger").removeClass("border-success") +} \ No newline at end of file diff --git a/application/templates/index.html b/application/templates/index.html new file mode 100644 index 0000000..ad19eac --- /dev/null +++ b/application/templates/index.html @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+ + +
+
+ + +
+ +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/data/images.jpeg b/data/images.jpeg new file mode 100644 index 0000000..e10f796 Binary files /dev/null and b/data/images.jpeg differ diff --git a/data/recs.json b/data/recs.json index fa4d95f..f1fd292 100644 --- a/data/recs.json +++ b/data/recs.json @@ -1 +1 @@ -{"Ossobuco à la Milanese": ["\n An den Beinscheiben außen die Haut in ca. 2 cm Abstand einschneiden, damit sich das Fleisch beim Anbraten nicht wellt. Man kann die Beinscheiben auch außen herum mit Küchengarn in Form binden. Das Fleisch in Mehl wälzen und in wenig Olivenöl - max. 1 EL - auf beiden Seiten goldbraun braten, dann salzen und pfeffern. Aus dem Bräter nehmen und kurz zur Seite stellen.\n\n\n\nTomatenmark anrösten, gehackte Zwiebel zusammen mit dem zerdrückten Knoblauch und dem geputzten und in kleine Würfel geschnittenen Gemüse anschwitzen und anschließend mit Wein ablöschen. Fleischbrühe dazugießen. Dosentomaten und Tomatenmark zugeben, gut durchrühren und ein paar Minuten weiterschmoren lassen. Die ganzen Tomaten ein wenig klein drücken.\n\n\n\nZum Schluss die Beinscheiben auf das Gemüse legen. Gewürznelke, Pimentkörner, Wacholderbeeren und die Pfefferkörner in ein Teeei oder einen Teefilterbeutel geben und zu den Beinscheiben geben. Dann bei geschlossenem Deckel ca. 3 - 4 Stunden bei 140 °C Umluft im Backofen schmoren lassen.\n\n\n\nIn der Zwischenzeit kann die Gremolata zubereitet werden. Dazu die Petersilie fein schneiden und die zwei frischen Knoblauchzehen fein hacken. Anschließend beides mit dem Abrieb der ganzen Zitrone vermischen. In ein kleines Gefäß füllen und mit einer Klarsichtfolie abdecken.\n\n\n\nDas Fleisch am Ende der Schmorzeit mit Salz, Pfeffer, Thymian und Rosmarin abschmecken. Beinscheiben aus dem Schmortopf nehmen. Soße und Gemüse durch ein Sieb passieren. Soße wieder in den Schmortopf geben und falls sie dicker sein soll, wird so lange Gemüse zugegeben und mit dem Pürierstab aufgemixt, bis die richtige Konsistenz entstanden ist.\n\n\n\nServiert wird das Ossobuco mit Spaghetti. Auf dem Teller wird das Fleisch mit ein wenig - oder auch mehr - von der Gremolata bestreut.\n\n", {"Beinscheibe(n), vom Rind, ca. 4 cm dick geschnitten": "4", "Mehl": "etwas", "Zwiebel(n)": "1", "Knoblauchzehe(n)": "2", "Karotte(n)": "1", "Lauchstange(n)": "1", "Staudensellerie": "½", "Tomate(n), geschält": "1Dose", "Tomatenmark": "1EL", "Rotwein zum Ablöschen": "", "Rinderfond oder Fleischbrühe": "½Liter", "Olivenöl zum Braten": "", "Gewürznelke(n)": "2", "Pimentkörner": "10", "Wacholderbeere(n)": "5", "Pfefferkörner": "", "Salz": "", "Pfeffer, schwarz, aus der Mühle": "", "Thymian": "", "Rosmarin": "", "Zitrone(n), unbehandelt": "1", "Blattpetersilie": "1Bund"}, "https://www.chefkoch.de/rezepte/3039711456645264/Ossobuco-a-la-Milanese.html"]} \ No newline at end of file +{"Ossobuco à la Milanese": ["\n An den Beinscheiben außen die Haut in ca. 2 cm Abstand einschneiden, damit sich das Fleisch beim Anbraten nicht wellt. Man kann die Beinscheiben auch außen herum mit Küchengarn in Form binden. Das Fleisch in Mehl wälzen und in wenig Olivenöl - max. 1 EL - auf beiden Seiten goldbraun braten, dann salzen und pfeffern. Aus dem Bräter nehmen und kurz zur Seite stellen.\n\nTomatenmark anrösten, gehackte Zwiebel zusammen mit dem zerdrückten Knoblauch und dem geputzten und in kleine Würfel geschnittenen Gemüse anschwitzen und anschließend mit Wein ablöschen. Fleischbrühe dazugießen. Dosentomaten und Tomatenmark zugeben, gut durchrühren und ein paar Minuten weiterschmoren lassen. Die ganzen Tomaten ein wenig klein drücken.\n\nZum Schluss die Beinscheiben auf das Gemüse legen. Gewürznelke, Pimentkörner, Wacholderbeeren und die Pfefferkörner in ein Teeei oder einen Teefilterbeutel geben und zu den Beinscheiben geben. Dann bei geschlossenem Deckel ca. 3 - 4 Stunden bei 140 °C Umluft im Backofen schmoren lassen.\n\nIn der Zwischenzeit kann die Gremolata zubereitet werden. Dazu die Petersilie fein schneiden und die zwei frischen Knoblauchzehen fein hacken. Anschließend beides mit dem Abrieb der ganzen Zitrone vermischen. In ein kleines Gefäß füllen und mit einer Klarsichtfolie abdecken.\n\nDas Fleisch am Ende der Schmorzeit mit Salz, Pfeffer, Thymian und Rosmarin abschmecken. Beinscheiben aus dem Schmortopf nehmen. Soße und Gemüse durch ein Sieb passieren. Soße wieder in den Schmortopf geben und falls sie dicker sein soll, wird so lange Gemüse zugegeben und mit dem Pürierstab aufgemixt, bis die richtige Konsistenz entstanden ist.\n\nServiert wird das Ossobuco mit Spaghetti. Auf dem Teller wird das Fleisch mit ein wenig - oder auch mehr - von der Gremolata bestreut.\n", {"Beinscheibe(n), vom Rind, ca. 4 cm dick geschnitten": "4", "Mehl": "etwas", "Zwiebel(n)": "1", "Knoblauchzehe(n)": "2", "Karotte(n)": "1", "Lauchstange(n)": "1", "Staudensellerie": "½", "Tomate(n), geschält": "1Dose", "Tomatenmark": "1EL", "Rotwein zum Ablöschen": "", "Rinderfond oder Fleischbrühe": "½Liter", "Olivenöl zum Braten": "", "Gewürznelke(n)": "2", "Pimentkörner": "10", "Wacholderbeere(n)": "5", "Pfefferkörner": "", "Salz": "", "Pfeffer, schwarz, aus der Mühle": "", "Thymian": "", "Rosmarin": "", "Zitrone(n), unbehandelt": "1", "Blattpetersilie": "1Bund"}, "https://www.chefkoch.de/rezepte/3039711456645264/Ossobuco-a-la-Milanese.html", "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"]} \ No newline at end of file diff --git a/mine.py b/mine.py index 97c3c67..3667544 100644 --- a/mine.py +++ b/mine.py @@ -6,6 +6,9 @@ import json from time import sleep import random import traceback +import cv2 +import base64 +from application.db import Session, Recipe, Ingredient, Link header_values = { 'name': 'Michael Foord', @@ -60,7 +63,7 @@ def getRecipe(links): recs = dict() with requests.Session() as session: counter = 0 - for link in links[:1]: + for link in links: counter += 1 try: site = session.get(link, headers=header_values) @@ -69,15 +72,24 @@ def getRecipe(links): namePath = "/html/body/main/article[1]/div/div[2]/h1/text()" ingredPath = "/html/body/main/article[2]/table/tbody/tr/td" # TODO: fix this recipPath = "/html/body/main/article[3]/div[1]/text()" + imgPath = './data/images.jpeg' name = tree.xpath(namePath)[0] ingred = tree.xpath(ingredPath) resip = tree.xpath(recipPath) + image = cv2.imread(imgPath) + ret, jpeg = cv2.imencode(".jpeg", image) + img = base64.b64encode(jpeg) + resString = "" for x in resip: - resString += x + "\n" + resString += x + dbSession = Session() + + r = Recipe(name=name, instructions=resString, url=link, img=img) + ingredDict = {} for i in range(0, len(ingred)-1, 2): #print(ingred[i+1][0].text) @@ -95,13 +107,19 @@ def getRecipe(links): except: amount = "" #print(stuff, amount) + a = Link(ingredient_amount=amount) + a.ingredient = Ingredient(name=stuff) + r.ingredient.append(a) + dbSession.add(r) + dbSession.commit() + ingredDict[stuff] = amount - recs[name] = [resString, ingredDict, link] + recs[name] = [resString, ingredDict, link, img.decode("utf-8")] print("") except Exception as e: print(traceback.format_exc()) - print(format(counter/100, '.2f'), link) + print(format(counter/len(links), '.2f'), link) sleep(random.randint(0, 5)) return recs diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a0536d3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +flask +flask_restful +sqlalchemy +requests +flask-restful-swagger-3 \ No newline at end of file diff --git a/run.py b/run.py new file mode 100644 index 0000000..61ef917 --- /dev/null +++ b/run.py @@ -0,0 +1,5 @@ +from application import app + +app.run(host="localhost", port='5001', debug=True) + + diff --git a/test.sqlite b/test.sqlite new file mode 100644 index 0000000..08c7ed3 Binary files /dev/null and b/test.sqlite differ