Servizio web per la conversione di file ECG in formato DICOM in immagini grafiche. Espone un'API REST costruita con FastAPI e delega il rendering al modulo dicom-ecg-plot, incluso come git submodule.
- Python 3.9+
- Git (con supporto ai submodule)
git clone --recurse-submodules <repo-url>
cd ecg-web
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtSe il repository è già stato clonato senza --recurse-submodules:
git submodule update --initCopia il file di esempio e modifica i valori:
cp .env.example .env| Variabile | Default | Descrizione |
|---|---|---|
AUTH_ENABLED |
true |
Abilita/disabilita l'autenticazione via API key |
API_KEYS |
(vuoto) | Lista di chiavi valide, separate da virgola |
RATE_LIMIT |
60/minute |
Limite richieste per IP (N/second, N/minute, N/hour) |
Per disabilitare l'autenticazione (es. in sviluppo locale):
AUTH_ENABLED=falsesource .venv/bin/activate
uvicorn app.main:app --port 8001 --reloadLa documentazione interattiva è disponibile su http://localhost:8001/docs.
Un client web di esempio è disponibile su http://localhost:8001/.
Quando AUTH_ENABLED=true, ogni richiesta agli endpoint /api/ecg/* deve includere
l'header:
X-API-Key: <chiave>
Le richieste senza chiave o con chiave non valida ricevono 401 Unauthorized.
All'indirizzo GET / è disponibile un client web minimale a pagina singola. Permette
di caricare un file DICOM, configurare tutte le opzioni di conversione e visualizzare
il risultato direttamente nel browser. Per i formati immagine (PNG, JPG, SVG) il
risultato è mostrato inline; per tutti i formati è disponibile un link di download.
Non richiede installazione separata: è incluso nel server API.
Restituisce i valori accettati da tutti i parametri di conversione.
curl -H "X-API-Key: mykey" http://localhost:8001/api/ecg/formats{
"layouts": ["3x4_1", "3x4", "6x2", "12x1"],
"papers": ["a4", "letter"],
"formats": ["png", "pdf", "svg", "svgz", "tiff", "jpg", "jpeg", "eps", "ps"],
"defaults": {
"layout": "3x4_1",
"paper": "a4",
"format": "png",
"minor_grid": false,
"interpretation": false,
"mm_mv": 10.0
}
}Converte un file DICOM ECG caricato come multipart/form-data.
Parametri
| Campo | Tipo | Default | Descrizione |
|---|---|---|---|
file |
file | — | File DICOM ECG (obbligatorio) |
layout |
string | 3x4_1 |
Layout: 3x4_1, 3x4, 6x2, 12x1 |
paper |
string | a4 |
Formato carta: a4, letter |
format |
string | png |
Formato output (vedi /api/ecg/formats) |
minor_grid |
bool | false |
Griglia minore a 1 mm |
interpretation |
bool | false |
Mostra il testo di interpretazione automatica |
mm_mv |
float | 10.0 |
Scala ampiezza in mm/mV |
Esempio
curl -X POST http://localhost:8001/api/ecg/convert \
-H "X-API-Key: mykey" \
-F "file=@ecg.dcm" \
-F "layout=3x4_1" \
-F "format=pdf" \
-F "minor_grid=true" \
-F "interpretation=true" \
-o ecg.pdfRecupera il file ECG da un server PACS tramite WADO e lo converte.
Il server WADO deve essere configurato in dicom-ecg-plot/ecgconfig.py.
Parametri
Stessi parametri di /convert, ma al posto del file:
| Campo | Tipo | Descrizione |
|---|---|---|
study_uid |
string | Study Instance UID |
series_uid |
string | Series Instance UID |
object_uid |
string | SOP Instance UID |
Esempio
curl -X POST http://localhost:8001/api/ecg/convert-wado \
-H "X-API-Key: mykey" \
-F "study_uid=1.2.3.4" \
-F "series_uid=1.2.3.4.5" \
-F "object_uid=1.2.3.4.5.6" \
-F "format=png" \
-o ecg.pngVerifica che il servizio sia attivo. Non richiede autenticazione.
curl http://localhost:8001/health
# {"status": "ok"}I messaggi di errore dell'API vengono restituiti nella lingua richiesta dal client
tramite l'header HTTP standard Accept-Language.
Lingue supportate: it (italiano), en (inglese, default).
# Risposta in italiano
curl -H "Accept-Language: it" ...
# → {"detail": "Layout non valido. Valori accettati: ..."}
# Risposta in inglese
curl -H "Accept-Language: en-US,en;q=0.9" ...
# → {"detail": "Invalid layout. Accepted values: ..."}Se l'header è assente o la lingua richiesta non è disponibile, viene usato l'inglese.
Aggiungere una nuova lingua: aprire app/i18n.py e aggiungere una voce al
dizionario MESSAGES con le stesse chiavi di en.
Il numero massimo di richieste per IP è configurabile tramite RATE_LIMIT nel .env.
Al superamento del limite il servizio risponde con 429 Too Many Requests.
Formato: N/second, N/minute, N/hour — es. 30/minute, 5/second, 500/hour.
ecg-web/
├── app/
│ ├── auth.py # Dipendenza FastAPI per l'autenticazione
│ ├── config.py # Configurazione via pydantic-settings
│ ├── i18n.py # Traduzioni e rilevamento lingua da Accept-Language
│ ├── limiter.py # Istanza globale slowapi
│ ├── main.py # Applicazione FastAPI
│ ├── routes/
│ │ ├── ecg.py # Endpoint /convert e /convert-wado
│ │ └── formats.py # Endpoint /formats
│ └── static/
│ └── index.html # Client web di esempio (servito su /)
├── dicom-ecg-plot/ # Git submodule
├── .env # Configurazione locale (non versionato)
├── .env.example # Template di configurazione
└── requirements.txt
Il file ecg-web.service è pronto all'uso.
1. Copia il progetto (adatta il percorso se necessario):
sudo cp -r . /opt/ecg-web
sudo chown -R debe:debe /opt/ecg-web2. Installa e avvia il servizio:
sudo cp /opt/ecg-web/ecg-web.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now ecg-web3. Verifica lo stato:
systemctl status ecg-web
journalctl -u ecg-web -fIl servizio è in ascolto su 127.0.0.1:8001. Per esporlo all'esterno, configura
un reverse proxy (nginx, Caddy, …) davanti al servizio.
Il servizio gira come utente ecg-web. Crearlo prima di avviare il servizio:
sudo useradd --system --no-create-home ecg-webSe il percorso di deploy differisce da /opt/ecg-web, modifica ecg-web.service
prima di copiarlo in /etc/systemd/system/.
Il file ecg-web.nginx.conf contiene un server block nginx pronto all'uso.
Gestisce il redirect HTTP → HTTPS, SSL via Let's Encrypt e il proxy verso
uvicorn su 127.0.0.1:8001.
Sostituire ecg.example.com con il proprio dominio prima di installare.
1. Ottieni un certificato SSL (se non già presente):
certbot --nginx -d tuo.dominio.it2. Installa la configurazione:
sudo cp ecg-web.nginx.conf /etc/nginx/sites-available/ecg-web
sudo ln -s /etc/nginx/sites-available/ecg-web /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxgit submodule update --remote dicom-ecg-plotMIT