didi-lot1-ai/ai_platform/modules/forensic_features/docs/API.md

6.7 KiB

API Reference

Toate endpoint-urile, parametrii, status codes, exemple curl.

Base URL

http://localhost:8080

Endpoints

POST /api/forensic-evidence

Singurul endpoint care contează în practică. Upload un video/imagine, primește înapoi evidence formatat pentru LLM.

Request

Content-Type: multipart/form-data

Field Type Required Default Description
video file DA Fișier video sau imagine (mp4, mov, avi, mkv, webm, jpg, jpeg, png). Max 2 GB.
modules string NU toate CSV de module IDs ("m25,m27,m28"). Default rulează toate cele 5.
encode_images string NU "1" "1" → atașează data URLs base64; "0" → doar paths absolute pe disk
every_n_frames int NU adaptiv Pas extracție cadre. None → orchestrator alege bazat pe durata video
async_mode string NU "0" "1" → returnează 202 cu job_id; "0" → blochează până la rezultat

Response

Sync mode (default) — 200 OK — JSON cu schema completă (vezi CONTRACT.md):

{
  "video_path":          "video.mp4",
  "n_frames_extracted":  64,
  "every_n_frames_used": 3,
  "auto_skipped":        ["m26 (no audio track)"],
  "modules_run":         ["m25", "m27", "m28", "m29"],
  "execution_time_ms":   48432.0,

  "fusion": {
    "score":           0.67,
    "label":           "FAKE",
    "confidence":      0.78,
    "n_contributing":  4,
    "n_no_signal":     0,
    "disagreement":    0.005,
    "contributions":   {"m25": 0.09, "m27": 0.23, "m28": 0.24, "m29": 0.11}
  },

  "explanation": [
    "Verdict forensic: FAKE (score=0.67, confidence=0.78, din 4 detectoare active)",
    "Top contributors: m28 INCERT, m27 FAKE, m25 INCERT"
  ],

  "modules": {
    "m25": { ... schema completă CONTRACT.md ... },
    "m27": { ... },
    "m28": { ... },
    "m29": { ... }
  },

  "evidence_text": "FORENSIC EVIDENCE (objective measurements...)\n\n[m25 ...] score=...\n...",

  "images": [
    {
      "name":     "m25_pulse_signal.png",
      "tool_id":  "m25",
      "abs_path": "/app/data/results/{job_id}/images/m25_pulse_signal.png",
      "size_bytes": 69384,
      "data_url": "data:image/png;base64,iVBORw0KG..."  // dacă encode_images=1
    },
    // ... 8-15 imagini total
  ],

  "summary": {
    "overall_score":      0.67,
    "overall_label":      "FAKE",
    "overall_confidence": 0.78,
    "n_modules_run":      4,
    "n_modules_signal":   4,
    "disagreement":       0.005
  },

  "instruction_for_llm": "HOW TO USE FORENSIC EVIDENCE ABOVE:\n...",

  "errors": []
}

Async mode (async_mode=1) — 202 Accepted:

{
  "job_id": "abc123def456789a",
  "status": "queued",
  "modules": ["m25", "m26", "m27", "m28", "m29"]
}

Apoi polling pe /api/status/{job_id} și preluare cu /api/result/{job_id}.

Error codes

Code Cauza
400 Câmp video lipsește, tip fișier nesuportat, sau modul necunoscut
500 Eroare în pipeline (vezi mesaj eroare în body)

Examples

Sync, toate modulele:

curl -X POST http://localhost:8080/api/forensic-evidence \
     -F "video=@suspicious_video.mp4"

Sync, doar 2 module + fără base64 (mai rapid):

curl -X POST http://localhost:8080/api/forensic-evidence \
     -F "video=@image.jpg" \
     -F "modules=m27,m28" \
     -F "encode_images=0"

Async, polling:

# Submit
JOB=$(curl -s -X POST http://localhost:8080/api/forensic-evidence \
      -F "video=@long_video.mp4" -F "async_mode=1" \
      | python -c "import sys,json; print(json.load(sys.stdin)['job_id'])")

# Wait
while [ "$(curl -s http://localhost:8080/api/status/$JOB \
           | python -c "import sys,json; print(json.load(sys.stdin)['status'])")" != "done" ]; do
    sleep 5
done

# Get result
curl http://localhost:8080/api/result/$JOB | jq .summary

GET /api/forensic-modules

Listează modulele disponibile, pentru introspection.

curl http://localhost:8080/api/forensic-modules
{
  "available_modules": [
    {"id": "m25", "input_type": "overview_frames",
     "import_path": "tools.m25_physiology.physiology", "function": "run"},
    {"id": "m26", "input_type": "video_path",
     "import_path": "tools.m26_audio.audio", "function": "run"},
    {"id": "m27", "input_type": "overview_frames",
     "import_path": "tools.m27_ai_detector.ai_detector", "function": "run"},
    {"id": "m28", "input_type": "overview_frames",
     "import_path": "tools.m28_forgery_heatmap.forgery_heatmap", "function": "run"},
    {"id": "m29", "input_type": "overview_frames",
     "import_path": "tools.m29_lighting.lighting", "function": "run"}
  ],
  "default": ["m25", "m26", "m27", "m28", "m29"]
}

GET /api/status/{job_id}

Polling pentru cereri async. Returns 200 cu status string.

curl http://localhost:8080/api/status/abc123def456789a
{
  "job_id":   "abc123def456789a",
  "status":   "running",
  "progress": "Running forensic modules m25-m29..."
}

Status values: queued, running, done, error.

Error code 404 dacă job_id nu există.


GET /api/result/{job_id}

Preluare rezultat job async. Comportament:

Job status Răspuns
queued sau running 202 cu status + progress
done 200 cu rezultatul complet (același ca sync)
error 500 cu mesajul de eroare
curl http://localhost:8080/api/result/abc123def456789a

Error code 404 dacă job_id nu există.


GET /health

Healthcheck pentru Docker / load balancer / monitoring.

curl http://localhost:8080/health
{
  "status":  "ok",
  "service": "forensic-features",
  "modules": ["m25", "m26", "m27", "m28", "m29"]
}

Notes

Limita upload

client_max_size=2 * 1024**3 = 2 GB per request. Pe video >2GB, preprocesezi cu ffmpeg înainte de upload.

Concurența

Job store este in-memory (Python dict). Asta înseamnă:

  • Joburile se pierd la restart container
  • Multi-replica fără sticky sessions = nu funcționează

Pentru producție serioasă, înlocuiește _jobs din api.py:30 cu un store persistent (Redis recomandat).

CORS

Activat default cu * pentru orice origine. Pentru producție public, restrictionează în api.py:build_app().

Rate limiting

NU există. Pentru producție public, pune un reverse proxy (nginx, Traefik) în față cu rate limiting.

Auth

NU există. Endpoint-urile sunt deschise. Pentru producție, integrează cu sistemul tău de auth via reverse proxy sau adaugă middleware.