refactoring
Gitea Actions Demo / build_and_push (push) Failing after 1m6s
Details
Gitea Actions Demo / build_and_push (push) Failing after 1m6s
Details
This commit is contained in:
parent
338032d6e8
commit
84229d2de9
|
|
@ -1 +1 @@
|
||||||
3.11
|
cpython-3.13.5-linux-x86_64-gnu
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import os
|
import os
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt # type: ignore
|
||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
from torchvision.datasets import ImageFolder # type: ignore
|
from torchvision.datasets import ImageFolder # type: ignore
|
||||||
|
|
@ -19,7 +19,7 @@ def get_labels(input_dir, img_size):
|
||||||
transforms.Resize(img_size),
|
transforms.Resize(img_size),
|
||||||
transforms.RandomHorizontalFlip(),
|
transforms.RandomHorizontalFlip(),
|
||||||
transforms.ToTensor(),
|
transforms.ToTensor(),
|
||||||
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
|
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
dataset = ImageFolder(root=input_dir, transform=transform)
|
dataset = ImageFolder(root=input_dir, transform=transform)
|
||||||
|
|
@ -47,7 +47,7 @@ def load_model(model_path: str, labels_dict: dict, device: str = "cuda") -> nn.M
|
||||||
model = torchvision.models.resnet50(weights=ResNet50_Weights.DEFAULT)
|
model = torchvision.models.resnet50(weights=ResNet50_Weights.DEFAULT)
|
||||||
model.fc = nn.Sequential(
|
model.fc = nn.Sequential(
|
||||||
nn.Dropout(0.5), # Регуляризация
|
nn.Dropout(0.5), # Регуляризация
|
||||||
torch.nn.Linear(model.fc.in_features, len(labels_dict))
|
torch.nn.Linear(model.fc.in_features, len(labels_dict)),
|
||||||
)
|
)
|
||||||
return model
|
return model
|
||||||
model = torch.load(model_path, map_location=device, weights_only=False)
|
model = torch.load(model_path, map_location=device, weights_only=False)
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,31 @@ name = "ai"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = "~=3.11"
|
requires-python = "~=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"granian>=2.2.4",
|
"granian==2.5",
|
||||||
"jinja2>=3.1.6",
|
"jinja2>=3.1.6",
|
||||||
"starlite>=1.51.16",
|
"numpy==2.3.4",
|
||||||
"numpy==1.23.5",
|
|
||||||
"pillow>=11.1.0",
|
"pillow>=11.1.0",
|
||||||
"markdown>=3.9",
|
"markdown>=3.9",
|
||||||
|
"aiocache",
|
||||||
|
"torch>=2.9.1",
|
||||||
|
"ruff>=0.14.5",
|
||||||
|
"mypy>=1.18.2",
|
||||||
|
"uvicorn>=0.38.0",
|
||||||
|
"pydantic>=2.12.4",
|
||||||
|
"litestar==2.18.0",
|
||||||
|
"ujson>=5.11.0",
|
||||||
|
"torchvision>=0.24.1",
|
||||||
|
"types-requests>=2.32.4.20250913",
|
||||||
|
"types-markdown>=3.10.0.20251106",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
default = [
|
default = [
|
||||||
"torch>=2.6.0",
|
"torch>=2.9.1",
|
||||||
"torchvision>=0.21.0",
|
"torchvision>=0.21.0",
|
||||||
"mypy>=1.15.0",
|
"mypy>=1.18",
|
||||||
"pyqt5>=5.15.11",
|
"pyqt5>=5.15.11",
|
||||||
"requests>=2.32.3",
|
"requests>=2.32.3",
|
||||||
"ruff>=0.11.5",
|
"ruff>=0.11.5",
|
||||||
|
|
@ -25,35 +35,15 @@ default = [
|
||||||
"matplotlib>=3.10.1",
|
"matplotlib>=3.10.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
api = [
|
|
||||||
"torch>=2.6.0",
|
|
||||||
"torchvision>=0.21.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.uv]
|
|
||||||
conflicts = [
|
|
||||||
[
|
|
||||||
{ extra = "default" },
|
|
||||||
{ extra = "api" },
|
|
||||||
],
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
torch = [
|
torch = [
|
||||||
{ index = "pytorch-cu124", extra = "default" },
|
{ index = "pytorch-cpu", extra = "default" },
|
||||||
{ index = "pytorch-cpu", extra = "api" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
torchvision = [
|
torchvision = [
|
||||||
{ index = "pytorch-cu124", extra = "default" },
|
{ index = "pytorch-cpu", extra = "default" },
|
||||||
{ index = "pytorch-cpu", extra = "api" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[tool.uv.index]]
|
|
||||||
name = "pytorch-cu124"
|
|
||||||
url = "https://download.pytorch.org/whl/cu124"
|
|
||||||
explicit = true
|
|
||||||
|
|
||||||
[[tool.uv.index]]
|
[[tool.uv.index]]
|
||||||
name = "pytorch-cpu"
|
name = "pytorch-cpu"
|
||||||
url = "https://download.pytorch.org/whl/cpu"
|
url = "https://download.pytorch.org/whl/cpu"
|
||||||
|
|
|
||||||
193
server/main.py
193
server/main.py
|
|
@ -1,93 +1,35 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
|
||||||
import markdown
|
import markdown
|
||||||
from PIL import Image
|
from litestar import (
|
||||||
from starlite import (
|
|
||||||
Controller,
|
Controller,
|
||||||
StaticFilesConfig,
|
|
||||||
get,
|
get,
|
||||||
post,
|
post,
|
||||||
Body,
|
|
||||||
MediaType,
|
MediaType,
|
||||||
RequestEncodingType,
|
Litestar,
|
||||||
Starlite,
|
|
||||||
UploadFile,
|
|
||||||
Template,
|
|
||||||
TemplateConfig,
|
|
||||||
HTTPException
|
|
||||||
)
|
)
|
||||||
from starlite.contrib.jinja import JinjaTemplateEngine
|
from litestar.enums import RequestEncodingType
|
||||||
import io
|
from litestar.datastructures import UploadFile
|
||||||
import os
|
from litestar.params import Body
|
||||||
import json
|
from litestar.exceptions import HTTPException
|
||||||
|
from litestar.contrib.jinja import JinjaTemplateEngine
|
||||||
|
from litestar.template.config import TemplateConfig
|
||||||
|
from litestar.response import Template
|
||||||
|
from litestar.static_files import create_static_files_router
|
||||||
|
|
||||||
import torch
|
|
||||||
from torchvision import transforms # type: ignore
|
from server.services.descriptions import CharactersService, Breed, CharactersRepository
|
||||||
import torch.nn.functional as F
|
from server.services.recognizer import RecognizerService, RecognizerRepository
|
||||||
|
|
||||||
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
||||||
|
|
||||||
|
|
||||||
def load_model(model_path, device="cpu"):
|
recognizer_service = RecognizerService(RecognizerRepository())
|
||||||
model = torch.load(model_path, map_location=device, weights_only=False)
|
characters_service = CharactersService(CharactersRepository())
|
||||||
model.eval()
|
|
||||||
return model
|
|
||||||
|
|
||||||
|
|
||||||
DOG_MODEL = load_model("server/models/dogs_model.pth")
|
class BreedsController(Controller):
|
||||||
CAT_MODEL = load_model("server/models/cats_model.pth")
|
|
||||||
|
|
||||||
with open("server/meta/labels_dogs.json", "r") as f:
|
|
||||||
data_labels = f.read()
|
|
||||||
labels_dogs = json.loads(data_labels)
|
|
||||||
|
|
||||||
with open("server/meta/labels_cats.json", "r") as f:
|
|
||||||
data_labels = f.read()
|
|
||||||
labels_cats = json.loads(data_labels)
|
|
||||||
|
|
||||||
|
|
||||||
with open("server/meta/images.json", "r") as f:
|
|
||||||
IMAGES = json.loads(f.read())
|
|
||||||
|
|
||||||
def predict_image(image, model, device="cuda") -> list[tuple]:
|
|
||||||
img_size = (224, 224)
|
|
||||||
preprocess = transforms.Compose(
|
|
||||||
[
|
|
||||||
transforms.Resize(img_size),
|
|
||||||
transforms.ToTensor(),
|
|
||||||
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
input_tensor = preprocess(image)
|
|
||||||
input_batch = input_tensor.unsqueeze(0).to(device) # Добавляем dimension для батча
|
|
||||||
|
|
||||||
with torch.no_grad():
|
|
||||||
output = model(input_batch)
|
|
||||||
|
|
||||||
probabilities = torch.nn.functional.softmax(output[0], dim=0)
|
|
||||||
k = 5
|
|
||||||
topk_probs, predicted_idx = torch.topk(probabilities, k)
|
|
||||||
|
|
||||||
data = []
|
|
||||||
for i in range(k):
|
|
||||||
data.append((predicted_idx[i].item(), float(topk_probs[i].item())))
|
|
||||||
return data
|
|
||||||
|
|
||||||
breed_dir = Path("server/meta/breed_descriptions")
|
|
||||||
DOGS_BEERS = []
|
|
||||||
|
|
||||||
# Идем по каждому текстовому файлу с описанием породы
|
|
||||||
for breed_file in breed_dir.glob("*.txt"):
|
|
||||||
breed_name = breed_file.stem # имя файла без расширения - название породы
|
|
||||||
description = breed_file.read_text(encoding="utf-8") # читаем описание из файла
|
|
||||||
DOGS_BEERS.append({
|
|
||||||
"name": breed_name.replace("_", " "),
|
|
||||||
"alias": breed_file.stem,
|
|
||||||
"description": description.strip()
|
|
||||||
})
|
|
||||||
DOGS_BEERS.sort(key=lambda b: b["name"])
|
|
||||||
|
|
||||||
class BeerdsController(Controller):
|
|
||||||
path = "/beerds"
|
path = "/beerds"
|
||||||
|
|
||||||
@post("/dogs")
|
@post("/dogs")
|
||||||
|
|
@ -95,96 +37,69 @@ class BeerdsController(Controller):
|
||||||
self, data: UploadFile = Body(media_type=RequestEncodingType.MULTI_PART)
|
self, data: UploadFile = Body(media_type=RequestEncodingType.MULTI_PART)
|
||||||
) -> dict:
|
) -> dict:
|
||||||
body = await data.read()
|
body = await data.read()
|
||||||
|
return await recognizer_service.predict_dog_image(body)
|
||||||
img_file = Image.open(io.BytesIO(body))
|
|
||||||
predicted_data = predict_image(img_file, DOG_MODEL, "cpu")
|
|
||||||
results = {}
|
|
||||||
images = []
|
|
||||||
for d in predicted_data:
|
|
||||||
predicted_idx, probabilities = d
|
|
||||||
predicted_label = labels_dogs[str(predicted_idx)]
|
|
||||||
name = predicted_label.replace("_", " ")
|
|
||||||
images.append({
|
|
||||||
"name": name,
|
|
||||||
"url": [f"/static/assets/dog/{predicted_label}/{i}" for i in IMAGES['dog'][predicted_label]]
|
|
||||||
})
|
|
||||||
results[probabilities] = name
|
|
||||||
return {
|
|
||||||
"results": results,
|
|
||||||
"images": images,
|
|
||||||
}
|
|
||||||
|
|
||||||
@post("/cats")
|
@post("/cats")
|
||||||
async def beerds_cats(
|
async def beerds_cats(
|
||||||
self, data: UploadFile = Body(media_type=RequestEncodingType.MULTI_PART)
|
self, data: UploadFile = Body(media_type=RequestEncodingType.MULTI_PART)
|
||||||
) -> dict:
|
) -> dict:
|
||||||
body = await data.read()
|
body = await data.read()
|
||||||
|
return await recognizer_service.predict_cat_image(body)
|
||||||
img_file = Image.open(io.BytesIO(body))
|
|
||||||
predicted_data = predict_image(img_file, CAT_MODEL, "cpu")
|
|
||||||
results = {}
|
|
||||||
images = []
|
|
||||||
for d in predicted_data:
|
|
||||||
predicted_idx, probabilities = d
|
|
||||||
predicted_label = labels_cats[str(predicted_idx)]
|
|
||||||
name = predicted_label.replace("_", " ")
|
|
||||||
images.append({
|
|
||||||
"name": name,
|
|
||||||
"url": [f"/static/assets/cat/{predicted_label}/{i}" for i in IMAGES['cat'][predicted_label]]
|
|
||||||
})
|
|
||||||
results[probabilities] = predicted_label
|
|
||||||
return {
|
|
||||||
"results": results,
|
|
||||||
"images": images,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class BaseController(Controller):
|
class DescriptionController(Controller):
|
||||||
path = "/"
|
path = "/"
|
||||||
|
|
||||||
@get("/")
|
@get("/")
|
||||||
async def dogs(self) -> Template:
|
async def dogs(self) -> Template:
|
||||||
return Template(name="dogs.html")
|
return Template(template_name="dogs.html")
|
||||||
|
|
||||||
@get("/cats")
|
@get("/cats")
|
||||||
async def cats(self) -> Template:
|
async def cats(self) -> Template:
|
||||||
return Template(name="cats.html")
|
return Template(template_name="cats.html")
|
||||||
|
|
||||||
@get("/contacts")
|
@get("/contacts")
|
||||||
async def contacts(self) -> Template:
|
async def contacts(self) -> Template:
|
||||||
return Template(name="contacts.html")
|
return Template(template_name="contacts.html")
|
||||||
|
|
||||||
@get("/donate")
|
@get("/donate")
|
||||||
async def donate(self) -> Template:
|
async def donate(self) -> Template:
|
||||||
return Template(name="donate.html")
|
return Template(template_name="donate.html")
|
||||||
|
|
||||||
@get("/dogs-characteristics")
|
@get("/dogs-characteristics")
|
||||||
async def dogs_characteristics(self) -> Template:
|
async def dogs_characteristics(self) -> Template:
|
||||||
return Template(name="dogs-characteristics.html", context={"breeds": DOGS_BEERS})
|
breeds = await characters_service.get_characters()
|
||||||
|
return Template(
|
||||||
|
template_name="dogs-characteristics.html", context={"breeds": breeds}
|
||||||
|
)
|
||||||
|
|
||||||
@get("/dogs-characteristics/{name:str}")
|
@get("/dogs-characteristics/{name:str}")
|
||||||
async def beer_description(self, name: str) -> Template:
|
async def beer_description(self, name: str) -> Template:
|
||||||
data = [b for b in DOGS_BEERS if b.get("alias") == name]
|
breed = await characters_service.get_character(name)
|
||||||
if len(data) == 0:
|
if breed is None:
|
||||||
raise HTTPException(status_code=404, detail="Порода не найдена")
|
raise HTTPException(status_code=404, detail="Порода не найдена")
|
||||||
return Template(name="beers-description.html", context={
|
images = await recognizer_service.images_dogs()
|
||||||
"text": markdown.markdown(data[0].get("description")),
|
return Template(
|
||||||
"title": data[0].get("name"),
|
template_name="beers-description.html",
|
||||||
"images": [f"/static/assets/dog/{name}/{i}" for i in IMAGES['dog'][name]],
|
context={
|
||||||
})
|
"text": markdown.markdown(breed.description),
|
||||||
|
"title": breed.name,
|
||||||
|
"images": [f"/static/assets/dog/{name}/{i}" for i in images[name]],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@get("/sitemap.xml", media_type=MediaType.XML)
|
@get("/sitemap.xml", media_type=MediaType.XML)
|
||||||
async def sitemaps(self) -> bytes:
|
async def sitemaps(self) -> bytes:
|
||||||
|
breeds: list[Breed] = await characters_service.get_characters()
|
||||||
lastmod = "2025-10-04T19:01:03+00:00"
|
lastmod = "2025-10-04T19:01:03+00:00"
|
||||||
beers_url = ""
|
beers_url = ""
|
||||||
for b in DOGS_BEERS:
|
for b in breeds:
|
||||||
beers_url += f'''
|
beers_url += f"""
|
||||||
<url>
|
<url>
|
||||||
<loc>https://xn-----6kcp3cadbabfh8a0a.xn--p1ai/dogs-characteristics/{b.get("alias")}</loc>
|
<loc>https://xn-----6kcp3cadbabfh8a0a.xn--p1ai/dogs-characteristics/{b.alias}</loc>
|
||||||
<lastmod>{lastmod}</lastmod>
|
<lastmod>{lastmod}</lastmod>
|
||||||
</url>
|
</url>
|
||||||
'''
|
"""
|
||||||
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset
|
<urlset
|
||||||
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
|
@ -214,7 +129,6 @@ class BaseController(Controller):
|
||||||
|
|
||||||
</urlset>
|
</urlset>
|
||||||
""".encode()
|
""".encode()
|
||||||
|
|
||||||
|
|
||||||
@get("/robots.txt", media_type=MediaType.TEXT)
|
@get("/robots.txt", media_type=MediaType.TEXT)
|
||||||
async def robots(self) -> str:
|
async def robots(self) -> str:
|
||||||
|
|
@ -226,11 +140,12 @@ Sitemap: https://xn-----6kcp3cadbabfh8a0a.xn--p1ai/sitemap.xml
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
app = Starlite(
|
app = Litestar(
|
||||||
debug=True,
|
debug=True,
|
||||||
route_handlers=[BeerdsController, BaseController],
|
route_handlers=[
|
||||||
static_files_config=[
|
BreedsController,
|
||||||
StaticFilesConfig(directories=[Path("server/static")], path="/static"),
|
DescriptionController,
|
||||||
|
create_static_files_router(path="/static", directories=["server/static"]),
|
||||||
],
|
],
|
||||||
template_config=TemplateConfig(
|
template_config=TemplateConfig(
|
||||||
directory=Path("server/templates"),
|
directory=Path("server/templates"),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
from server.services.descriptions.repository import (
|
||||||
|
CharactersRepository,
|
||||||
|
ACharactersRepository,
|
||||||
|
)
|
||||||
|
from server.services.descriptions.service import CharactersService
|
||||||
|
from server.services.descriptions.domain import Breed
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"CharactersRepository",
|
||||||
|
"ACharactersRepository",
|
||||||
|
"CharactersService",
|
||||||
|
"Breed",
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Breed:
|
||||||
|
name: str
|
||||||
|
alias: str
|
||||||
|
description: str
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
from server.services.descriptions.repository.repository import (
|
||||||
|
CharactersRepository,
|
||||||
|
ACharactersRepository,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = ("CharactersRepository", "ACharactersRepository")
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue