Nik97 commited on
Commit
363a877
1 Parent(s): 2db0bd6

Upload 7 files

Browse files
BreakdownFeature.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contains only NLP zero-shot classification function codes!
2
+ import sqlite3
3
+ from flask import g
4
+ from transformers import pipeline
5
+
6
+ # Set up zero-shot classification pipeline
7
+ classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
8
+
9
+ # The main "breakdown" functionality. Performs NLP using zero-shot!
10
+ def breakdown(userStory):
11
+
12
+ # The results are stored into a dictionary variable with predifined labels
13
+ processedStory = classifier(userStory, candidate_labels=["developer", "tester", "project manager", "system admin"])
14
+
15
+ # Extract labels and scores
16
+ scores = processedStory['scores']
17
+ labels = processedStory['labels']
18
+
19
+ # As the index of a score is always equal to its associated label,
20
+ # We only need to index of the score to find correct label.
21
+ maxScoreIndex = scores.index(max(scores)) # Gets the index of the highest score/accuracy
22
+ maxLabel = labels[maxScoreIndex] # Gets the associated label name
23
+
24
+ # Return labels
25
+ return maxLabel
26
+
27
+ # Function to grab all contents in the "Breakdown" table (except for unique ids)
28
+ # If adding any additional attributes to the table, this has to be updated accordingly
29
+ def getBreakdownContents():
30
+ db = getattr(g, '_database', None) # Gets the _database attribute from the 'g' object. If it does not exist, returns 'None'
31
+ if db is None:
32
+ db = g._database = sqlite3.connect('Refineverse.db') # If db is None, create a new connection for db and g._database.
33
+ cursor = db.cursor() # Creates a cursor object to handle data
34
+ cursor.execute("SELECT user_story, assignedLabel FROM Breakdown") # The cursor executes the query
35
+ rows = cursor.fetchall() # Stores the results of fetchall() into a variable
36
+ return rows
37
+
38
+ # Function to insert a new row into the "Breakdown" table
39
+ # Using "with" for the connection here seems important, as otherwise it results in an exception
40
+ def insertBreakdownRow(user_story, assigned_label):
41
+ with sqlite3.connect('Refineverse.db') as conn: # 'With' will automatically take care of closing and opening the connection
42
+ cursor = conn.cursor()
43
+ cursor.execute("INSERT INTO Breakdown (user_story, assignedLabel) VALUES (?, ?)", (user_story, assigned_label))
44
+ conn.commit()
45
+
Refineverse.db ADDED
Binary file (20.5 kB). View file
 
Refineverse.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Plugin will run on this file & Strictly only contains codes for routing between files!
2
+ from flask import Flask, render_template, request, flash, g
3
+ from TextSummarizationFeature import summarize, getTextSumContents, insertTextSumRow
4
+ from BreakdownFeature import breakdown, getBreakdownContents, insertBreakdownRow
5
+ from TranslationFeature import translate_text, switch, getTranslatedContents, insertTranslationRow
6
+
7
+ app = Flask(__name__)
8
+ app.secret_key = 'refineverseAdmin' # Used to encrypt cookies & sessions
9
+
10
+ # Routing to Main Dashboard file
11
+ @app.route('/')
12
+ def index():
13
+ return render_template('RefineverseDashboardUI.html')
14
+
15
+
16
+ # Routing to text summarization file
17
+ @app.route('/text_summarization', methods=["POST", "GET"])
18
+ def text_summarization():
19
+ if request.method == "POST":
20
+ try:
21
+ # Grab the user story text from the textarea in html form
22
+ Entered_story = request.form["input_text"]
23
+
24
+ # The results are stored into a dictionary variable
25
+ summarizedStory = summarize(Entered_story)
26
+
27
+ flash("Your user story has been summarized!")
28
+
29
+ # Insert into TextSummarization table in Refineverse.db
30
+ insertTextSumRow(Entered_story, summarizedStory)
31
+
32
+ #Can consider to add View Summarized History feature
33
+
34
+ # Render and display summarized user story
35
+ return render_template('TextSummarizationUI.html', summarizedStory=summarizedStory)
36
+
37
+ except ValueError as e:
38
+ if str(e) == "Empty input!":
39
+ flash("The input text cannot be empty! Please enter a user story.", 'error')
40
+ return render_template('TextSummarizationUI.html')
41
+ elif str(e) == "Incorrect format!":
42
+ flash("Incorrect user story format! Please enter in the right format.", 'error')
43
+ return render_template('TextSummarizationUI.html')
44
+ elif str(e) == "Invalid length!":
45
+ flash("Your inputted user story is too short to summarize. Please enter a longer story!", 'error')
46
+ return render_template('TextSummarizationUI.html')
47
+ else:
48
+ flash("An error of type '{}' occurred: {}".format(type(e).__name__, str(e)), 'error')
49
+ return render_template('TextSummarizationUI.html')
50
+
51
+ # Not sure in what use-case will a KeyError be hit, but I'll leave this here for now
52
+ except KeyError:
53
+ flash("Please enter a valid user story!")
54
+ return render_template('TextSummarizationUI.html')
55
+
56
+ # Catch-all exception handling
57
+ except Exception as e:
58
+ flash("An error of type '{}' occurred: {}".format(type(e).__name__, str(e)), 'error')
59
+ return render_template('TextSummarizationUI.html')
60
+
61
+ else:
62
+ return render_template('TextSummarizationUI.html')
63
+
64
+
65
+ # Routing to Project Task Breakdown file
66
+ @app.route("/project_breakdown", methods=["POST", "GET"]) # This tells flask the route to get to the page
67
+ def project_breakdown():
68
+ if request.method == "POST":
69
+ try:
70
+ # Grab the user story contents
71
+ userStory = request.form["user-story-text"]
72
+
73
+ # The results are stored into a dictionary variable
74
+ processedLabel = breakdown(userStory)
75
+
76
+ # Display success popup message
77
+ flash("Your user story has been allocated as a " + processedLabel + " task!")
78
+
79
+ insertBreakdownRow(userStory, processedLabel) # Inserts data into the Breakdown table
80
+ rows = getBreakdownContents() # Grab all contents inside the Breakdown table
81
+
82
+ return render_template('ProjectBreakdownUI.html', rows=rows)
83
+
84
+ # The first matched error will be executed, and all other exception blocks will be skipped.
85
+ # Thus, please order exceptions from most specific to most general!
86
+ except KeyError:
87
+ flash("Please enter a valid user story!", 'error')
88
+ rows = getBreakdownContents()
89
+ return render_template('ProjectBreakdownUI.html', row=rows)
90
+
91
+ # Use this to get the error name and error message, then create a dedicated custom error message!
92
+ except Exception as e:
93
+ flash("An error of type '{}' occurred: {}".format(type(e).__name__, str(e)), 'error')
94
+ rows = getBreakdownContents()
95
+ return render_template('ProjectBreakdownUI.html', rows=rows)
96
+
97
+ else: # For "GET" scenarios (the loading page, etc.)
98
+ # To always display the table, we must grab the contents of Breakdown every time the page loads
99
+ rows = getBreakdownContents()
100
+ return render_template('ProjectBreakdownUI.html', rows=rows)
101
+
102
+
103
+ # Routing to Translation file
104
+ @app.route('/language_translation', methods=["POST", "GET"])
105
+ def language_translation():
106
+ if request.method == "POST":
107
+ try:
108
+ # Grab all relevant information for processing
109
+ input_text = request.form['input'] # Grab user text input
110
+
111
+ # Grab source language code
112
+ source_language = request.form['source_language']
113
+
114
+ # Grab target language code
115
+ target_language = request.form['target_language']
116
+
117
+ # Generate translated text using custom function
118
+ translatedStory = translate_text(input_text, source_language, target_language)
119
+
120
+ # Display success popup message
121
+ flash("Your user story has been translated to " + switch(target_language) + " !")
122
+
123
+ # Insert into Translation table in Refineverse.db
124
+ insertTranslationRow(input_text, translatedStory)
125
+
126
+ # Can consider to create a function to view translated history feature
127
+
128
+ # Display the page
129
+ return render_template('LanguageTranslationUI.html', input_text=input_text, translatedStory=translatedStory)
130
+
131
+ # Exception handling. Important to note that it is neccesary to still return render_template!
132
+ except ValueError as e:
133
+ if str(e) == "Empty input!":
134
+ flash("The input text cannot be empty! Please enter a user story.", 'error')
135
+ return render_template('LanguageTranslationUI.html')
136
+ elif str(e) == "Incorrect format!":
137
+ flash("Unable to translate your user story. Please enter in the correct format.", 'error')
138
+ return render_template('LanguageTranslationUI.html')
139
+ else:
140
+ flash("An error of type '{}' occurred: {}".format(type(e).__name__, str(e)), 'error')
141
+ return render_template('LanguageTranslationUI.html')
142
+
143
+ except Exception as e:
144
+ flash("An error of type '{}' occurred: {}".format(type(e).__name__, str(e)), 'error')
145
+ return render_template('LanguageTranslationUI.html')
146
+
147
+ else:
148
+ return render_template('LanguageTranslationUI.html')
149
+
150
+
151
+ # Used when the application is torn down
152
+ # Its purpose is to close the database connection if it has not been closed
153
+ @app.teardown_appcontext
154
+ def close_connection(exception):
155
+ db = getattr(g, '_database', None)
156
+ if db is not None:
157
+ db.close() # Closes the database connection
158
+
159
+
160
+ # Initialise the app
161
+ if __name__ == '__main__':
162
+ app.run() # can set to True for debugging
TextSummarizationFeature.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contains only NLP text summarization function codes!
2
+ import re # Python's built-in library for regular expressions (or Regex)
3
+ import sqlite3
4
+ from flask import g
5
+ from transformers import pipeline
6
+
7
+ def summarize(Entered_story):
8
+
9
+ # Check if the input is empty
10
+ if not Entered_story.strip():
11
+ raise ValueError("Empty input!")
12
+
13
+ # Validate that the input is in the correct format
14
+ if not validate_story(Entered_story):
15
+ raise ValueError("Incorrect format!")
16
+
17
+ # Before we do anything, make sure the input is long enough for summarization.
18
+ if len(Entered_story) < 200:
19
+ raise ValueError("Invalid length!")
20
+
21
+ # Set the pipeline to use the correct NLP type and model
22
+ summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
23
+
24
+ # Take note: The max_length & min_length variables refer to the OUTPUT length!
25
+ summary = summarizer(Entered_story, max_length=100, min_length=30, do_sample=False)[0]["summary_text"]
26
+
27
+ return summary
28
+
29
+
30
+ # User Input Format Validation Function for english only
31
+ def validate_story(Entered_story):
32
+ pattern = r'As a (?P<role>[^,.]+), I want to (?P<goal>[^,.]+)(,|.)+so that (?P<benefit>.+)'
33
+ match = re.search(pattern, Entered_story, flags=re.DOTALL)
34
+ return bool(match)
35
+
36
+
37
+ # User Input Format Validation Function for all 4 languages
38
+ #def validate_story(Entered_story):
39
+
40
+ # Pattern for English language
41
+ #pattern_en = r'As a (?P<role>[^,.]+), I want to (?P<goal>[^,.]+)(,|.)+so that (?P<benefit>.+)'
42
+
43
+ # Pattern for Chinese language
44
+ #pattern_zh = r'作为(?P<role>[^,.]+),我想要(?P<goal>[^,.]+)(,|。)+以便(?P<benefit>.+)'
45
+
46
+ # Pattern for Malay language
47
+ #pattern_ms = r'Sebagai(?P<role>[^,.]+), saya mahu(?P<goal>[^,.]+)(,|.)+supaya(?P<benefit>.+)'
48
+
49
+ # Pattern for Tamil language
50
+ #pattern_ta = r'என(?P<role>[^,.]+) எனக்கு வேண்டும்(?P<goal>[^,.]+)(,|.)+அதனால்(?P<benefit>.+) பயன்படுத்தி வைக்கும்'
51
+
52
+ # Pattern for Thai language
53
+ #pattern_th = r'ในฐานะ(?P<role>[^,.]+) ฉันต้องการ(?P<goal>[^,.]+)(,|.)+เพื่อที่ฉัน(?P<benefit>.+)'
54
+
55
+ # Try each pattern to see if there is a match
56
+ #match_en = re.search(pattern_en, Entered_story, flags=re.DOTALL)
57
+ #match_zh = re.search(pattern_zh, Entered_story, flags=re.DOTALL)
58
+ #match_ms = re.search(pattern_ms, Entered_story, flags=re.DOTALL)
59
+ #match_ta = re.search(pattern_ta, Entered_story, flags=re.DOTALL)
60
+ #match_th = re.search(pattern_th, Entered_story, flags=re.DOTALL)
61
+
62
+ # Return True if at least one pattern matches, otherwise False
63
+ #return bool(match_en or match_zh or match_ms or match_ta or match_th)
64
+
65
+
66
+ # Function to grab all contents in the "TextSummarization" table (except for unique ids)
67
+ # If adding any additional attributes to the table, this has to be updated accordingly
68
+ def getTextSumContents():
69
+ db = getattr(g, '_database', None) # Gets the _database attribute from the 'g' object. If it does not exist, returns 'None'
70
+ if db is None:
71
+ db = g._database = sqlite3.connect('Refineverse.db') # If db is None, create a new connection for db and g._database.
72
+ cursor = db.cursor() # Creates a cursor object to handle data
73
+ cursor.execute("SELECT Entered_story, summary FROM TextSummarization") # The cursor executes the query
74
+ rows = cursor.fetchall() # Stores the results of fetchall() into a variable
75
+ return rows
76
+
77
+
78
+ # Function to insert a new row into the "TextSummarization" table
79
+ # Using "with" for the connection here seems important, as otherwise it results in an exception
80
+ def insertTextSumRow( Entered_story, summary):
81
+ with sqlite3.connect('Refineverse.db') as conn: # 'With' will automatically take care of closing and opening the connection
82
+ cursor = conn.cursor()
83
+ cursor.execute("INSERT INTO TextSummarization (Entered_story, summary) VALUES (?, ?)", (Entered_story, summary))
84
+ conn.commit()
TranslationFeature.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contains only NLP translation codes!
2
+ import re
3
+ import sqlite3
4
+ from flask import g
5
+ from transformers import M2M100ForConditionalGeneration, M2M100Tokenizer
6
+
7
+ model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100_1.2B") # Setting the model to use
8
+ tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100_1.2B") # Setting the tokenizer to use
9
+
10
+ # Main function of the translation feature. Performs translation!
11
+ def translate_text(input_text, source_language, target_language):
12
+
13
+ # Grabs the source language to be used in the tokenizer
14
+ tokenizer.src_lang = source_language
15
+
16
+ # Check if the input is empty
17
+ if not input_text.strip():
18
+ raise ValueError("Empty input!")
19
+
20
+ # Validate that the input is in the correct format
21
+ if not validate_input(input_text):
22
+ raise ValueError("Incorrect format!")
23
+
24
+ # Creates encoded text
25
+ encoded_text = tokenizer(input_text, return_tensors="pt")
26
+
27
+ # Generates new tokens using encoded text from source language
28
+ generated_tokens = model.generate(**encoded_text, forced_bos_token_id=tokenizer.get_lang_id(target_language), max_new_tokens=512)
29
+
30
+ # Decode and display text
31
+ translated_text = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)[0]
32
+
33
+ return translated_text
34
+
35
+
36
+ # Helper function for displaying appropriate language names in flash messages.
37
+ # Note: Python does not have a built-in switch function, so this is just a rough implementation of the logic.
38
+ def switch(lang):
39
+ if lang == "en":
40
+ return "English"
41
+ elif lang == "zh":
42
+ return "Chinese"
43
+ elif lang == "ms":
44
+ return "Malay"
45
+ elif lang == "ta":
46
+ return "Tamil"
47
+ elif lang == "th":
48
+ return "Thai"
49
+
50
+
51
+ # User Input Format Validation Function for all 4 languages
52
+ def validate_input(input_text):
53
+
54
+ # Pattern for English language
55
+ pattern_en = r'As a (?P<role>[^,.]+), I want to (?P<goal>[^,.]+)(,|.)+so that (?P<benefit>.+)'
56
+
57
+ # Pattern for Chinese language
58
+ pattern_zh = r'作为(?P<role>[^,.]+),我想要(?P<goal>[^,.]+)(,|。)+以便(?P<benefit>.+)'
59
+
60
+ # Pattern for Malay language
61
+ pattern_ms = r'Sebagai(?P<role>[^,.]+), saya mahu(?P<goal>[^,.]+)(,|.)+supaya(?P<benefit>.+)'
62
+
63
+ # Pattern for Tamil language
64
+ pattern_ta = r'என(?P<role>[^,.]+) எனக்கு வேண்டும்(?P<goal>[^,.]+)(,|.)+அதனால்(?P<benefit>.+) பயன்படுத்தி வைக்கும்'
65
+
66
+ # Pattern for Thai language
67
+ pattern_th = r'ในฐานะ(?P<role>[^,.]+) ฉันต้องการ(?P<goal>[^,.]+)(,|.)+เพื่อที่ฉัน(?P<benefit>.+)'
68
+
69
+ # Try each pattern to see if there is a match
70
+ match_en = re.search(pattern_en, input_text, flags=re.DOTALL)
71
+ match_zh = re.search(pattern_zh, input_text, flags=re.DOTALL)
72
+ match_ms = re.search(pattern_ms, input_text, flags=re.DOTALL)
73
+ match_ta = re.search(pattern_ta, input_text, flags=re.DOTALL)
74
+ match_th = re.search(pattern_th, input_text, flags=re.DOTALL)
75
+
76
+ # Return True if at least one pattern matches, otherwise False
77
+ return bool(match_en or match_zh or match_ms or match_ta or match_th)
78
+
79
+ #For english language only
80
+ #def validate_input(input_text):
81
+ #pattern = r'As a (?P<role>[^,.]+), I want to (?P<goal>[^,.]+)(,|.)+so that (?P<benefit>.+)'
82
+ #match = re.search(pattern, input_text, flags=re.DOTALL)
83
+ #return bool(match)
84
+
85
+
86
+ # Function to grab all contents in the "Translation" table (except for unique ids)
87
+ # If adding any additional attributes to the table, this has to be updated accordingly
88
+ def getTranslatedContents():
89
+ db = getattr(g, '_database', None) # Gets the _database attribute from the 'g' object. If it does not exist, returns 'None'
90
+ if db is None:
91
+ db = g._database = sqlite3.connect('Refineverse.db') # If db is None, create a new connection for db and g._database.
92
+ cursor = db.cursor() # Creates a cursor object to handle data
93
+ cursor.execute("SELECT input_text, translated_text FROM Translation") # The cursor executes the query
94
+ rows = cursor.fetchall() # Stores the results of fetchall() into a variable
95
+ return rows
96
+
97
+
98
+ # Function to insert a new row into the "Translation" table
99
+ # Using "with" for the connection here seems important, as otherwise it results in an exception
100
+ def insertTranslationRow(input_text, translated_text):
101
+ with sqlite3.connect('Refineverse.db') as conn: # 'With' will automatically take care of closing and opening the connection
102
+ cursor = conn.cursor()
103
+ cursor.execute("INSERT INTO Translation (input_text, translated_text) VALUES (?, ?)", (input_text, translated_text))
104
+ conn.commit()
createDatabase.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file is used to create an SQLite database.
2
+ # If adding more tables, you should delete the exising databases, or alter the code here to drop the pre-exising tables first.
3
+ import sqlite3
4
+
5
+ # Establishes a connection to the specified DB. If the DB does not exist, it creates a new one.
6
+ connection = sqlite3.connect("Refineverse.db")
7
+ cursor = connection.cursor() # A cursor object that is used to handle data.
8
+
9
+ # Creating the Breakdown table
10
+ cursor.execute('''
11
+ CREATE TABLE IF NOT EXISTS Breakdown (
12
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ user_story TEXT,
14
+ assignedLabel TEXT
15
+ )
16
+ ''')
17
+
18
+ # Creating the TextSummarization table
19
+ cursor.execute('''
20
+ CREATE TABLE IF NOT EXISTS TextSummarization (
21
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
22
+ Entered_story TEXT,
23
+ summary TEXT
24
+ )
25
+ ''')
26
+
27
+ # Creating the Translation table
28
+ cursor.execute('''
29
+ CREATE TABLE IF NOT EXISTS Translation (
30
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
31
+ input_text TEXT,
32
+ translated_text TEXT
33
+ )
34
+ ''')
35
+
36
+ connection.close() # Closes the connection
requirements.txt ADDED
Binary file (1.17 kB). View file