Salta ai contenuti

Scrivere un plugin di modalità

Un plugin di modalità insegna alla piattaforma un tipo di dato: quali file accetta, come il browser di chi carica li de-identifica e li raggruppa prima di cifrarli, e come i membri li visualizzano. È un pacchetto del catalogo dei plugin come un plugin di attività: leggi prima I plugin e il catalogo dei plugin e Scrivere un plugin di attività, che trattano il pacchetto, l’host, la build e la console.

export default definePlugin((h) => ({
modalities: [{ descriptor, deid, accept, ingest, viewers }],
}));

Un plugin di modalità è descritto da un descrittore di modalità (schema modality/descriptor-v1): il suo ID e la versione (i manifest lo indicano come id@major), il nome e la categoria nel catalogo, gli spazi di selezione usati dai suoi visualizzatori, i formati, i profili e le opzioni di de-identificazione, i layout e gli hanging protocol, e i tipi di annotazione che i suoi visualizzatori possono mostrare (annotationTypes, integrati o propri). Il passo Modalità della procedura guidata offre esattamente ciò che elenca; l’app verifica il descrittore rispetto allo schema quando carica il plugin. Formati supportati elenca i formati, i valori di Modality DICOM e i layout dei plugin integrati.

deid dà a ogni profilo e opzione elencati dal descrittore un nome e una descrizione in inglese, e il valore predefinito di ogni opzione. I profili integrati sono ps3.15-basic (il Basic Application Level Confidentiality Profile di DICOM) e strip-metadata; un plugin che accetta DICOM usa il primo.

Accettare file: regole di accettazione e acquisizione

Sezione intitolata “Accettare file: regole di accettazione e acquisizione”

accept elenca le firme dei file (i primi byte) e i nomi che il plugin accetta; la pagina di caricamento indirizza ogni file al primo plugin del manifest che lo accetta.

ingest() avvia un worker che serve una IngestPipeline (@yggdrasil/plugin-api documenta ogni passo): scan raggruppa i file in serie, review elenca cosa cambia la de-identificazione, describe fornisce i metadati de-identificati di studio e serie e la ricevuta, e prepare fornisce i byte de-identificati e i metadati di ogni asset, che l’app poi cifra e carica. Ogni passo gira nel browser di chi carica: nulla ne esce prima di essere de-identificato e cifrato. I passi devono essere deterministici per gli stessi file.

Non convertire mai durante l’acquisizione. La piattaforma conserva i file così come sono arrivati, rimuovendo solo ciò che identifica il paziente; i visualizzatori leggono il formato conservato.

Un plugin del catalogo è un unico modulo, quindi il suo worker di acquisizione è lo stesso modulo avviato di nuovo:

import { serveIngest } from "@yggdrasil/plugin-api/ingest";
const pipeline = { scan, review, describe, identify, prepare };
// In the worker: serve the pipeline. In the page: register the plugin.
if (!("document" in globalThis)) serveIngest(pipeline);
const ingest = () => new Worker(import.meta.url, { type: "module" });

Il worker non ha un host: può usare solo ciò che il plugin include nel bundle (@yggdrasil/plugin-api/ingest non importa nulla). I browser non verificano l’integrità dello script di un worker; il worker gira sotto la Content Security Policy dell’app, che consente WebAssembly ma non eval.

viewers associa ciascun layout del descrittore a un componente React. Il componente riceve gli asset della serie con i loro metadati decifrati e una funzione read(assetId, start?, end?) che restituisce byte decifrati, e renderizza la barra degli strumenti e il pannello laterale di cui ha bisogno tramite gli slot della shell del visualizzatore. I plugin non raggiungono mai l’API né le chiavi: l’host fornisce loro solo ciò che il membro ha aperto.

L’anteprima della procedura guidata: serie di esempio

Sezione intitolata “L’anteprima della procedura guidata: serie di esempio”

L’anteprima dell’area di lavoro nella procedura guidata mostra le voci di una bozza su immagini di esempio, mai sui dati del progetto. Un plugin fornisce le proprie con previewSamples(sequences) (API dei plugin 1.1.0): serie di esempio (una per sequenza, se il plugin mostra le sequenze separatamente), ciascuna un elenco di asset con i metadati che la sua acquisizione scriverebbe e una funzione che produce i byte, sintetici e generati nella pagina. Senza di essa, l’anteprima indica che non ha esempi per il plugin.

I coordinateSpaces del descrittore indicano dove stanno le forme (pixel, patient, media-time, slide, mesh, …), e annotationTypes quali tipi i suoi visualizzatori possono mostrare. Un visualizzatore che disegna forme usa i selettori di annotation/selectors-v1.

  • Il server conosce solo i plugin di modalità integrati: verifica gli ID scelti da una voce del manifest (formati, profilo, layout) solo per i plugin ygg.*, e lascia quelli di un plugin del catalogo ai controlli del plugin stesso nelle app dei membri.
  • I processori e il worker di esportazione leggono i file conservati così come sono; un nuovo formato li raggiunge come i suoi byte originali.
  • Le miniature sono integrate solo per le modalità integrate.