Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task: generate model from code asset #2382

Merged
merged 3 commits into from
Dec 7, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,38 +68,31 @@
</div>
<template #preview>
<tera-drilldown-preview v-model:output="selectedModelFramework" :options="modelFrameworks">
<section v-if="modelValid === false || previewHTML === ''">
<div v-if="isProcessing">
<i class="pi pi-spin pi-spinner" :style="{ fontSize: '2rem' }"></i>
</div>
</section>
<section v-if="previewHTML !== ''">
<template v-if="selectedModelFramework === ModelFramework.Petrinet">
<!--Potentially put tera-model-diagram here just for petrinets-->
<tera-progress-spinner v-if="isProcessing" :font-size="2" />
<section>
<template v-if="selectedModelFramework === ModelFramework.Petrinet && selectedModel">
<tera-model-diagram :model="selectedModel" :is-editable="false"></tera-model-diagram>
<!--Potentially breakdown tera-model-descriptions state and parameter tables and put them here-->
</template>
<template v-if="selectedModelFramework === ModelFramework.Decapodes">
<template v-if="selectedModelFramework === ModelFramework.Decapodes && previewHTML">
<div :innerHTML="previewHTML" />
</template>
<div class="flex flex-column gap-2">
<label>Model name</label>
<InputText v-model="modelName" />
</div>
</section>
<template #footer>
<Button
:disabled="!modelValid || modelName === ''"
:loading="savingAsset"
:disabled="!isModelValid()"
label="Save as new model"
severity="secondary"
outlined
@click="saveAsNewModel"
style="margin-right: auto"
/>
<Button label="Cancel" severity="secondary" outlined />
<Button label="Cancel" severity="secondary" @click="emit('close')" outlined />
<Button
:disabled="!modelValid || modelName === ''"
:disabled="!isModelValid()"
label="Apply changes and close"
@click="getModel"
@click="constructModel"
/>
</template>
</tera-drilldown-preview>
Expand All @@ -112,14 +105,13 @@ import { onMounted, onUnmounted, ref } from 'vue';
import Dropdown from 'primevue/dropdown';
import Panel from 'primevue/panel';
import Button from 'primevue/button';
import InputText from 'primevue/inputtext';
import InputSwitch from 'primevue/inputswitch';
import { VAceEditor } from 'vue3-ace-editor';
import { VAceEditorInstance } from 'vue3-ace-editor/types';
import 'ace-builds/src-noconflict/mode-python';
import 'ace-builds/src-noconflict/mode-julia';
import 'ace-builds/src-noconflict/mode-r';
import { ProgrammingLanguage } from '@/types/Types';
import { ProgrammingLanguage, Model, AssetType } from '@/types/Types';
import { WorkflowNode } from '@/types/workflow';
import { cloneDeep, isEmpty } from 'lodash';
import { KernelSessionManager } from '@/services/jupyter';
Expand All @@ -128,6 +120,14 @@ import { logger } from '@/utils/logger';
import TeraDrilldown from '@/components/drilldown/tera-drilldown.vue';
import TeraDrilldownSection from '@/components/drilldown/tera-drilldown-section.vue';
import TeraDrilldownPreview from '@/components/drilldown/tera-drilldown-preview.vue';
import { getCodeAsset, getCodeFileAsText } from '@/services/code';
import { codeToAMR } from '@/services/knowledge';
import TeraModelDiagram from '@/components/model/petrinet/model-diagrams/tera-model-diagram.vue';
import { getModel } from '@/services/model';
import { addAsset } from '@/services/project';
import { useProjects } from '@/composables/project';
import TeraProgressSpinner from '@/components/widgets/tera-progress-spinner.vue';
import { useToastService } from '@/services/toast';
import { ModelFromCodeState } from './model-from-code-operation';

