BenjiELCA commited on
Commit
1f38f38
1 Parent(s): 3289919

can choose the best path for the vizi

Browse files
Files changed (2) hide show
  1. modules/toWizard.py +101 -17
  2. modules/toXML.py +11 -9
modules/toWizard.py CHANGED
@@ -2,6 +2,37 @@ import xml.etree.ElementTree as ET
2
  from modules.utils import class_dict
3
  from xml.dom import minidom
4
  from modules.utils import error
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  def rescale(scale, boxes):
7
  for i in range(len(boxes)):
@@ -56,8 +87,8 @@ def connect(data, text_mapping, i):
56
  target_idx = data['links'][i][1]
57
  # Check if the target index is valid
58
  if target_idx==None or target_idx >= len(data['links']):
59
- error('There is an error with the Vizi file, care when you download it.')
60
- return None, None
61
 
62
  current_id = data['BPMN_id'][i]
63
  current_text = text_mapping[current_id]
@@ -111,7 +142,44 @@ def find_merge(bpmn_id, links):
111
 
112
  return merge_elements
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  def create_wizard_file(data, text_mapping):
 
 
 
 
 
 
 
115
  root = ET.Element('methodAndStyleWizard')
116
 
117
  modelName = ET.SubElement(root, 'modelName')
@@ -128,32 +196,44 @@ def create_wizard_file(data, text_mapping):
128
 
129
  processDescription = ET.SubElement(root, 'processDescription')
130
 
 
131
  for idx, Bpmn_id in enumerate(data['BPMN_id']):
132
  # Start Event
133
  element_type = Bpmn_id.split('_')[0]
134
- if element_type == 'messageEvent':
135
  eventType = 'Message'
136
  elif element_type == 'event':
137
  eventType = 'None'
138
  if idx >= len(data['links']):
139
  continue
140
- if check_start(data['links'][idx]) and (element_type=='event' or element_type=='messageEvent'):
141
- startEvent = ET.SubElement(root, 'startEvent', attrib={'name': text_mapping[Bpmn_id], 'eventType': eventType, 'isRegular': 'False'})
 
 
142
 
143
  requestMessage = ET.SubElement(root, 'requestMessage')
144
  requester = ET.SubElement(root, 'requester')
145
 
146
  endEvents = ET.SubElement(root, 'endStates')
 
 
 
 
 
147
 
148
  # Add end states event to the collaboration element
149
  for idx, Bpmn_id in enumerate(data['BPMN_id']):
150
  # End States
151
  if idx >= len(data['links']):
152
  continue
153
- if check_end(data['links'][idx]) and (Bpmn_id.split('_')[0] == 'event' or Bpmn_id.split('_')[0] == 'messageEvent'):
154
  if text_mapping[Bpmn_id] == '':
155
  text_mapping[Bpmn_id] = '(unnamed)'
156
- ET.SubElement(endEvents, 'endState', attrib={'name': text_mapping[Bpmn_id], 'eventType': 'None', 'isRegular': 'False'})
 
 
 
 
157
 
158
 
159
  # Add activities to the collaboration element
@@ -166,9 +246,15 @@ def create_wizard_file(data, text_mapping):
166
  if next_text is not None and len(next_text) == 1:
167
  ET.SubElement(endStates, 'endState', attrib={'name': next_text[0], 'isRegular': 'True'})
168
  elif next_text is not None and len(next_text) >= 2 and next_id.split('_')[0] == 'exclusiveGateway':
169
- ET.SubElement(endStates, 'endState', attrib={'name': next_text[0], 'isRegular': 'True'})
170
- for i in range(1, len(next_text)):
171
- ET.SubElement(endStates, 'endState', attrib={'name': next_text[i], 'isRegular': 'False'})
 
 
 
 
 
 
172
  ET.SubElement(activity, 'subActivities')
173
  ET.SubElement(activity, 'subActivityFlows')
174
  ET.SubElement(activity, 'messageFlows')
@@ -176,15 +262,15 @@ def create_wizard_file(data, text_mapping):
176
  merge_object = find_merge(data['BPMN_id'], data['links'])
177
 
178
  activityFlows = ET.SubElement(root, 'activityFlows')
179
- i=0
180
  for i, link in enumerate(data['links']):
181
  # create flow with start event
182
- if link[0] is None and link[1] is not None and (data['BPMN_id'][i].split('_')[0] == 'event' or data['BPMN_id'][i].split('_')[0] == 'messageEvent'):
183
  current_text, next_text, _ = connect(data, text_mapping, i)
184
  if current_text is None or next_text is None:
185
  continue
186
  ET.SubElement(activityFlows, 'activityFlow', attrib={'startEvent': current_text, 'endState': '---', 'target': next_text[0], 'isMerging': 'False', 'isPredefined': 'True'})
187
- i+=1
 
188
  # create flow with tasks
189
  if link[0] is not None and link[1] is not None and data['BPMN_id'][i].split('_')[0] == 'task':
190
  current_text, next_text, next_id = connect(data, text_mapping, i)
@@ -197,8 +283,8 @@ def create_wizard_file(data, text_mapping):
197
  merge = 'False'
198
 
199
  if len(next_text) == 2 and next_id.split('_')[0] == 'exclusiveGateway':
200
- ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': next_text[0]+'?', 'target': next_text[0], 'isMerging': 'False', 'isPredefined': 'True'})
201
- ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': '---', 'target': next_text[1], 'isMerging': 'False', 'isPredefined': 'True'})
202
  elif len(next_text) > 1 and next_id.split('_')[0] == 'parallelGateway':
203
  for next in next_text:
204
  ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': '---', 'target': next, 'isMerging': merge, 'isPredefined': 'True'})
@@ -206,8 +292,6 @@ def create_wizard_file(data, text_mapping):
206
  ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': '---', 'target': next_text[0], 'isMerging': merge, 'isPredefined': 'True'})
207
  else:
208
  ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': '---', 'target': next_text, 'isMerging': merge, 'isPredefined': 'True'})
209
-
210
- i+=1
211
 
212
  ET.SubElement(root, 'participants')
213
 
 
2
  from modules.utils import class_dict
3
  from xml.dom import minidom
4
  from modules.utils import error
5
+ from transformers import pipeline
6
+
7
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
8
+ import torch
9
+ import logging
10
+
11
+ # Suppress specific warnings from transformers
12
+ logging.getLogger("transformers.modeling_utils").setLevel(logging.ERROR)
13
+
14
+ # Function to initialize the model and tokenizer
15
+ def initialize_model():
16
+ tokenizer = AutoTokenizer.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment-latest")
17
+ model = AutoModelForSequenceClassification.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment-latest")
18
+ return tokenizer, model
19
+
20
+ # Function to perform sentiment analysis and return the highest scoring emotion and its score between positive and negative
21
+ def analyze_sentiment(sentence, tokenizer, model):
22
+ inputs = tokenizer(sentence, return_tensors="pt")
23
+ outputs = model(**inputs)
24
+ probs = torch.nn.functional.softmax(outputs.logits, dim=-1).squeeze().tolist()
25
+ labels = ["negative", "neutral", "positive"]
26
+ results = dict(zip(labels, probs))
27
+
28
+ # Filter out the neutral score and get the highest score between positive and negative
29
+ relevant_results = {k: results[k] for k in ["positive", "negative"]}
30
+ highest_emotion = max(relevant_results, key=relevant_results.get)
31
+ highest_score = relevant_results[highest_emotion]
32
+ return highest_emotion, highest_score
33
+
34
+ # Initialize model and tokenizer
35
+ tokenizer, model = initialize_model()
36
 
37
  def rescale(scale, boxes):
38
  for i in range(len(boxes)):
 
87
  target_idx = data['links'][i][1]
88
  # Check if the target index is valid
89
  if target_idx==None or target_idx >= len(data['links']):
90
+ error('There may be an error with the Vizi file, care when you download it.')
91
+ return None, None, None
92
 
93
  current_id = data['BPMN_id'][i]
94
  current_text = text_mapping[current_id]
 
142
 
143
  return merge_elements
144
 
