результаты админка
Gitea Actions Demo / build_and_push (push) Successful in 24m17s Details

This commit is contained in:
artem 2026-01-26 18:01:27 +03:00
parent 59758f17a3
commit 6a1bbb9a08
8 changed files with 116 additions and 2 deletions

View File

@ -8,10 +8,14 @@ from wtforms import fields, validators
from server.admin.auth import POOL, User from server.admin.auth import POOL, User
from server.admin.config import app, db_sync from server.admin.config import app, db_sync
from server.admin.views.attachments import AttachmentView from server.admin.views.attachments import AttachmentView
from server.admin.views.results import ResultsView
from server.admin.views.vote import VotesView
from server.config import get_app_config from server.config import get_app_config
from server.infra.db import AsyncDB from server.infra.db import AsyncDB
from server.modules.attachments import AtachmentService, DBAttachmentRepository, S3StorageDriver from server.modules.attachments import AtachmentService, DBAttachmentRepository, S3StorageDriver
from server.modules.attachments.repository.models import Attachment from server.modules.attachments.repository.models import Attachment
from server.modules.rate.repository.models import Vote
from server.modules.recognizer.repository.models import ResultBeerds
login_manager = flask_login.LoginManager() login_manager = flask_login.LoginManager()
login_manager.init_app(app) login_manager.init_app(app)
@ -119,5 +123,7 @@ if __name__ == "__main__":
) )
admin.add_view(AttachmentView(Attachment, db_sync.session)) admin.add_view(AttachmentView(Attachment, db_sync.session))
admin.add_view(ResultsView(ResultBeerds, db_sync.session))
admin.add_view(VotesView(Vote, db_sync.session))
app.run(debug=False, host="0.0.0.0", port=8000) app.run(debug=False, host="0.0.0.0", port=8000)

View File

@ -0,0 +1,38 @@
import flask_login
from flask import flash, redirect, request, url_for
from flask_admin.contrib.sqla import ModelView
from markupsafe import Markup
# Create customized model view class
class ResultsView(ModelView):
can_edit = False
can_delete = False
can_create = False
column_default_sort = ("result.created_at", True)
def is_accessible(self):
"""Check if current user can access admin interface"""
return flask_login.current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
"""Redirect to login if not accessible"""
flash("Please login to access this page.", "danger")
return redirect(url_for("admin.login_view", next=request.url))
@staticmethod
def _list_thumbnail(view, _context, model, _name):
data = ""
data += f'<img src="/attachments{model.result.attachment.path}.original.jpg" width="100" />'
return Markup(data)
column_formatters = {
"path": _list_thumbnail,
}
column_list = [
"result",
"path",
"beerd",
]

View File

@ -0,0 +1,38 @@
import flask_login
from flask import flash, redirect, request, url_for
from flask_admin.contrib.sqla import ModelView
from markupsafe import Markup
class VotesView(ModelView):
can_edit = False
can_delete = False
can_create = False
column_default_sort = ("created_at", True)
def is_accessible(self):
"""Check if current user can access admin interface"""
return flask_login.current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
"""Redirect to login if not accessible"""
flash("Please login to access this page.", "danger")
return redirect(url_for("admin.login_view", next=request.url))
@staticmethod
def _list_thumbnail(view, _context, model, _name):
data = ""
data += f'<img src="/attachments{model.attachment.path}.original.jpg" width="100" />'
return Markup(data)
column_formatters = {
"path": _list_thumbnail,
}
column_list = [
"created_at",
"path",
"beerd",
"rate",
]

View File

@ -17,3 +17,6 @@ class Beerds(UJsonMixin):
alias: str = field(metadata={"sa": Column(Text(), nullable=False)}) alias: str = field(metadata={"sa": Column(Text(), nullable=False)})
descriptions: str = field(metadata={"sa": Column(Text(), nullable=False)}) descriptions: str = field(metadata={"sa": Column(Text(), nullable=False)})
signs: dict | None = field(default=None, metadata={"sa": Column(JSON(), nullable=False)}) signs: dict | None = field(default=None, metadata={"sa": Column(JSON(), nullable=False)})
def __str__(self):
return self.name

View File

