Livrare LOT 1 - Didi

This commit is contained in:
Dezvoltari Evotech 2026-06-25 14:13:25 -07:00
commit 5380c3fc63
990 changed files with 133308 additions and 0 deletions

View file

@ -0,0 +1,260 @@
# 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](CONTRACT.md)):
```jsonc
{
"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**:
```json
{
"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**:
```bash
curl -X POST http://localhost:8080/api/forensic-evidence \
-F "video=@suspicious_video.mp4"
```
**Sync, doar 2 module + fără base64 (mai rapid)**:
```bash
curl -X POST http://localhost:8080/api/forensic-evidence \
-F "video=@image.jpg" \
-F "modules=m27,m28" \
-F "encode_images=0"
```
**Async, polling**:
```bash
# 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.
```bash
curl http://localhost:8080/api/forensic-modules
```
```json
{
"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.
```bash
curl http://localhost:8080/api/status/abc123def456789a
```
```json
{
"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 |
```bash
curl http://localhost:8080/api/result/abc123def456789a
```
Error code 404 dacă job_id nu există.
---
### `GET /health`
Healthcheck pentru Docker / load balancer / monitoring.
```bash
curl http://localhost:8080/health
```
```json
{
"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.