Add Docker build and deploy pipeline
All checks were successful
deploy-ai / deploy (push) Successful in 2m56s

This commit is contained in:
SlimusMinus
2026-10-07 23:53:52 +03:00
parent 848f40846a
commit a17829014b
14 changed files with 206 additions and 59 deletions

View File

@@ -0,0 +1,8 @@
__pycache__
*.pyc
.env
venv
.venv
models
.idea
.git

22
ai-moderation/Dockerfile Normal file
View File

@@ -0,0 +1,22 @@
FROM python:3.12-slim
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1
WORKDIR /app
# torch ставим отдельно в облегчённой версии для процессора (без CUDA)
RUN pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app ./app
RUN useradd -r -u 1001 app \
&& mkdir -p /models \
&& chown app /models
USER app
ENV MODEL_CACHE_DIR=/models
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -0,0 +1,109 @@
import torch
from PIL import Image
from transformers import Owlv2ForObjectDetection, Owlv2Processor
from app.config.settings import settings
from app.ml.image.weapon_prediction_result import WeaponPredictionResult
class WeaponDetector:
QUERIES = [
"a gun",
"a pistol",
"a revolver",
"a rifle",
"a shotgun",
"an assault rifle",
"a knife",
"a machete",
"a sword",
"a bomb",
"a grenade",
"a crossbow",
"a bow and arrow",
"brass knuckles",
"a nunchaku"
]
def __init__(self):
self.device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Loading OWLv2 weapon detector on {self.device}")
self.model = Owlv2ForObjectDetection.from_pretrained(
settings.WEAPON_MODEL
)
self.processor = Owlv2Processor.from_pretrained(
settings.WEAPON_MODEL
)
self.model.to(self.device)
self.model.eval()
def predict(
self,
image: Image.Image
) -> WeaponPredictionResult:
inputs = self.processor(
text=self.QUERIES,
images=image,
return_tensors="pt"
)
inputs = {
key: value.to(self.device)
for key, value in inputs.items()
}
with torch.no_grad():
outputs = self.model(**inputs)
target_sizes = torch.tensor([image.size[::-1]])
results = self.processor.post_process_grounded_object_detection(
outputs,
threshold=0.0,
target_sizes=target_sizes
)[0]
scores = results["scores"].tolist()
labels = results["labels"].tolist()
boxes = results["boxes"].tolist()
image_area = image.width * image.height
label_scores = {}
for score, label_index, box in zip(scores, labels, boxes):
box_area = (box[2] - box[0]) * (box[3] - box[1])
if box_area < image_area * settings.WEAPON_MIN_AREA_FRACTION:
continue
if score >= settings.WEAPON_THRESHOLD:
query = self.QUERIES[label_index]
label_scores[query] = max(
label_scores.get(query, 0.0),
score
)
if not label_scores:
return WeaponPredictionResult(
label="normal",
score=0.0
)
best_label = max(
label_scores,
key=label_scores.get
)
print("====================")
print("WEAPON RESULT")
print("Scores:", label_scores)
return WeaponPredictionResult(
label=best_label,
score=label_scores[best_label],
detected_labels=sorted(label_scores.keys()),
box_count=len(label_scores)
)

View File

@@ -0,0 +1,14 @@
from dataclasses import dataclass, field
@dataclass(slots=True)
class WeaponPredictionResult:
label: str
score: float
detected_labels: list[str] = field(
default_factory=list
)
box_count: int = 0

Binary file not shown.