didi-lot1-ai/ai_platform/modules/extractors/API.md

6.3 KiB

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.

{ "status": "ok", "version": "0.1.0" }

GET /ready

Readiness + optional tooling availability (informational; the service degrades gracefully if ffprobe/ffmpeg are absent).

{ "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.

Requestmultipart/form-data

Field Type Description
file file Image, video or audio file
curl -X POST http://localhost:54400/v1/metadata \
  -F "file=@photo.jpg"

Response 200 OK

{
  "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.

Requestapplication/json

Field Type Description
text string Text to analyze (min length 1)
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.:

{
  "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.

Requestapplication/json

Field Type Description
text string Text to analyze (min length 1)
labels string[] | null Entity types to extract (defaults to the RO set)
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.

Requestmultipart/form-data

Field Type Description
file file Image file
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.

Requestmultipart/form-data

Field Type Description
file file Image file

Optional query param: threshold (float, 0..1) — confidence threshold.

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)
{ "detail": "empty file" }

Request Headers

Header Required Notes
Content-Type yes multipart/form-data (set by the client)