File size: 11,120 Bytes
8e10d25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import spacy
#spacy model imported in the init of class Semantica2
#nlp = spacy.load('es_core_news_sm')
#nlp = spacy.load('es_core_news_md')
#nlp = spacy.load('es_core_news_lg')

from codeScripts.Dependencies.SentenceTransformer2 import *
from codeScripts.rubricsOut import SemanticOutput, OrtographicOutput, SintacticOutput
from codeScripts.utils import spelling_corrector, mu_index, FHuertas_index, check_senteces_words, save_json,create_file_path

#Done

class Semantica2():
    """
    This class allows to compute the semantic level of the rubric
    """
    #funciones para la extraccion/generacion de kw --- no integradas
    def __init__(self, settings):        

        self.output = SemanticOutput(settings)
        self.spacy_model = spacy.load(settings.spacy_package)
        self.settings = settings
    
    def computeSimilarity(self,sentences1,sentences2,similarityMethod):
        """
        This function applies a defined method to obtain the similarity between two sentences
        Inputs:
            -sentences1: First set of sentences to compare
            -sentences2: Second set of sentences to compare
            -similarityMethod: The inherited similarity method selected in getSimilarity
        Outputs:
            -similar: The similarity score
        """
        if similarityMethod.lower() == "spacy":
            r1 = self.spacy_model(sentences1)
            r2 = self.spacy_model(sentences2)
            similar = round(r1.similarity(r2), 3)
        else:
            similar = self.settings.BertModels_glbl.similarity(self.settings.model_path, sentences1, sentences2)[0][0].item()
        
        return similar
 
class Ortografia2 ():
    """
    This class allows to compute the ortographic level of the rubric
    """
    def __init__(self, settings):
        self.output = OrtographicOutput()
        self.settings = settings
    
    def Evaluation(self, respuesta_alumno):
        """
        This method is used for calculating the ortographic mark.
        Inputs:
            respuesta_alumno: The student's answer.
        Outputs:
            nota_Orto: The generated mark.
        """
        #some exceptions that should not be considered as mistakes
        exceptionsTxt = open('codeScripts/OrtographicExceptions.txt', encoding="utf-8")
        exceptions = exceptionsTxt.readline()
        exceptionsTxt.close()
        
        nota_Orto = 0
        if respuesta_alumno == "":
            self.output.number_mistakes.append(0)
            self.settings.faltasOrto = 0
        else:
            #obtaining the number of mistakes using hunspell
            errores, mistakes = spelling_corrector(respuesta_alumno, self.settings.hunspell_aff, self.settings.hunspell_dic)
            for mistake in mistakes:
                if mistake not in exceptions:
                    if mistake not in self.output.mistakes:
                        self.output.mistakes.append(mistake)
                else:
                    errores-=1

            #storing the mistakes for debugging purposes      
            self.output.number_mistakes.append(errores)
            
            #counting the number of errors when surpassing a fixed number of them (config parameter)
            
            if errores <= self.settings.FaltasSalvaguarda:
                nota_Orto = self.settings.PesoOrtografia
                self.settings.faltasOrto = 0
            else:
                self.settings.faltasOrto = errores
                
                #computing the mark applying rubric weights
                try:
                    rel = self.settings.PesoOrtografia/self.settings.NMaxErrores 
                    nota_Orto = self.settings.PesoOrtografia - (errores - self.settings.FaltasSalvaguarda) * rel
                except:
                    nota_Orto = 0

                if nota_Orto < 0:
                    nota_Orto = 0
        
        
        return nota_Orto

    def SaveMistakes(self):
        """
        This method is used for saving some information about the students' found mistakes
        """
        save_json(create_file_path('RecopiledMistakes.json', doctype= 2),self.output.mistakes, False)
        save_json(create_file_path('NumberMistakes.json', doctype= 2),self.output.number_mistakes, False)

class Sintaxis2():
    """
    This class allows to compute the syntactic level of the rubric
    """
    def __init__(self, settings):
        self.output = SintacticOutput()
        self.settings = settings

    def Evaluation(self, respuesta_alumno):
        """
        This method is used for calculating the syntactic mark.
        Inputs:
            respuesta_alumno: The student's answer.
        Outputs:
            nota_Sintaxis: The generated mark.
        """
        if respuesta_alumno == '':
            self.output.leg_FH.append(0)
            self.output.leg_mu.append(0)
            self.settings.palabrasPorFrase = 0
            return 0
        else:
            #obtaining FH and mu indexes
            sentencesLenght, wordsLenght, syll, letter_per_word = check_senteces_words(respuesta_alumno)
            FH, _ = FHuertas_index(sentencesLenght, wordsLenght, syll)
            mu, _ = mu_index(sentencesLenght, wordsLenght, letter_per_word)

            #storing the indexes
            self.output.leg_FH.append(FH)
            self.output.leg_mu.append(mu)
            
            #calculating the grade
            nota_Sintaxis = (self.settings.PesoSintaxis/2) * FH/80 + (self.settings.PesoSintaxis/2) * mu/60
            if nota_Sintaxis > self.settings.PesoSintaxis:
                nota_Sintaxis = self.settings.PesoSintaxis

            self.settings.palabrasPorFrase = round(wordsLenght/sentencesLenght,2)
            return nota_Sintaxis       
        
    def saveResults(self):
        """
        This method is used for saving some information about the students' readability
        """
        self.output.saveLegibilityResults()

def GenerateFeedback(settings, respuesta, OrtoMark, SintMark, SemanMarkSpacy, SemanMarkBert):
    """
    This function is used to analyze grades and generate appropriate feedback based on sentences.
    Inputs:
        -settings: The settings of the experiment.
        -respuesta: The student's response.
        -OrtoMark: The calification of the ortographic level.
        -SintMark: The calification of the syntactic level.
        -SemanMarkSpacy: The calification of the semantic level - spacy.
        -SemanMarkBert: The calification of the semantic level - bert.
    Outputs:
        -feedback: The generated feedback.
    """
    feedback = ""
    #if blank response
    if respuesta == "":
        feedback = feedback + "Respuesta en blanco"
    else:
        #pre-defined sentences in case: <5 - <10 - 10
        if settings.Ortografia:
            feedback = feedback + "\nNivel ortográfico: \n"
            if  OrtoMark < settings.PesoOrtografia/2:
                feedback = feedback + "El estudiante cometió " + str(settings.faltasOrto) + " faltas de ortografía y no alcanzó el aprobado en este nivel de la rúbrica. El sistema reconoce un fallo si se ha producido un error en acento de puntuación o en una palabra no recogida en un diccionario español. \n"
            elif OrtoMark < settings.PesoOrtografia:
                feedback = feedback + "El estudiante cometió " + str(settings.faltasOrto) + " faltas de ortografía. El sistema reconoce un fallo si se ha producido un error en acento de puntuación o en una palabra no recogida en un diccionario español. \n"
            else:
                feedback = feedback + "El estudiante redactó su respuesta sin aparentes fallos de ortografía. \n"
            
           
        if settings.Sintaxis:
            feedback = feedback + "\nNivel sintáctico: \n"
            if  SintMark < settings.PesoSintaxis/2:
                feedback = feedback + "La respuesta del estudiante incluye elementos que dificultan su correcta legibilidad y no alcanzó el aprobado en este nivel de la rúbrica. Hay " + str(settings.palabrasPorFrase) + " palabras por frase. El sistema tiene en consideración para la legibilidad el promedio de sílabas por palabra y la media de palabras por frase. Además, el uso de guiones o puntos es desaconsejable.  \n"
            elif SintMark < settings.PesoSintaxis:
                feedback = feedback + "La respuesta del estudiante incluye elementos que dificultan su correcta legibilidad. Hay " + str(settings.palabrasPorFrase) + " palabras por frase. El sistema tiene en consideración para la legibilidad el promedio de sílabas por palabra y la media de palabras por frase. Además, el uso de guiones o puntos es desaconsejable.  \n"
            else:
                feedback = feedback + "La respuesta del estudiante fue redactada con aparente buena legibilidad \n"

        if settings.Semantica:
            feedback = feedback + "\nNivel semántico, primer modelo: \n"
            if  SemanMarkSpacy < settings.PesoSemantics/2:
                feedback = feedback + "El estudiante no responde correctamente a todas las minipreguntas y no alcanzó el aprobado en este nivel de la rúbrica. Debería profundizar más en " + settings.minipreguntasMalSpacy + ". El sistema evalúa una respuesta en base a la similitud que existe entre ésta y la respuesta de referencia de cada minipregunta.   \n"
            elif SemanMarkSpacy < settings.PesoSemantics:
                feedback = feedback + "El estudiante no responde correctamente a todas las minipreguntas. Para mejorar podría profundizar más en " + settings.minipreguntasMalSpacy + ". El sistema evalúa una respuesta en base a la similitud que existe entre ésta y la respuesta de referencia de cada minipregunta. \n"
            else:
                feedback = feedback + "El estudiante responde a cada minipregunta de forma similar a la respuesta de referencia.  \n"

            feedback = feedback + "\nNivel semántico, segundo modelo: \n"
            if SemanMarkBert < settings.PesoSemantics/2:
                feedback = feedback + "El estudiante no responde correctamente a todas las minipreguntas y no alcanzó el aprobado en este nivel de la rúbrica. Debería profundizar más en " + settings.minipreguntasMalBert + ". El sistema evalúa una respuesta en base a la similitud que existe entre ésta y la respuesta de referencia de cada minipregunta.\n" 
            elif SemanMarkBert < settings.PesoSemantics:
                feedback = feedback + "El estudiante no responde correctamente a todas las minipreguntas. Para mejorar podría profundizar más en " + settings.minipreguntasMalBert + ". El sistema evalúa una respuesta en base a la similitud que existe entre ésta y la respuesta de referencia de cada minipregunta. \n"
            else:
                feedback = feedback + "El estudiante responde a cada minipregunta de forma similar a la respuesta de referencia.  \n"

            feedback = feedback + "\n\nPor favor, si observa alguna diferencia significativa entre la calificación de ambos modelos, entre a valorar la nota del estudiante. "


    return feedback