Skip to content

About

Open-source procurement and B2B sourcing intelligence engine

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

OpenTradeIntel

Open-source procurement and B2B sourcing intelligence engine.

CI PyPI version Python versions GitHub release License

OpenTradeIntel queries real EU public procurement notices from the official TED Search API, normalizes them into typed tenders, and ranks them against a local supplier catalog. It also accepts local JSON/CSV tender data. The project is an early-stage, self-hosted toolkit for SMEs, exporters, sourcing and procurement teams, researchers, developers, and trade-intelligence projects.

Why?

Procurement requirements and catalogs often arrive in incompatible spreadsheets or data exports. OpenTradeIntel provides a small, inspectable baseline for validating that data, normalizing common terms, and explaining why one catalog product ranks above another—without sending commercial data to an external AI service.

Features

  • Typed tender/RFQ and product models using Pydantic.
  • JSON and CSV ingestion behind extensible connector/parser interfaces.
  • Official public TED v3 Search API connector with no API key or scraper.
  • TED keyword, CPV, country, page-number, and iteration-token search support.
  • Direct TED -> normalized tender -> local catalog -> ranked matches workflow.
  • Local text, unit, category, keyword, and market normalization.
  • Deterministic 0–100 matching with a complete component breakdown.
  • Typer CLI and FastAPI API backed by the same application service.
  • Dependency-free MCP adapter and optional provider protocol.
  • Synthetic examples, tests, Docker packaging, and OSS project files.
  • No API key, LLM, database, queue, or network call required by core features.

Install

Install the latest release from PyPI:

pip install opentradeintel

Or add it to a uv-managed project:

uv add opentradeintel

Verify the installed CLI:

opentradeintel version
opentradeintel --help

TED in 30 seconds

Search active public notices through the official TED API:

uv run opentradeintel ted search \
  --query "dried fruit" \
  --limit 10 \
  --output json

Search by CPV/place and save normalized tenders:

uv run opentradeintel ted search \
  --cpv 15897200 \
  --country DE \
  --limit 20 \
  --output-file tenders.json

Match the returned notices directly against a local catalog:

uv run opentradeintel ted match \
  --query "dried fruit" \
  --catalog examples/catalogs/sample.csv \
  --match-limit 3

ted match returns at most 10 catalog matches per notice by default; use --match-limit to choose a different positive bound.

TED search requires outbound HTTPS access but no credential. Local file matching and the deterministic core remain fully offline.

Quick start

Requirements: Python 3.12 or newer and uv.

git clone https://github.com/b2baitrade-ui/opentradeintel.git
cd opentradeintel
uv sync --all-groups --locked
uv run opentradeintel --help

Inspect the synthetic tender:

uv run opentradeintel inspect examples/tenders/sample.json

Match it against the synthetic catalog:

uv run opentradeintel match \
  --tender examples/tenders/sample.json \
  --catalog examples/catalogs/sample.csv

Example excerpt (values are computed, not hard-coded):

1. Dried Mango 500g
   Score: 100/100

   Reasons:
   [+] Product similarity: 40/40 (name 24/24, keywords 16/16)
   [+] Category: 15/15 (dried fruit)
   [+] Certifications: 20/20 (2/2 covered)
   [+] Market compatibility: 15/15
   [+] MOQ compatibility: 10/10

Supplier, tender, and benchmark examples are synthetic. examples/ted/ is a clearly attributed, trimmed snapshot of public TED procurement data.

API

Start the API:

uv run uvicorn opentradeintel.api.app:app --reload

Available routes:

  • GET /health
  • GET /version
  • POST /match
  • Interactive OpenAPI documentation at /docs

Minimal request:

curl -X POST http://127.0.0.1:8000/match \
  -H "Content-Type: application/json" \
  -d '{
    "tender": {
      "id": "demo-rfq", "title": "Dried mango", "buyer": "Demo Buyer",
      "description": "Organic dried fruit", "products": ["mango"],
      "quantity": 1000, "unit": "kg", "destination": "Germany",
      "currency": "EUR", "required_certifications": ["EU Organic"],
      "source": "synthetic-demo"
    },
    "products": [{
      "sku": "DM-1", "name": "Dried mango", "description": "Organic slices",
      "category": "Dried fruit", "origin": "Exampleland",
      "certifications": ["EU Organic"], "min_order_quantity": 100,
      "available_markets": ["EU"], "keywords": ["mango", "organic"]
    }]
  }'

How matching works

The score is the integer sum of five deterministic components:

Component Maximum Baseline behavior
Product similarity 40 Product-name token coverage (24) plus keyword coverage (16)
Category 15 Normalized category tokens appear in the tender
Certifications 20 Proportional coverage of required certifications
Market 15 Destination and available-market aliases intersect
MOQ 10 Tender quantity meets product minimum order quantity

Missing quantity or MOQ receives five neutral points and a warning. Results include reasons, warnings, and the component breakdown. Exact CPV overlap is a score-neutral tie-break signal; SKU is the final stable tie-breaker. See matching documentation and the 20-opportunity benchmark.

Architecture

local JSON/CSV -> connector -> parser -------\
                                             -> typed Tender -> OpportunityService -> matcher
official TED -> search client -> TED mapper -/                              -> CLI / FastAPI / MCP adapter

The boundaries are intentionally small. New source connectors acquire text; parsers interpret formats; interfaces never reimplement matching. See architecture and connector guidance.

Data privacy

OpenTradeIntel does not require procurement or supplier data to be sent to an external AI API. The default workflow is local, deterministic, and suitable for self-hosting. Users remain responsible for access control, retention, applicable procurement rules, and the accuracy of final commercial decisions.

AI providers and MCP

AI is optional. The EnrichmentProvider protocol is a future extension point; no provider is installed or called by core. .env.example contains a blank optional key only to document that future integration. The dependency-free OpenTradeIntelMCPAdapter remains an interface only; registering it with a concrete MCP SDK is deferred.

Docker

docker compose up --build
curl http://127.0.0.1:8000/health

The runtime image uses Python 3.12, runs as a non-root user, and exposes port 8000.

Developing

uv sync --all-groups --locked
uv run ruff check .
uv run ruff format --check .
uv run mypy src tests benchmarks examples
uv run pytest
uv run python benchmarks/run.py

On systems with GNU Make, make check runs the same gates. See development documentation.

Roadmap

Version 0.2 adds the official TED public connector and a measurable matcher baseline. PDF/XLSX parsing, additional reviewed public connectors, evaluated semantic methods, and a concrete MCP server remain future candidates. See the honest, non-binding roadmap.

Contributing

Issues and pull requests are welcome. Read CONTRIBUTING.md before adding a parser or connector, and follow the Code of Conduct.

Security

Do not open a public issue for a vulnerability. Follow the private reporting instructions in SECURITY.md.

License

Licensed under the Apache License 2.0.

About

Open-source procurement and B2B sourcing intelligence engine

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages