Ctrl K
ComunidadGuías…

pyproject.toml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
[project]
name = "opennvr-ai-adapter"
# The reference adapter server. Versioned with the OpenNVR release train
# (v0.1.0 = the first public cut). Not published to PyPI — it ships as the
# per-adapter GHCR images built on each `v*` tag. The standalone SDK under
# opennvr_adapter_sdk/ versions independently (1.x = AI Adapter Contract v1)
# and IS published to PyPI, off `sdk-v*` tags.
version = "0.1.10"
description = "Clean Architecture AI Adapter for OpenNVR"
requires-python = ">=3.11, <3.13"

# ── Core dependencies ──────────────────────────────────────────────────────────
# These are installed in EVERY deployment regardless of which adapters are used.
# Keep this list lean: only what the FastAPI server, routing, and base adapter
# infrastructure needs.
dependencies = [
    "fastapi==0.127.0",
    "uvicorn==0.40.0",
    "pydantic==2.12.5",
    "PyYAML==6.0.3",
    "httpx==0.28.1",
    "requests==2.32.5",
    "pillow==12.0.0",
    "numpy==1.26.4",
    "opencv-python==4.10.0.84",
    # Required by FastAPI for any multipart/form-data route. Every
    # adapter that accepts image/audio body via the SDK's body parser
    # (insightface /faces/register + every /infer with multipart) and
    # every conformance test that POSTs multipart hits the SDK's
    # ``await request.form()`` call which assert-raises without this
    # package. Not a transitive dep of fastapi as of 0.127, even
    # though many older installs happened to drag it in via Starlette.
    # Pin per FastAPI's own minimum:
    #   https://fastapi.tiangolo.com/tutorial/request-forms-and-files/
    "python-multipart>=0.0.7",
]

# ── Optional adapter dependency groups ────────────────────────────────────────
# Install only what your deployment actually uses:
#
#   uv sync --extra yolo          → YOLOv8 person detection (ONNX, CPU-friendly)
#   uv sync --extra yolo11        → YOLOv11 person counting with ByteTrack
#   uv sync --extra pose          → YOLO11n-pose human keypoints (ONNX, CPU-first)
#   uv sync --extra package       → package-detection parcels on a doorstep (ONNX, CPU, on demand)
#   uv sync --extra clip --extra cpu   → CLIP embeddings for semantic search
#   uv sync --extra face          → InsightFace recognition (ArcFace, Buffalo-L)
#   uv sync --extra blip          → BLIP scene captioning (local, needs torch)
#   uv sync --extra huggingface   → HuggingFace cloud inference proxy
#   uv sync --extra stt           → Whisper speech-to-text (faster-whisper, CPU or GPU)
#   uv sync --extra tts           → Piper text-to-speech (ONNX, CPU-friendly)
#   uv sync --extra lpr           → fast-plate-ocr license-plate recognition (ONNX, CPU-only)
#   uv sync --extra cpu           → PyTorch CPU-only build (needed by yolo11+blip)
#   uv sync --extra gpu           → PyTorch CUDA build (needed by yolo11+blip on GPU)
#   uv sync --extra all           → Everything (backward-compatible default)
#
# Note: the Ollama LLM adapter (ollama_adapter) needs NO extras — it only speaks
# HTTP to a local Ollama daemon (https://ollama.ai) via httpx, already in core.
#
# Multi-profile example:
#   uv sync --extra yolo --extra face          → detection + recognition, no torch
#   uv sync --extra yolo11 --extra blip --extra cpu → counting + captions on CPU
[project.optional-dependencies]

# YOLOv8 ONNX adapter (yolov8_adapter) — lightweight, no torch needed.
# What it needs to SERVE, and nothing else: adapters/yolov8/ imports
# onnxruntime, cv2 and numpy, and adapters/yolov8/Dockerfile installs
# onnxruntime alone. onnx and onnxslim used to sit here as well; they are
# the ultralytics EXPORT step (download_models.py), which also needs
# ultralytics — never listed here either, because it drags torch in — so
# the two of them were dead weight when serving and still not enough to
# export with. The export recipe names all three where it lives.
yolo = [
    "onnxruntime==1.23.2",
]

# YOLOv11 PyTorch adapter with ByteTrack (yolov11_adapter)
# Requires torch — add --extra cpu or --extra gpu as well
yolo11 = [
    "ultralytics==8.3.240",
    "matplotlib==3.10.8",
    "networkx==3.6.1",
    "protobuf>=6.33.2",
]

# YOLO-pose ONNX adapter (adapters/yolo_pose) — human keypoints, CPU-first.
# What the adapter actually needs to SERVE, and nothing else (CONTRIBUTING,
# Path A): onnxruntime to run the graph, plus the OpenCV/numpy already in
# core. adapters/yolo_pose/ imports exactly onnxruntime, cv2 and numpy —
# and the image (adapters/yolo_pose/Dockerfile) installs no onnx, no
# onnxslim, no ultralytics, and passes conformance.
#
# The .pt -> .onnx export is an authoring task on a development machine,
# not a runtime dep, so its three packages (ultralytics, onnx, onnxslim)
# live with the recipe in adapters/yolo_pose/README.md. Listing two of
# the three here would be the worst of both: dependencies that are dead
# weight in the serving profile and still not enough to export with.
pose = [
    "onnxruntime==1.23.2",
    # Serving dep, not a model dep: bare uvicorn has no WebSocket
    # implementation, so /infer/stream answers the upgrade with a 404
    # unless one is installed. Streaming is this adapter's primary
    # path, so it is not optional here.
    "websockets>=12,<18",
]

# Package-detection ONNX adapter (adapters/package_detection) — parcels.
# Same serving stack as yolo/pose: onnxruntime plus the OpenCV/numpy in
# core, nothing else. No websockets — it serves HTTP /infer only. The
# training/export recipe (ultralytics, onnx, onnxslim, roboflow) is an
# authoring task in adapters/package_detection/train_package_model.py.
package = [
    "onnxruntime==1.23.2",
]

# CLIP embedding adapter (adapters/clip) — the `embed` task: one vector
# per frame, and one per QUERY IN WORDS, in the same space.
# Requires torch — add --extra cpu or --extra gpu as well, exactly like
# yolo11, blip and vlm. torch is NOT listed here: it is pinned once, in
# the cpu/gpu extras, so the operator picks the wheel their hardware
# wants instead of every extra fighting over it.
#
# pillow is not listed either — it is a core dependency at an exact pin
# (see [project.dependencies]). Restating it here as a range is what
# broke the lock: `pillow>=10,<12` excludes the pinned 12.0.0, and uv
# resolves EVERY extra even for `uv sync --extra dev`, so a conflict in
# an unused extra fails the whole install.
clip = [
    "open-clip-torch>=2.24,<4",
]

# InsightFace face recognition adapter (insightface_adapter).
# Unlike yolo/pose, the `onnx` here is NOT an export leftover: insightface
# itself requires onnx>=1.13, so this line is a deliberate version pin on
# a dependency the adapter really does load. Leave it.
face = [
    "insightface>=0.7.3",
    "onnx==1.20.0",
    "onnxruntime==1.23.2",
    "scipy==1.16.3",
    "polars==1.36.1",
]

# BLIP image captioning adapter (blip_adapter)
# Requires torch — add --extra cpu or --extra gpu as well
blip = [
    "transformers==5.0.0",
]

# VLM open-vocabulary detection adapter (adapters/vlm) — OWL-ViT v2.
# Requires torch — add --extra cpu or --extra gpu as well. Pillow for
# image decode. GPU strongly recommended (CPU inference is slow).
vlm = [
    "transformers==5.0.0",
    "pillow>=10.0.0",
]

# HuggingFace cloud inference proxy (huggingface_adapter)
huggingface = [
    "huggingface_hub==1.3.4",
]

# Whisper speech-to-text adapter (whisper_adapter)
# faster-whisper ships its own CTranslate2 runtime — no torch required on CPU.
# For CUDA inference, also install --extra gpu so torch.cuda.is_available() gates
# the "auto" device picker. av is pulled transitively by faster-whisper for audio
# decoding (WAV/MP3/FLAC/OGG/M4A).
stt = [
    "faster-whisper>=1.1.0",
]

# Piper text-to-speech adapter (piper_adapter)
# piper-tts reuses the onnxruntime we already depend on transitively via yolo,
# so adding TTS costs only the Python wrapper + the voice file (~25 MB/voice).
tts = [
    "piper-tts>=1.2.0",
]

