diff --git a/packages/client/hmi-client/src/components/workflow/ops/model-from-equations/tera-model-from-equations-drilldown.vue b/packages/client/hmi-client/src/components/workflow/ops/model-from-equations/tera-model-from-equations-drilldown.vue
index 82ce5a3190..3022db9d40 100644
--- a/packages/client/hmi-client/src/components/workflow/ops/model-from-equations/tera-model-from-equations-drilldown.vue
+++ b/packages/client/hmi-client/src/components/workflow/ops/model-from-equations/tera-model-from-equations-drilldown.vue
@@ -28,11 +28,11 @@
Specify which equations to use for this model.
@@ -198,6 +198,7 @@ import TeraDrilldownSection from '@/components/drilldown/tera-drilldown-section.
import TeraPdfEmbed from '@/components/widgets/tera-pdf-embed.vue';
import TeraTextEditor from '@/components/documents/tera-text-editor.vue';
import { logger } from '@/utils/logger';
+import SplitButton from 'primevue/splitbutton';
import { ModelFromEquationsState, EquationBlock } from './model-from-equations-operation';
const emit = defineEmits(['close', 'update-state', 'append-output', 'update-output', 'select-output']);
@@ -207,6 +208,17 @@ const props = defineProps<{
const selectedOutputId = ref('');
+const runItems = [
+ {
+ label: 'SKEMA',
+ command: () => onRun('skema')
+ },
+ {
+ label: 'Mira',
+ command: () => onRun('mira')
+ }
+];
+
const clonedState = ref({
equations: [],
text: '',
@@ -365,7 +377,7 @@ function onCheckBoxChange(equation) {
emit('update-state', state);
}
-async function onRun() {
+async function onRun(extractionService: 'mira' | 'skema' = 'skema') {
isOutputOpen.value = true;
isModelLoading.value = true;
const equationsText = clonedState.value.equations
@@ -382,7 +394,8 @@ async function onRun() {
equations: cleanedEquations,
documentId: document.value?.id,
workflowId: props.node.workflowId,
- nodeId: props.node.id
+ nodeId: props.node.id,
+ extractionService
};
const modelId = await equationsToAMR(request);
// If there isn't a modelId returned at least show the cleaned equations
@@ -580,4 +593,17 @@ watch(
.p-panel:deep(.p-panel-footer) {
display: none;
}
+
+:deep(.p-splitbutton .p-button:first-of-type) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-right: 0 none;
+ pointer-events: none;
+}
+
+:deep(.p-splitbutton .p-button:last-of-type) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ color: #fff;
+}
diff --git a/packages/client/hmi-client/src/services/knowledge.ts b/packages/client/hmi-client/src/services/knowledge.ts
index 7287fad835..5882ab28a4 100644
--- a/packages/client/hmi-client/src/services/knowledge.ts
+++ b/packages/client/hmi-client/src/services/knowledge.ts
@@ -38,6 +38,7 @@ export interface EquationsToAMRRequest {
documentId?: DocumentAsset['id'];
workflowId?: Workflow['id'];
nodeId?: WorkflowNode['id'];
+ extractionService?: 'mira' | 'skema';
}
/**
diff --git a/packages/client/hmi-client/src/services/notificationEventHandlers.ts b/packages/client/hmi-client/src/services/notificationEventHandlers.ts
index 5470f396f3..7a8cd54c56 100644
--- a/packages/client/hmi-client/src/services/notificationEventHandlers.ts
+++ b/packages/client/hmi-client/src/services/notificationEventHandlers.ts
@@ -2,6 +2,7 @@ import { useProjects } from '@/composables/project';
import {
CloneProjectStatusUpdate,
ExtractionStatusUpdate,
+ ModelEnrichmentStatusUpdate,
NotificationItem,
NotificationItemStatus
} from '@/types/common';
@@ -205,14 +206,13 @@ export const createNotificationEventHandlers = (notificationItems: Ref(ClientEventType.KnowledgeEnrichmentModel, (event, created) => {
+ registerHandler(ClientEventType.KnowledgeEnrichmentModel, (event, created) => {
created.sourceName = 'Model Enrichment';
-
// Check if the event data contains a workflowId and nodeId
- if (event.data.additionalProperties.workflowId && event.data.additionalProperties.nodeId) {
- created.assetId = event.data.additionalProperties.workflowId as string;
+ if (event.data.data?.workflowId && event.data.data?.nodeId) {
+ created.assetId = event.data.data.workflowId as string;
created.pageType = AssetType.Workflow;
- created.nodeId = event.data.additionalProperties.nodeId as string;
+ created.nodeId = event.data.data.nodeId as string;
getWorkflow(created.assetId, created.projectId).then((workflow) =>
Object.assign(created, { context: workflow?.name || '' })
);
@@ -220,7 +220,7 @@ export const createNotificationEventHandlers = (notificationItems: Ref
diff --git a/packages/client/hmi-client/src/types/common.ts b/packages/client/hmi-client/src/types/common.ts
index 8589ad7638..365a2b27f0 100644
--- a/packages/client/hmi-client/src/types/common.ts
+++ b/packages/client/hmi-client/src/types/common.ts
@@ -158,6 +158,8 @@ interface Comparison {
conclusion: string;
}
+export type ModelEnrichmentStatusUpdate = StatusUpdate<{ modelId: string; workflowId: string; nodeId: string }>;
+
export type ExtractionStatusUpdate = StatusUpdate<{ documentId: string }>;
export type CloneProjectStatusUpdate = StatusUpdate<{ projectId: string }>;
export interface NotificationItem extends NotificationItemStatus, AssetRoute {
diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/knowledge/KnowledgeController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/knowledge/KnowledgeController.java
index fd95ebe3e1..77115797c9 100644
--- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/knowledge/KnowledgeController.java
+++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/knowledge/KnowledgeController.java
@@ -80,6 +80,7 @@
import software.uncharted.terarium.hmiserver.service.notification.NotificationGroupInstance;
import software.uncharted.terarium.hmiserver.service.notification.NotificationService;
import software.uncharted.terarium.hmiserver.service.tasks.EquationsCleanupResponseHandler;
+import software.uncharted.terarium.hmiserver.service.tasks.LatexToAMRResponseHandler;
import software.uncharted.terarium.hmiserver.service.tasks.TaskService;
import software.uncharted.terarium.hmiserver.service.tasks.TaskService.TaskMode;
import software.uncharted.terarium.hmiserver.utils.ByteMultipartFile;
@@ -260,29 +261,54 @@ public ResponseEntity equationsToModel(
}
}
- // Create a request for SKEMA with the cleaned-up equations.
- final JsonNode skemaRequest = mapper.createObjectNode().put("model", "petrinet").set("equations", equationsReq);
-
- // Get an AMR from Skema Unified Service
+ // Get an AMR from Skema Unified Service or MIRA
final Model responseAMR;
- try {
- responseAMR = skemaUnifiedProxy.consolidatedEquationsToAMR(skemaRequest).getBody();
- if (responseAMR == null) {
- log.warn("Skema Unified Service did not return a valid AMR based on the provided equations");
- throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, messages.get("skema.bad-equations"));
+ String extractionService = "mira";
+ if (req.get("extractionService") != null) {
+ extractionService = req.get("extractionService").asText();
+ }
+
+ if (extractionService.equals("mira")) {
+ final TaskRequest taskReq = new TaskRequest();
+ final String latex = req.get("equations").toString();
+ taskReq.setType(TaskType.MIRA);
+ try {
+ taskReq.setInput(latex.getBytes());
+ taskReq.setScript(LatexToAMRResponseHandler.NAME);
+ taskReq.setUserId(currentUserService.get().getId());
+ final TaskResponse taskResp = taskService.runTaskSync(taskReq);
+ final JsonNode taskResponseJSON = mapper.readValue(taskResp.getOutput(), JsonNode.class);
+ final String amrString = taskResponseJSON.get("response").asText();
+ ObjectNode objNode = (ObjectNode) mapper.readTree(amrString);
+
+ final JsonNode testNode = mapper.readValue(amrString, JsonNode.class);
+ responseAMR = mapper.convertValue(testNode, Model.class);
+ } catch (Exception e) {
+ log.error("failed to convert latex equations to AMR", e);
+ throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "failed to convert latex equations to AMR");
+ }
+ } else {
+ try {
+ // Create a request for SKEMA with the cleaned-up equations.
+ final JsonNode skemaRequest = mapper.createObjectNode().put("model", "petrinet").set("equations", equationsReq);
+ responseAMR = skemaUnifiedProxy.consolidatedEquationsToAMR(skemaRequest).getBody();
+ if (responseAMR == null) {
+ log.warn("Skema Unified Service did not return a valid AMR based on the provided equations");
+ throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, messages.get("skema.bad-equations"));
+ }
+ } catch (final FeignException e) {
+ log.error(
+ "An exception occurred while Skema Unified Service was trying to produce an AMR based on the provided equations",
+ e
+ );
+ throw handleSkemaFeignException(e);
+ } catch (final Exception e) {
+ log.error(
+ "An unhandled error occurred while Skema Unified Service was trying to produce an AMR based on the provided equations",
+ e
+ );
+ throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, messages.get("skema.internal-error"));
}
- } catch (final FeignException e) {
- log.error(
- "An exception occurred while Skema Unified Service was trying to produce an AMR based on the provided equations",
- e
- );
- throw handleSkemaFeignException(e);
- } catch (final Exception e) {
- log.error(
- "An unhandled error occurred while Skema Unified Service was trying to produce an AMR based on the provided equations",
- e
- );
- throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, messages.get("skema.internal-error"));
}
// We only handle Petri Net models