145
+ def find_positive_end(bpmn_ids, links, text_mapping):
146
+ emotion_data = []
147
+ for idx, bpmn_id in enumerate(bpmn_ids):
148
+ if idx >= len(links):
149
+ continue
150
+ if check_end(links[idx]) and (bpmn_id.split('_')[0] in ['event', 'message']):
151
+ # Perform sentiment analysis and get the highest scoring emotion and its score between positive and negative
152
+ highest_emotion, highest_score = analyze_sentiment(text_mapping[bpmn_id], tokenizer, model)
153
+ emotion_data.append((bpmn_id, highest_emotion, highest_score))
154
+
155
+ # Sort by emotion label with 'positive' first and 'negative' second,
156
+ # then by score in descending order
157
+ sorted_emotions = sorted(emotion_data, key=lambda x: (x[1] != 'positive', -x[2]))
158
+
159
+ return sorted_emotions[0][0] if len(sorted_emotions) > 0 else None
160
+
161
+ def find_best_direction(texts_list):
162
+ emotion_data = []
163
+ for text in texts_list:
164
+ highest_emotion, highest_score = analyze_sentiment(text, tokenizer, model)
165
+ emotion_data.append((text, highest_emotion, highest_score))
166
+
167
+ # Sort by emotion label with 'positive' first and 'negative' second,
168
+ # then by score in descending order
169
+ sorted_emotions = sorted(emotion_data, key=lambda x: (x[1] != 'positive', -x[2]))
170
+
171
+ return sorted_emotions[0][0] if len(sorted_emotions) > 0 else None
172
+
173
+
174
+
175
  def create_wizard_file(data, text_mapping):
176
+
177
+ #add a name into the text_mapping when there is no name
178
+ for idx, key in enumerate(text_mapping.keys()):
179
+ if text_mapping[key] == '':
180
+ text_mapping[key] = f'unnamed_{key}'
181
+
182
+
183
  root = ET.Element('methodAndStyleWizard')
184
 
185
  modelName = ET.SubElement(root, 'modelName')
 
196
 
197
  processDescription = ET.SubElement(root, 'processDescription')
198
 
199
+ first = False
200
  for idx, Bpmn_id in enumerate(data['BPMN_id']):
201
  # Start Event
202
  element_type = Bpmn_id.split('_')[0]
203
+ if element_type == 'message':
204
  eventType = 'Message'
205
  elif element_type == 'event':
206
  eventType = 'None'
207
  if idx >= len(data['links']):
208
  continue
209
+ if check_start(data['links'][idx]) and (element_type=='event' or element_type=='message'):
210
+ if text_mapping[Bpmn_id] == '':
211
+ text_mapping[Bpmn_id] = 'start'
212
+ startEvent = ET.SubElement(root, 'startEvent', attrib={'name': text_mapping[Bpmn_id], 'eventType': eventType, 'isRegular': 'True'})
213
 
214
  requestMessage = ET.SubElement(root, 'requestMessage')
215
  requester = ET.SubElement(root, 'requester')
216
 
217
  endEvents = ET.SubElement(root, 'endStates')
218
+
219
+ positive_end = find_positive_end(data['BPMN_id'], data['links'], text_mapping)
220
+ if positive_end is not None:
221
+ print("Best end is: ",text_mapping[positive_end])
222
+
223
 
224
  # Add end states event to the collaboration element
225
  for idx, Bpmn_id in enumerate(data['BPMN_id']):
226
  # End States
227
  if idx >= len(data['links']):
228
  continue
229
+ if check_end(data['links'][idx]) and (Bpmn_id.split('_')[0] == 'event' or Bpmn_id.split('_')[0] == 'message'):
230
  if text_mapping[Bpmn_id] == '':
231
  text_mapping[Bpmn_id] = '(unnamed)'
232
+
233
+ if Bpmn_id == positive_end:
234
+ ET.SubElement(endEvents, 'endState', attrib={'name': text_mapping[Bpmn_id], 'eventType': 'None', 'isRegular': 'True'})
235
+ else:
236
+ ET.SubElement(endEvents, 'endState', attrib={'name': text_mapping[Bpmn_id], 'eventType': 'None', 'isRegular': 'False'})
237
 
238
 
239
  # Add activities to the collaboration element
 
246
  if next_text is not None and len(next_text) == 1:
