From 3baab00f80e4b6bf654f42b3260b75af87c87794 Mon Sep 17 00:00:00 2001 From: artem Date: Sat, 7 Feb 2026 14:11:56 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=83=20=D1=88=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .python-version | 2 +- Makefile | 2 +- server/infra/web/recognizer.py | 21 ++++++++++-- .../descriptions/repository/__init__.py | 3 +- server/modules/rate/repository/models.py | 2 +- server/modules/recognizer/service.py | 29 ++++++++++++++++- server/templates/share.html | 32 +++++++++++++++++++ 7 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 server/templates/share.html diff --git a/.python-version b/.python-version index 3410832..edfb72e 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -cpython-3.13.5-linux-x86_64-gnu +cpython-3.13.12-linux-x86_64-gnu \ No newline at end of file diff --git a/Makefile b/Makefile index 73088d9..d671aec 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ format: uv run ruff format lint: - uv run mypy ./ --explicit-package-bases; + uv run mypy ./server --explicit-package-bases; ruff check --fix pipinstall: diff --git a/server/infra/web/recognizer.py b/server/infra/web/recognizer.py index 27b306e..79d9951 100644 --- a/server/infra/web/recognizer.py +++ b/server/infra/web/recognizer.py @@ -3,11 +3,13 @@ from dataclasses import dataclass from typing import Annotated import inject -from litestar import Controller, Request, Response, post +from litestar import Controller, Request, Response, get, post from litestar.datastructures import UploadFile from litestar.enums import RequestEncodingType from litestar.params import Body +from litestar.response import Template +from server.modules.attachments import AtachmentService from server.modules.recognizer import RecognizerService @@ -37,7 +39,7 @@ class BreedsController(Controller): recognizer_service: RecognizerService = inject.instance(RecognizerService) body = await data.f.read() result = await recognizer_service.predict_dog_image(body, user_id, data.device_id) - return Response( + return Response( content=result.to_serializable(), media_type="application/json", cookies=new_cookies, @@ -49,3 +51,18 @@ class BreedsController(Controller): body = await data.read() result = await recognizer_service.predict_cat_image(body) return result.to_serializable() + + @get("/dogs/share/{result_id:str}") + async def beerds_share(self, result_id: str) -> Template: + recognizer_service: RecognizerService = inject.instance(RecognizerService) + result = await recognizer_service.get_results(result_id) + attach_service: AtachmentService = inject.instance(AtachmentService) + attachments = await attach_service.get_info_byid(session=None, attach_id= [result.attachment_id]) + return Template( + template_name="share.html", + context={ + "result": result, + "attachments": attachments, + }, + ) + diff --git a/server/modules/descriptions/repository/__init__.py b/server/modules/descriptions/repository/__init__.py index 67ffca7..5bd08e1 100644 --- a/server/modules/descriptions/repository/__init__.py +++ b/server/modules/descriptions/repository/__init__.py @@ -1,7 +1,8 @@ from server.modules.descriptions.repository.repository import ( ACharactersRepository, + Breed, CharactersRepository, PGCharactersRepository, ) -__all__ = ("CharactersRepository", "ACharactersRepository", "PGCharactersRepository") +__all__ = ("CharactersRepository", "ACharactersRepository", "PGCharactersRepository", "Breed") diff --git a/server/modules/rate/repository/models.py b/server/modules/rate/repository/models.py index 34809b9..748c433 100644 --- a/server/modules/rate/repository/models.py +++ b/server/modules/rate/repository/models.py @@ -13,9 +13,9 @@ from sqlalchemy.orm import relationship from server.config import get_app_config from server.infra.db.db_mapper import mapper_registry -from server.modules.rate import domain from server.modules.attachments.repository.attachments import Attachment from server.modules.descriptions.repository.models import Beerds +from server.modules.rate import domain @mapper_registry.mapped diff --git a/server/modules/recognizer/service.py b/server/modules/recognizer/service.py index e52e405..dc8668d 100644 --- a/server/modules/recognizer/service.py +++ b/server/modules/recognizer/service.py @@ -14,7 +14,7 @@ import torch from torchvision import transforms # type: ignore from server.modules.attachments.domains.attachments import Attachment -from server.modules.descriptions.repository import ACharactersRepository +from server.modules.descriptions.repository import ACharactersRepository, Breed from server.modules.recognizer.repository import ARecognizerRepository, models TorchModel = NewType("TorchModel", torch.nn.Module) @@ -48,6 +48,17 @@ class RecognizerResult(UJsonMixin): description: dict[str, list] | None uploaded_attach_id: str | None +@dataclass +class SharingBeerds(UJsonMixin): + alias: str + name: str + images: list[ResultImages] + +@dataclass +class SharingResult(UJsonMixin): + beerds: list[SharingBeerds] + attachment_id: str + class RecognizerService: __slots__ = ("_repository", "_attachment_service", "_repository_characters") @@ -81,6 +92,22 @@ class RecognizerService: [ch.id for ch in characters if ch.name in beerd_names], ) + async def get_results(self, result_id: str) -> SharingResult: + results = await self._repository.get_results() + beerds_store: dict[str, Breed] = {b.id: b for b in await self._repository_characters.get_characters()} + images_dogs = await self._repository.images_dogs() + for r in results: + if r.result.id != result_id: + continue + beers: list[SharingBeerds] = [] + for beerd in r.beerds: + beers.append(SharingBeerds( + alias=beerds_store[beerd.beerd_id].alias, + name=beerds_store[beerd.beerd_id].name, + images = [ResultImages(name=beerds_store[beerd.beerd_id].name, url=[f"/static/assets/cat/{beerds_store[beerd.beerd_id].name}/{i}" for i in images_dogs[beerds_store[beerd.beerd_id].name.replace(" ", "_")]])] + )) + return SharingResult(beerds=beers, attachment_id=r.result.attachment_id) + async def predict_dog_image(self, image: bytes, user_id: str, device_id: str | None) -> RecognizerResult: if device_id is None: device_id = "mobile" diff --git a/server/templates/share.html b/server/templates/share.html new file mode 100644 index 0000000..90c938d --- /dev/null +++ b/server/templates/share.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} + +{% block meta %} + +{% endblock %} +{% block title %}Определение породы кошки по фото бесплатно{% endblock %} +{% block content %} +

Определить породу кошки по фото

+

Загрузите фото, чтобы опеределить породу собаки или щенка. Если порода смешанная (или порода определена неточно), после загрузки будет показана вероятность породы животного.

+

Определение породы происходит при помощи нейронной сети - точность опеределения составляет 60%, сеть обучена на 65 породах. Если на фото будет неизвестная порода будет предложено несколько похожих пород.

+{% endblock %} +{% block form %} +
+
+

Результаты

+ {% for result in result.beerds %} +
{{ result.name }} (вероятность: {{ result.percent }}%)
{{ attachments[result.attachment_id].path }}Описание и фото
+ +
+ {% endfor %} + +
+
+{% endblock %} \ No newline at end of file