111 слов | 1 минута

YOLOv8 + Bitrix: интеграция через Python-микросервис

Напрямую запускать нейросети из PHP через exec() неэффективно: загрузка модели занимает 1–3 секунды на каждый запрос.

Оптимальная архитектура:

  1. Python-скрипт с FastAPI загружает модель один раз при старте и ждёт запросы.
  2. PHP отправляет изображение на локальный порт и мгновенно получает JSON.
Bitrix (PHP) → HTTP POST → Python FastAPI (порт 5000) → YOLOv8 → JSON

Настройка Python-сервиса

Установка зависимостей

pip install fastapi uvicorn ultralytics python-multipart

Создание сервиса poker_api.py

from fastapi import FastAPI, UploadFile, File
from ultralytics import YOLO
from PIL import Image
import io

app = FastAPI()

# Модель загружается один раз при старте
model = YOLO("yolov8m.pt")

@app.post("/predict")
async def predict(file: UploadFile = File(...)):
    # Читаем изображение из памяти без сохранения на диск
    image_data = await file.read()
    image = Image.open(io.BytesIO(image_data))

    results = model(image)

    cards = []
    for r in results:
        for box in r.boxes:
            cls_id = int(box.cls[0])
            class_name = model.names[cls_id]
            conf = float(box.conf[0])

            cards.append({
                "card": class_name,
                "confidence": round(conf, 2),
                "box": box.xywh.tolist()[0]  # [x, y, w, h]
            })

    return {"result": cards}

Запуск сервиса

# Для разработки
uvicorn poker_api:app --host 127.0.0.1 --port 5000

Для production используйте systemd или supervisor для фонового запуска.

Интеграция в PHP (Битрикс)

use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Web\Json;

function recognizeCards($filePath)
{
    $httpClient = new HttpClient();

    $boundary = '--------------------------' . microtime(true);
    $httpClient->setHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary);

    if (!file_exists($filePath)) {
        return false;
    }

    $fileContent = file_get_contents($filePath);
    $filename = basename($filePath);

    $body = "--" . $boundary . "\r\n";
    $body .= "Content-Disposition: form-data; name=\"file\"; filename=\"" . $filename . "\"\r\n";
    $body .= "Content-Type: image/jpeg\r\n\r\n";
    $body .= $fileContent . "\r\n";
    $body .= "--" . $boundary . "--\r\n";

    $response = $httpClient->post('http://127.0.0.1:5000/predict', $body);

    if ($httpClient->getStatus() == 200) {
        try {
            $data = Json::decode($response);
            return $data['result'];
        } catch (\Exception $e) {
            return false;
        }
    }

    return false;
}

Пример вызова

$imagePath = $_SERVER["DOCUMENT_ROOT"] . "/upload/image.jpg";
$cards = recognizeCards($imagePath);

if ($cards) {
    foreach ($cards as $card) {
        echo "Объект: <b>" . $card['card'] . "</b> ";
        echo "(Точность: " . round($card['confidence'] * 100) . "%)<br>";
    }
}

Преимущества архитектуры

Параметр Значение
Скорость Модель загружается один раз, обработка запроса — доли секунды
Изоляция Ошибка в Python-скрипте не влияет на PHP-процесс Битрикса
Масштабируемость При высокой нагрузке Python-сервис можно вынести на отдельный GPU-сервер
Обновление модели Замена model.onnx/.pt без изменений на стороне PHP