RobPruzan's picture
Adding title
7cfde5a
raw
history blame
14.5 kB
import csv
import string
import json
import gensim.downloader as api
import matplotlib.pyplot as plt
import nltk
import numpy as np
import pandas as pd
import gradio as gr
import readability
import seaborn as sns
import torch
from fuzzywuzzy import fuzz
from nltk.corpus import stopwords
from nltk.corpus import wordnet as wn
from nltk.tokenize import word_tokenize
from sklearn.metrics.pairwise import cosine_similarity
from transformers import DistilBertTokenizer
from transformers import pipeline
nltk.download('wordnet')
nltk.download('omw-1.4')
nltk.download('cmudict')
nltk.download('stopwords')
nltk.download('punkt')
glove_vectors = api.load('glove-wiki-gigaword-100')
tokenizer = DistilBertTokenizer.from_pretrained('distilbert-base-uncased')
device = torch.device('cuda' if torch.cuda.is_available else 'cpu')
# loading model
PATH = 'pytorchBERTmodel'
model = torch.load(PATH, map_location=torch.device('cpu'))
model.eval()
model.to('cpu')
p = pipeline("automatic-speech-recognition")
def wn_syns(word):
synonyms = []
for syn in wn.synsets(word):
for lm in syn.lemmas():
synonyms.append(lm.name())
return set(synonyms)
w2v = dict({})
for idx, key in enumerate(glove_vectors.key_to_index.keys()):
w2v[key] = glove_vectors.get_vector(key)
def calculate_diversity(text):
stop_words = set(stopwords.words('english'))
for i in string.punctuation:
stop_words.add(i)
tokenized_text = word_tokenize(text)
tokenized_text = list(map(lambda word: word.lower(), tokenized_text))
sim_words = {}
if len(tokenized_text) <= 1:
return 1, "More Text Required"
for idx, anc in enumerate(tokenized_text):
if anc in stop_words or not anc in w2v or anc.isdigit():
sim_words[idx] = '@'
continue
vocab = [anc]
for pos, comp in enumerate(tokenized_text):
if pos == idx:
continue
if comp in stop_words:
continue
if not comp.isalpha():
continue
try:
if cosine_similarity(w2v[anc].reshape(1, -1), w2v[comp].reshape(1, -1)) > .7 or comp in wn_syns(anc):
vocab.append(comp)
except KeyError:
continue
sim_words[idx] = vocab
print(sim_words)
scores = {}
for key, value in sim_words.items():
if len(value) == 1:
scores[key] = -1
continue
# if len(value) == 2:
# scores[key] = -1
# continue
t_sim = len(value)
t_rep = (len(value)) - (len(set(value)))
score = ((t_sim - t_rep) / t_sim) ** 2
scores[key] = score
mean_score = 0
total = 0
for value in scores.values():
if value == -1:
continue
mean_score += value
total += 1
try:
return scores, {"Diversity Score": mean_score / total}
except ZeroDivisionError:
return scores, {"Dviersity Score": "Not Enough Data"}
def get_scores(text):
return calculate_diversity(text)[0]
def get_mean_score(text):
return calculate_diversity(text)[1]
def dict_to_list(dictionary, max_size=10):
outer_list = []
inner_list = []
for key, value in dictionary.items():
inner_list.append(value)
if len(inner_list) == max_size:
outer_list.append(inner_list)
inner_list = []
if len(inner_list) > 0:
outer_list.append(inner_list)
return outer_list
def heatmap(scores, df):
total = 0
loops = 0
for ratio in scores.values():
# conditional to visualize the difference between no ratio and a 0 ratio score
if ratio != -.3:
total += ratio
loops += 1
diversity_average = total / loops
return sns.heatmap(df, cmap='gist_gray_r', vmin=-.3).set(
title='Word Diversity Score Heatmap (Average Score: ' + str(diversity_average) + ')')
def stats(text):
results = readability.getmeasures(text, lang='en')
return results
def predict(text, tokenizer=tokenizer):
model.eval()
model.to('cpu')
def prepare_data(text, tokenizer):
input_ids = []
attention_masks = []
encoded_text = tokenizer.encode_plus(
text,
truncation=True,
add_special_tokens=True,
max_length=315,
pad_to_max_length=True,
return_attention_mask=True,
return_tensors='pt'
)
input_ids.append(encoded_text['input_ids'])
attention_masks.append(encoded_text['attention_mask'])
input_ids = torch.cat(input_ids, dim=0)
attention_masks = torch.cat(attention_masks, dim=0)
return {'input_ids': input_ids, 'attention_masks': attention_masks}
tokenized_example_text = prepare_data(text, tokenizer)
with torch.no_grad():
result = model(
tokenized_example_text['input_ids'].to('cpu'),
attention_mask=tokenized_example_text['attention_masks'].to('cpu'),
return_dict=True
).logits
return result
def level(score):
if score <= 3:
return "n Elementary School"
elif 3 <= score <= 6:
return " Middle School"
elif 6 <= score <= 8:
return " High School"
else:
return " College"
def reading_difficulty(excerpt):
if len(excerpt) == 0:
return "No Text Provided"
windows = []
words = tokenizer.tokenize(excerpt)
if len(words) > 301:
for idx, text in enumerate(words):
if idx % 300 == 0:
if idx <= len(words) - 301:
x = ' '.join(words[idx: idx + 299])
windows.append(x)
win_preds = []
for text in windows:
win_preds.append(predict(text, tokenizer).item())
result = np.mean(win_preds)
score = -(result * 1.786 + 6.4) + 10
return "Difficulty Level: " + str(round(score, 2)) + '/10' + ' | A' + str(
level(score)) + " student could understand this"
else:
result = predict(excerpt).item()
score = -(result * 1.786 + 6.4) + 10
return 'Difficulty Level: ' + str(round(score, 2)) + '/10' + ' | A' + str(
level(score)) + " student could understand this"
def calculate_stats(file_name, data_index):
# unicode escape only for essays
with open(file_name, encoding='unicode_escape') as f:
information = {'lines': 0, 'words_per_sentence': 0, 'words': 0, 'syll_per_word': 0, 'characters_per_word': 0,
'reading_difficulty': 0}
reader = csv.reader(f)
for line in reader:
if len(line[data_index]) < 100:
continue
# if detect(line[data_index][len(line[data_index]) -400: len(line[data_index])-1]) == 'en':
try:
stat = stats(line[data_index])
except ValueError:
continue
information['lines'] += 1
information['words_per_sentence'] += stat['sentence info']['words_per_sentence']
information['words'] += stat['sentence info']['words']
information['syll_per_word'] += stat['sentence info']['syll_per_word']
information['characters_per_word'] += stat['sentence info']['characters_per_word']
information['reading_difficulty'] += reading_difficulty(line[data_index])
for i in information:
if i != 'lines' and i != 'words':
information[i] /= information['lines']
return information
def transcribe(audio):
# speech to text using pipeline
text = p(audio)["text"]
return text
def compute_score(target, actual):
print(target)
target = target.lower()
actual = actual.lower()
return fuzz.ratio(target, actual)
def phon(text):
alph = nltk.corpus.cmudict.dict()
text = word_tokenize(text)
pronun = []
for word in text:
try:
pronun.append(alph[word][0])
except Exception as e:
pronun.append(word)
def remove_digits(lists):
for lst in lists:
for idx, word in enumerate(lst):
lst[idx] = ''.join([letter for letter in word if not letter.isdigit()])
return lists
output = []
for i in remove_digits(pronun):
output.append('-'.join(i).lower())
return ' '.join(output)
def plot():
diversity = calculate_diversity(text)[0]
print(diversity)
df = pd.DataFrame(dict_to_list(diversity))
return heatmap(diversity, df)
def diversity_inter(text):
words = word_tokenize(text)
scores = get_scores(text)
interpret_values = [('', 0.0)]
for key, value in scores.items():
interpret_values.append((words[key], value))
interpret_values.append(('', 0.0))
print(interpret_values)
return {'original': text, 'interpretation': interpret_values}
def sliding_window(text):
words = word_tokenize(text)
improved_window = []
improved_wind_preds = []
for idx, text in enumerate(words):
if idx <= len(words) - 26:
x = ' '.join(words[idx: idx + 25])
throw_away = []
score = 0
for idx, i in enumerate(range(idx, idx + 25)):
if idx == 0:
better_prediction = -(predict(x).item() * 1.786 + 6.4) + 10
score = better_prediction
throw_away.append((better_prediction, i))
else:
throw_away.append((score, i))
improved_window.append(throw_away)
average_scores = {k: 0 for k in range(len(words) - 1)}
total_windows = {k: 0 for k in range(len(words) - 1)}
for idx, i in enumerate(improved_window):
for score, idx in i:
average_scores[idx] += score
total_windows[idx] += 1
for k, v in total_windows.items():
if v != 0:
average_scores[k] /= v
inter_scores = [v for v in average_scores.values()]
copy_list = inter_scores.copy()
print(inter_scores)
while len(inter_scores) <= len(words) - 1:
inter_scores.append(copy_list[-1])
x = list(range(len(inter_scores)))
y = inter_scores
fig, ax = plt.subplots()
ax.plot(x, y, color='orange', linewidth=2)
ax.grid(False)
plt.xlabel('Word Number', fontweight='bold')
plt.ylabel('Difficulty Score', fontweight='bold')
fig.patch.set_facecolor('white')
plt.suptitle('Difficulty Score Across Text', fontsize=14, fontweight='bold')
plt.style.use('ggplot')
fig = plt.gcf()
map = [('', 0)]
maxy = max(inter_scores)
miny = min(inter_scores)
spread = maxy - miny
for idx, i in enumerate(words):
map.append((i, (inter_scores[idx] - miny) / spread))
map.append(('', 0))
return fig, map
def get_plot(text):
return sliding_window(text)[0]
def get_dif_inter(text):
return {'original': text, 'interpretation': sliding_window(text)[1]}
def speech_to_text(speech, target):
text = p(speech)["text"]
return text.lower(), {'Pronunciation Score': compute_score(text, target) / 100}, phon(target)
def speech_to_score(speech):
text = p(speech)["text"]
return reading_difficulty(text), text
def my_i_func(text):
return {"original": "", "interpretation": [('', 0.0), ('what', -0.2), ('great', 0.3), ('day', 0.5), ('', 0.0)]}
def gen_syns(word, level):
with open('balanced_synonym_data.json') as f:
data = json.loads(f.read())
school_to_level = {"Elementary Level":'1', "Middle School Level":'2', "Highschool Level":'3', "College Level":'4'}
pins = wn_syns(word)
reko = []
for i in pins:
if i in data[school_to_level[level]]:
reko.append(i)
str_reko = ""
for idx, i in enumerate(reko):
if idx != len(reko) -1:
str_reko+= i + ' | '
else:
str_reko+= i
return str_reko
with gr.Blocks(title="Automatic Literacy and Speech Assesmen") as demo:
with gr.Column():
with gr.Row():
with gr.Box():
with gr.Column():
with gr.Group():
with gr.Tabs():
with gr.TabItem("Text"):
in_text = gr.Textbox(label="In Text")
grade = gr.Button("Grade Your Text")
with gr.TabItem("Speech"):
audio_file = gr.Audio(source="microphone",type="filepath")
grade1 = gr.Button("Grade Your Speech")
with gr.Group():
gr.Markdown("Reading Level Based Synonyms")
words = gr.Textbox(label="Word For Synonyms")
lvl = gr.Dropdown(choices=["Elementary Level", "Middle School Level", "High School Level", "College Level" ], label="Intended Reading Level For Synonym")
get_syns = gr.Button("Get Synonyms")
reccos = gr.Label()
with gr.Box():
diff_output = gr.Label(label='Difficulty Level',show_label=True)
gr.Markdown("Diversity Score Across Text")
plotter = gr.Plot()
with gr.Row():
with gr.Box():
div_output = gr.Label(label='Diversity Score', show_label=False)
gr.Markdown("Diversity Heamap | Blue cells are omitted from score")
interpretation = gr.components.Interpretation(in_text, label="Diversity Heapmap")
with gr.Box():
interpretation2 = gr.components.Interpretation(in_text, label="Difficulty Heapmap")
with gr.Row():
with gr.Box():
with gr.Group():
target = gr.Textbox(label="Target Text")
with gr.Group():
audio_file1 = gr.Audio(source="microphone",type="filepath")
b1 = gr.Button("Grade Your Pronunciation")
with gr.Box():
some_val = gr.Label()
text = gr.Textbox()
phones = gr.Textbox()
grade.click(reading_difficulty, inputs=in_text, outputs=diff_output)
grade.click(get_mean_score, inputs=in_text, outputs=div_output)
grade.click(diversity_inter, inputs=in_text, outputs=interpretation)
grade.click(get_dif_inter, inputs=in_text, outputs=interpretation2)
grade.click(get_plot, inputs=in_text, outputs=plotter)
grade1.click(speech_to_score, inputs=audio_file, outputs=diff_output)
b1.click(speech_to_text, inputs=[audio_file1, target], outputs=[text, some_val, phones])
get_syns.click(gen_syns, inputs=[words, lvl], outputs=reccos)
demo.launch(debug=True)