добил до конца получения результата по ссылке
Gitea Actions Demo / build_and_push (push) Has been cancelled Details

This commit is contained in:
artem 2026-02-07 21:14:32 +03:00
parent 3baab00f80
commit 90331a7036
8 changed files with 96 additions and 32 deletions

View File

@ -35,4 +35,5 @@ class ResultsView(ModelView):
"result",
"path",
"beerd",
"probability"
]

View File

@ -57,12 +57,11 @@ class BreedsController(Controller):
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])
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,
"attachment": attachments[0],
},
)

View File

@ -0,0 +1,29 @@
"""3baab00
Revision ID: 081eb0827a55
Revises: bebaddef3e8d
Create Date: 2026-02-07 20:46:53.971562
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "081eb0827a55"
down_revision: str | None = "bebaddef3e8d"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("recognizer_results_beerds", sa.Column("probability", sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("recognizer_results_beerds", "probability")
# ### end Alembic commands ###

View File

@ -1,6 +1,3 @@
from server.modules.recognizer.repository.repository import (
ARecognizerRepository,
RecognizerRepository,
)
from server.modules.recognizer.repository.repository import ARecognizerRepository, RecognizerRepository, ResultBeerds
__all__ = ("RecognizerRepository", "ARecognizerRepository")
__all__ = ("RecognizerRepository", "ARecognizerRepository", "ResultBeerds")

View File

@ -6,6 +6,7 @@ from sqlalchemy import (
Column,
DateTime,
ForeignKeyConstraint,
Integer,
String,
)
from sqlalchemy.orm import relationship
@ -62,3 +63,4 @@ class ResultBeerds(UJsonMixin):
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
recognizer_results_id: str = field(metadata={"sa": Column(String(), nullable=False)})
beerd_id: str = field(metadata={"sa": Column(String(), nullable=False)})
probability: int = field(metadata={"sa": Column(Integer(), nullable=True)})

View File

@ -17,6 +17,12 @@ class ResultWithBeerds:
beerds: list[rm.ResultBeerds]
@dataclass
class ResultBeerds:
beerd_id: str
probability: float
class ARecognizerRepository(metaclass=ABCMeta):
@abstractmethod
async def images_dogs(self) -> dict:
@ -39,7 +45,7 @@ class ARecognizerRepository(metaclass=ABCMeta):
"""Получить **все** результаты (кэшируется)."""
@abstractmethod
async def create_result_with_beerds(self, result: rm.Results, beerd_ids: list[str]) -> None:
async def create_result_with_beerds(self, result: rm.Results, beerd_ids: list[ResultBeerds]) -> None:
"""
Создать новый результат и сразу же вставить связанные `ResultBeerds`.
@ -74,7 +80,7 @@ class RecognizerRepository(ARecognizerRepository):
data_labels = f.read()
return ujson.loads(data_labels)
async def create_result_with_beerds(self, result: rm.Results, beerd_ids: list[str]) -> None:
async def create_result_with_beerds(self, result: rm.Results, beerd_ids: list[ResultBeerds]) -> None:
"""
Создаёт запись в ``recognizer_results`` и сразу же добавляет
одну запись в ``recognizer_results_beerds`` (если передан список
@ -101,7 +107,8 @@ class RecognizerRepository(ARecognizerRepository):
{
"id": str(uuid4()),
"recognizer_results_id": result.id,
"beerd_id": beerd_id,
"beerd_id": beerd_id.beerd_id,
"probability": beerd_id.probability,
}
for beerd_id in beerd_ids
]

View File

@ -15,7 +15,7 @@ from torchvision import transforms # type: ignore
from server.modules.attachments.domains.attachments import Attachment
from server.modules.descriptions.repository import ACharactersRepository, Breed
from server.modules.recognizer.repository import ARecognizerRepository, models
from server.modules.recognizer.repository import ARecognizerRepository, ResultBeerds, models
TorchModel = NewType("TorchModel", torch.nn.Module)
@ -48,11 +48,14 @@ class RecognizerResult(UJsonMixin):
description: dict[str, list] | None
uploaded_attach_id: str | None
@dataclass
class SharingBeerds(UJsonMixin):
alias: str
name: str
images: list[ResultImages]
images: list[str]
probability: float
@dataclass
class SharingResult(UJsonMixin):
@ -60,6 +63,12 @@ class SharingResult(UJsonMixin):
attachment_id: str
@dataclass
class ResultNameBeerds:
name: str
probability: float
class RecognizerService:
__slots__ = ("_repository", "_attachment_service", "_repository_characters")
@ -79,7 +88,10 @@ class RecognizerService:
async def images_dogs(self) -> dict:
return await self._repository.images_dogs()
async def create_result(self, attachment: Attachment, user_id: str, device_id: str, beerd_names: list[str]):
async def create_result(
self, attachment: Attachment, user_id: str, device_id: str, beerd_results: list[ResultNameBeerds]
):
beerd_names = {b.name: b for b in beerd_results}
characters = await self._repository_characters.get_characters()
await self._repository.create_result_with_beerds(
models.Results(
@ -89,7 +101,11 @@ class RecognizerService:
device_id=device_id,
created_at=datetime.now(UTC),
),
[ch.id for ch in characters if ch.name in beerd_names],
[
ResultBeerds(beerd_id=ch.id, probability=beerd_names[ch.name].probability)
for ch in characters
if ch.name in beerd_names
],
)
async def get_results(self, result_id: str) -> SharingResult:
@ -101,11 +117,15 @@ class RecognizerService:
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(" ", "_")]])]
))
name = beerds_store[beerd.beerd_id].name.replace(" ", "_")
beers.append(
SharingBeerds(
alias=f"/dogs-characteristics/{beerds_store[beerd.beerd_id].alias}",
name=beerds_store[beerd.beerd_id].name,
probability=beerd.probability,
images=[f"/static/assets/dog/{name}/{i}" for i in images_dogs[name]],
)
)
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:
@ -128,7 +148,14 @@ class RecognizerService:
)
description.setdefault(name, []).append(f"/dogs-characteristics/{name.replace(' ', '_')}")
results[probabilities] = name
asyncio.create_task(self.create_result(attachment, user_id, device_id, [results[key] for key in results]))
asyncio.create_task(
self.create_result(
attachment,
user_id,
device_id,
[ResultNameBeerds(name=results[key], probability=key*100) for key in results],
)
)
return RecognizerResult(
results=results, images=images, description=description, uploaded_attach_id=attachment.id
)

View File

@ -1,26 +1,28 @@
{% extends "base.html" %}
{% block meta %}
<meta name="description" content="Определение породы кошки по фото бесплатно и без регистраций. Определение породы происходит при помощи нейронной сети - точность опеределения составляет 70%." />
<meta name="description" content="Порода по фото - поделиться результатом" />
{% endblock %}
{% block title %}Определение породы кошки по фото бесплатно{% endblock %}
{% block title %}Результат определение породы по фото{% endblock %}
{% block content %}
<h1>Определить породу кошки по фото</h1>
<p>Загрузите фото, чтобы опеределить породу собаки или щенка. Если порода смешанная (или порода определена неточно), после загрузки будет показана вероятность породы животного.</p>
<p>Определение породы происходит при помощи нейронной сети - точность опеределения составляет 60%, сеть обучена на 65 породах. Если на фото будет неизвестная порода будет предложено несколько похожих пород.</p>
<h1>Мой результат определения породы по фото</h1>
{% endblock %}
{% block form %}
<div>
<div id="upload-image">
<div id="upload-image-text">Ваше изображение:</div>
<img id="image" style="max-width: 200px;" src="/attachments{{ attachment.path }}.original.jpg">
</div>
<div id="result">
<h3 class="image-results">Результаты</h3>
{% for result in result.beerds %}
<div class="image-block"><div class="image-text">{{ result.name }} (вероятность: {{ result.percent }}%) <br>{{ attachments[result.attachment_id].path }}<a href="{{ result.path }}" target="_blank">Описание и фото</a></div>
{% for result in result.beerds %}
<div class="image-block"><div class="image-text">{{ result.name }} (вероятность: {{ result.probability }}%) <br><a href="{{ result.alias }}" target="_blank">Описание и фото</a></div>
<div class="gallery-container">
<div class="main-image-container">
<img src="{{ result.images[0].path }}" class="main-image" data-urls="[&quot;/static/assets/dog/леонбергер/leonberger_140.webp&quot;,&quot;/static/assets/dog/леонбергер/leonberger_30.webp&quot;,&quot;/static/assets/dog/леонбергер/leonberger_47.webp&quot;,&quot;/static/assets/dog/леонбергер/leonberger_50.webp&quot;,&quot;/static/assets/dog/леонбергер/leonberger_82.webp&quot;]"></div>
<img src="{{ result.images[0] }}" class="main-image"></div>
<div class="thumbnails" style="display:none;">
{% for image in result.images %}
<img src="{{ image.path }}" class="thumbnail">
<img src="{{ image }}" class="thumbnail">
{% endfor %}
</div>
</div>