diff --git a/.eslintrc.js b/.eslintrc.js
index c318b07c..c6844387 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -84,7 +84,7 @@ module.exports = {
'max-classes-per-file': 'off',
// ORIGINAL tslint.json -> "max-line-length": [true, 140],
- 'max-len': ['error', {code: 160}],
+ // 'max-len': ['error', {code: 160}],
// ORIGINAL tslint.json -> "member-access": false,
'@typescript-eslint/explicit-member-accessibility': 'off',
diff --git a/package.json b/package.json
index 4d7ce8b3..3e2265e2 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
"core-js": "2.6.3",
"d3": "^5.9.2",
"file-saver": "^2.0.5",
+ "jquery": "^3.6.1",
"keyword-extractor": "0.0.25",
"lodash": "^4.17.21",
"madr": "2.1.2",
@@ -49,6 +50,7 @@
"rxjs": "6.5.5",
"simplemde": "1.11.2",
"tslib": "^1.10.0",
+ "whatwg-fetch": "^3.6.2",
"zone.js": "~0.10.3"
},
"devDependencies": {
diff --git a/src/app/core/component/textmatcher/textmatcher.component.html b/src/app/core/component/textmatcher/textmatcher.component.html
index 3a158232..a7f5a6cd 100644
--- a/src/app/core/component/textmatcher/textmatcher.component.html
+++ b/src/app/core/component/textmatcher/textmatcher.component.html
@@ -1,73 +1,117 @@
+
-
- Input the known Information
-
+
+ Describe your context
+
+
+
+
Rephrased input: {{rephrasedInput}}
+
+
+
+
The best matching algorithm with cosine similarity is
+ {{resultAlgorithm.name}}.
+
+
The Cosine Similarity is
+ {{resultAlgorithm.cosineSimilarity}}
+
+
+
+
+
+
+ Name
+
+ {{result.name}}
+
+
+
+ Cosine similarity
+ {{result.cosineSimilarity}}
+
+
+
+
+
+
+
+
+ Aggregation in progress... {{ progressValue }}%
-
-
Rephrased input: {{rephrasedInput}}
-
-
-
The best matching algorithm with cosine similarity is {{resultAlgorithm.name}}.
-
The Cosine Similarity is {{resultAlgorithm.cosineSimilarity}}
-
-
-
- Number of displayed algorithms
-
- {{number}}
-
-
-
-
-
-
- Name
- {{result.name}}
-
-
- Cosine similarity
- {{result.cosineSimilarity}}
-
-
-
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/src/app/core/component/textmatcher/textmatcher.component.ts b/src/app/core/component/textmatcher/textmatcher.component.ts
index e93b64f4..3555a895 100644
--- a/src/app/core/component/textmatcher/textmatcher.component.ts
+++ b/src/app/core/component/textmatcher/textmatcher.component.ts
@@ -1,186 +1,412 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
-import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { MatSelectModule } from '@angular/material/select';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatButtonModule } from '@angular/material/button';
+import { FormControl } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
-import { MatTableModule, MatTableDataSource } from '@angular/material/table';
-import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatTableDataSource } from '@angular/material/table';
+import { createServiceTemplate, createDeploymentModel, updateServiceTemplate, createNodeType, updateNodeType } from '../../../core/util/winery-utils';
+import { uploadCSARToContainer } from '../../util/opentosca-utils';
+import Pattern from '../../model/hal/pattern.model';
+import { UiFeatures } from '../../directives/pattern-atlas-ui-repository-configuration.service';
+import { MatDialog } from '@angular/material/dialog';
+import { DialoggraphComponent } from '../dialoggraph/dialoggraph.component';
+import * as consts from '../../util/constants';
+import { environment } from 'src/environments/environment';
+const QUANTME_NAMESPACE_PULL = 'http://quantil.org/quantme/pull';
+const OPENTOSCA_NAMESPACE_NODETYPE = 'http://opentosca.org/nodetypes';
+
@Component({
selector: 'pp-textmatcher',
templateUrl: './textmatcher.component.html',
styleUrls: ['./textmatcher.component.scss']
})
export class TextmatcherComponent implements OnInit {
-
-
- inputfield: FormControl;
- extractedAlgorithmInformation = []; //array of arrays with extracted keywords
- infos = [];
- keyword_extractor: any;
-
- checked = true;
-
- showMatchingResults: boolean;
- resultAlgorithm: any;
-
- numbers = [1,3,5,10];
- selectednumber = 3;
-
- tabledata = new MatTableDataSource([{ name: 'test', cosineSimilarity: 1 }]); // initial value
- fulltabledata: any;
- columnsToDisplay = ['name', 'cosineSimilarity'];
-
- rephrasedInput = '';
- showRephrasedInput: boolean;
-
- constructor(public dialogRef: MatDialogRef,
- private http: HttpClient,
- @Inject(MAT_DIALOG_DATA) public data) {
- //onbackground click handler als andere lösung
- dialogRef.disableClose = true;
-
- }
-
-
- ngOnInit(): void {
-
- this.showMatchingResults = false;
- this.showRephrasedInput = false;
-
- if(this.data.prev.length > 0) {
- this.resultAlgorithm = this.data.prev[0].resultAlgorithm;
- this.tabledata = this.data.prev[0].tabledata;
- this.fulltabledata = this.data.prev[0].fulltabledata;
- this.columnsToDisplay = this.data.prev[0].columnsToDisplay;
- this.rephrasedInput = this.data.prev[0].rephrasedInput;
- this.selectednumber = this.data.prev[0].selectedNumber;
-
- if (this.data.prev[0].inputfieldvalue != ''){
- this.inputfield = new FormControl(this.data.prev[0].inputfieldvalue);
- }else{
- this.inputfield = new FormControl('');
- }
- this.showMatchingResults = true;
- if(this.rephrasedInput != ''){
- this.showRephrasedInput = true;
- }
- }else{
- this.inputfield = new FormControl('');
- }
-
-
- let href = 'https://platform.planqk.de/algorithms/fae60bca-d2b6-4aa2-88b7-58caace34179';
- this.data.data.forEach(algorithm => {
- if((algorithm.href !== '')&&(algorithm.href != null)){
- let splitarray = algorithm.href.split('platform.planqk.de');
- let datahref = splitarray[0] + 'platform.planqk.de/qc-catalog' + splitarray[1];
- this.http.get(datahref).subscribe(algodata => {
- this.infos.push({ name: algorithm.name, data: algodata });
- });
- }else{
- //do something if no href
- }
- });
-
- }
-
- checkboxClicked(event){
- if(this.checked){
- this.checked = false;
- }else{
- this.checked = true;
- }
- }
-
- numberChanged() {
- this.tabledata.data = this.fulltabledata.slice(0, this.selectednumber);
- }
-
- closeDialog(algorithmName: string) {
- let previous = { resultAlgorithm: this.resultAlgorithm,
- tabledata: this.tabledata,
- fulltabledata: this.fulltabledata,
- columnsToDisplay: this.columnsToDisplay,
- inputfieldvalue: this.inputfield.value,
- rephrasedInput: this.rephrasedInput,
- selectedNumber: this.selectednumber, };
-
- this.dialogRef.close({ algoname: algorithmName, prev: previous });
- }
-
- closeDialog2() {
- if((this.inputfield.value != '') && this.showMatchingResults){
- let previous = { resultAlgorithm: this.resultAlgorithm,
- tabledata: this.tabledata,
- fulltabledata: this.fulltabledata,
- columnsToDisplay: this.columnsToDisplay,
- inputfieldvalue: this.inputfield.value,
- rephrasedInput: this.rephrasedInput,
- selectedNumber: this.selectednumber, };
-
- this.dialogRef.close({ algoname: undefined, prev: previous });
- }else{
- this.dialogRef.close(null);
- }
- }
-
-
- openLink(){
- let alg = this.data.data.filter(algorithm => algorithm.name == this.resultAlgorithm.name);
- if(alg.length > 0){
- this.closeDialog(this.resultAlgorithm.name);
- };
-
- }
-
- openLink2(algname){
- let alg = this.data.data.filter(algorithm => algorithm.name == algname);
- if(alg.length > 0){
- this.closeDialog(algname);
- };
- }
-
- extractInformation(isRake){
- let datatosend = { input: this.inputfield.value, algodata: this.infos };
- let url = 'http://localhost:1985/api/matcher/';
- if(isRake){
- url = url + 'rake/';
- }
-
- if(this.checked){
- url = url + 'openai';
- }
- this.rephrasedInput = '';
- this.showRephrasedInput = false;
-
- this.http.post(url, datatosend).subscribe(resultdata => {
- this.tabledata.data = resultdata.result;
- this.fulltabledata = this.tabledata.data;
- console.log('tabledata:');
- console.log(this.fulltabledata);
- this.tabledata.data = this.fulltabledata.slice(0, this.selectednumber);
-
- if(resultdata.hasOwnProperty('rephrasedInput')){
- this.rephrasedInput = resultdata.rephrasedInput;
- this.showRephrasedInput = true;
- }
-
- const maximumkey = this.fulltabledata.reduce(function(prev, current) {
- return (prev.cosineSimilarity > current.cosineSimilarity) ? prev : current;
- });
-
- if(maximumkey.cosineSimilarity > 0){
- this.showMatchingResults = true;
- this.resultAlgorithm = maximumkey;
- }else{
- this.showMatchingResults = false;
- console.log('no similarities found!');
- }
- });
- }
-
-}
+
+
+ patterns: Array = [];
+ inputfield: FormControl;
+ extractedAlgorithmInformation = []; // Array of arrays with extracted keywords
+ infos = [];
+ keyword_extractor: any;
+ isLoadingLinkData = true;
+ isLoadingPatternData = true;
+ graphVisible = true
+ progressValue = 0; // Value for the progress bar
+ isAggregating = false; // Flag to control progress bar visibility
+ readonly UiFeatures = UiFeatures;
+
+ checked = true;
+
+ showMatchingResults: boolean;
+ resultAlgorithm: any;
+ showAlgoPopups = true;
+
+ numbers = [1, 3, 5, 10];
+ selectednumber = 3;
+
+ tabledata = new MatTableDataSource([{ name: 'test', cosineSimilarity: 1 }]); // Initial value
+ fulltabledata: any;
+ columnsToDisplay = ['name', 'cosineSimilarity'];
+ deploymentFileContentUrl: any;
+
+ rephrasedInput = '';
+ showRephrasedInput: boolean;
+
+ // New state variable for aggregation
+ isAggregationComplete = false;
+
+ constructor(
+ public dialogRef: MatDialogRef,
+ private http: HttpClient,
+ private dialog: MatDialog,
+ @Inject(MAT_DIALOG_DATA) public data
+ ) {
+ dialogRef.disableClose = true;
+ }
+
+ openGraphDialog() {
+ console.log(environment.LATEX_RENDERER_API_URL)
+
+ const dialogRef = this.dialog.open(DialoggraphComponent, {
+ autoFocus: false,
+ data: {
+ nodes: consts.PATTERNS,
+ highlightedNodes: consts.Grover.data,
+ edges: consts.EDGES,
+ edgeInformation: consts.EDGE_INFORMATION,
+ optionalNodeIds: undefined,
+ name: this.fulltabledata[0].name,
+ href: '',
+ },
+ height: '70%',
+ width: '100%'
+ });
+
+ dialogRef.afterClosed().subscribe(result => {
+ console.log('closed dialog');
+ });
+ }
+
+ setGraphVisible(newValueGraphVisible: boolean) {
+ if (newValueGraphVisible) { // reset the search field so all patterns are shown in the graph
+ //this.filter.setValue('');
+ }
+ this.graphVisible = newValueGraphVisible;
+ console.log('graoh visile')
+ console.log(newValueGraphVisible)
+ // if user toggled to early, we will retrigger
+ // this.toggleBeforeDataLoaded = this.isLoadingLinkData && this.isLoadingPatternData;
+ }
+
+ ngOnInit(): void {
+ this.showMatchingResults = false;
+ this.showRephrasedInput = false;
+
+ if (this.data.prev.length > 0) {
+ const filteredFullTableData = this.data.prev[0].fulltabledata.filter(
+ (r: any) => r.cosineSimilarity != null
+ );
+
+ this.resultAlgorithm = this.data.prev[0].resultAlgorithm;
+ this.fulltabledata = filteredFullTableData;
+ this.tabledata = new MatTableDataSource(
+ this.fulltabledata.slice(0, this.selectednumber)
+ );
+ this.columnsToDisplay = this.data.prev[0].columnsToDisplay;
+ this.rephrasedInput = this.data.prev[0].rephrasedInput;
+ this.selectednumber = this.data.prev[0].selectedNumber;
+
+ if (this.data.prev[0].inputfieldvalue != '') {
+ this.inputfield = new FormControl(this.data.prev[0].inputfieldvalue);
+ } else {
+ this.inputfield = new FormControl('');
+ }
+
+ this.showMatchingResults = true;
+ if (this.rephrasedInput != '') {
+ this.showRephrasedInput = true;
+ }
+ } else {
+ this.inputfield = new FormControl('');
+ }
+
+ // HTTP call to fetch algorithms
+ this.http.get(environment.atlas + '/algorithms').subscribe((algodata: any) => {
+ algodata.content.forEach((algorithm: any) => {
+ if (algorithm.id === '3c7722e2-09c3-4667-9a0d-a45d3ddc42ae') {
+ algorithm.applicationAreas = ['variables', 'boolean Problems', 'formula', 'computers', 'logic', 'assignment'];
+ }
+
+ this.infos.push({ name: algorithm.name, data: algorithm });
+ });
+ });
+
+ console.log('Received Data:', this.data);
+ console.log(this.infos);
+ }
+
+ checkboxClicked(event) {
+ this.checked = !this.checked;
+ }
+
+ numberChanged() {
+ this.tabledata.data = this.fulltabledata.slice(0, this.selectednumber);
+ }
+
+ closeDialog(algorithmName: string) {
+ const previous = {
+ resultAlgorithm: this.resultAlgorithm,
+ tabledata: this.tabledata,
+ fulltabledata: this.fulltabledata,
+ columnsToDisplay: this.columnsToDisplay,
+ inputfieldvalue: this.inputfield.value,
+ rephrasedInput: this.rephrasedInput,
+ selectedNumber: this.selectednumber,
+ };
+
+ this.dialogRef.close({ algoname: algorithmName, prev: previous });
+ }
+
+
+ closeDialog2() {
+ if (this.inputfield.value != '' && this.showMatchingResults) {
+ const previous = {
+ resultAlgorithm: this.resultAlgorithm,
+ tabledata: this.tabledata,
+ fulltabledata: this.fulltabledata,
+ columnsToDisplay: this.columnsToDisplay,
+ inputfieldvalue: this.inputfield.value,
+ rephrasedInput: this.rephrasedInput,
+ selectedNumber: this.selectednumber,
+ };
+
+ this.dialogRef.close({ algoname: undefined, prev: previous });
+ } else {
+ this.dialogRef.close(null);
+ }
+ }
+
+ openLink() {
+ const alg = this.data.data.filter(algorithm => algorithm.name == this.resultAlgorithm.name);
+ if (alg.length > 0) {
+ this.closeDialog(this.resultAlgorithm.name);
+ }
+ }
+
+ openLink2(algname) {
+ const alg = this.data.data.filter(algorithm => algorithm.name == algname);
+ if (alg.length > 0) {
+ this.closeDialog(algname);
+ }
+ }
+
+ extractInformation(isRake: boolean) {
+ const datatosend = { input: this.inputfield.value, algodata: this.infos };
+ let url = environment.textMatcher + '/api/matcher/';
+
+ if (isRake) {
+ url += 'rake/';
+ }
+
+
+ // url += 'openai';
+
+
+ this.rephrasedInput = '';
+ this.showRephrasedInput = false;
+
+ this.http.post(url, datatosend).subscribe(resultdata => {
+ const filteredResults = resultdata.result.filter(
+ (r: any) => r.cosineSimilarity != null
+ );
+
+ this.fulltabledata = filteredResults;
+ this.tabledata.data = this.fulltabledata.slice(0, this.selectednumber);
+
+ if (resultdata.hasOwnProperty('rephrasedInput')) {
+ this.rephrasedInput = resultdata.rephrasedInput;
+ this.showRephrasedInput = true;
+ }
+
+ if (this.fulltabledata.length > 0) {
+ const maximumkey = this.fulltabledata.reduce((prev: any, current: any) => {
+ return prev.cosineSimilarity > current.cosineSimilarity ? prev : current;
+ });
+
+ if (maximumkey.cosineSimilarity > 0) {
+ this.showMatchingResults = true;
+ this.resultAlgorithm = maximumkey;
+ } else {
+ this.showMatchingResults = false;
+ console.log('No similarities found!');
+ }
+ } else {
+ this.showMatchingResults = false;
+ console.log('No data available after filtering.');
+ }
+ }, error => {
+ console.error('Error during information extraction:', error);
+ this.showMatchingResults = false;
+ });
+ }
+
+ aggregateSolutions() {
+ this.isAggregating = true; // Show progress bar
+ this.progressValue = 0;
+ console.log('Aggregation process started...');
+
+ if (this.fulltabledata && this.fulltabledata.length > 0) {
+ const totalSteps = this.fulltabledata.length; // Total number of steps to complete
+ let completedSteps = 0; // Track completed steps
+
+ const firstEntry = this.fulltabledata[0]; // Get the first entry of the table
+ const atlasEndpoint = environment.atlas;
+
+ // Find matching algorithm by name from the provided algorithms list
+ const matchingAlgorithm = this.data.algorithms.find(algorithm => algorithm.name === firstEntry.name);
+
+ if (matchingAlgorithm) {
+ console.log('Matching algorithm found:', matchingAlgorithm);
+
+ // Make the first request to get implementations
+ const implementationsUrl = atlasEndpoint + `/algorithms/${matchingAlgorithm.id}/implementations`;
+ this.http.get(implementationsUrl).subscribe(implementations => {
+ console.log('Implementations:', implementations);
+
+ // For each implementation, get implementation packages
+ implementations.content.forEach(implementation => {
+ const packagesUrl = atlasEndpoint +`/algorithms/${matchingAlgorithm.id}/implementations/${implementation.id}/implementation-packages`;
+ this.http.get(packagesUrl).subscribe(packages => {
+ console.log('Implementation Packages:', packages);
+
+ // Filter packages where the description contains some word of the input field
+ const inputKeywords = this.inputfield.value ? this.inputfield.value.split(' ') : [];
+ console.log('Input Keywords:', inputKeywords);
+
+ const filteredPackages = packages.content.filter(pkg => {
+ return inputKeywords.some(keyword => pkg.description.toLowerCase().includes(keyword.toLowerCase()));
+ });
+
+ // For each package, fetch the file content
+ filteredPackages.forEach(pkg => {
+ const fileContentUrl = atlasEndpoint +`/algorithms/${matchingAlgorithm.id}/implementations/${implementation.id}/implementation-packages/${pkg.id}/file/content`;
+
+ this.http.get(fileContentUrl, { responseType: 'text' }).subscribe(fileContent => {
+ // Store the file content in a variable for deployment
+ this.deploymentFileContentUrl = fileContentUrl;
+
+ // Update progress value
+ completedSteps++;
+ this.progressValue = Math.round((completedSteps / (2 * totalSteps)) * 100);
+
+ setTimeout(() => {
+ this.progressValue = Math.round((completedSteps / totalSteps) * 100);
+ this.isAggregationComplete = true; // Enable Deploy button once aggregation is done
+
+ }, 3000);
+ // Once aggregation is complete, hide the progress bar
+ if (completedSteps === totalSteps) {
+ //this.isAggregating = false;
+ }
+ }, error => {
+ console.error('Error fetching file content:', error);
+ completedSteps++; // Count as completed even if it fails
+ this.progressValue = Math.round((completedSteps / totalSteps) * 100);
+ if (completedSteps === totalSteps) {
+ //this.isAggregating = false; // Hide progress bar if all attempts are done
+ }
+ });
+ });
+ }, error => {
+ console.error('Error fetching implementation packages:', error);
+ completedSteps++; // Count as completed even if it fails
+ this.progressValue = Math.round((completedSteps / totalSteps) * 100);
+ if (completedSteps === totalSteps) {
+ this.isAggregating = false; // Hide progress bar if all attempts are done
+ }
+ });
+ });
+ }, error => {
+ console.error('Error fetching implementations:', error);
+ this.isAggregating = false; // Hide progress bar on error
+ });
+
+ } else {
+ console.log('No matching algorithm found for the first entry.');
+ this.isAggregating = false; // Hide progress bar if no matching algorithm
+ }
+ } else {
+ console.log('No data available to aggregate.');
+ this.isAggregating = false; // Hide progress bar if no data
+ }
+ }
+
+
+ async deploySolution() {
+ if (this.isAggregationComplete) {
+ if (this.fulltabledata && this.fulltabledata.length > 0) {
+ const wineryEndpoint = environment.winery;
+ const firstEntryName = this.fulltabledata[0].name; // Get the first entry of the table
+
+ // Function to generate a random string of length 6
+ const generateRandomString = (length = 6) => {
+ return Math.random().toString(36).substring(2, 2 + length); // Generates a random string
+ };
+
+
+ // Make sure to properly wait for the file content to be fetched
+ try {
+ const fileContent = await this.http.get(this.deploymentFileContentUrl, { responseType: 'blob' }).toPromise();
+ console.log('File content fetched successfully:', fileContent);
+
+ const idwinery = firstEntryName.replaceAll('_', '') + generateRandomString();
+ const opentoscaEndpoint = environment.openToscaContainer;
+ console.log('ID Winery:', idwinery);
+
+ // First, create the service template with the new activity id
+ const serviceTemplate = await createServiceTemplate(idwinery, QUANTME_NAMESPACE_PULL);
+ console.log('Service Template created:', serviceTemplate);
+
+ // Create the nodetype to add it to the created service template
+ await createNodeType(idwinery + 'Container', OPENTOSCA_NAMESPACE_NODETYPE);
+ await updateNodeType(idwinery + 'Container', OPENTOSCA_NAMESPACE_NODETYPE);
+
+ // Update the service template with the created node type
+ const updatedServiceTemplate = await updateServiceTemplate(idwinery, QUANTME_NAMESPACE_PULL);
+ console.log('Service Template updated:', updatedServiceTemplate);
+
+ // Finally, create the deployment model containing the implementation
+ const versionUrl = wineryEndpoint + 'servicetemplates/' + updatedServiceTemplate;
+ const deploymentModelUrlResult = await createDeploymentModel(
+ fileContent,
+ wineryEndpoint,
+ idwinery + '_DA',
+ 'http://opentosca.org/artifacttemplates',
+ '{http://opentosca.org/artifacttypes}DockerContainerArtifact',
+ 'service',
+ versionUrl
+ );
+
+ let uploadResult = await uploadCSARToContainer(
+ opentoscaEndpoint,
+ idwinery,
+ wineryEndpoint + `/servicetemplates/http%253A%252F%252Fquantil.org%252Fquantme%252Fpull/${idwinery}/?csar`,
+ wineryEndpoint
+ );
+ console.log('Deployment Model URL Result:', deploymentModelUrlResult);
+
+ console.log('Solution deployed successfully!');
+ } catch (error) {
+ console.error('Error during solution deployment:', error);
+ }
+ } else {
+ console.error('No fulltabledata available to deploy.');
+ }
+ } else {
+ console.error('Aggregation process not completed, cannot deploy the solution.');
+ }
+ }
+
+
+}
diff --git a/src/app/core/default-pl-renderer/default-pl-renderer.component.html b/src/app/core/default-pl-renderer/default-pl-renderer.component.html
index ae08b69c..9d367eac 100644
--- a/src/app/core/default-pl-renderer/default-pl-renderer.component.html
+++ b/src/app/core/default-pl-renderer/default-pl-renderer.component.html
@@ -41,7 +41,7 @@