247
  ET.SubElement(endStates, 'endState', attrib={'name': next_text[0], 'isRegular': 'True'})
248
  elif next_text is not None and len(next_text) >= 2 and next_id.split('_')[0] == 'exclusiveGateway':
249
+ best_direction = find_best_direction(next_text)
250
+ if best_direction is not None:
251
+ print("Best direction is: ", best_direction)
252
+ for i in range(len(next_text)):
253
+ if next_text[i] == best_direction:
254
+ ET.SubElement(endStates, 'endState', attrib={'name': next_text[i], 'isRegular': 'True'})
255
+ else:
256
+ ET.SubElement(endStates, 'endState', attrib={'name': next_text[i], 'isRegular': 'False'})
257
+
258
  ET.SubElement(activity, 'subActivities')
259
  ET.SubElement(activity, 'subActivityFlows')
260
  ET.SubElement(activity, 'messageFlows')
 
262
  merge_object = find_merge(data['BPMN_id'], data['links'])
263
 
264
  activityFlows = ET.SubElement(root, 'activityFlows')
 
265
  for i, link in enumerate(data['links']):
266
  # create flow with start event
267
+ if link[0] is None and link[1] is not None and (data['BPMN_id'][i].split('_')[0] == 'event' or data['BPMN_id'][i].split('_')[0] == 'message'):
268
  current_text, next_text, _ = connect(data, text_mapping, i)
269
  if current_text is None or next_text is None:
270
  continue
271
  ET.SubElement(activityFlows, 'activityFlow', attrib={'startEvent': current_text, 'endState': '---', 'target': next_text[0], 'isMerging': 'False', 'isPredefined': 'True'})
272
+ continue
273
+
274
  # create flow with tasks
275
  if link[0] is not None and link[1] is not None and data['BPMN_id'][i].split('_')[0] == 'task':
276
  current_text, next_text, next_id = connect(data, text_mapping, i)
 
283
  merge = 'False'
284
 
285
  if len(next_text) == 2 and next_id.split('_')[0] == 'exclusiveGateway':
286
+ ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': next_text[0], 'target': next_text[0], 'isMerging': 'False', 'isPredefined': 'True'})
287
+ ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': next_text[1], 'target': next_text[1], 'isMerging': 'False', 'isPredefined': 'True'})
288
  elif len(next_text) > 1 and next_id.split('_')[0] == 'parallelGateway':
289
  for next in next_text:
290
  ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': '---', 'target': next, 'isMerging': merge, 'isPredefined': 'True'})
 
292
  ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': '---', 'target': next_text[0], 'isMerging': merge, 'isPredefined': 'True'})
293
  else:
294
  ET.SubElement(activityFlows, 'activityFlow', attrib={'activity': current_text, 'endState': '---', 'target': next_text, 'isMerging': merge, 'isPredefined': 'True'})
 
 
295
 
296
  ET.SubElement(root, 'participants')
297
 
modules/toXML.py CHANGED
@@ -181,7 +181,7 @@ def create_XML(full_pred, text_mapping, size_scale, scale):
181
 
182
  #if there is no pool or lane, create a pool with all elements
183
  if len(full_pred['pool_dict']) == 0 or (len(full_pred['pool_dict']) == 1 and len(next(iter(full_pred['pool_dict'].values()))) == len(full_pred['labels'])):
184
- full_pred, text_mapping = create_big_pool(full_pred, text_mapping)
185
 
186
  #modify the boxes positions
187
  old_boxes = copy.deepcopy(full_pred)
@@ -250,13 +250,13 @@ def create_XML(full_pred, text_mapping, size_scale, scale):
250
  return pretty_xml_as_string
251
 
252
  # Function that creates a single pool with all elements
253
- def create_big_pool(full_pred, text_mapping, marge=50):
254
  # If no pools or lanes are detected, create a single pool with all elements
255
  new_pool_index = 'pool_1'
256
  size_elements = get_size_elements(st.session_state.size_scale)
257
  elements_pool = list(range(len(full_pred['boxes'])))
258
  min_x, min_y, max_x, max_y = calculate_pool_bounds(full_pred['boxes'],full_pred['labels'], elements_pool, size_elements)
