Commit 30cb1371e39accf566d309905b7938fb4065b16c
Exists in
master
Merge branch 'devel'
Showing
10 changed files
with
290 additions
and
226 deletions
Show diff stats
data/preposicoes.csv
install/linux/install.sh
... | ... | @@ -30,7 +30,7 @@ read -r -p "Deseja fazer o download das dependências? [Y/n] " response |
30 | 30 | echo -e "# Instalando dependências...\n" |
31 | 31 | sudo apt-get update |
32 | 32 | sudo apt-get install -y python-dev python-setuptools python-pip python-yaml python-numpy python-matplotlib |
33 | - sudo pip install nltk nltk_tgrep --upgrade | |
33 | + sudo pip install nltk==3.0.5 nltk_tgrep --upgrade | |
34 | 34 | |
35 | 35 | fi |
36 | 36 | ... | ... |
src/AplicaRegras.py
... | ... | @@ -6,7 +6,6 @@ |
6 | 6 | |
7 | 7 | #LAViD - Laboratório de Aplicações de Vídeo Digital |
8 | 8 | |
9 | -import platform | |
10 | 9 | import re |
11 | 10 | import xml.etree.ElementTree as ET |
12 | 11 | from os.path import expanduser |
... | ... | @@ -38,12 +37,10 @@ class AplicaRegras(object): |
38 | 37 | # Gera arvore a partir do arquivos regras.xml |
39 | 38 | def get_root(self): |
40 | 39 | '''Verifica qual o SO e gera o path de onde se encontra o diretório data. |
41 | - ''' | |
42 | - if "TRANSLATE_DATA" in environ: | |
40 | + ''' | |
41 | + if "TRANSLATE_DATA" in environ: | |
43 | 42 | arq_regras = path.join(environ.get("TRANSLATE_DATA"), "regras.xml") |
44 | 43 | return ET.parse(arq_regras).getroot() |
45 | - elif platform.system() == 'Windows': | |
46 | - return ET.parse(environ.get("HOMEDRIVE")+'\\vlibras-libs\\vlibras-translate\data\\regras.xml').getroot() | |
47 | 44 | return ET.parse(expanduser("~")+'/vlibras-translate/data/regras.xml').getroot() |
48 | 45 | |
49 | 46 | # Aplica regras morfológicas apartir do arquivo regras.xml |
... | ... | @@ -264,8 +261,15 @@ class AplicaRegras(object): |
264 | 261 | # EU FELIZ PASSADO -> EU FELIZ |
265 | 262 | if morfo[i] is not None and morfo[i][1] == "NTK" and morfo[i][0]: |
266 | 263 | new_node = self.gerar_no(morfo[i]) |
267 | - arvore[lista_pos_arv[i-1][:-3]].insert(2, new_node) | |
268 | - #arvore[lista_pos_arv[i-1][:-2]].insert(2, new_node) | |
264 | + | |
265 | + #arvore[lista_pos_arv[i-1][:-3]].insert(2, new_node) | |
266 | + #arvore[lista_pos_arv[i-1][:-3]].insert(2, new_node) | |
267 | + | |
268 | + if str(arvore[lista_pos_arv[i-1][:-3]]).count('(') > 7: | |
269 | + arvore[lista_pos_arv[i-1][:-2]].insert(2, new_node) | |
270 | + else: | |
271 | + arvore[lista_pos_arv[i-1][:-3]].insert(2, new_node) | |
272 | + | |
269 | 273 | try: |
270 | 274 | lista_pos_arv.insert(i,lista_pos_arv[i]) |
271 | 275 | except: |
... | ... | @@ -399,9 +403,14 @@ class AplicaRegras(object): |
399 | 403 | tag = it.get_ticket() |
400 | 404 | |
401 | 405 | if tag == "NUM": |
406 | + try: | |
407 | + num_romano = roman_to_int(it.get_word().encode('utf-8')) | |
408 | + lista_simplificada[it.get_count()] = [num_romano.decode('utf-8'), 'NUM-R'] | |
409 | + except: | |
410 | + pass | |
402 | 411 | num = True |
403 | 412 | |
404 | - if tag[-2:] == "-P" and self.verificar_excecao_plural(it.get_word()): | |
413 | + if tag != "NPR-P" and tag[-2:] == "-P" or tag[-2:] == "_P" and self.verificar_excecao_plural(it.get_word()): | |
405 | 414 | singular = self.analisar_plural(it.get_word()) |
406 | 415 | lista_simplificada[it.get_count()][0] = singular |
407 | 416 | |
... | ... | @@ -438,7 +447,7 @@ class AplicaRegras(object): |
438 | 447 | return token[:-2]+"l" |
439 | 448 | return token |
440 | 449 | elif(token[-1] == "s"): |
441 | - #TODO: Palavras paroxítonas ou proparoxítonas terminadas em S. Ex: lápis, vírus, tagênis, ônibus, etc | |
450 | + #TODO: Palavras paroxítonas ou proparoxítonas terminadas em S. Ex: lápis, vírus, tagênis, ônibus, etc | |
442 | 451 | return token[:-1] |
443 | 452 | else: |
444 | 453 | return token | ... | ... |
src/AplicaSinonimos.py
... | ... | @@ -27,26 +27,10 @@ class AplicaSinonimos(object): |
27 | 27 | '''Percorre a lista fazendo a substituição pelos sinonimos. |
28 | 28 | ''' |
29 | 29 | lista_corrigida = [] |
30 | - palavras_compostas = self.carregar_palavras_compostas() | |
31 | 30 | for tupla in lista_anotada: |
32 | 31 | sinonimo = self.verificar_sinonimo(tupla[0]) |
33 | - try: | |
34 | - token_composto_2 = lista_corrigida[-1] + "_" + sinonimo | |
35 | - token_composto_3 = lista_corrigida[-2] + "_" + lista_corrigida[-1] + "_" + sinonimo | |
36 | - if token_composto_2.upper() in palavras_compostas: | |
37 | - lista_corrigida[-1] = token_composto_2 | |
38 | - elif token_composto_3.upper() in palavras_compostas: | |
39 | - lista_corrigida.pop() | |
40 | - lista_corrigida[-1] = token_composto_3 | |
41 | - else: | |
42 | - lista_corrigida.append(sinonimo) | |
43 | - except IndexError: | |
44 | - lista_corrigida.append(sinonimo) | |
45 | - | |
46 | - try: | |
47 | - return " ".join(lista_corrigida) | |
48 | - except: | |
49 | - return " ".join([str(x[0]) for x in lista_anotada]) | |
32 | + lista_corrigida.append(sinonimo) | |
33 | + return self.verificar_palavra_composta(lista_corrigida) | |
50 | 34 | |
51 | 35 | # Verifica se há sinonimo do token |
52 | 36 | def verificar_sinonimo(self, token): |
... | ... | @@ -56,13 +40,23 @@ class AplicaSinonimos(object): |
56 | 40 | return self.dicionarios.get_sinonimo(token) |
57 | 41 | return token |
58 | 42 | |
43 | + def verificar_palavra_composta(self, lista): | |
44 | + palavras_compostas = self.carregar_palavras_compostas() | |
45 | + try: | |
46 | + sentenca_corrigida = "_".join(lista).upper() | |
47 | + except: | |
48 | + sentenca_corrigida = "_".join([str(x[0]) for x in lista]).upper() | |
49 | + | |
50 | + for p in palavras_compostas: | |
51 | + if p in sentenca_corrigida: | |
52 | + sentenca_corrigida = sentenca_corrigida.replace(p, p.replace("_", "#*#")) | |
53 | + return sentenca_corrigida.replace("_", " ").replace("#*#", "_") | |
54 | + | |
59 | 55 | def carregar_palavras_compostas(self): |
60 | 56 | path = self.localizar_arquivo_palavras_compostas() |
61 | 57 | return set(open(path).read().decode('utf-8').split()) |
62 | 58 | |
63 | 59 | def localizar_arquivo_palavras_compostas(self): |
64 | - if platform.system() == 'Windows': | |
65 | - return environ.get("HOMEDRIVE")+'\\vlibras-libs\\vlibras-translate\data\\palavras_compostas.csv' | |
66 | - elif "TRANSLATE_DATA" in environ: | |
60 | + if "TRANSLATE_DATA" in environ: | |
67 | 61 | return path.join(environ.get("TRANSLATE_DATA"), "palavras_compostas.csv") |
68 | 62 | return expanduser("~")+'/vlibras-translate/data/palavras_compostas.csv' |
69 | 63 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,165 @@ |
1 | +#! /usr/bin/env python2.6 | |
2 | +# -*- coding: utf-8 -*- | |
3 | + | |
4 | +#--------------------------------- | |
5 | + | |
6 | +# Editado: | |
7 | + | |
8 | +#Autor: Erickson Silva | |
9 | +#Email: <erickson.silva@lavid.ufpb.br> <ericksonsilva@live.com> | |
10 | + | |
11 | +#LAViD - Laboratório de Aplicações de Vídeo Digital | |
12 | + | |
13 | +#--------------------------------- | |
14 | + | |
15 | + | |
16 | +# Donatus Brazilian Portuguese Parser | |
17 | +# | |
18 | +# Copyright (C) 2010-2013 Leonel F. de Alencar | |
19 | +# | |
20 | +# Author: Leonel F. de Alencar <leonel.de.alencar@ufc.br> | |
21 | +# Homepage: <http://www.leonel.profusehost.net/> | |
22 | +# | |
23 | +# Project's URL: <http://sourceforge.net/projects/donatus/> | |
24 | +# For license information, see LICENSE.TXT | |
25 | +# | |
26 | +# $Id: alexp.py $ | |
27 | + | |
28 | +"""Este módulo contém funções que permitem utilizar o Aelius para etiquetar uma sentença, construindo entradas lexicais com base nas etiquetas atribuídas às palavras da sentença. Essas entradas lexicais são integradas em uma gramática CFG dada, que é transformada em um parser, utilizado para gerar uma árvore de estrutura sintagmática da sentença. | |
29 | +""" | |
30 | +import re,nltk, time, random | |
31 | +from os.path import expanduser | |
32 | +from os import environ, path | |
33 | +from Aelius.Extras import carrega | |
34 | +from Aelius import AnotaCorpus, Toqueniza | |
35 | +from unicodedata import normalize | |
36 | + | |
37 | + | |
38 | +class ClassificaSentencas(object): | |
39 | + | |
40 | + def __init__(self): | |
41 | + self.sentenca_anotada = "" | |
42 | + self.sleep_times = [0.1,0.2] | |
43 | + | |
44 | + def toqueniza(self, s): | |
45 | + """Decodifica string utilizando utf-8, retornando uma lista de tokens em unicode. | |
46 | + """ | |
47 | + regex = re.compile('[%s]' % re.escape('“”')) | |
48 | + regex2 = re.compile('[%s]' % re.escape('«»')) | |
49 | + try: | |
50 | + decodificada = regex2.sub('',regex.sub('"',s.replace("–", "-").replace("—", "-"))).decode("utf-8") | |
51 | + except: | |
52 | + decodificada = s.decode("utf-8") | |
53 | + return Toqueniza.TOK_PORT.tokenize(decodificada) | |
54 | + | |
55 | + def obter_classificacao_morfologica(self): | |
56 | + return self.sentenca_anotada | |
57 | + | |
58 | + def etiqueta_sentenca(self, s): | |
59 | + """Aplica um dos etiquetadores do Aelius na etiquetagem da sentença dada como lista de tokens. | |
60 | + """ | |
61 | + etiquetador = carrega("AeliusHunPos") | |
62 | + anotada = AnotaCorpus.anota_sentencas([s],etiquetador,"hunpos")[0] | |
63 | + while (anotada[0][1] is None): | |
64 | + time.sleep(random.choice(sleep_times)) | |
65 | + anotada = AnotaCorpus.anota_sentencas([s],etiquetador,"hunpos")[0] | |
66 | + regex = re.compile('[%s]' % re.escape('!"#&\'()*+,-./:;<=>?@[\\]^_`{|}~')) | |
67 | + tag_punctuation = [".",",","QT","("] | |
68 | + anotada_corrigida = [] | |
69 | + for x in anotada: | |
70 | + if x[1] not in tag_punctuation: | |
71 | + if x[1] == "NUM": | |
72 | + try: | |
73 | + float(x[0].replace(',', '.')) | |
74 | + anotada_corrigida.append(x) | |
75 | + continue | |
76 | + except: | |
77 | + pass | |
78 | + | |
79 | + tupla = [regex.sub('',x[0]).lower(),x[1]] | |
80 | + if tupla[0] != "": anotada_corrigida.append(tupla) | |
81 | + else: | |
82 | + if x[0] == ".": | |
83 | + anotada_corrigida.append(["[ponto]".decode("utf-8"),"SPT"]) | |
84 | + elif x[0] == "?": | |
85 | + anotada_corrigida.append(["[interrogacao]".decode("utf-8"),"SPT"]) | |
86 | + elif x[0] == "!": | |
87 | + anotada_corrigida.append(["[exclamacao]".decode("utf-8"),"SPT"]) | |
88 | + return anotada_corrigida | |
89 | + | |
90 | + def gera_entradas_lexicais(self, lista): | |
91 | + """Gera entradas lexicais no formato CFG do NLTK a partir de lista de pares constituídos de tokens e suas etiquetas. | |
92 | + """ | |
93 | + entradas=[] | |
94 | + for e in lista: | |
95 | + # é necessário substituir símbolos como "-" e "+" do CHPTB | |
96 | + # que não são aceitos pelo NLTK como símbolos não terminais | |
97 | + c=re.sub(r"[-+]","_",e[1]) | |
98 | + c=re.sub(r"\$","_S",c) | |
99 | + entradas.append("%s -> '%s'" % (c, self.remove_acento(e[0]))) | |
100 | + return entradas | |
101 | + | |
102 | + def corrige_anotacao(self, lista): | |
103 | + """Esta função deverá corrigir alguns dos erros de anotação mais comuns do Aelius. No momento, apenas é corrigida VB-AN depois de TR. | |
104 | + """ | |
105 | + i=1 | |
106 | + while i < len(lista): | |
107 | + if lista[i][1] == "VB-AN" and lista[i-1][1].startswith("TR"): | |
108 | + lista[i]=(lista[i][0],"VB-PP") | |
109 | + i+=1 | |
110 | + | |
111 | + def encontra_arquivo(self): | |
112 | + """Encontra arquivo na pasta vlibras-translate. | |
113 | + """ | |
114 | + if "TRANSLATE_DATA" in environ: | |
115 | + return path.join(environ.get("TRANSLATE_DATA"), "cfg.syn.nltk") | |
116 | + return expanduser("~") + "/vlibras-translate/data/cfg.syn.nltk" | |
117 | + | |
118 | + def extrai_sintaxe(self): | |
119 | + """Extrai gramática armazenada em arquivo cujo caminho é definido relativamente ao diretório nltk_data. | |
120 | + """ | |
121 | + arquivo = self.encontra_arquivo() | |
122 | + if arquivo: | |
123 | + f=open(arquivo,"rU") | |
124 | + sintaxe=f.read() | |
125 | + f.close() | |
126 | + return sintaxe | |
127 | + else: | |
128 | + print "Arquivo %s não encontrado em nenhum dos diretórios de dados do NLTK:\n%s" % (caminho,"\n".join(nltk.data.path)) | |
129 | + | |
130 | + def analisa_sentenca(self, sentenca): | |
131 | + """Retorna lista de árvores de estrutura sintagmática para a sentença dada sob a forma de uma lista de tokens, com base na gramática CFG cujo caminho é especificado como segundo argumento da função. Esse caminho é relativo à pasta nltk_data da instalação local do NLTK. A partir da etiquetagem morfossintática da sentença são geradas entradas lexicais que passam a integrar a gramática CFG. O caminho da gramática e o parser gerado são armazenados como tupla na variável ANALISADORES. | |
132 | + """ | |
133 | + parser = self.constroi_analisador(sentenca) | |
134 | + codificada=[] | |
135 | + for t in self.sentenca_anotada: | |
136 | + if t[1] != "SPT": | |
137 | + codificada.append(self.remove_acento(t[0]).encode("utf-8")) | |
138 | + trees=parser.parse_one(codificada) | |
139 | + return trees | |
140 | + | |
141 | + def constroi_analisador(self, s): | |
142 | + """Constrói analisador a partir de uma única sentença não anotada, dada como lista de tokens, e uma lista de regras sintáticas no formato CFG, armazenadas em arquivo. Esta função tem um bug, causado pela maneira como o Aelius etiqueta sentenças usando o módulo ProcessaNomesProprios: quando a sentença se inicia por paravra com inicial minúscula, essa palavra não é incorporada ao léxico, mas a versão com inicial maiúscula. | |
143 | + """ | |
144 | + self.sentenca_anotada = self.etiqueta_sentenca(s) | |
145 | + self.corrige_anotacao(self.sentenca_anotada) | |
146 | + entradas = self.gera_entradas_lexicais(self.sentenca_anotada) | |
147 | + lexico="\n".join(entradas) | |
148 | + gramatica="%s\n%s" % (self.extrai_sintaxe().strip(),lexico) | |
149 | + cfg=nltk.CFG.fromstring(gramatica) | |
150 | + return nltk.ChartParser(cfg) | |
151 | + | |
152 | + def remove_acento(self, texto): | |
153 | + try: | |
154 | + return normalize('NFKD', texto.encode('utf-8').decode('utf-8')).encode('ASCII', 'ignore') | |
155 | + except: | |
156 | + return normalize('NFKD', texto.encode('iso-8859-1').decode('iso-8859-1')).encode('ASCII','ignore') | |
157 | + | |
158 | + def exibe_arvores(self, arvores): | |
159 | + """Função 'wrapper' para a função de exibição de árvores do NLTK""" | |
160 | + nltk.draw.draw_trees(*arvores) | |
161 | + | |
162 | + def iniciar_classificacao(self, sentenca): | |
163 | + tokens = self.toqueniza(sentenca) | |
164 | + tree = self.analisa_sentenca(tokens) | |
165 | + return tree | |
0 | 166 | \ No newline at end of file | ... | ... |
src/ConverteExtenso.py
... | ... | @@ -25,7 +25,45 @@ ext = [{"um":"1", "dois":"2", "tres":"3", "quatro":"4", "cinco":"5", "seis":"6", |
25 | 25 | und = {"mil":1000, "milhao":1000000, "bilhao":1000000000, "trilhao":1000000000000} |
26 | 26 | unds = {"mil":"000", "milhao":"000000","milhoes":"000000", "bilhao":"000000000","bilhoes":"000000000", "trilhao":"000000000000", "trilhoes":"000000000000"} |
27 | 27 | |
28 | - | |
28 | +def int_to_roman(input): | |
29 | + if not isinstance(input, type(1)): | |
30 | + raise TypeError, "expected integer, got %s" % type(input) | |
31 | + if not 0 < input < 4000: | |
32 | + raise ValueError, "Argument must be between 1 and 3999" | |
33 | + ints = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1) | |
34 | + nums = ('M', 'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I') | |
35 | + result = [] | |
36 | + | |
37 | + for i in range(len(ints)): | |
38 | + count = int(input / ints[i]) | |
39 | + result.append(nums[i] * count) | |
40 | + input -= ints[i] * count | |
41 | + return ''.join(result) | |
42 | + | |
43 | +def roman_to_int(input): | |
44 | + if not isinstance(input, type("")): | |
45 | + raise TypeError, "expected string, got %s" % type(input) | |
46 | + input = input.upper( ) | |
47 | + nums = {'M':1000, | |
48 | + 'D':500, | |
49 | + 'C':100, | |
50 | + 'L':50, | |
51 | + 'X':10, | |
52 | + 'V':5, | |
53 | + 'I':1} | |
54 | + sum = 0 | |
55 | + for i in range(len(input)): | |
56 | + try: | |
57 | + value = nums[input[i]] | |
58 | + if i+1 < len(input) and nums[input[i+1]] > value: | |
59 | + sum -= value | |
60 | + else: sum += value | |
61 | + except KeyError: | |
62 | + raise ValueError, 'input is not a valid Roman numeral: %s' % input | |
63 | + | |
64 | + if int_to_roman(sum) == input: return str(sum) | |
65 | + else: | |
66 | + raise ValueError, 'input is not a valid Roman numeral: %s' % input | |
29 | 67 | |
30 | 68 | def oneDigit(x): |
31 | 69 | return ext[0][x] | ... | ... |
src/LerDicionarios.py
... | ... | @@ -8,20 +8,20 @@ |
8 | 8 | |
9 | 9 | import os |
10 | 10 | import csv |
11 | -import platform | |
12 | 11 | |
13 | -class Singleton(object): | |
12 | +class Singleton(type): | |
14 | 13 | ''' Permite a criação de apenas uma instância da classe |
15 | 14 | ''' |
15 | + _instances = {} | |
16 | + def __call__(cls, *args, **kwargs): | |
17 | + if cls not in cls._instances: | |
18 | + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) | |
19 | + return cls._instances[cls] | |
16 | 20 | |
17 | - def __new__(cls, *args, **kwargs): | |
18 | - if '_inst' not in vars(cls): | |
19 | - cls._inst = object.__new__(cls, *args, **kwargs) | |
20 | - return cls._inst | |
21 | - | |
22 | -class LerDicionarios(Singleton): | |
21 | +class LerDicionarios(object): | |
23 | 22 | '''Carrega todos os arquivos (dicionários) necessários para auxiliar durante o processo de tradução. |
24 | 23 | ''' |
24 | + __metaclass__ = Singleton | |
25 | 25 | |
26 | 26 | def __init__(self): |
27 | 27 | self.path = self.get_path() |
... | ... | @@ -37,31 +37,13 @@ class LerDicionarios(Singleton): |
37 | 37 | self.set_vb_ligacao = [] |
38 | 38 | self.dic_vb_muda_negacao = [] |
39 | 39 | self.file = '' |
40 | - self.carregar_dicionarios() | |
41 | 40 | |
42 | 41 | def get_path(self): |
43 | 42 | '''Verifica qual o SO e gera o path de onde se encontra o diretório data. |
44 | 43 | ''' |
45 | 44 | if "TRANSLATE_DATA" in os.environ: |
46 | 45 | return os.environ.get("TRANSLATE_DATA") |
47 | - elif platform.system() == 'Windows': | |
48 | - return os.environ.get("HOMEDRIVE") + "\\vlibras-libs\\vlibras-translate\data\\" | |
49 | - return os.path.expanduser("~") + "/vlibras-translate/data" | |
50 | - | |
51 | - def carregar_dicionarios(self): | |
52 | - '''Realiza a leitura dos arquivos e atribui à estruturas de dicionários e sets. | |
53 | - ''' | |
54 | - self.carregar_excecoes_plural() | |
55 | - self.carregar_adverbios_intensidade() | |
56 | - self.carregar_adverbios_tempo() | |
57 | - self.carregar_artigos() | |
58 | - self.carregar_preposicoes() | |
59 | - self.carregar_sinonimos() | |
60 | - self.carregar_subs_2_generos() | |
61 | - self.carregar_pronomes_tratamento() | |
62 | - self.carregar_verbos_infinitivo() | |
63 | - self.carregar_verbos_ligacao() | |
64 | - self.carregar_verbos_muda_negacao | |
46 | + return os.path.expanduser("~") + "/vlibras-translate/data" | |
65 | 47 | |
66 | 48 | def montar_diretorio(self, arquivo): |
67 | 49 | return os.path.join(self.path, arquivo) |
... | ... | @@ -225,74 +207,104 @@ class LerDicionarios(Singleton): |
225 | 207 | def has_excecao_plural(self, token): |
226 | 208 | '''Verifica se o token recebido consta no arquivo de exceções de plural. |
227 | 209 | ''' |
210 | + if not self.set_exc_plural: | |
211 | + self.carregar_excecoes_plural() | |
228 | 212 | return token not in self.set_exc_plural |
229 | 213 | |
230 | 214 | def has_adverbio_intensidade(self, token): |
231 | 215 | '''Verifica se o token recebido consta no arquivo de advérbios de intensidade. |
232 | 216 | ''' |
217 | + if not self.dic_adv_intensidade: | |
218 | + self.carregar_adverbios_intensidade() | |
233 | 219 | return self.dic_adv_intensidade.has_key(token) |
234 | 220 | |
235 | 221 | def has_adverbio_tempo(self, token): |
236 | 222 | '''Verifica se o token recebido consta no arquivo de advérbios de tempo. |
237 | 223 | ''' |
224 | + if not self.set_adv_tempo: | |
225 | + self.carregar_adverbios_tempo() | |
238 | 226 | return token in self.set_adv_tempo |
239 | 227 | |
240 | 228 | def has_artigo(self, token): |
241 | 229 | '''Verifica se o token recebido consta no arquivo de artigos a serem removidos. |
242 | 230 | ''' |
231 | + if not self.set_art: | |
232 | + self.carregar_artigos() | |
243 | 233 | return token in self.set_art |
244 | 234 | |
245 | 235 | def has_preposicao(self, token): |
246 | 236 | '''Verifica se o token recebido consta no arquivo de preposições a serem removidas. |
247 | 237 | ''' |
238 | + if not self.set_prep: | |
239 | + self.carregar_preposicoes() | |
248 | 240 | return token in self.set_prep |
249 | 241 | |
250 | 242 | def has_sinonimo(self, token): |
251 | 243 | '''Verifica se o token recebido consta no arquivo de sinonimos. |
252 | 244 | ''' |
245 | + if not self.dic_sin: | |
246 | + self.carregar_sinonimos() | |
253 | 247 | return self.dic_sin.has_key(token) |
254 | 248 | |
255 | 249 | def has_pron_tratam(self, token): |
256 | 250 | '''Verifica se o token recebido consta no arquivo de pronomes de tratamento. |
257 | 251 | ''' |
252 | + if not self.set_pron_trat: | |
253 | + self.carregar_pronomes_tratamento() | |
258 | 254 | return token in self.set_pron_trat |
259 | 255 | |
260 | 256 | def has_subst_2_generos (self, token): |
261 | 257 | '''Verifica se o token recebido consta no arquivo de substantivos comuns de 2 generos. |
262 | 258 | ''' |
259 | + if not self.set_sb_2_gen: | |
260 | + self.carregar_subs_2_generos() | |
263 | 261 | return token in self.set_sb_2_gen |
264 | 262 | |
265 | 263 | def has_verbo_infinitivo(self, token): |
266 | 264 | '''Verifica se o token recebido consta no arquivo de verbos no infinitivo. |
267 | 265 | ''' |
266 | + if not self.dic_vb_infinitivo: | |
267 | + self.carregar_verbos_infinitivo() | |
268 | 268 | return self.dic_vb_infinitivo.has_key(token) |
269 | 269 | |
270 | 270 | def has_verbo_ligacao(self, token): |
271 | 271 | '''Verifica se o token recebido consta no arquivo de verbos de ligação. |
272 | 272 | ''' |
273 | + if not self.set_vb_ligacao: | |
274 | + self.carregar_verbos_ligacao() | |
273 | 275 | return token in self.set_vb_ligacao |
274 | 276 | |
275 | 277 | def has_verbo_muda_negacao(self, token): |
276 | 278 | '''Verifica se o token recebido consta no arquivo de verbos que mudam de negação. |
277 | 279 | ''' |
280 | + if not self.dic_vb_muda_negacao: | |
281 | + self.carregar_verbos_muda_negacao() | |
278 | 282 | return self.dic_vb_muda_negacao.has_key(token) |
279 | 283 | |
280 | 284 | def get_adverbio_intensidade(self, token): |
281 | 285 | '''Verifica se o token recebido consta no arquivo de advérbios de intensidade. |
282 | 286 | ''' |
287 | + if not self.dic_adv_intensidade: | |
288 | + self.carregar_adverbios_intensidade() | |
283 | 289 | return self.dic_adv_intensidade[token] |
284 | 290 | |
285 | 291 | def get_sinonimo(self, token): |
286 | 292 | '''Obtém o sinônimo do token. |
287 | 293 | ''' |
294 | + if not self.dic_sin: | |
295 | + self.carregar_sinonimos() | |
288 | 296 | return self.dic_sin[token] |
289 | 297 | |
290 | 298 | def get_verbo_infinitivo(self, token): |
291 | 299 | '''Obtém o verbo no infinitivo do token. |
292 | 300 | ''' |
301 | + if not self.dic_vb_infinitivo: | |
302 | + self.carregar_verbos_infinitivo() | |
293 | 303 | return self.dic_vb_infinitivo[token] |
294 | 304 | |
295 | 305 | def get_verbo_muda_negacao(self, token): |
296 | 306 | '''Obtém o verbo que muda a negação do token. |
297 | 307 | ''' |
308 | + if not self.dic_vb_muda_negacao: | |
309 | + self.carregar_verbos_muda_negacao() | |
298 | 310 | return self.dic_vb_muda_negacao[token] |
299 | 311 | \ No newline at end of file | ... | ... |
src/PortGlosa.py
... | ... | @@ -11,22 +11,20 @@ from ThreadTradutor import * |
11 | 11 | from TraduzSentencas import * |
12 | 12 | from LerDicionarios import * |
13 | 13 | |
14 | - | |
15 | 14 | tradutor = TraduzSentencas() |
16 | -dicionario = LerDicionarios() | |
17 | 15 | taxas = [] |
18 | 16 | |
19 | 17 | def traduzir(texto, log=None, threads=False, taxa_qualidade=False): |
20 | - tradutor.set_level(log) if log != None else tradutor.desativar_logging() | |
18 | + #tradutor.set_level(log) if log != None else tradutor.desativar_logging() | |
21 | 19 | if texto.isspace() or texto == "": |
22 | 20 | #or not checar_idioma(texto): |
23 | 21 | return "ESCOLHER TEXTO CERTO" |
24 | 22 | |
25 | - elif threads: | |
26 | - return iniciar_com_threads(texto, taxa_qualidade) | |
23 | + #elif threads: | |
24 | + # return iniciar_com_threads(texto, taxa_qualidade) | |
27 | 25 | |
28 | - else: | |
29 | - return iniciar_sem_threads(texto, taxa_qualidade) | |
26 | + #else: | |
27 | + return iniciar_sem_threads(texto, taxa_qualidade) | |
30 | 28 | |
31 | 29 | def iniciar_com_threads(texto, taxa_qualidade): |
32 | 30 | texto_quebrado = quebrar_texto(texto) |
... | ... | @@ -64,6 +62,7 @@ def quebrar_texto(texto): |
64 | 62 | if '.' not in texto: |
65 | 63 | return [texto] |
66 | 64 | |
65 | + dicionario = LerDicionarios() | |
67 | 66 | texto_quebrado = texto.split() |
68 | 67 | tamanho_texto_quebrado = len(texto_quebrado) |
69 | 68 | sentencas = [] | ... | ... |
src/TraduzSentencas.py
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | |
7 | 7 | #LAViD - Laboratório de Aplicações de Vídeo Digital |
8 | 8 | |
9 | -import alexp | |
9 | +from ClassificaSentencas import * | |
10 | 10 | from AplicaRegras import * |
11 | 11 | from AplicaSinonimos import * |
12 | 12 | import logging |
... | ... | @@ -24,6 +24,7 @@ class TraduzSentencas(object): |
24 | 24 | def __init__(self): |
25 | 25 | '''Instancia os aplicadores de regras e sinônimos. |
26 | 26 | ''' |
27 | + self.classificador = ClassificaSentencas() | |
27 | 28 | self.aplic_regras = AplicaRegras() |
28 | 29 | self.aplic_sin = AplicaSinonimos() |
29 | 30 | self.check_level() |
... | ... | @@ -33,13 +34,13 @@ class TraduzSentencas(object): |
33 | 34 | ''' |
34 | 35 | try: |
35 | 36 | has_sintatica = True |
36 | - analise_sintatica = alexp.run(sentenca) | |
37 | + analise_sintatica = self.classificador.iniciar_classificacao(sentenca) | |
37 | 38 | except Exception as ex: |
38 | 39 | self.salvar_log(str(traceback.format_exc())) |
39 | 40 | analise_sintatica = None |
40 | 41 | has_sintatica = False |
41 | 42 | |
42 | - analise_morfologica = alexp.getAnaliseMorfologica() | |
43 | + analise_morfologica = self.classificador.obter_classificacao_morfologica() | |
43 | 44 | |
44 | 45 | if (isinstance(analise_sintatica,type(None))): |
45 | 46 | regras_aplicadas = self.aplic_regras.aplicar_regras_morfo(analise_morfologica) | ... | ... |
src/alexp.py
... | ... | @@ -1,156 +0,0 @@ |
1 | -#! /usr/bin/env python2.6 | |
2 | -# -*- coding: utf-8 -*- | |
3 | - | |
4 | -#--------------------------------- | |
5 | - | |
6 | -# Editado: | |
7 | - | |
8 | -#Autor: Erickson Silva | |
9 | -#Email: <erickson.silva@lavid.ufpb.br> <ericksonsilva@live.com> | |
10 | - | |
11 | -#LAViD - Laboratório de Aplicações de Vídeo Digital | |
12 | - | |
13 | -#--------------------------------- | |
14 | - | |
15 | - | |
16 | -# Donatus Brazilian Portuguese Parser | |
17 | -# | |
18 | -# Copyright (C) 2010-2013 Leonel F. de Alencar | |
19 | -# | |
20 | -# Author: Leonel F. de Alencar <leonel.de.alencar@ufc.br> | |
21 | -# Homepage: <http://www.leonel.profusehost.net/> | |
22 | -# | |
23 | -# Project's URL: <http://sourceforge.net/projects/donatus/> | |
24 | -# For license information, see LICENSE.TXT | |
25 | -# | |
26 | -# $Id: alexp.py $ | |
27 | - | |
28 | -"""Este módulo contém funções que permitem utilizar o Aelius para etiquetar uma sentença, construindo entradas lexicais com base nas etiquetas atribuídas às palavras da sentença. Essas entradas lexicais são integradas em uma gramática CFG dada, que é transformada em um parser, utilizado para gerar uma árvore de estrutura sintagmática da sentença. | |
29 | -""" | |
30 | -import re,nltk,platform, time, random | |
31 | -from os.path import expanduser | |
32 | -from os import environ, path | |
33 | -from Aelius.Extras import carrega | |
34 | -from Aelius import AnotaCorpus | |
35 | -from unicodedata import normalize | |
36 | - | |
37 | -sentenca_anotada="" | |
38 | -sleep_times=[0.1,0.2] | |
39 | - | |
40 | -def toqueniza(s): | |
41 | - """Decodifica string utilizando utf-8, retornando uma lista de tokens em unicode. | |
42 | - """ | |
43 | - regex = re.compile('[%s]' % re.escape('“”')) | |
44 | - decodificada=regex.sub('"',s.replace("–", "-").replace("—", "-")).decode("utf-8") | |
45 | - return AnotaCorpus.TOK_PORT.tokenize(decodificada) | |
46 | - | |
47 | -def getAnaliseMorfologica(): | |
48 | - return sentenca_anotada | |
49 | - | |
50 | -def etiquetaSentenca(s): | |
51 | - """Aplica um dos etiquetadores do Aelius na etiquetagem da sentença dada como lista de tokens. | |
52 | - """ | |
53 | - etiquetador = carrega("AeliusHunPos") | |
54 | - anotada = AnotaCorpus.anota_sentencas([s],etiquetador,"hunpos")[0] | |
55 | - while (anotada[0][1] is None): | |
56 | - time.sleep(random.choice(sleep_times)) | |
57 | - anotada = AnotaCorpus.anota_sentencas([s],etiquetador,"hunpos")[0] | |
58 | - regex = re.compile('[%s]' % re.escape('!"#&\'()*+,-./:;<=>?@[\\]^_`{|}~')) | |
59 | - tag_punctuation = [".",",","QT","("] | |
60 | - anotada_corrigida = [] | |
61 | - for x in anotada: | |
62 | - if x[1] not in tag_punctuation: | |
63 | - if x[1] == "NUM": | |
64 | - anotada_corrigida.append(x) | |
65 | - continue | |
66 | - tupla = [regex.sub('',x[0]).lower(),x[1]] | |
67 | - if tupla[0] != "": anotada_corrigida.append(tupla) | |
68 | - else: | |
69 | - if x[0] == ".": | |
70 | - anotada_corrigida.append(["[ponto]".decode("utf-8"),"SPT"]) | |
71 | - elif x[0] == "?": | |
72 | - anotada_corrigida.append(["[interrogacao]".decode("utf-8"),"SPT"]) | |
73 | - elif x[0] == "!": | |
74 | - anotada_corrigida.append(["[exclamacao]".decode("utf-8"),"SPT"]) | |
75 | - return anotada_corrigida | |
76 | - | |
77 | -def geraEntradasLexicais(lista): | |
78 | - """Gera entradas lexicais no formato CFG do NLTK a partir de lista de pares constituídos de tokens e suas etiquetas. | |
79 | - """ | |
80 | - entradas=[] | |
81 | - for e in lista: | |
82 | - # é necessário substituir símbolos como "-" e "+" do CHPTB | |
83 | - # que não são aceitos pelo NLTK como símbolos não terminais | |
84 | - c=re.sub(r"[-+]","_",e[1]) | |
85 | - c=re.sub(r"\$","_S",c) | |
86 | - entradas.append("%s -> '%s'" % (c, removeAcento(e[0]))) | |
87 | - return entradas | |
88 | - | |
89 | -def corrigeAnotacao(lista): | |
90 | - """Esta função deverá corrigir alguns dos erros de anotação mais comuns do Aelius. No momento, apenas é corrigida VB-AN depois de TR. | |
91 | - """ | |
92 | - i=1 | |
93 | - while i < len(lista): | |
94 | - if lista[i][1] == "VB-AN" and lista[i-1][1].startswith("TR"): | |
95 | - lista[i]=(lista[i][0],"VB-PP") | |
96 | - i+=1 | |
97 | - | |
98 | -def encontraArquivo(): | |
99 | - """Encontra arquivo na pasta vlibras-translate. | |
100 | - """ | |
101 | - so = platform.system() | |
102 | - if "TRANSLATE_DATA" in environ: | |
103 | - return path.join(environ.get("TRANSLATE_DATA"), "cfg.syn.nltk") | |
104 | - elif so == 'Windows': | |
105 | - return environ.get("HOMEDRIVE") + "\\vlibras-libs\\vlibras-translate\data\cfg.syn.nltk" | |
106 | - return expanduser("~") + "/vlibras-translate/data/cfg.syn.nltk" | |
107 | - | |
108 | -def extraiSintaxe(): | |
109 | - """Extrai gramática armazenada em arquivo cujo caminho é definido relativamente ao diretório nltk_data. | |
110 | - """ | |
111 | - arquivo=encontraArquivo() | |
112 | - if arquivo: | |
113 | - f=open(arquivo,"rU") | |
114 | - sintaxe=f.read() | |
115 | - f.close() | |
116 | - return sintaxe | |
117 | - else: | |
118 | - print "Arquivo %s não encontrado em nenhum dos diretórios de dados do NLTK:\n%s" % (caminho,"\n".join(nltk.data.path)) | |
119 | - | |
120 | -def analisaSentenca(sentenca): | |
121 | - """Retorna lista de árvores de estrutura sintagmática para a sentença dada sob a forma de uma lista de tokens, com base na gramática CFG cujo caminho é especificado como segundo argumento da função. Esse caminho é relativo à pasta nltk_data da instalação local do NLTK. A partir da etiquetagem morfossintática da sentença são geradas entradas lexicais que passam a integrar a gramática CFG. O caminho da gramática e o parser gerado são armazenados como tupla na variável ANALISADORES. | |
122 | - """ | |
123 | - parser=constroiAnalisador(sentenca) | |
124 | - codificada=[] | |
125 | - for t in sentenca_anotada: | |
126 | - if t[1] != "SPT": | |
127 | - codificada.append(removeAcento(t[0]).encode("utf-8")) | |
128 | - trees=parser.parse_one(codificada) | |
129 | - return trees | |
130 | - | |
131 | -def constroiAnalisador(s): | |
132 | - """Constrói analisador a partir de uma única sentença não anotada, dada como lista de tokens, e uma lista de regras sintáticas no formato CFG, armazenadas em arquivo. Esta função tem um bug, causado pela maneira como o Aelius etiqueta sentenças usando o módulo ProcessaNomesProprios: quando a sentença se inicia por paravra com inicial minúscula, essa palavra não é incorporada ao léxico, mas a versão com inicial maiúscula. | |
133 | - """ | |
134 | - global sentenca_anotada | |
135 | - sentenca_anotada=etiquetaSentenca(s) | |
136 | - corrigeAnotacao(sentenca_anotada) | |
137 | - entradas=geraEntradasLexicais(sentenca_anotada) | |
138 | - lexico="\n".join(entradas) | |
139 | - gramatica="%s\n%s" % (extraiSintaxe().strip(),lexico) | |
140 | - cfg=nltk.CFG.fromstring(gramatica) | |
141 | - return nltk.ChartParser(cfg) | |
142 | - | |
143 | -def removeAcento(texto): | |
144 | - try: | |
145 | - return normalize('NFKD', texto.encode('utf-8').decode('utf-8')).encode('ASCII', 'ignore') | |
146 | - except: | |
147 | - return normalize('NFKD', texto.encode('iso-8859-1').decode('iso-8859-1')).encode('ASCII','ignore') | |
148 | - | |
149 | -def exibeArvores(arvores): | |
150 | - """Função 'wrapper' para a função de exibição de árvores do NLTK""" | |
151 | - nltk.draw.draw_trees(*arvores) | |
152 | - | |
153 | -def run(sentenca): | |
154 | - tokens=toqueniza(sentenca) | |
155 | - tree=analisaSentenca(tokens) | |
156 | - return tree | |
157 | 0 | \ No newline at end of file |