const props = defineProps<{
Expand All @@ -144,28 +144,41 @@ enum ModelFramework {
const isProcessing = ref(false);

const editor = ref<VAceEditorInstance['_editor'] | null>(null);
const modelName = ref('');
blanchco marked this conversation as resolved.
Show resolved Hide resolved
const programmingLanguages = Object.values(ProgrammingLanguage);
const selectedProgrammingLanguage = ref(ProgrammingLanguage.Julia);
const selectedProgrammingLanguage = ref(ProgrammingLanguage.Python);
const modelFrameworks = Object.values(ModelFramework);
const selectedModelFramework = ref(
isEmpty(props.node.state.modelFramework)
? ModelFramework.Decapodes
? ModelFramework.Petrinet
: props.node.state.modelFramework
);
const modelValid = ref(false);
const decapodesModelValid = ref(false);
const kernelManager = new KernelSessionManager();
const previewHTML = ref('');

const selectedModel = ref<Model>();
const codeBlock = {
...props.node.state,
name: 'Code block 1',
includeInProcess: true
};

const savingAsset = ref(false);

const codeBlocks = ref([codeBlock]);

onMounted(async () => {
if (props.node.inputs[0].value?.[0]) {
const codeAsset = await getCodeAsset(props.node.inputs[0].value[0]);

// for now get the first files source code
if (codeAsset?.id && codeAsset?.files) {
const filename = Object.keys(codeAsset.files)[0];
const codeContent = await getCodeFileAsText(codeAsset.id, filename);
codeBlocks.value[0].codeContent = codeContent ?? '';
}
}

try {
const jupyterContext = buildJupyterContext();
if (jupyterContext) {
Expand All @@ -187,10 +200,6 @@ function buildJupyterContext() {
selectedModelFramework.value === ModelFramework.Decapodes ? 'decapodes_creation' : null;
const languageName =
selectedProgrammingLanguage.value === ProgrammingLanguage.Julia ? 'julia-1.9' : null;
if (contextName === null || languageName === null) {
logger.warn("Can't work with current language. Do nothing.");
return null;
}

return {
context: contextName,
Expand All @@ -206,55 +215,85 @@ function setKernelContext() {
}
}

function handleCode() {
async function handleCode() {
isProcessing.value = true;

const code = editor.value?.getValue();
const messageContent = <JSONObject>{
declaration: code
};
if (selectedModelFramework.value === ModelFramework.Petrinet) {
const modelId = await codeToAMR(props.node.inputs[0].value?.[0]);
const newModel = await getModel(modelId);
if (newModel) {
selectedModel.value = newModel;
}
isProcessing.value = false;
}

modelValid.value = false;
if (selectedModelFramework.value === ModelFramework.Decapodes) {
const code = editor.value?.getValue();
const messageContent = <JSONObject>{
declaration: code
};

kernelManager
.sendMessage('compile_expr_request', messageContent)
?.register('compile_expr_response', handleCompileExprResponse)
?.register('decapodes_preview', handleDecapodesPreview);
decapodesModelValid.value = false;

kernelManager
.sendMessage('compile_expr_request', messageContent)
?.register('compile_expr_response', handleCompileExprResponse)
?.register('decapodes_preview', handleDecapodesPreview);
}
}

function getModel() {
function constructModel() {
const modelContent = {
name: modelName.value
name: 'new model'
};

modelValid.value = false;
decapodesModelValid.value = false;

kernelManager
.sendMessage('construct_amr_request', modelContent)
?.register('construct_amr_response', handleConstructAmrResponse);
}

function saveAsNewModel() {
const messageContent = {
header: {
description: modelName.value,
name: modelName.value,
_type: 'Header',
model_version: 'v1.0',
schema: 'modelreps.io/DecaExpr',
schema_name: 'DecaExpr'
async function saveAsNewModel() {
if (selectedModelFramework.value === ModelFramework.Petrinet) {
const projectId = useProjects().activeProject.value?.id;

if (!projectId || !selectedModel.value) return;

savingAsset.value = true;
const response = await addAsset(projectId, AssetType.Models, selectedModel.value.id);
savingAsset.value = false;

if (!response) {
logger.error('Could not save asset to project');
return;
}
};

modelValid.value = false;
useToastService().success('', 'Model saved successfully.');
}

kernelManager
.sendMessage('save_amr_request', messageContent)
?.register('save_amr_response', handleSaveAmrResponse);
if (selectedModelFramework.value === ModelFramework.Decapodes) {
const messageContent = {
header: {
description: 'new description',
name: 'new model',
_type: 'Header',
model_version: 'v1.0',
schema: 'modelreps.io/DecaExpr',
schema_name: 'DecaExpr'
}
};

decapodesModelValid.value = false;

kernelManager
.sendMessage('save_amr_request', messageContent)
YohannParis marked this conversation as resolved.
Show resolved Hide resolved
?.register('save_amr_response', handleSaveAmrResponse);
}
}

function handleCompileExprResponse() {
modelValid.value = true;
decapodesModelValid.value = true;
}

function handleDecapodesPreview(data: any) {
Expand Down Expand Up @@ -288,6 +327,18 @@ function addCodeBlock() {
function removeCodeBlock(index: number) {
codeBlocks.value.splice(index, 1);
}

function isModelValid() {
if (selectedModelFramework.value === ModelFramework.Petrinet) {
return !!selectedModel.value;
}

if (selectedModelFramework.value === ModelFramework.Decapodes) {
return decapodesModelValid.value;
}

return false;
}
</script>

<style scoped>
Expand Down