259
- box = [min_x-marge, min_y-marge, max_x+marge, max_y+marge]
260
  full_pred['boxes'] = np.append(full_pred['boxes'], [box], axis=0)
261
  full_pred['pool_dict'][new_pool_index] = elements_pool
262
  full_pred['BPMN_id'].append('pool_1')
@@ -557,26 +557,28 @@ def create_bpmn_object(process, bpmnplane, text_mapping, definitions, size, data
557
  ET.SubElement(element, 'bpmn:timerEventDefinition', id=f'TimerEventDefinition_{i+1}')
558
  add_diagram_elements(bpmnplane, element_id, x, y, size['timerEvent'][0], size['timerEvent'][1])
559
 
560
-
561
- def calculate_pool_bounds(boxes, labels, keep_elements, size):
562
  min_x, min_y = float('inf'), float('inf')
563
  max_x, max_y = float('-inf'), float('-inf')
564
 
565
  for i in keep_elements:
566
  if i >= len(labels):
567
- print("Problem with the index")
568
  continue
569
 
570
  element = labels[i]
571
  if element in {None, 7, 13, 14, 15}:
572
  continue
573
 
574
-
575
- if size == None:
576
  element_width = boxes[i][2] - boxes[i][0]
577
  element_height = boxes[i][3] - boxes[i][1]
578
  else:
579
- element_width, element_height = size[class_dict[labels[i]]]
 
 
 
 
580
 
581
  x, y = boxes[i][:2]
582
  min_x = min(min_x, x)
 
181
 
182
  #if there is no pool or lane, create a pool with all elements
183
  if len(full_pred['pool_dict']) == 0 or (len(full_pred['pool_dict']) == 1 and len(next(iter(full_pred['pool_dict'].values()))) == len(full_pred['labels'])):
184
+ full_pred, text_mapping = create_big_pool(full_pred, text_mapping, size_elements)
185
 
186
  #modify the boxes positions
187
  old_boxes = copy.deepcopy(full_pred)
 
250
  return pretty_xml_as_string
251
 
252
  # Function that creates a single pool with all elements
253
+ def create_big_pool(full_pred, text_mapping, size_elements, marge=50):
254
  # If no pools or lanes are detected, create a single pool with all elements
255
  new_pool_index = 'pool_1'
256
  size_elements = get_size_elements(st.session_state.size_scale)
257
  elements_pool = list(range(len(full_pred['boxes'])))
258
  min_x, min_y, max_x, max_y = calculate_pool_bounds(full_pred['boxes'],full_pred['labels'], elements_pool, size_elements)
259
+ box = [min_x - marge, min_y - marge//2, max_x + marge, max_y + marge//2]
260
  full_pred['boxes'] = np.append(full_pred['boxes'], [box], axis=0)
261
  full_pred['pool_dict'][new_pool_index] = elements_pool
262
  full_pred['BPMN_id'].append('pool_1')
 
557
  ET.SubElement(element, 'bpmn:timerEventDefinition', id=f'TimerEventDefinition_{i+1}')
558
  add_diagram_elements(bpmnplane, element_id, x, y, size['timerEvent'][0], size['timerEvent'][1])
559
 
560
+ def calculate_pool_bounds(boxes, labels, keep_elements, size=None, class_dict=None):
 
561
  min_x, min_y = float('inf'), float('inf')
562
  max_x, max_y = float('-inf'), float('-inf')
563
 
564
  for i in keep_elements:
565
  if i >= len(labels):
566
+ print(f"Problem with the index: {i}")
567
  continue
568
 
569
  element = labels[i]
570
  if element in {None, 7, 13, 14, 15}:
571
  continue
572
 
573
+ if size is None or class_dict is None:
 
574
  element_width = boxes[i][2] - boxes[i][0]
575
  element_height = boxes[i][3] - boxes[i][1]
576
  else:
577
+ if labels[i] in class_dict:
578
+ element_width, element_height = size[class_dict[labels[i]]]
579
+ else:
580
+ print(f"Class label {labels[i]} not found in class_dict.")
581
+ continue
582
 
583
  x, y = boxes[i][:2]
584
  min_x = min(min_x, x)