# --- Web API --- fastapi>=0.115.0 uvicorn[standard]>=0.30.6 pydantic>=2.9.2 python-multipart>=0.0.6 # --- Config --- python-dotenv>=1.0.1 # --- Authentication --- # Signs/verifies the access tokens issued by /api/auth/login. Pure Python, no # compiled extension - nothing extra to build on the slim image. Password # hashing uses hashlib.pbkdf2_hmac from the standard library, so there is # deliberately no bcrypt/argon2/passlib dependency here. PyJWT>=2.9.0 # --- MCP (Model Context Protocol) --- # Serves the catalog as tools for AI clients at /mcp (see app/mcp_server.py), # mounted onto the FastAPI app so it needs no separate process or container. # Requires Python >=3.10; the Dockerfile's python:3.11-slim satisfies that, and # app/main.py degrades to serving the REST API alone if the import fails. fastmcp>=3.4.7 # --- Database / pgvector --- psycopg[binary]>=3.2.3 pgvector>=0.2.5 # --- Embeddings (RAG retrieval) --- # sentence-transformers pulls in its own CPU-friendly torch wheel # automatically - no need to pin torch separately. Imports are LAZY # (see app/services/embeddings_service.py) so the API still boots fast # even before this is installed/loaded. sentence-transformers>=3.0.1 # --- HTTP clients --- requests>=2.31.0 aiohttp>=3.9.5 httpx>=0.27.2 # --- Catalog ingestion pipeline (discovery / images / pricing) --- # Only required if you plan to run cli/ingest_brand.py or # POST /api/catalog/generate to pull in NEW brands. If you only ever use # the bundled seed data (scripts/seed_sample_data.py) + RAG chat/search, # you can skip everything below this line. # Retry/backoff for the barcode enrichment sources # (app/services/enrichment/barcode/retry.py). This is NOT an optional extra: # retry.py imports it at module scope, and that module is reached at BOOT, via # app/main.py -> routers/{uploads,batch_catalog} -> api/batch_common # -> core/store_catalog_pipeline -> enrichment/barcode/retry # so a missing tenacity is not a degraded feature, it is the container exiting 1 # on boot with ModuleNotFoundError before uvicorn ever binds a socket. Swarm # then restarts it, and each restart re-runs ~21s of pandas/scipy/sklearn # imports, which on a 1-vCPU host reads as pinned-at-100% CPU rather than as a # crash. # # This note used to name the store_catalog router as the importer. That router # was deleted with the Store Catalog Ingestion tab; the chain above is the one # that survives, and it runs through every remaining ingestion route. Re-check # it here before ever concluding this dependency has become unused. tenacity>=8.2.3 beautifulsoup4>=4.12.3 lxml>=4.9.3 python-slugify>=8.0.4 ddgs>=9.14.4 Pillow>=10.0.0 # TFLite runtime for the img_vector image embedder (app/services/image_embedder.py). # Runtime only - no TensorFlow - about 20MB; wheels exist for the container's # cp311 manylinux and for cp314 Windows. Imported lazily on first use, so a # missing wheel means "no image vectors", never a failed boot. ai-edge-litert>=2.2.0 # The Nearle Flutter app preprocesses with OpenCV (centre crop, INTER_AREA # resize, 0..1) and its vectors must match ours to a few decimals, so the # backend preprocesses with the same library. Headless: no GUI, no libGL. # abi3 wheel, ~55MB. Pinned below 5 to stay on the app's major version. opencv-python-headless>=4.8,<5 # Server-side OCR for POST /api/search/identify (app/services/ocr_service.py): # rapidocr's PP-OCR models on onnxruntime, CPU. rapidocr ITSELF IS NOT LISTED # HERE, on purpose - its metadata demands opencv-python (the GUI build), which # a normal install unpacks over opencv-python-headless above and which then # fails on libGL.so.1 in the slim image, breaking the image embedder too. It is # installed with `--no-deps` from requirements-ocr.txt (see the Dockerfile), # and the dependencies it really needs are declared below instead: # - onnxruntime: the inference engine, which rapidocr does not declare (it is # one of several it can use). Imported lazily; missing means "no server # OCR", never a failed boot. # - the rest are pure-Python helpers from its metadata (Shapely and pyclipper # for the detection polygons, omegaconf/PyYAML for its config). onnxruntime>=1.17,<2 omegaconf>=2.1,!=2.2.1 pyclipper>=1.2.0 Shapely>=1.7.1,!=2.0.4 PyYAML>=6.0 tqdm>=4.60 colorlog>=6.0 six>=1.15.0 aiofiles>=23.2.1 # Playwright (Python) - last-resort image-search fallback only. # Run `playwright install chromium` once after pip install to enable it; # the pipeline works fine without it (just one fewer fallback source). # playwright>=1.47.0 # Commented out, not deleted. It is the last-resort image-search tier, and the # Dockerfile never installs its browser binary - so in a container the tier is # skipped at runtime no matter what, while the package still costs 137MB. The # import is lazy (app/services/playwright_image_fallback.py does it inside the # function), so its absence is handled on the existing "not installed" path. # Uncomment, and run `playwright install chromium`, if you ever want that tier. # --- S3 / DigitalOcean Spaces (optional product image storage) --- boto3>=1.34.162 # --- ML / analytics (app/intelligence/*, incl. nutrition similarity & --- # --- clustering) - CPU-only estimators only (GradientBoosting/Random- --- # --- Forest/KMeans/NearestNeighbors), no GPU dependency, per the 8GB --- # --- RAM / CPU-only environment this project targets. Was already an --- # --- implicit dependency (app/intelligence/*.py imports these) but was --- # --- missing from this file - declared explicitly now. --- scikit-learn>=1.5.2 pandas>=2.2.2 # pandas' Excel readers are optional extras it does not install itself, and the # upload endpoints (/api/user/products/upload-file, /api/upload/*) accept .xlsx # and .xls. Undeclared, they happened to be present in some environments and # absent in others - so an Excel upload that worked locally failed in the # container with "Missing optional dependency 'openpyxl'". openpyxl reads # .xlsx/.xlsm; xlrd is only for the legacy .xls format. openpyxl>=3.1.5 xlrd>=2.0.1 numpy>=1.26.4 scipy>=1.13.1 joblib>=1.4.2 # --- Dev/test tooling --- # Moved to requirements-dev.txt so the Docker image does not carry the test # stack it can never run. To work on this project, install both: # pip install -r requirements.txt -r requirements-dev.txt