From 5de2df71a9e9f31575ed6e8c31e433005906f369 Mon Sep 17 00:00:00 2001 From: Stef Date: Thu, 10 Apr 2025 21:01:25 +0200 Subject: [PATCH] A bunch of mess --- __pycache__/models.cpython-313.pyc | Bin 0 -> 1064 bytes __pycache__/server.cpython-313.pyc | Bin 0 -> 4129 bytes dbmanager.py | 1 - instance/data.sqlite | Bin 0 -> 16384 bytes migrations/README | 1 + migrations/__pycache__/env.cpython-313.pyc | Bin 0 -> 4546 bytes migrations/alembic.ini | 50 ++++++++ migrations/env.py | 113 ++++++++++++++++++ migrations/script.py.mako | 24 ++++ migrations/versions/7a26306b04df_.py | 33 +++++ .../__pycache__/7a26306b04df_.cpython-313.pyc | Bin 0 -> 1284 bytes requirements.txt | 7 ++ server.py | 38 +++++- views.py | 0 14 files changed, 261 insertions(+), 6 deletions(-) create mode 100644 __pycache__/models.cpython-313.pyc create mode 100644 __pycache__/server.cpython-313.pyc delete mode 100644 dbmanager.py create mode 100644 instance/data.sqlite create mode 100644 migrations/README create mode 100644 migrations/__pycache__/env.cpython-313.pyc create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako create mode 100644 migrations/versions/7a26306b04df_.py create mode 100644 migrations/versions/__pycache__/7a26306b04df_.cpython-313.pyc create mode 100644 views.py diff --git a/__pycache__/models.cpython-313.pyc b/__pycache__/models.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cac5294aae138a847ae3af9bed71f5782e980e70 GIT binary patch literal 1064 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 literal 0 HcmV?d00001 diff --git a/migrations/README b/migrations/README new file mode 100644 index 0000000..0e04844 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Single-database configuration for Flask. diff --git a/migrations/__pycache__/env.cpython-313.pyc b/migrations/__pycache__/env.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6cb1fb1a9547950c7012c2d48ddd4c00773bb142 GIT binary patch literal 4546 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 literal 0 HcmV?d00001 diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 0000000..ec9d45c --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,50 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic,flask_migrate + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[logger_flask_migrate] +level = INFO +handlers = +qualname = flask_migrate + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 0000000..4c97092 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,113 @@ +import logging +from logging.config import fileConfig + +from flask import current_app + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + + +def get_engine(): + try: + # this works with Flask-SQLAlchemy<3 and Alchemical + return current_app.extensions['migrate'].db.get_engine() + except (TypeError, AttributeError): + # this works with Flask-SQLAlchemy>=3 + return current_app.extensions['migrate'].db.engine + + +def get_engine_url(): + try: + return get_engine().url.render_as_string(hide_password=False).replace( + '%', '%%') + except AttributeError: + return str(get_engine().url).replace('%', '%%') + + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option('sqlalchemy.url', get_engine_url()) +target_db = current_app.extensions['migrate'].db + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def get_metadata(): + if hasattr(target_db, 'metadatas'): + return target_db.metadatas[None] + return target_db.metadata + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=get_metadata(), literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + conf_args = current_app.extensions['migrate'].configure_args + if conf_args.get("process_revision_directives") is None: + conf_args["process_revision_directives"] = process_revision_directives + + connectable = get_engine() + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=get_metadata(), + **conf_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/7a26306b04df_.py b/migrations/versions/7a26306b04df_.py new file mode 100644 index 0000000..75e10d9 --- /dev/null +++ b/migrations/versions/7a26306b04df_.py @@ -0,0 +1,33 @@ +"""empty message + +Revision ID: 7a26306b04df +Revises: +Create Date: 2025-04-10 20:56:03.819230 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '7a26306b04df' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('plate', + 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 ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('plate') + # ### end Alembic commands ### diff --git a/migrations/versions/__pycache__/7a26306b04df_.cpython-313.pyc b/migrations/versions/__pycache__/7a26306b04df_.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4437c72ae548f491b9fb5bd26cbf8a63eaa91076 GIT binary patch literal 1284 zcma)5OK;Oa5MDcu* zUf_s$s0fg_mRtWyK?t;PgG+CP2#F)JPE149LoLnh?9A*uKX)=26~Q+<{Kw8D5cR3m@Yy5F^6TF$Do1REjFR)CeWg?ynnp1(Ri zkq5C{oGRxhuS`#r3X^$N-Qz{(1SST}1vc0p&FqyQ9Rt9jKh(J`@Lulyvn|J6{?j0I z0eZV9#foJ)mJUwv5c@oo14}GjK*gS@B{Zp&=<_~0UVp}DCvl|i2^o``T!NV&D_W{A z-{Aj|_^q!xn3bL@msEIG+exQ3EV&- zyV$qGRi;|tbtkZGY^~%J!dJlt&1lJb$R99~8cd!I+?MCFRMii$jR}*rkT|~06b^(H z$HQ!Ri8!7?+BMvs4SX6B!|}uSsKcvbi)OigmtsQeG;Fli>y^N4dDstW{gxBnZZ+yl zBzS<$u)4TX_Z*uTA;6H<*Wg7Y^utHL(rmL-s|j8fCTAf0DIm&GwSj&}^5ezL#izHv zfl%G7KCxch*qVDb_x#RwaaWp%we}0L)qd9A7I#N3@8Df&CN{WlZ@jC$uDzMxsq9K6 z(0-Q2K1gG)Dj%iuzthR2Ook!Pe+cFy5jYXRh7YK)4PVA0ewMfwH4xaF~ zqIBdmNGxpy>wdTCvv5BLL^&q9P0w%6KfU-#8jT+023Shht-#cEmNH!IH5{`SpFVUA z*IdP3n`C%Yh4g-Umf`XBgKL8rzPYLcYOqTIC%B1yi|T9Wkp4fU6t66DSqQ5cK5_zR{B B4;26a literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index 7c31518..ddbdc71 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +alembic==1.15.2 anyascii==0.3.2 blinker==1.9.0 certifi==2025.1.31 @@ -10,8 +11,12 @@ cycler==0.12.1 defusedxml==0.7.1 filelock==3.18.0 Flask==3.1.0 +Flask-Login==0.6.3 +Flask-Migrate==4.1.0 +Flask-SQLAlchemy==3.1.1 fonttools==4.57.0 fsspec==2025.3.2 +greenlet==3.1.1 h5py==3.13.0 huggingface-hub==0.30.2 idna==3.10 @@ -20,6 +25,7 @@ Jinja2==3.1.6 kiwisolver==1.4.8 langdetect==1.0.9 loguru==0.7.2 +Mako==1.3.10 MarkupSafe==3.0.2 matplotlib==3.10.1 mpmath==1.3.0 @@ -46,6 +52,7 @@ seaborn==0.13.2 setuptools==78.1.0 shapely==2.1.0 six==1.17.0 +SQLAlchemy==2.0.40 sympy==1.13.1 torch==2.6.0 torchvision==0.21.0 diff --git a/server.py b/server.py index eb87231..92bd37c 100644 --- a/server.py +++ b/server.py @@ -1,20 +1,42 @@ from flask import Flask, request, jsonify -import os +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate +from datetime import datetime from pyplatex import ANPR -import torch from ultralytics.nn.tasks import DetectionModel +import os +import torch import asyncio torch.serialization.add_safe_globals({"DetectionModel": DetectionModel}) # 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(): @@ -37,12 +59,13 @@ def data(): if file.filename.lower().endswith(".jpg"): filepath = os.path.join(UPLOAD_FOLDER, file.filename) file.save(filepath) - print(asyncio.run(process_image(filepath))) + plate = asyncio.run(process_image(filepath)) return jsonify( { "message": "File uploaded successfully", "filename": file.filename, "status": True, + "anpr": plate, } ) @@ -51,8 +74,13 @@ def data(): async def process_image(file: str): anpr = ANPR() - plates = await anpr.detect(file) - return plates + anpr_info = await anpr.detect(file) + number_plate = anpr_info["plate_number"] + if number_plate: + db.session.add(LoggedItem(plate=number_plate)) + db.session.commit() + return number_plate + return "ERROR" if __name__ == "__main__": diff --git a/views.py b/views.py new file mode 100644 index 0000000..e69de29