# fast-plate-ocr license-plate recognition adapter (fast_plate_ocr_adapter).
# Brings its own onnxruntime; weights (~3 MB per bundle) are downloaded on
# first load() and cached locally. CPU-only — no torch needed.
#
# Python-version marker: fast-plate-ocr 2.x publishes wheels for Python
# 3.11 across all supported platforms (Linux x86_64 + aarch64, macOS),
# but as of 2026-05 has NOT shipped any Python 3.12 wheels. Empirically
# verified by the universal-resolve failure we saw on the CI matrix:
# every Python-3.12 platform variant uv probed (darwin, linux x86_64,
# linux aarch64) reported "only fast-plate-ocr<=1.1.0 is available".
#
# The marker below makes the universal-lockfile resolution skip fast-
# plate-ocr on Python 3.12 entirely so the rest of the install can
# succeed across the deployment matrix. Operators who need LPR have
# two options:
#   1. Run the adapter on Python 3.11 (pyproject's lower bound) until
#      upstream publishes 3.12 wheels — straightforward, the Docker
#      image can pin to 3.11 in its base image.
#   2. Cross-build the wheel locally and pin via `tool.uv.sources`.
#
# Empirically verified against PyPI: the LATEST published version of
# fast-plate-ocr is 1.1.0 — there is no 2.x release. The previous
# `>=2.0` pin was speculative against an unreleased 2.x API and made
# the universal lockfile resolution unsatisfiable on every platform
# (uv kept correctly reporting "only fast-plate-ocr<=1.1.0 is
# available"). Verified via the PyPI JSON API:
#   https://pypi.org/pypi/fast-plate-ocr/json
# Use `>=1.1.0` so 1.1.0 satisfies today and any future 2.x ships
# naturally if/when upstream releases it.
#
# KNOWN ADAPTER GAP — TODO before LPR ships end-to-end:
# adapters/fast_plate_ocr/service.py:252 calls
# ``self._recognizer.run(image_bytes, return_confidence=True)`` with
# raw bytes. fast-plate-ocr 1.1.0's ``run()`` accepts
# ``str | list[str] | numpy.ndarray | list[numpy.ndarray]`` only,
# NOT raw bytes. The adapter needs ``cv2.imdecode`` (or PIL.Image →
# numpy array) before passing to ``run()`` — see how the InsightFace
# adapter handles the same body shape. Tracked separately; the CI
# fix below only addresses the universal-resolve break.
#
# CI is unaffected by the adapter gap above: CI runs
# ``uv sync --extra dev`` (no [lpr]), and the fast-plate-ocr adapter
# tests stub the recognizer entirely via
# tests/_fast_plate_ocr_service_fixtures.py so they exercise the
# wrapper logic without touching real fast-plate-ocr code.
lpr = [
    # The [onnx] extra is REQUIRED: since 1.x, onnxruntime is optional
    # upstream ("pip install 'fast-plate-ocr[onnx]'" per its own error
    # message) — without it LicensePlateRecognizer raises
    # ModuleNotFoundError at load() and every inference 503s. Found in
    # the field: the published adapter image could never read a plate.
    "fast-plate-ocr[onnx]>=1.1.0",
    # Plate LOCALIZATION (same author, ONNX/CPU): the platform sends
    # whole-vehicle crops, and OCR without a detection stage
    # hallucinates on them — see adapters/fast_plate_ocr/service.py.
    "open-image-models[onnx]>=0.6.0",
]

# PyTorch CPU-only — required by yolo11 and blip on CPU-only machines
cpu = [
    "torch==2.9.1+cpu",
    "torchvision==0.24.1+cpu",
]

# PyTorch CUDA — required by yolo11 and blip on GPU machines
gpu = [
    "torch==2.9.1",
    "torchvision==0.24.1",
]

# Development tools
dev = [
    "pytest>=8.0.0",
    "pytest-asyncio>=0.23.5",
    "pytest-cov>=4.1.0",
    "httpx>=0.28.1",
]

# Backward-compatible "install everything" profile
# Equivalent to the old plain `uv sync` that had all deps in [project.dependencies]
all = [
    "opennvr-ai-adapter[yolo,yolo11,pose,package,face,blip,vlm,clip,huggingface,stt,tts,lpr]",
]

# ── PyTorch index source ───────────────────────────────────────────────────────
[tool.uv.sources]
torch = { index = "pytorch-cpu" }
torchvision = { index = "pytorch-cpu" }

[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true

# ── Pytest config ──────────────────────────────────────────────────────────────
# The project ships several top-level packages (``app``, ``adapters``,
# ``conformance``, ``opennvr_adapter_sdk``) that live at the repo root.
# Without a ``[build-system]`` + ``[tool.hatch.build.targets.wheel]``
# packages declaration, ``uv sync`` installs the declared dependencies
# but does NOT install the project's own code as an importable
# package — so ``uv run pytest`` can't find ``app.utils.loader`` from
# tests/conftest.py. Adding the repo root to pythonpath here is the
# minimum fix; a proper hatch/setuptools packaging declaration is a
# separate (larger) cleanup.
[tool.pytest.ini_options]
pythonpath = ["."]
# Two adapters keep their tests beside their code; without this line
# the ci.yml ``pytest tests/`` never collected them.
testpaths = ["tests", "adapters/ollamavlm/tests", "adapters/vlm/tests"]
asyncio_mode = "auto"