Skip to content

Commit

Permalink
WIP: Validate StructureMap (#281)
Browse files Browse the repository at this point in the history
* Create validateStructureMap command

* Add parseCompositionFile function

* Add a function that parses the composition file

* Update the QRgeneration and call it from validateStructureMap command

* Add a folder for saving the QRs

* Fix failing Validation test class

* Add structueMap validation against QRs

* Remove default values for SM command

* Add extractedResources sub folder

* Add the extractedResources from the bundle to the directory

* Add validation code for the project

* Fix spotless

* Fix failing path

* Add FctValidation for questionnaireToStructureMapId Mapping

* Add test cases for validateStructureMap

* Use questionnaireProcessor

* Update validate Structuremap for project

* Finalize tests

* Add documentation

* Fix structureMap path

---------

Co-authored-by: sharon2719 <[email protected]>
Co-authored-by: Sharon Akinyi <[email protected]>
  • Loading branch information
3 people authored Oct 23, 2024
1 parent 6493f4c commit a70d0cb
Show file tree
Hide file tree
Showing 9 changed files with 693 additions and 29 deletions.
2 changes: 2 additions & 0 deletions efsity/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ fhircore-tooling.iml
# build files
bin
target

generatedResources
32 changes: 32 additions & 0 deletions efsity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,38 @@ $ fct validateFileStructure -i ~/Workspace/fhir-resources/<project> -s ~/path/to
If the file structure matches the schema then a positive result is printed to the terminal, otherwise an error
is thrown showing the issue.

### Validating Questionnaires and StructureMap
The tool supports two validation modes:

**1.Single mode** - Validates a single StructureMap and questionnaire.
**2.Project mode** - Validates all project files, including multiple questionnaires and StructureMaps.

The tool maps each questionnaire to the specified StructureMap, then generates the corresponding `QuestionnaireResponse`. Once generated, a bundle is created with the related resources (e.g., Patient, Condition).

To run the tool, ensure the following:

1. Install h`api=fhir-jpaserver-starter`.
2. In `src/main/resources/application.yaml`, set `hapi: fhir`: to `true`.
3. Run the command: `mvn spring-boot:run`

The server will be accessible at http://localhost:8080/fhir, and the `CapabilityStatement` can be found at http://localhost:8080/fhir/metadata.
**Options**
```
-i or --input Path to the project questionnaire folder to be validated.
-q or --questionnaire Path to a single questionnaire file to be validated.
-v or --validate (Optional) Boolean flag to validate FHIR resources before publishing. Default is `false`.
-sm or --structure-map Path to the folder containing StructureMaps. Nested directories are supported.
```

```console (single-mode)
$ fct validateStructureMap -q ~/Workspace/fhir-resources/<project>/questionnaire-folder/resource.json -sm ~/Workspace/fhir-resources/coda/structure_map-folder/coda-child-structure-map.txt
```

```console (project-mode)
$ fct validateStructureMap -i ~/Workspace/fhir-resources/<project>/questionnaire-folder/ -sm ~/Workspace/fhir-resources/coda/structure_map-folder/`
```

### Localization
Tool that supports localization by the use of the translation extension

Expand Down
3 changes: 2 additions & 1 deletion efsity/src/main/java/org/smartregister/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
TranslateCommand.class,
QuestionnaireResponseGeneratorCommand.class,
ValidateFileStructureCommand.class,
PublishFhirResourcesCommand.class
PublishFhirResourcesCommand.class,
ValidateStructureMapCommand.class,
})
public class Main implements Runnable {
public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,15 @@ public void run() {
validateOptions();
if (inputFilePath != null) {
try {
generateResponse(inputFilePath, mode, extrasPath, fhir_base_url, apiKey);
generateResponse(
inputFilePath,
mode,
outputFilePath,
extrasPath,
fhir_base_url,
apiKey,
aiModel,
maxTokens);
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand All @@ -111,8 +119,15 @@ private void validateOptions() {
}
}

private void generateResponse(
String inputFilePath, String mode, String extrasPath, String fhir_base_url, String apiKey)
public static void generateResponse(
String inputFilePath,
String mode,
String outputFilePath,
String extrasPath,
String fhir_base_url,
String apiKey,
String aiModel,
String maxTokens)
throws IOException {
long start = System.currentTimeMillis();

Expand All @@ -127,17 +142,17 @@ private void generateResponse(
String questionnaireResponseString =
(Objects.equals(mode, "populate"))
? populateMode(questionnaireData, fhir_base_url, extrasPath)
: aiMode(questionnaireData, apiKey);
: aiMode(questionnaireData, apiKey, aiModel, maxTokens);

// Write response to file
FctUtils.printInfo("Writing response to file");
String output =
Files.isDirectory(Paths.get(this.outputFilePath))
? this.outputFilePath
Files.isDirectory(Paths.get(outputFilePath))
? outputFilePath
+ File.separator
+ inputFile.getNameWithoutExtension()
+ Constants.QUESTIONNAIRE_RESPONSE_SUFFIX
: this.outputFilePath;
: outputFilePath;

FctUtils.writeJsonFile(output, questionnaireResponseString);
FctUtils.printInfo(
Expand All @@ -148,7 +163,7 @@ private void generateResponse(
FctUtils.printCompletedInDuration(start);
}

Boolean checkResource(
static Boolean checkResource(
String questionnaire_id, String resourceType, JSONObject resource, String fhir_base_url)
throws IOException {
JSONObject request = new JSONObject();
Expand Down Expand Up @@ -305,7 +320,7 @@ static JSONObject generateAnswer(
}
}

JSONArray getAnswers(JSONArray questions, JSONArray responses, JSONObject extras) {
static JSONArray getAnswers(JSONArray questions, JSONArray responses, JSONObject extras) {
for (int i = 0; i < questions.length(); i++) {
JSONObject current_question = questions.getJSONObject(i);
String question_type = current_question.getString("type");
Expand All @@ -327,7 +342,7 @@ JSONArray getAnswers(JSONArray questions, JSONArray responses, JSONObject extras
return responses;
}

String populateMode(String questionnaireData, String fhir_base_url, String extrasPath)
static String populateMode(String questionnaireData, String fhir_base_url, String extrasPath)
throws IOException {
JSONObject resource = new JSONObject(questionnaireData);
String questionnaire_id = resource.getString("id");
Expand Down Expand Up @@ -369,7 +384,8 @@ String populateMode(String questionnaireData, String fhir_base_url, String extra
return String.valueOf(questionnaire_response);
}

String aiMode(String questionnaireData, String apiKey) throws IOException {
static String aiMode(String questionnaireData, String apiKey, String aiModel, String maxTokens)
throws IOException {
if (true) {
throw new IllegalStateException("Sorry, the AI mode is temporarily unsupported");
}
Expand All @@ -383,7 +399,7 @@ String aiMode(String questionnaireData, String apiKey) throws IOException {

// Generate response
String generatedResponseString =
aiGenerated(questionnaireJsonString, apiKey, this.aiModel, this.maxTokens);
aiGenerated(questionnaireJsonString, apiKey, aiModel, maxTokens);
JSONObject obj = new JSONObject(generatedResponseString);
JSONArray choices = obj.getJSONArray("choices");
String questionnaireResponseString = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,22 @@ public class StructureMapExtractResourcesCommand implements Runnable {
public void run() {

try {
extractResource(qr, sm);
extractResource(qr, sm, output);

} catch (IOException e) {
throw new RuntimeException(e);
}
}

private void extractResource(String qrFilePath, String structureMapFilePath) throws IOException {
static void extractResource(String qrFilePath, String structureMapFilePath, String output)
throws IOException {

long start = System.currentTimeMillis();

FctUtils.printInfo(String.format("Questionnaire Response file path \u001b[35m%s\u001b[0m", qr));
FctUtils.printInfo(String.format("Structure Map file path \u001b[35m%s\u001b[0m", sm));
FctUtils.printInfo(
String.format("Questionnaire Response file path \u001b[35m%s\u001b[0m", qrFilePath));
FctUtils.printInfo(
String.format("Structure Map file path \u001b[35m%s\u001b[0m", structureMapFilePath));

FctFile questionnaireResponse = FctUtils.readFile(qrFilePath);

Expand Down
Loading

0 comments on commit a70d0cb

Please sign in to comment.