227 lines
6.3 KiB
Markdown
227 lines
6.3 KiB
Markdown
# Extractors API
|
|
|
|
## Base URL
|
|
|
|
```
|
|
{BASE_URL}
|
|
```
|
|
|
|
- **Local development:** `http://localhost:54400`
|
|
- **Docker (internal):** `http://extractors:54400`
|
|
- **Production:** use your configured hostname (port `14400`)
|
|
|
|
## Authentication
|
|
|
|
None at the service level — access is mediated by the platform API gateway
|
|
(Bearer token at the perimeter). Do not expose this service directly.
|
|
|
|
## Endpoints
|
|
|
|
### GET /health
|
|
|
|
Liveness probe.
|
|
|
|
```json
|
|
{ "status": "ok", "version": "0.1.0" }
|
|
```
|
|
|
|
### GET /ready
|
|
|
|
Readiness + optional tooling availability (informational; the service degrades
|
|
gracefully if ffprobe/ffmpeg are absent).
|
|
|
|
```json
|
|
{ "status": "ready", "ffprobe": true, "ffmpeg": true }
|
|
```
|
|
|
|
### POST /v1/metadata
|
|
|
|
Extract deterministic media metadata & integrity features. The applicable
|
|
extractors are chosen automatically from the detected media type.
|
|
|
|
**Request** — `multipart/form-data`
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `file` | file | Image, video or audio file |
|
|
|
|
```bash
|
|
curl -X POST http://localhost:54400/v1/metadata \
|
|
-F "file=@photo.jpg"
|
|
```
|
|
|
|
**Response** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"filename": "photo.jpg",
|
|
"media_type": "image",
|
|
"sha256": "9f86d081884c7d65...",
|
|
"size_bytes": 84211,
|
|
"analyses": {
|
|
"integrity": {
|
|
"tool_id": "integrity",
|
|
"name": "Integrity & signature",
|
|
"ok": true,
|
|
"results": { "container": "JPEG", "sha256": "9f86...", "size_bytes": 84211 },
|
|
"evidence": ["Container: JPEG.", "SHA-256: 9f86d081884c7d65…"],
|
|
"anomalies": [],
|
|
"confidence": 1.0
|
|
},
|
|
"exif": {
|
|
"tool_id": "exif",
|
|
"name": "EXIF metadata",
|
|
"ok": true,
|
|
"results": {
|
|
"format": "JPEG", "dimensions": [4032, 3024],
|
|
"make": "Apple", "model": "iPhone 13",
|
|
"datetimeoriginal": "2024:06:15 14:30:00",
|
|
"gps": { "latitude": 44.426, "longitude": 26.102 },
|
|
"software": "Adobe Photoshop 25.0"
|
|
},
|
|
"evidence": ["Captured with Apple iPhone 13.", "GPS location present: 44.426, 26.102."],
|
|
"anomalies": ["Editing/generation software detected in EXIF: Adobe Photoshop 25.0."],
|
|
"confidence": 0.95
|
|
},
|
|
"ela": {
|
|
"tool_id": "ela", "name": "Error Level Analysis", "ok": true,
|
|
"results": { "quality": 90, "mean_error": 6.1, "max_error": 211.0, "p99_error": 38.0, "hot_pixel_fraction": 0.031 },
|
|
"evidence": ["ELA mean error 6.1, p99 38.0 (quality=90)."],
|
|
"anomalies": ["Localized high-error region(s) detected — possible splice/edit (3.1% of pixels)."],
|
|
"confidence": 0.6
|
|
}
|
|
},
|
|
"evidence": ["..."],
|
|
"anomalies": ["..."],
|
|
"execution_time_ms": 42.7
|
|
}
|
|
```
|
|
|
|
For **video** inputs the `analyses` block contains `integrity`, `video_metadata`
|
|
(codec/width/height/fps/bitrate/encoder) and `spectrogram`. For **audio**:
|
|
`integrity` + `spectrogram`.
|
|
|
|
Each extractor returns a uniform `FeatureResult`:
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `tool_id` | string | Stable extractor id |
|
|
| `name` | string | Human-readable name |
|
|
| `ok` | bool | Ran without error |
|
|
| `results` | object | Structured extracted data |
|
|
| `evidence` | string[] | Neutral findings (LLM-readable) |
|
|
| `anomalies` | string[] | Tampering/edit hints |
|
|
| `confidence` | number\|null | 0..1 (extraction confidence, not a verdict) |
|
|
| `error` | string\|null | Set when `ok` is false |
|
|
|
|
### POST /v1/sentiment
|
|
|
|
Classify the sentiment of a text via the LLM gateway (Romanian-aware prompt,
|
|
detects irony/sarcasm). **Delegated to the LLM gateway** — returns `503` if no
|
|
gateway is configured.
|
|
|
|
**Request** — `application/json`
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `text` | string | Text to analyze (min length 1) |
|
|
|
|
```bash
|
|
curl -X POST http://localhost:54400/v1/sentiment \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"text": "Ce zi frumoasă!"}'
|
|
```
|
|
|
|
**Response** `200 OK` — a `FeatureResult` (same schema as above), e.g.:
|
|
|
|
```json
|
|
{
|
|
"tool_id": "sentiment",
|
|
"name": "Sentiment",
|
|
"ok": true,
|
|
"results": { "label": "positive", "score": 0.92 },
|
|
"evidence": ["Sentiment: positive (0.92)."],
|
|
"anomalies": [],
|
|
"confidence": 0.92
|
|
}
|
|
```
|
|
|
|
### POST /v1/ner
|
|
|
|
Extract named entities via GLiNER multilingual (`urchade/gliner_multi-v2.1`).
|
|
**Requires the optional `ml` extra** — returns `503` if the model is unavailable.
|
|
|
|
**Request** — `application/json`
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `text` | string | Text to analyze (min length 1) |
|
|
| `labels` | string[] \| null | Entity types to extract (defaults to the RO set) |
|
|
|
|
```bash
|
|
curl -X POST http://localhost:54400/v1/ner \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"text": "Klaus Iohannis și Guvernul României."}'
|
|
```
|
|
|
|
**Response** `200 OK` — a `FeatureResult`; `results` carries the extracted
|
|
entities (text, label, span, score).
|
|
|
|
### POST /v1/ocr
|
|
|
|
Extract visible text verbatim from an image via the LLM vision model.
|
|
**Delegated to the LLM gateway** — returns `503` if no gateway is configured.
|
|
|
|
**Request** — `multipart/form-data`
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `file` | file | Image file |
|
|
|
|
```bash
|
|
curl -X POST http://localhost:54400/v1/ocr \
|
|
-F "file=@scan.png"
|
|
```
|
|
|
|
**Response** `200 OK` — a `FeatureResult`; `results` carries the recognized text.
|
|
|
|
### POST /v1/detect
|
|
|
|
Detect objects (COCO classes) via YOLO (`yolov8n`), returning boxes + confidence.
|
|
**Requires the optional `ml` extra** — returns `503` if the model is unavailable.
|
|
|
|
**Request** — `multipart/form-data`
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `file` | file | Image file |
|
|
|
|
Optional query param: `threshold` (float, 0..1) — confidence threshold.
|
|
|
|
```bash
|
|
curl -X POST "http://localhost:54400/v1/detect?threshold=0.4" \
|
|
-F "file=@street.jpg"
|
|
```
|
|
|
|
**Response** `200 OK` — a `FeatureResult`; `results` carries detected objects
|
|
(label, box, confidence).
|
|
|
|
## Error Responses
|
|
|
|
| Status | Meaning |
|
|
|--------|---------|
|
|
| 400 | Empty file |
|
|
| 413 | File exceeds `EXTRACTORS_MAX_UPLOAD_MB` |
|
|
| 422 | Missing `file` field |
|
|
| 502 | `LLMError` — the LLM gateway returned an error (`/v1/sentiment`, `/v1/ocr`) |
|
|
| 503 | `LLMNotConfigured` (no gateway for `/v1/sentiment`, `/v1/ocr`) or the `ml` extra/model is unavailable (`/v1/ner`, `/v1/detect`) |
|
|
|
|
```json
|
|
{ "detail": "empty file" }
|
|
```
|
|
|
|
## Request Headers
|
|
|
|
| Header | Required | Notes |
|
|
|--------|----------|-------|
|
|
| `Content-Type` | yes | `multipart/form-data` (set by the client) |
|