Skip to main content

UI Development Concepts

AIRC User Interface Overview

AI-Rad-Companion UI consists of several common (general) parts which are not related to any specific extension - the main application frame, cases lists, general configuration and access to help and knowledge base. Then there are extension specific parts:

  • Confirmation UI (case detail)
  • Configuration UI (extension specific)
  • About Box (regulatory information section)

The extension specific components are implemented by the extension developer. They are then integrated within the AIRC UI during the onboarding process.

The following picture shows the overview of the UI architecture. The blue boxes represent the artifacts provided by an extension developer.

AIRC UI Overview

Because of the way the extension components are integrated, they need to be implemented in a very specific way, in particular: an ASP.NET Core web application must be provided which will run in a docker container. It shall expose an API which provides single java script bundle with the implementation of the 3 custom elements - Confirmation, Configuration, About box. The web application should also expose APIs needed by those components, e.g. to read/write the configuration and the case results and images. The web application shall use the ExtensionSDK library to connect to AIRC services. The services provide access to input images, the results created by the processing unit, the configuration etc.

Web Backend Development

AIRC Extension SDK

AIRC Extension SDK is a C# library which is used to connect to AIRC engine services which provide access to input images, enable store and retrieve algorithm results, user configuration etc. There are two entrypoints: IWebBackendContext which is used in web backend development and IProcessingUnitContext used in processing units. We will focus on the first one in this section.

To use the IWebBackendContext in the web backend controllers:

  • Install the AIRC.ExtensionSDK NuGet package.
  • Create an instance using the factory method and add it to services as a singleton

The simplest example is:

`services.AddSingleton(SdkFactory.InitializeWebBackendContext()`

Note that this would work only for web application running in "normal" AIRC environment (cloud/edge). AIRC Extension SDK supports also modes where the application is executed locally (ExecutionMode.Local for local testing and development) and as an Open Apps application - ExecutionMode.LocalRaw. There is a factory method for instantiation of the IWebBackendContext for each of these modes. Use ExecutionConfigurationParser to determine the mode from the command line arguments:

 switch (ExecutionConfigurationParser.ParseExecutionMode(Configuration))
{
case ExecutionMode.Normal:
services.AddSingleton(SdkFactory.InitializeWebBackendContext());
break;

case ExecutionMode.Local:
var localCommonConfiguration = ExecutionConfigurationParser.ParseLocalCommonConfiguration(Configuration);
services.AddSingleton(SdkFactory.InitializeLocalWebBackendContext(localCommonConfiguration));
break;

case ExecutionMode.LocalRaw:
var localRawCommonConfiguration = ExecutionConfigurationParser.ParseLocalRawCommonConfiguration(Configuration);
services.AddSingleton(SdkFactory.InitializeLocalRawWebBackendContext(localRawCommonConfiguration));
break;
}

The connection information (URLs, secrets, etc.) for AIRC mode are read from the environmental variables in the background. No command line parameters are used when running in AIRC mode. The parameters for local modes (input and output directories etc...) are read by ExecutionConfigurationParser from the command line arguments.

Extension Configuration Handling

Extension configuration is a site (tenant) specific configuration which can be modified by user in the Configuration UI and is then available in the processing unit, when a case is processed.

note

In the AIRC environment the system creates a snapshot of the configuration after each change. If configuration is changed while a case is being processed, it would use the snapshot which was valid at the time of the case creation.

IWebBackendContext provides access to the IConfiguration interface via the property IWebBackendContext.Configuration. The IConfiguration has methods to read and write the site specific (tenant) configuration and also the configuration for given case.

The configuration data is stored in a serialized form as a byte array, see IConfigData interface definition. If the processing unit is a "Wrapper Extension" (i.e. the generic AIRC extension which wraps an algorithm executable, currently the only supported mode in Developer Portal), the serialized configuration data must be of type ConfigDataExt. This type consist of generic part, which is used for configuration of the wrapper extension and then the application specific part which is again stored serialized and converted byte array.

This is the example of serializing and storing configuration modified in UI as ConfigDataExt

//serialize user configuration

var serializedUserConfig = JsonConvert.SerializeObject(userConfigurationTransfer);
var serializedUserConfigBytes = Encoding.UTF8.GetBytes(serializedUserConfig);
var configDataExt = new ConfigDataExt();
configDataExt.SerializedUserConfig = serializedUserConfigBytes.ToList();
configDataExt.GenericConfig = genericConfigTransfer;

//serialize the complete configuration

var serializedConfig = JsonConvert.SerializeObject(configDataExt);
var serializedConfigBytes = Encoding.UTF8.GetBytes(serializedConfig);
var configData = new ConfigData(1, serializedConfigBytes);

//store the configuration
await webBackendContext.Configuration.StoreGlobalConfigAsync(ownerId, configData).ConfigureAwait(false);

note

The content of ConfigDataExt.SerializedUserConfig will be saved as a plain text (bytes converted to string) in a file ("config.json" by default) in the configuration directory of the processing unit.

Access to the input images

The interface IInputStorage (accessible via IWebBackendContext.InputStorage) provides access to the input DICOM series. Note that some of the methods are currently not available in the Open Apps environment. Use one of the following methods to read the input data:

        // Get meta data (UIDs) of all available input series which are currently present.
Task<IEnumerable<SeriesMetaData>> GetInputSeriesMetaDataAsync(string tenantId, string caseId);

// Get input files of a series with given series UID
Task<SeriesData> GetInputSeriesAsync(string tenantId, string caseId, string studyInstanceUid, string seriesInstanceUid);

// Get the input file of given Instance UID
Task<byte[]> GetInputImageAsync(string tenantId, string caseId, string studyInstanceUid, string seriesInstanceUid, string sopInstanceUid);

Access to the result images

All the dicom objects created by the processing unit (SC images, Structured Reports) are stored in the Result storage. These files are accessible by the interface IResultStorage (IWebBackendContext.ResultStorage). Use the following methods to read the result data:

        //Get the metadata (UIDs) of all available result series which are currently present.
Task<IEnumerable<SeriesMetaData>> GetResultSeriesMetaDataAsync(string tenantId, string caseId);

//Get the result series with the given series UID
Task<(SeriesData seriesData, StorageEntityTag entityTag)> GetSeriesAsync(
string tenantId,
string caseId,
string extensionInvocationId,
string studyInstanceUid,
string seriesInstanceUid);

//Get the single image from a result series with given UID and index.
Task<(byte[] imageData, StorageEntityTag entityTag)> GetImageAsync(
string tenantId,
string caseId,
string extensionInvocationId,
string studyInstanceUid,
string seriesInstanceUid,
int index);
note

The extensionInvocationId is a unique ID which is assigned by the AIRC engine to a concrete processing run of an extension. It will be passed to the extension confirmation component in the FE and shall be passed with the API request to the BE controller together with caseId when reading the data.