save result definitions
Gitea Actions Demo / build_and_push (push) Successful in 31m34s
Details
Gitea Actions Demo / build_and_push (push) Successful in 31m34s
Details
This commit is contained in:
parent
ee7739b875
commit
877dde5c18
|
|
@ -7,7 +7,6 @@ from server.modules.attachments import AtachmentService
|
||||||
|
|
||||||
|
|
||||||
class AtachmentController(Controller):
|
class AtachmentController(Controller):
|
||||||
|
|
||||||
@get("/attachments/{raw_path:path}", media_type="image/jpeg")
|
@get("/attachments/{raw_path:path}", media_type="image/jpeg")
|
||||||
async def get_file(self, raw_path: str) -> Response:
|
async def get_file(self, raw_path: str) -> Response:
|
||||||
attach_service: AtachmentService = inject.instance(AtachmentService)
|
attach_service: AtachmentService = inject.instance(AtachmentService)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ class DescriptionController(Controller):
|
||||||
return Template(
|
return Template(
|
||||||
template_name="beers-description.html",
|
template_name="beers-description.html",
|
||||||
context={
|
context={
|
||||||
"text": markdown.markdown(breed.description),
|
"text": markdown.markdown(breed.description or ""),
|
||||||
"title": breed.name,
|
"title": breed.name,
|
||||||
"images": [f"/static/assets/dog/{name}/{i}" for i in images[name]],
|
"images": [f"/static/assets/dog/{name}/{i}" for i in images[name]],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
|
import uuid
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
import inject
|
import inject
|
||||||
from litestar import (
|
from litestar import Controller, Request, Response, post
|
||||||
Controller,
|
|
||||||
post,
|
|
||||||
)
|
|
||||||
from litestar.datastructures import UploadFile
|
from litestar.datastructures import UploadFile
|
||||||
from litestar.enums import RequestEncodingType
|
from litestar.enums import RequestEncodingType
|
||||||
from litestar.params import Body
|
from litestar.params import Body
|
||||||
|
|
@ -12,15 +11,37 @@ from litestar.params import Body
|
||||||
from server.modules.recognizer import RecognizerService
|
from server.modules.recognizer import RecognizerService
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BeerdsData:
|
||||||
|
f: UploadFile
|
||||||
|
device_id: str
|
||||||
|
|
||||||
|
|
||||||
class BreedsController(Controller):
|
class BreedsController(Controller):
|
||||||
path = "/beerds"
|
path = "/beerds"
|
||||||
|
|
||||||
@post("/dogs")
|
@post("/dogs")
|
||||||
async def beerds_dogs(self, data: Annotated[UploadFile, Body(media_type=RequestEncodingType.MULTI_PART)]) -> dict:
|
async def beerds_dogs(
|
||||||
|
self,
|
||||||
|
request: Request,
|
||||||
|
data: Annotated[BeerdsData, Body(media_type=RequestEncodingType.MULTI_PART)],
|
||||||
|
) -> Response:
|
||||||
|
user_id = request.cookies.get("user_id")
|
||||||
|
|
||||||
|
# Cookie, которые нужно добавить в ответ (если пользователь новый)
|
||||||
|
new_cookies: dict[str, str] | None = None
|
||||||
|
if not user_id:
|
||||||
|
user_id = str(uuid.uuid4())
|
||||||
|
new_cookies = {"user_id": user_id}
|
||||||
|
|
||||||
recognizer_service: RecognizerService = inject.instance(RecognizerService)
|
recognizer_service: RecognizerService = inject.instance(RecognizerService)
|
||||||
body = await data.read()
|
body = await data.f.read()
|
||||||
result = await recognizer_service.predict_dog_image(body)
|
result = await recognizer_service.predict_dog_image(body, user_id, data.device_id)
|
||||||
return result.to_serializable()
|
return Response(
|
||||||
|
content=result.to_serializable(),
|
||||||
|
media_type="application/json",
|
||||||
|
cookies=new_cookies,
|
||||||
|
)
|
||||||
|
|
||||||
@post("/cats")
|
@post("/cats")
|
||||||
async def beerds_cats(self, data: Annotated[UploadFile, Body(media_type=RequestEncodingType.MULTI_PART)]) -> dict:
|
async def beerds_cats(self, data: Annotated[UploadFile, Body(media_type=RequestEncodingType.MULTI_PART)]) -> dict:
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ def inject_config(binder: inject.Binder):
|
||||||
db = AsyncDB(cnf)
|
db = AsyncDB(cnf)
|
||||||
loop.run_until_complete(db.connect())
|
loop.run_until_complete(db.connect())
|
||||||
attach_service = AtachmentService(S3StorageDriver(cnf=cnf), DBAttachmentRepository(db))
|
attach_service = AtachmentService(S3StorageDriver(cnf=cnf), DBAttachmentRepository(db))
|
||||||
binder.bind(RecognizerService, RecognizerService(RecognizerRepository(), attach_service))
|
characters_repository = PGCharactersRepository(db)
|
||||||
binder.bind(CharactersService, CharactersService(PGCharactersRepository(db)))
|
binder.bind(RecognizerService, RecognizerService(RecognizerRepository(db), attach_service, characters_repository))
|
||||||
|
binder.bind(CharactersService, CharactersService(characters_repository))
|
||||||
binder.bind(VotesService, VotesService(PGVoteRepository(db)))
|
binder.bind(VotesService, VotesService(PGVoteRepository(db)))
|
||||||
binder.bind(AtachmentService, attach_service)
|
binder.bind(AtachmentService, attach_service)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from server.infra.db.db_mapper import mapper_registry
|
||||||
from server.modules.attachments.repository.models import *
|
from server.modules.attachments.repository.models import *
|
||||||
from server.modules.descriptions.repository.models import *
|
from server.modules.descriptions.repository.models import *
|
||||||
from server.modules.rate.repository.models import *
|
from server.modules.rate.repository.models import *
|
||||||
|
from server.modules.recognizer.repository.models import *
|
||||||
from sqlalchemy import engine_from_config, pool
|
from sqlalchemy import engine_from_config, pool
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
"""ee7739b
|
||||||
|
|
||||||
|
Revision ID: bebaddef3e8d
|
||||||
|
Revises: 474b572b7fe2
|
||||||
|
Create Date: 2026-01-17 13:16:39.809170
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = "bebaddef3e8d"
|
||||||
|
down_revision: str | None = "474b572b7fe2"
|
||||||
|
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.create_table(
|
||||||
|
"recognizer_results",
|
||||||
|
sa.Column("id", sa.String(), nullable=False),
|
||||||
|
sa.Column("attachment_id", sa.String(), nullable=False),
|
||||||
|
sa.Column("user_id", sa.String(), nullable=False),
|
||||||
|
sa.Column("device_id", sa.String(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(["attachment_id"], ["attachments.id"], name="votes_attachment_id_fk"),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recognizer_results_beerds",
|
||||||
|
sa.Column("id", sa.String(), nullable=False),
|
||||||
|
sa.Column("recognizer_results_id", sa.String(), nullable=False),
|
||||||
|
sa.Column("beerd_id", sa.String(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(["beerd_id"], ["beerds.id"], name="recognizer_results_beerd_id_fk"),
|
||||||
|
sa.ForeignKeyConstraint(["recognizer_results_id"], ["recognizer_results.id"], name="recognizer_results_id_fk"),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table("recognizer_results_beerds")
|
||||||
|
op.drop_table("recognizer_results")
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
@ -6,4 +6,4 @@ class Breed:
|
||||||
id: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
alias: str
|
alias: str
|
||||||
description: str
|
description: str | None
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ class PGCharactersRepository(ACharactersRepository):
|
||||||
id=str(row.id),
|
id=str(row.id),
|
||||||
name=row.name.strip(),
|
name=row.name.strip(),
|
||||||
alias=row.alias.strip(),
|
alias=row.alias.strip(),
|
||||||
description=row.descriptions.strip(),
|
description=None,
|
||||||
)
|
)
|
||||||
for row in rows
|
for row in rows
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
|
from dataclasses_ujson.dataclasses_ujson import UJsonMixin # type: ignore
|
||||||
|
from sqlalchemy import (
|
||||||
|
Column,
|
||||||
|
DateTime,
|
||||||
|
ForeignKeyConstraint,
|
||||||
|
String,
|
||||||
|
)
|
||||||
|
|
||||||
|
from server.infra.db.db_mapper import mapper_registry
|
||||||
|
|
||||||
|
|
||||||
|
@mapper_registry.mapped
|
||||||
|
@dataclass
|
||||||
|
class Results(UJsonMixin):
|
||||||
|
__sa_dataclass_metadata_key__ = "sa"
|
||||||
|
__tablename__ = "recognizer_results"
|
||||||
|
__table_args__ = (ForeignKeyConstraint(["attachment_id"], ["attachments.id"], "votes_attachment_id_fk"),)
|
||||||
|
|
||||||
|
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
|
||||||
|
attachment_id: str = field(metadata={"sa": Column(String(), nullable=False)})
|
||||||
|
user_id: str = field(metadata={"sa": Column(String(), nullable=False)})
|
||||||
|
device_id: str = field(metadata={"sa": Column(String(), nullable=False)})
|
||||||
|
created_at: datetime = field(
|
||||||
|
default=datetime.now(UTC),
|
||||||
|
metadata={"sa": Column(DateTime(timezone=True), nullable=False)},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mapper_registry.mapped
|
||||||
|
@dataclass
|
||||||
|
class ResultBeerds(UJsonMixin):
|
||||||
|
__sa_dataclass_metadata_key__ = "sa"
|
||||||
|
__tablename__ = "recognizer_results_beerds"
|
||||||
|
__table_args__ = (
|
||||||
|
ForeignKeyConstraint(["recognizer_results_id"], ["recognizer_results.id"], "recognizer_results_id_fk"),
|
||||||
|
ForeignKeyConstraint(["beerd_id"], ["beerds.id"], "recognizer_results_beerd_id_fk"),
|
||||||
|
)
|
||||||
|
|
||||||
|
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)})
|
||||||
|
|
@ -1,8 +1,20 @@
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from dataclasses import dataclass
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
import ujson
|
import ujson
|
||||||
from aiocache import Cache, cached # type: ignore
|
from aiocache import Cache, cached # type: ignore
|
||||||
|
from sqlalchemy import insert, select
|
||||||
|
|
||||||
|
from server.infra.db import AsyncDB
|
||||||
|
from server.modules.recognizer.repository import models as rm
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ResultWithBeerds:
|
||||||
|
result: rm.Results
|
||||||
|
beerds: list[rm.ResultBeerds]
|
||||||
|
|
||||||
|
|
||||||
class ARecognizerRepository(metaclass=ABCMeta):
|
class ARecognizerRepository(metaclass=ABCMeta):
|
||||||
|
|
@ -22,10 +34,23 @@ class ARecognizerRepository(metaclass=ABCMeta):
|
||||||
def labels_cats(self) -> dict:
|
def labels_cats(self) -> dict:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_results(self) -> list[ResultWithBeerds]:
|
||||||
|
"""Получить **все** результаты (кэшируется)."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def create_result_with_beerds(self, result: rm.Results, beerd_ids: list[str]) -> None:
|
||||||
|
"""
|
||||||
|
Создать новый результат и сразу же вставить связанные `ResultBeerds`.
|
||||||
|
|
||||||
|
`beerd_ids` – список id пород, которые должны быть привязаны к
|
||||||
|
результату. Если список пуст, создаётся только результат.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class RecognizerRepository(ARecognizerRepository):
|
class RecognizerRepository(ARecognizerRepository):
|
||||||
def __init__(self):
|
def __init__(self, db: AsyncDB):
|
||||||
pass
|
self._db = db
|
||||||
|
|
||||||
@cached(ttl=60, cache=Cache.MEMORY)
|
@cached(ttl=60, cache=Cache.MEMORY)
|
||||||
async def images_dogs(self) -> dict:
|
async def images_dogs(self) -> dict:
|
||||||
|
|
@ -48,3 +73,65 @@ class RecognizerRepository(ARecognizerRepository):
|
||||||
with open("server/modules/recognizer/repository/meta/labels_dogs.json") as f: # noqa: ASYNC230
|
with open("server/modules/recognizer/repository/meta/labels_dogs.json") as f: # noqa: ASYNC230
|
||||||
data_labels = f.read()
|
data_labels = f.read()
|
||||||
return ujson.loads(data_labels)
|
return ujson.loads(data_labels)
|
||||||
|
|
||||||
|
async def create_result_with_beerds(self, result: rm.Results, beerd_ids: list[str]) -> None:
|
||||||
|
"""
|
||||||
|
Создаёт запись в ``recognizer_results`` и сразу же добавляет
|
||||||
|
одну запись в ``recognizer_results_beerds`` (если передан список
|
||||||
|
beerd_id) – все в одном `INSERT`‑запросе и одной транзакции.
|
||||||
|
|
||||||
|
При отсутствии `id` у результата генерируется uuid4.
|
||||||
|
"""
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# 1️⃣ Подготовим объект результата
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
if not result.id:
|
||||||
|
result.id = str(uuid4())
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# 2️⃣ Откроем транзакцию и добавим результат
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
async with self._db.async_session() as session:
|
||||||
|
async with session.begin(): # начинается транзакция
|
||||||
|
session.add(result) # INSERT recognizer_results
|
||||||
|
|
||||||
|
# Если есть связанные beerd, делаем один bulk‑INSERT
|
||||||
|
if beerd_ids:
|
||||||
|
values = [
|
||||||
|
{
|
||||||
|
"id": str(uuid4()),
|
||||||
|
"recognizer_results_id": result.id,
|
||||||
|
"beerd_id": beerd_id,
|
||||||
|
}
|
||||||
|
for beerd_id in beerd_ids
|
||||||
|
]
|
||||||
|
# Один INSERT … VALUES (..), (..), …
|
||||||
|
await session.execute(insert(rm.ResultBeerds).values(values))
|
||||||
|
await session.commit() # завершаем транзакцию
|
||||||
|
|
||||||
|
@cached(ttl=60, cache=Cache.MEMORY)
|
||||||
|
async def get_results(self) -> list[ResultWithBeerds]:
|
||||||
|
async with self._db.async_session() as session:
|
||||||
|
# 1️⃣ Получаем все результаты
|
||||||
|
stmt_res = select(rm.Results)
|
||||||
|
res_res = await session.execute(stmt_res)
|
||||||
|
results = res_res.scalars().all()
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 2️⃣ Получаем все beerds, относящиеся к этим результатам
|
||||||
|
res_ids = [r.id for r in results]
|
||||||
|
stmt_beerds = (
|
||||||
|
select(rm.ResultBeerds).where(rm.ResultBeerds.recognizer_results_id.in_(res_ids)) # type:ignore
|
||||||
|
)
|
||||||
|
res_beerds = await session.execute(stmt_beerds)
|
||||||
|
beerds_list = res_beerds.scalars().all()
|
||||||
|
|
||||||
|
# 3️⃣ Формируем карту id → beerds
|
||||||
|
by_res: dict[str, list[rm.ResultBeerds]] = {}
|
||||||
|
for b in beerds_list:
|
||||||
|
by_res.setdefault(b.recognizer_results_id, []).append(b)
|
||||||
|
|
||||||
|
# 4️⃣ Собираем DTO‑ы
|
||||||
|
return [ResultWithBeerds(result=r, beerds=by_res.get(r.id, [])) for r in results]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
import asyncio
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from datetime import UTC, datetime
|
||||||
from typing import Any, NewType, Protocol
|
from typing import Any, NewType, Protocol
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from dataclasses_ujson.dataclasses_ujson import UJsonMixin # type: ignore
|
from dataclasses_ujson.dataclasses_ujson import UJsonMixin # type: ignore
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
@ -11,7 +14,8 @@ import torch
|
||||||
from torchvision import transforms # type: ignore
|
from torchvision import transforms # type: ignore
|
||||||
|
|
||||||
from server.modules.attachments.domains.attachments import Attachment
|
from server.modules.attachments.domains.attachments import Attachment
|
||||||
from server.modules.recognizer.repository import ARecognizerRepository
|
from server.modules.descriptions.repository import ACharactersRepository
|
||||||
|
from server.modules.recognizer.repository import ARecognizerRepository, models
|
||||||
|
|
||||||
TorchModel = NewType("TorchModel", torch.nn.Module)
|
TorchModel = NewType("TorchModel", torch.nn.Module)
|
||||||
|
|
||||||
|
|
@ -46,11 +50,17 @@ class RecognizerResult(UJsonMixin):
|
||||||
|
|
||||||
|
|
||||||
class RecognizerService:
|
class RecognizerService:
|
||||||
__slots__ = ("_repository", "_attachment_service")
|
__slots__ = ("_repository", "_attachment_service", "_repository_characters")
|
||||||
|
|
||||||
def __init__(self, repository: ARecognizerRepository, attachment_service: AttachmentService):
|
def __init__(
|
||||||
|
self,
|
||||||
|
repository: ARecognizerRepository,
|
||||||
|
attachment_service: AttachmentService,
|
||||||
|
repository_characters: ACharactersRepository,
|
||||||
|
):
|
||||||
self._repository = repository
|
self._repository = repository
|
||||||
self._attachment_service = attachment_service
|
self._attachment_service = attachment_service
|
||||||
|
self._repository_characters = repository_characters
|
||||||
|
|
||||||
async def images_cats(self) -> dict:
|
async def images_cats(self) -> dict:
|
||||||
return await self._repository.images_cats()
|
return await self._repository.images_cats()
|
||||||
|
|
@ -58,7 +68,22 @@ class RecognizerService:
|
||||||
async def images_dogs(self) -> dict:
|
async def images_dogs(self) -> dict:
|
||||||
return await self._repository.images_dogs()
|
return await self._repository.images_dogs()
|
||||||
|
|
||||||
async def predict_dog_image(self, image: bytes) -> RecognizerResult:
|
async def create_result(self, attachment: Attachment, user_id: str, device_id: str, beerd_names: list[str]):
|
||||||
|
characters = await self._repository_characters.get_characters()
|
||||||
|
await self._repository.create_result_with_beerds(
|
||||||
|
models.Results(
|
||||||
|
id=str(uuid4()),
|
||||||
|
attachment_id=attachment.id,
|
||||||
|
user_id=user_id,
|
||||||
|
device_id=device_id,
|
||||||
|
created_at=datetime.now(UTC),
|
||||||
|
),
|
||||||
|
[ch.id for ch in characters if ch.name in beerd_names],
|
||||||
|
)
|
||||||
|
|
||||||
|
async def predict_dog_image(self, image: bytes, user_id: str, device_id: str | None) -> RecognizerResult:
|
||||||
|
if device_id is None:
|
||||||
|
device_id = "mobile"
|
||||||
attachment = await self._attachment_service.create(image)
|
attachment = await self._attachment_service.create(image)
|
||||||
predicted_data = self._predict(image, DOG_MODEL)
|
predicted_data = self._predict(image, DOG_MODEL)
|
||||||
results = {}
|
results = {}
|
||||||
|
|
@ -76,6 +101,7 @@ class RecognizerService:
|
||||||
)
|
)
|
||||||
description.setdefault(name, []).append(f"/dogs-characteristics/{name.replace(' ', '_')}")
|
description.setdefault(name, []).append(f"/dogs-characteristics/{name.replace(' ', '_')}")
|
||||||
results[probabilities] = name
|
results[probabilities] = name
|
||||||
|
asyncio.create_task(self.create_result(attachment, user_id, device_id, [results[key] for key in results]))
|
||||||
return RecognizerResult(
|
return RecognizerResult(
|
||||||
results=results, images=images, description=description, uploaded_attach_id=attachment.id
|
results=results, images=images, description=description, uploaded_attach_id=attachment.id
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
|
|
||||||
let urlCreator = window.URL || window.webkitURL;
|
let urlCreator = window.URL || window.webkitURL;
|
||||||
|
|
||||||
let current_attachment_id = 0;
|
let currentAttachmentID = 0;
|
||||||
let current_beerd_name = [];
|
let currentBeerdName = [];
|
||||||
|
const deviceID = "web";
|
||||||
|
|
||||||
async function SavePhoto(self) {
|
async function SavePhoto(self) {
|
||||||
document.getElementById("result").innerHTML = "";
|
document.getElementById("result").innerHTML = "";
|
||||||
let photo = document.getElementById("file-input").files[0];
|
let photo = document.getElementById("file-input").files[0];
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append("f", photo);
|
formData.append("f", photo);
|
||||||
|
formData.append('device_id', deviceID);
|
||||||
let response = await fetch(self.action, { method: "POST", body: formData });
|
let response = await fetch(self.action, { method: "POST", body: formData });
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let json = await response.json();
|
let json = await response.json();
|
||||||
current_attachment_id = json.uploaded_attach_id;
|
currentAttachmentID = json.uploaded_attach_id;
|
||||||
|
|
||||||
let text = "<h3 class='image-results'>Результаты</h3>";
|
let text = "<h3 class='image-results'>Результаты</h3>";
|
||||||
let uniqChecker = {};
|
let uniqChecker = {};
|
||||||
|
|
@ -37,7 +39,7 @@ async function SavePhoto(self) {
|
||||||
|
|
||||||
// Обработка основных результатов
|
// Обработка основных результатов
|
||||||
for (let key in json.results) {
|
for (let key in json.results) {
|
||||||
current_beerd_name.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 {
|
||||||
|
|
@ -218,8 +220,8 @@ function closeModal() {
|
||||||
// Подготовьте объект‑payload. Добавьте id‑токены, если нужны.
|
// Подготовьте объект‑payload. Добавьте id‑токены, если нужны.
|
||||||
const payload = {
|
const payload = {
|
||||||
rate: value,
|
rate: value,
|
||||||
attachment_id: current_attachment_id,
|
attachment_id: currentAttachmentID,
|
||||||
beerd_name: current_beerd_name[0],
|
beerd_name: currentBeerdName[0],
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,6 @@
|
||||||
{% block form %}{% endblock %}
|
{% block form %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</section>
|
</section>
|
||||||
<script src="/static/scripts.js?v=6"></script>
|
<script src="/static/scripts.js?v=7"></script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue