diff --git a/AT_frontend/app.py b/AT_frontend/app.py index c6640bd..90560ce 100644 --- a/AT_frontend/app.py +++ b/AT_frontend/app.py @@ -1,13 +1,18 @@ from flask import Flask, render_template, session, redirect, url_for, session from flask_wtf import FlaskForm -from wtforms import (StringField, BooleanField, - RadioField, SelectField, - TextAreaField, SubmitField) +from wtforms import ( + StringField, + BooleanField, + RadioField, + SelectField, + TextAreaField, + SubmitField, +) from wtforms.validators import DataRequired app = Flask(__name__) -app.config['SECRET_KEY'] = 'mijngeheimesleutel' +app.config["SECRET_KEY"] = "mijngeheimesleutel" -if __name__ == '__main__': - app.run(debug=True) \ No newline at end of file +if __name__ == "__main__": + app.run(debug=True) diff --git a/__pycache__/models.cpython-313.pyc b/__pycache__/models.cpython-313.pyc index cac5294..f92f762 100644 Binary files a/__pycache__/models.cpython-313.pyc and b/__pycache__/models.cpython-313.pyc differ diff --git a/__pycache__/server.cpython-313.pyc b/__pycache__/server.cpython-313.pyc index ecdf14b..0b96abd 100644 Binary files a/__pycache__/server.cpython-313.pyc and b/__pycache__/server.cpython-313.pyc differ diff --git a/application/__init__.py b/application/__init__.py new file mode 100644 index 0000000..37f224d --- /dev/null +++ b/application/__init__.py @@ -0,0 +1,14 @@ +from flask import Flask +from flask_migrate import Migrate +from flask_sqlalchemy import SQLAlchemy + +# Web Server +app = Flask(__name__) +app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data.sqlite" +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False +app.config["SECRET_KEY"] = "bvjchsygvduycgsyugc" + +# ORM +db = SQLAlchemy(app) + +migrate = Migrate(app, db) diff --git a/application/__pycache__/__init__.cpython-313.pyc b/application/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..f5f2e62 Binary files /dev/null and b/application/__pycache__/__init__.cpython-313.pyc differ diff --git a/uploads/image.jpg b/image.jpg similarity index 53% rename from uploads/image.jpg rename to image.jpg index 80f57d6..0e3f4a9 100644 Binary files a/uploads/image.jpg and b/image.jpg differ diff --git a/image0.jpg b/image0.jpg new file mode 100644 index 0000000..e80034c Binary files /dev/null and b/image0.jpg differ diff --git a/image1.jpg b/image1.jpg new file mode 100644 index 0000000..e80034c Binary files /dev/null and b/image1.jpg differ diff --git a/image2.jpg b/image2.jpg new file mode 100644 index 0000000..0e3f4a9 Binary files /dev/null and b/image2.jpg differ diff --git a/instance/data.sqlite b/instance/data.sqlite index bdbf78b..39d42f7 100644 Binary files a/instance/data.sqlite and b/instance/data.sqlite differ diff --git a/migrations/__pycache__/env.cpython-313.pyc b/migrations/__pycache__/env.cpython-313.pyc index 6cb1fb1..8c50a3e 100644 Binary files a/migrations/__pycache__/env.cpython-313.pyc and b/migrations/__pycache__/env.cpython-313.pyc differ diff --git a/migrations/versions/__pycache__/7a26306b04df_.cpython-313.pyc b/migrations/versions/__pycache__/7a26306b04df_.cpython-313.pyc deleted file mode 100644 index 4437c72..0000000 Binary files a/migrations/versions/__pycache__/7a26306b04df_.cpython-313.pyc and /dev/null differ diff --git a/migrations/versions/__pycache__/ac8b1871be3d_.cpython-313.pyc b/migrations/versions/__pycache__/ac8b1871be3d_.cpython-313.pyc new file mode 100644 index 0000000..eed28ac Binary files /dev/null and b/migrations/versions/__pycache__/ac8b1871be3d_.cpython-313.pyc differ diff --git a/migrations/versions/7a26306b04df_.py b/migrations/versions/ac8b1871be3d_.py similarity index 51% rename from migrations/versions/7a26306b04df_.py rename to migrations/versions/ac8b1871be3d_.py index 75e10d9..e762caa 100644 --- a/migrations/versions/7a26306b04df_.py +++ b/migrations/versions/ac8b1871be3d_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: 7a26306b04df +Revision ID: ac8b1871be3d Revises: -Create Date: 2025-04-10 20:56:03.819230 +Create Date: 2025-04-22 22:32:26.012696 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '7a26306b04df' +revision = 'ac8b1871be3d' down_revision = None branch_labels = None depends_on = None @@ -18,10 +18,16 @@ depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table('plate', + op.create_table('AllowedPlates', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('plate', sa.String(length=40), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('LoggedItems', + sa.Column('dateLogged', sa.DateTime(), nullable=False), + sa.Column('allowed', sa.Boolean(), server_default=sa.text('0'), nullable=False), sa.Column('id', sa.Integer(), nullable=False), sa.Column('plate', sa.String(length=40), nullable=False), - sa.Column('dateLogged', sa.DateTime(), nullable=True), sa.PrimaryKeyConstraint('id') ) # ### end Alembic commands ### @@ -29,5 +35,6 @@ def upgrade(): def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('plate') + op.drop_table('LoggedItems') + op.drop_table('AllowedPlates') # ### end Alembic commands ### diff --git a/models.py b/models.py new file mode 100644 index 0000000..a5e1148 --- /dev/null +++ b/models.py @@ -0,0 +1,32 @@ +from datetime import datetime +from application import db + + +# db classes +class Plate(db.Model): + __abstract__ = True + id = db.Column(db.Integer, primary_key=True) + plate = db.Column(db.String(40), nullable=False) + + +class LoggedItem(Plate): + __tablename__ = "LoggedItems" + dateLogged = db.Column(db.DateTime, nullable=False) + allowed = db.Column(db.Boolean, nullable=False, server_default=db.false()) + + def __init__( + self, + plate: str, + datetime: datetime, + allowed: bool = False, + ): + self.plate = plate + self.allowed = allowed + self.dateLogged = datetime + + +class AllowedPlate(Plate): + __tablename__ = "AllowedPlates" + + def __init__(self, plate: str): + self.plate = plate diff --git a/seed.py b/seed.py new file mode 100644 index 0000000..dab44f6 --- /dev/null +++ b/seed.py @@ -0,0 +1,6 @@ +from application import db, app +from models import AllowedPlate + +with app.app_context(): + db.session.add(AllowedPlate("MUN389")) + db.session.commit() diff --git a/server.py b/server.py index 92bd37c..f730bf0 100644 --- a/server.py +++ b/server.py @@ -1,86 +1,69 @@ -from flask import Flask, request, jsonify -from flask_sqlalchemy import SQLAlchemy -from flask_migrate import Migrate -from datetime import datetime -from pyplatex import ANPR -from ultralytics.nn.tasks import DetectionModel +from flask import request, jsonify +from pyplatex import ANPR # type: ignore +from ultralytics.nn.tasks import DetectionModel # type: ignore import os import torch import asyncio +from application import app, db +from models import LoggedItem, AllowedPlate +from datetime import datetime -torch.serialization.add_safe_globals({"DetectionModel": DetectionModel}) +torch.serialization.add_safe_globals( # type: ignore + {"DetectionModel": DetectionModel} # type: ignore +) -# Web Server -app = Flask(__name__) -app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data.sqlite" -app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False -app.config["SECRET_KEY"] = "bvjchsygvduycgsyugc" - -# ORM -db = SQLAlchemy() -db.init_app(app) - -migrate = Migrate(app, db) # Saving images locally UPLOAD_FOLDER = "uploads" os.makedirs(UPLOAD_FOLDER, exist_ok=True) -# db classes -class Plate(db.Model): - id = db.Column(db.Integer, primary_key=True) - plate = db.Column(db.String(40), nullable=False) - - -class LoggedItem(Plate): - dateLogged = db.Column(db.DateTime, default=datetime.now) - - # Default app route @app.route("/") def home(): return "Hello, World!" +i = 0 + + # API to process vehicle @app.route("/api", methods=["POST"]) def data(): - # Check if image is present - if "image" not in request.files: - return jsonify({"error": "No file part"}), 400 + data = request.data + global i - file = request.files["image"] # get the image from the packet + with open(f"image{i}.jpg", "wb") as f: + f.write(data) - if file.filename == "" or not file.filename: - return jsonify({"error": "No selected file"}), 400 + status = asyncio.run(process_image(f"image{i}.jpg")) - # Check if image ends in .jpg - if file.filename.lower().endswith(".jpg"): - filepath = os.path.join(UPLOAD_FOLDER, file.filename) - file.save(filepath) - plate = asyncio.run(process_image(filepath)) - return jsonify( - { - "message": "File uploaded successfully", - "filename": file.filename, - "status": True, - "anpr": plate, - } - ) - - return jsonify({"error": "Only JPEG files allowed"}), 400 + i += 1 + return jsonify( + { + "message": "Image sent succesfully", + "status": status, + } + ) -async def process_image(file: str): +async def process_image(file: str) -> bool: anpr = ANPR() - anpr_info = await anpr.detect(file) + anpr_info: ... = await anpr.detect(file) # type: ignore number_plate = anpr_info["plate_number"] if number_plate: - db.session.add(LoggedItem(plate=number_plate)) + allowed = ( + AllowedPlate.query.filter_by(plate=number_plate).first() + is not None + ) + db.session.add( + LoggedItem( + plate=number_plate, allowed=allowed, datetime=datetime.now() + ) + ) db.session.commit() - return number_plate - return "ERROR" + return allowed + return False if __name__ == "__main__":