@ -9,10 +9,13 @@ from sqlalchemy import (
ForeignKeyConstraint, ForeignKeyConstraint,
String, String,
) )
from sqlalchemy.orm import relationship
from server.config import get_app_config from server.config import get_app_config
from server.infra.db.db_mapper import mapper_registry from server.infra.db.db_mapper import mapper_registry
from server.modules.rate import domain from server.modules.rate import domain
from server.modules.attachments.repository.attachments import Attachment
from server.modules.descriptions.repository.models import Beerds
@mapper_registry.mapped @mapper_registry.mapped
@ -25,6 +28,12 @@ class Vote(UJsonMixin):
ForeignKeyConstraint(["beerd_id"], ["beerds.id"], "votes_beerd_id_fk"), ForeignKeyConstraint(["beerd_id"], ["beerds.id"], "votes_beerd_id_fk"),
) )
__mapper_args__ = {
"properties": {
"beerd": relationship(Beerds, foreign_keys="Vote.beerd_id"),
"attachment": relationship(Attachment, foreign_keys="Vote.attachment_id"),
}
}
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)}) id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
attachment_id: str = field(metadata={"sa": Column(String(), nullable=False)}) attachment_id: str = field(metadata={"sa": Column(String(), nullable=False)})
beerd_id: str = field(metadata={"sa": Column(String(), nullable=False)}) beerd_id: str = field(metadata={"sa": Column(String(), nullable=False)})

View File

@ -8,8 +8,11 @@ from sqlalchemy import (
ForeignKeyConstraint, ForeignKeyConstraint,
String, String,
) )
from sqlalchemy.orm import relationship
from server.infra.db.db_mapper import mapper_registry from server.infra.db.db_mapper import mapper_registry
from server.modules.attachments.repository.attachments import Attachment
from server.modules.descriptions.repository.models import Beerds
@mapper_registry.mapped @mapper_registry.mapped
@ -19,6 +22,12 @@ class Results(UJsonMixin):
__tablename__ = "recognizer_results" __tablename__ = "recognizer_results"
__table_args__ = (ForeignKeyConstraint(["attachment_id"], ["attachments.id"], "votes_attachment_id_fk"),) __table_args__ = (ForeignKeyConstraint(["attachment_id"], ["attachments.id"], "votes_attachment_id_fk"),)
__mapper_args__ = {
"properties": {
"attachment": relationship(Attachment, foreign_keys="Results.attachment_id"),
}
}
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)}) id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
attachment_id: str = field(metadata={"sa": Column(String(), nullable=False)}) attachment_id: str = field(metadata={"sa": Column(String(), nullable=False)})
user_id: str = field(metadata={"sa": Column(String(), nullable=False)}) user_id: str = field(metadata={"sa": Column(String(), nullable=False)})
@ -28,6 +37,10 @@ class Results(UJsonMixin):
metadata={"sa": Column(DateTime(timezone=True), nullable=False)}, metadata={"sa": Column(DateTime(timezone=True), nullable=False)},
) )
def __str__(self):
formatted_date = self.created_at.strftime("%Y-%m-%d %H:%M")
return f"{formatted_date}, device_id: {self.device_id}, user_id: {self.user_id}"
@mapper_registry.mapped @mapper_registry.mapped
@dataclass @dataclass
@ -39,6 +52,13 @@ class ResultBeerds(UJsonMixin):
ForeignKeyConstraint(["beerd_id"], ["beerds.id"], "recognizer_results_beerd_id_fk"), ForeignKeyConstraint(["beerd_id"], ["beerds.id"], "recognizer_results_beerd_id_fk"),
) )
__mapper_args__ = {
"properties": {
"result": relationship(Results, foreign_keys="ResultBeerds.recognizer_results_id"),
"beerd": relationship(Beerds, foreign_keys="ResultBeerds.beerd_id"),
}
}
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)}) id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
recognizer_results_id: str = field(metadata={"sa": Column(String(), nullable=False)}) recognizer_results_id: str = field(metadata={"sa": Column(String(), nullable=False)})
beerd_id: str = field(metadata={"sa": Column(String(), nullable=False)}) beerd_id: str = field(metadata={"sa": Column(String(), nullable=False)})

View File

@ -41,7 +41,7 @@ async function SavePhoto(self) {
for (let key in json.results) { for (let key in json.results) {
currentBeerdName.push(json.results[key]); currentBeerdName.push(json.results[key]);
if (json.description != undefined) { if (json.description != undefined) {
text += `<div class='image-block'><div class='image-text'>${json.results[key]} (вероятность: ${Math.round(parseFloat(key) * 100)}%) <br/><a href="${json.description[json.results[key]]}" target='_blank'>Описание </a></div>`; text += `<div class='image-block'><div class='image-text'>${json.results[key]} (вероятность: ${Math.round(parseFloat(key) * 100)}%) <br/><a href="${json.description[json.results[key]]}" target='_blank'>Описание и фото</a></div>`;
} else { } else {
text += `<div class='image-block'><div class='image-text'>${json.results[key]} (вероятность: ${Math.round(parseFloat(key) * 100)}%)</div>`; text += `<div class='image-block'><div class='image-text'>${json.results[key]} (вероятность: ${Math.round(parseFloat(key) * 100)}%)</div>`;
} }

View File

@ -45,6 +45,6 @@
{% block form %}{% endblock %} {% block form %}{% endblock %}
</body> </body>
</section> </section>
<script src="/static/scripts.js?v=7"></script> <script src="/static/scripts.js?v=8"></script>
</html> </html>