File size: 6,941 Bytes
7f59544
4057e14
 
 
1c359f1
 
 
 
e85a261
9a541e5
7f59544
1c359f1
c6ba15f
4ab86fc
4707333
1c359f1
 
7f59544
1c359f1
 
 
 
7f59544
9a541e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4057e14
7968b20
 
1c359f1
 
9a541e5
4057e14
1c359f1
9a541e5
4057e14
7968b20
1c359f1
 
 
 
 
 
 
 
 
4057e14
1c359f1
9a541e5
1c359f1
 
 
 
7968b20
 
 
 
 
 
 
 
1c359f1
 
 
 
 
 
 
 
 
7968b20
1c359f1
 
 
 
 
 
 
 
 
7968b20
 
1c359f1
 
4057e14
9a541e5
 
 
 
b5221e6
 
 
 
 
 
 
9a541e5
 
b5221e6
9a541e5
b5221e6
9a541e5
b5221e6
9a541e5
b5221e6
9a541e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b5221e6
9a541e5
b5221e6
9a541e5
b5221e6
9a541e5
 
b5221e6
 
 
4057e14
 
9a541e5
 
 
 
 
 
4057e14
9a541e5
7968b20
9a541e5
 
 
4057e14
9a541e5
4057e14
 
1c359f1
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
import gradio as gr
import pandas as pd
import numpy as np
import pickle
import nltk
from nltk import word_tokenize 
from nltk.util import ngrams
from unidecode import unidecode
nltk.download('punkt')
import re

# leemos diccionario de entidades
diccionario = pd.read_csv('diccionario.csv', encoding = 'utf-8-sig', usecols = ['Entidad', 'Categoria'])
diccionario = diccionario.dropna()
diccionario = diccionario[diccionario['Categoria'] != 'Año']
diccionario = diccionario.iloc[1:]
all_dicts = diccionario.apply(lambda x: {x['Entidad']: x['Categoria']}, axis = 1)

# formateamos diccionario
entities_dict = {}
for i in all_dicts:
  entities_dict.update(i)

def f_remove_accents(old: str):

    '''
    Función que limpia acentos de las letras.
    old: texto a limpiar (str)
    '''

    new = re.sub(r'[àáâãäå]', 'a', old)
    new = re.sub(r'[èéêë]', 'e', new)
    new = re.sub(r'[ìíîï]', 'i', new)
    new = re.sub(r'[òóôõö]', 'o', new)
    new = re.sub(r'[ùúûü]', 'u', new)
    return new

