Metadata-Version: 2.4
Name: opentradeintel
Version: 0.2.0
Summary: Open-source procurement and B2B sourcing intelligence engine
Project-URL: Homepage, https://github.com/b2baitrade-ui/opentradeintel
Project-URL: Documentation, https://github.com/b2baitrade-ui/opentradeintel/tree/main/docs
Project-URL: Issues, https://github.com/b2baitrade-ui/opentradeintel/issues
Project-URL: Repository, https://github.com/b2baitrade-ui/opentradeintel
Project-URL: Changelog, https://github.com/b2baitrade-ui/opentradeintel/blob/main/CHANGELOG.md
Author: b2baitrade-ui
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: procurement,rfq,sourcing,tenders,trade-intelligence
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.12
Requires-Dist: fastapi<1,>=0.116
Requires-Dist: httpx2<3,>=2.12
Requires-Dist: pydantic<3,>=2.11
Requires-Dist: typer<1,>=0.16
Requires-Dist: uvicorn<1,>=0.35
Description-Content-Type: text/markdown

# OpenTradeIntel

> Open-source procurement and B2B sourcing intelligence engine.

[![CI](https://github.com/b2baitrade-ui/opentradeintel/actions/workflows/ci.yml/badge.svg)](https://github.com/b2baitrade-ui/opentradeintel/actions/workflows/ci.yml)
![Python](https://img.shields.io/badge/python-%3E%3D3.12-3776AB)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](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.

## TED in 30 seconds

Search active public notices through the official TED API:

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

Search by CPV/place and save normalized tenders:

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

Match the returned notices directly against a local catalog:

```bash
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](https://docs.astral.sh/uv/).

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

Inspect the synthetic tender:

```bash
uv run opentradeintel inspect examples/tenders/sample.json
```

Match it against the synthetic catalog:

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

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

```text
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:

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

Available routes:

- `GET /health`
- `GET /version`
- `POST /match`
- Interactive OpenAPI documentation at `/docs`

Minimal request:

```bash
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](docs/matching.md) and the [20-opportunity benchmark](docs/benchmark.md).

## Architecture

```text
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](docs/architecture.md) and [connector guidance](docs/connectors.md).

## 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

```bash
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

```bash
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](docs/development.md).

## 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](ROADMAP.md).

## Contributing

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

## Security

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

## License

Licensed under the [Apache License 2.0](LICENSE).