def predict(text: str, goal = ''):

  output_sernac, output_sernac_categories, output_other, output_objective = np.nan, np.nan, np.nan, np.nan

  diccionario = entities_dict.copy()
  tokens = word_tokenize(text, language = 'spanish')
  tokens_lower = [f_remove_accents(token.lower()) for token in tokens] # tokens en minuscula

  dict_tokens = {tokens_lower[i]: tokens[i] for i in range(len(tokens))}
  dict_keys = {f_remove_accents(key.lower()): key for key in diccionario.keys()}

  # Evaluar el grado de ngramas en texto
  ngram_range = 5 # rango de ngramas a evaluar
  nmin = 1 # numero minimo de ngramas presente en el texto
  grams_detected = {}
  for i in range(2, ngram_range + 1):
    n_grams = [' '.join(ngram) for ngram in list(nltk.ngrams(tokens_lower, i))]
    intersection = list(set(n_grams) & set(dict_keys.keys()))
    if len(intersection) > 0:
      nmin = i
      grams_detected.update({nmin: intersection})

  sep = '%$·'
  tmp_text = ' '.join(tokens_lower)
  for i in range(5, 1, -1):
    try:
      # obtener todos los ngramas de nivel "i"
      for j in range(len(grams_detected[i])):
        entity =  grams_detected[i][j]
        tokens_entity = tuple(word_tokenize(entity))
        ngrams = list(nltk.ngrams(tmp_text.split(' '), i))
        tmp_list = [(f'{i}{sep}{j}',) if ngram == tokens_entity else ngram for ngram in ngrams]
        pos_list = [key for key, value in dict(enumerate(tmp_list)).items() if f'{i}{sep}{j}' in value[0]]
        exclude_list = [value + k for value in pos_list for k in range(1, i)]
        tmp_list = [value for key, value in dict(enumerate(tmp_list)).items() if key not in exclude_list]
        tmp_text = ' '.join([i[0] for i in tmp_list] + [token for token in tmp_text.split(' ')[-i+1:] if token not in tokens_entity])
    except KeyError: # en caso de que no existan ngramas de nivel "i", pass
      pass

  labeled_tokens = []
  # si hay solo entidades de largo 1, devuelvo oracion etiquetada token a token
  if nmin < 2:
    for token in tokens_lower:
      labeled_tokens.append((dict_tokens[token], diccionario[dict_keys[token]]) if token in dict_keys.keys() else (token, None))

  # si hay entidades de largo 2 o mas, devuelvo texto etiquetado con ngramas
  else:
    tmp_text = ' '.join(tmp_text.split()) # texto sin espacios
    tmp_tokens = tmp_text.split()
    for token in tmp_tokens:
      if sep in token:
        level, pos = token.split(sep)
        encoded_token = grams_detected[int(level)][int(pos)]
        labeled_tokens.append((encoded_token, diccionario[dict_keys[encoded_token]]))
      elif token in dict_keys.keys():
        #labeled_tokens.append((dict_tokens[token], diccionario[dict_keys[token]]))
        labeled_tokens.append((token, diccionario[dict_keys[token]]))
      else:
        labeled_tokens.append((token, None))

  # CLASSIFICATION

  input = np.array([text, goal], ndmin = 2)

  # SERNAC CLASSIFICATION

  with open('sernac_model.pkl', 'rb') as model:
    clf = pickle.load(model)

  labels = [label for label in clf.classes_]

  probas = clf.predict_proba(input)
  sernac_probas = {labels[i]: float(probas[0][i]) for i in range(probas.shape[1])}

  sernac_categories, other_categories = {}, {}

  if clf.predict(input) == 'SERNAC':

    # SERNAC CATEGORIES CLASSIFICATION

    with open('sernac_categories_model.pkl', 'rb') as model:
      clf = pickle.load(model)

    labels = [label for label in clf.classes_]

    probas = clf.predict_proba(input)

    sernac_categories = {labels[i]: float(probas[0][i]) for i in range(probas.shape[1])}

  else: 

    # OTHER CATEGORIES CLASSIFICATION

    with open('other_categories_model.pkl', 'rb') as model:
      clf = pickle.load(model)

    labels = [label for label in clf.classes_]

    probas = clf.predict_proba(input)

    other_categories = {labels[i]: float(probas[0][i]) for i in range(probas.shape[1])}

  objective_categories = {}
  if goal != '':

    with open('objective_model.pkl', 'rb') as model:
      clf = pickle.load(model)

    labels = [label for label in clf.classes_]

    probas = clf.predict_proba(input)

    objective_categories = {labels[i]: float(probas[0][i]) for i in range(probas.shape[1])}

  # RETURN
  return labeled_tokens, sernac_probas, sernac_categories, other_categories, objective_categories


# DEMO
demo = gr.Interface(
    predict,
    inputs = [gr.Textbox(placeholder = "Ingresa el reclamo acá", label = 'Reclamo'), gr.Textbox(placeholder = "Ingresa el objetivo acá (opcional)", label = 'Objetivo')],
    outputs = [gr.Highlightedtext(label = 'Entidades detectadas'), 
               gr.outputs.Label(label = 'Clasificación SERNAC'), 
               gr.outputs.Label(label = 'Clasificación categorías SERNAC'), 
               gr.outputs.Label(label = 'Clasificación categorías No SERNAC'),
               gr.outputs.Label(label = 'Clasificación objetivo')],
    examples=[
        ['este septiembre iremos manejando a tEmUco en un tóyòtA para pasar las fiestas patrias', 'ir a temuco'],
        ['no puedo, tengo que ir desde san pedro hasta la reina y luego hasta san pedro de la paz', ''],
        ['Buenas tardes, hace unas semanas compre un suzuki swift a derco de santiago, llevaba 2 semanas y la caja de cambios se echó a perder. Tengo asegurado el auto con BCI, pero aun no obtengo respuesta.', 'exijo una explicación!'],
        ['Tengo un toyota urban cruiser 1.3 año 2010 el cual consume mucho aceite y nunca me han respondido si tiene alguna solución o garantía me gustaría que fueran más concretas las respuestas gracias', 'Obtener una solucion Que reparación hay que hacer o si tiene garantía?'],
        ['Mi auto del año presenta Falla de motor y sensores siendo que lo compre nuevo 0km y tiene recién 5400kms.. Es un Peugeot 2008 gti... El servicio es como las pelotas.. Me mandaron a un servicio técnico en Calama que estaba cerrado', '']
    ],
    title = 'Demo ML'
)

demo.launch()