-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathagente_de_diálogo_baseado_em_regras_e_dados.py
273 lines (218 loc) · 12.4 KB
/
agente_de_diálogo_baseado_em_regras_e_dados.py
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# -*- coding: utf-8 -*-
"""Agente de diálogo baseado em regras e dados.ipynb
Automatically generated by Colaboratory.
Original file is located at
https://colab.research.google.com/drive/1fWfQot8B3XeHJ21ZTs7CgLd9C9XYkLRb
># AGENTE DE DIÁLOGO HÍBRIDO BASEADO EM REGRAS E DADOS
>CURSO: Tecnólogo em Inteligência Artificial Aplicada
>DISCIPLINA: Agentes Conversacionais
>AUTORA: Carla Edila Silveira
>OBJETIVO: construir um agente de diálogo que trará ocorrências sobre determinado tema
>MELHORIA: obtenção de dados sobre o Brasil a partir de diferentes fontes
>GITHUB: https://github.com/rosacarla/Chatbot-baseado-em-regras-e-dados
>DATA: 05/09/2023
______________________________________________________________________
<body>
<center>
<img src="https://i.postimg.cc/0Q7ZcBm7/header.png" align="middle">
</center>
</body>
>## 1. Qual o contexto do projeto?
><p align="justify">Um agente de diálogo de <i>question answering</i> que, baseado em um corpus de texto sobre um assunto, traz informações mais relevantes de acordo com a consulta do usuário.</p>
>## 2. Quais ferramentas e técnicas adotar?
>* **NLTK** - toolkit de PLN em Python
>* **Expressões Regulares** - pacote de regex do Python
>* **urllib e BeautifulSoup** - bibliotecas para obter dados de páginas HTML
>* **scikit-learn** - pacote com funcionalidades de manipulação de dados e Machine Learning (serão utilizados TF-IDF e Similaridade de cosseno)
> ## 3. Construção do agente de diálogo
>A operação do agente será deste modo:
>1. Recebe **entrada** do usuário
>2. **Pré-processa** a entrada do usuário
>3. Calcula a **similaridade** entre a entrada e as sentenças do corpus
>4. Obtém a sentença **mais similar do corpus**
>5. Mostra-a como **resposta** ao usuário
>Antes destas etapas, será criado o corpus ao obter automaticamente dados da Wikipedia.
> ## 4. Importação de bibliotecas
> Importar pacote de expressões regulares do Python e acesso ao WordNet dado pelo NLTK.
"""
import nltk
nltk.download('punkt')
nltk.download('rslp')# Stemming em pt-br
from nltk.corpus import stopwords
nltk.download('stopwords')# Lista de stopwords
import numpy as np
import random
import string
import requests
from bs4 import BeautifulSoup
import bs4 as bs
import urllib.request
import re
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
warnings.filterwarnings("ignore", category=UserWarning)
""">## 5. Construção do corpus
><p align="justify">Será feito um <i>web-scraping</i> para obter os dados automaticamente da Wikipedia. Este processo deve ser executado só uma vez, e o arquivo salvo em forma de texto na máquina.</p>
"""
# Busca paginas sobre o BRASIL. Para mudar o tema basta colocar o link para outra pagina.
# É possivel obter dados de páginas diferentes, basta definir uma lista de links e iterar sobre elas.
# Lista de URLs para consulta
urls = ['https://pt.wikipedia.org/wiki/Brasil',
'https://brasilescola.uol.com.br/geografia/pais-brasil.htm',
'https://www.worldbank.org/pt/country/brazil/overview',
'https://www.bbc.com/portuguese/articles/cw56kkzgnq6o',
'https://www.bbc.com/portuguese/articles/c3gjpmvkv5eo',
'https://www.bbc.com/portuguese/articles/c51qdpqxneno',
'https://www.bbc.com/portuguese/articles/cj79kpjlp59o',
'https://www.observatoriodasmetropoles.net.br/ibge-apresenta-os-primeiros-resultados-do-censo-2022/'
]
# Inicializa string para armazenar o texto
texto = ''
# Itera sobre URLs
for url in urls:
try:
# Solicita HTTP para obter conteudo da pagina
codigo_html = urllib.request.urlopen(url)
# Le conteudo da pagina
codigo_html = codigo_html.read()
# Processa codigo HTML lido
html_processado = BeautifulSoup(codigo_html, 'html.parser')
# Busca todos os paragrafos do texto
paragrafos = html_processado.find_all('p')
# Concatena os textos dos paragrafos
for p in paragrafos:
texto += p.text + '\n'
except Exception as e:
print(f'Erro ao processar a página {url}: {str(e)}')
# Normaliza texto para minusculas
texto = texto.lower()
# Imprime primeiros 1000 caracteres do texto
print(texto[:1000])
""">## 6. Pré-processamento do corpus
> É necessário remover caracteres especiais do texto e dividí-lo em sentenças válidas.
"""
texto = re.sub(r'\[[0-9]*\]', ' ', texto)
texto = re.sub(r'\s+', ' ', texto)
texto[0:1000]
sentencas = nltk.sent_tokenize(texto, language='portuguese')
palavras = nltk.word_tokenize(texto, language='portuguese')
sentencas[10:15]
""">## 7. Funções de pré-processamento de entrada do usuário
><p align="justify">Cria funções para pré-processar as entradas do usuário, com retirada de pontuações e uso de Stemming nos textos, para que palavras similares sejam processadas igualmente pelo algoritmo (por ex., pedra e pedregulho teriam mesma forma léxica).</p>
"""
# Commented out IPython magic to ensure Python compatibility.
# Instala biblioteca unidecode para eliminar acentuacao de palavras em Python
# %pip install unidecode
# Importa biblioteca unicode
from unidecode import unidecode
# Define funcao que faz Stemming em todo texto
def stemming(tokens):
stemmer = nltk.stem.RSLPStemmer()
novotexto = []
for token in tokens:
novotexto.append(stemmer.stem(token.lower()))
return novotexto
# Funcao que remove pontuacao, stopwords e aplica stemming
def preprocessa(documento):
# Remove pontuacao
documento = documento.translate(str.maketrans('', '', string.punctuation))
# Remove acentos
documento = unidecode(documento)
# Tokenizacao de palavras
tokens = nltk.word_tokenize(documento, language='portuguese')
# Remove stopwords
stopwords_pt = set(stopwords.words('portuguese'))
tokens = [token.lower() for token in tokens if token.lower() not in stopwords_pt]
# Aplica stemming
tokens = stemming(tokens)
return tokens
# Conferir como fica um texto apos seu pre processamento
preprocessa("Olá meu nome é Lucas, eu moro no Brasil, e você?")
""">## 8. Resposta a saudações
><p align="justify">Embora seja um sistema de diálogo baseado em tarefas, é provável que o usuário inicie conversas com saudações ao agente. Por isso, será desenvolvida uma função (regras) para tratar desta situação.</p>
><p align="justify">Serão criado grupos de respostas possíveis, dentre as quais serão escolhidas algumas aleatoriamente, para evitar que o agente fique repetitivo.</p>
"""
saudacoes_entrada = ("olá", "bom dia", "boa tarde", "boa noite", "oi", "como vai", "e aí", "tudo bem")
saudacoes_respostas = ["olá", "olá, espero que esteja tudo bem contigo", "Olá! Como posso ajudar você hoje?", "oi", "Oie",
"Seja bem-vindo, em que posso te ajudar?", "Oi! Estou à disposição para responder às suas perguntas.",
"Olá! Estou aqui para fornecer informações sobre o Brasil. O que você gostaria de saber?",
"Oi! Bem-vindo! O que você deseja saber sobre o Brasil?"]
# Funcao para responder a saudacao
def geradorsaudacoes(saudacao):
for token in saudacao.split():
if token.lower() in saudacoes_entrada:
return random.choice(saudacoes_respostas)
# Se nenhuma saudacao conhecida for encontrada, retorna None
return None
# Ao reexecutar este exemplo serao vistas respostas diferentes
geradorsaudacoes('Olá')
""">## 9. Resposta a consultas do usuário
><p align="justify">Função para tratar consultas do usuário, com a comparação da similaridade entre a entrada do usuário e as sentenças do corpus. Se houver, a sentença mais similar será mostrada como resposta.</p>
><p align="justify">Nesta função utilizam-se os algoritmos TD-IDF (<i>Term Frequency – Inverse Document Frequency</i>) e similaridade de cosseno.</p>
"""
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
# Funcao para responder a consultas do usuario
def geradorrespostas(entradausuario): # testar com sentencas
resposta = ''
sentencas.append(entradausuario)
word_vectorizer = TfidfVectorizer(tokenizer=preprocessa, stop_words=stopwords.words('portuguese'))
all_word_vectors = word_vectorizer.fit_transform(sentencas)
similar_vector_values = cosine_similarity(all_word_vectors[-1], all_word_vectors)
similar_sentence_number = similar_vector_values.argsort()[0][-2]
matched_vector = similar_vector_values.flatten()
matched_vector.sort()
vector_matched = matched_vector[-2]
if vector_matched == 0:
resposta = resposta + "Me desculpe, não entendi o que você pediu."
return resposta
else:
resposta = resposta + sentencas[similar_sentence_number]
return resposta
""">## 10. Interação com o agente de diálogo
><p align="justify">Define um algoritmo que continue interagindo com o usuário até que ele decida finalizar.</p>
><p align="justify">O resultado não é sempre o ideal, porém cobre muitas das possíveis perguntas. Se utilizássemos apenas regras de diálogo para responder perguntas sobre um assunto, precisaríamos de centenas de regras.</p>
><p align="justify"> Como as respostas são baseadas em dados, apenas uma regra que calcula similaridade com o corpus é suficiente. Faça perguntas como:</p>
>* *Qual o esporte mais popular no Brasil?*
>* *Quais eventos esportivos o Brasil já organizou?*
>* *Como é a cozinha brasileira?*
>* *Onde são realizadas pesquisas tecnológicas no Brasil?*
"""
# Inicia interacao com usuario
print("Olá, eu sou o Agente Tupiniquim. Me pergunte qualquer coisa sobre nosso país ou diga 'tchau' para sair.")
continue_dialogue = True
while continue_dialogue:
# Obtem entrada do usuario
human_text = input().lower()
if human_text != 'tchau':
if human_text == 'obrigado' or human_text == 'muito obrigado' or human_text == 'agradecido' or human_text == 'valeu':
continue_dialogue = False
print("Agente Tupiniquim: Disponha!")
else:
if geradorsaudacoes(human_text) != None:
print("Agente Tupiniquim: " + geradorsaudacoes(human_text))
else:
print("Agente Tupiniquim: ", end="")
print(geradorrespostas(human_text))
sentencas.remove(human_text)
else:
continue_dialogue = False
print("Agente Tupiniquim: Até a próxima!")
""">## 11. Como melhorar o projeto?
><p align="justify">Este agente de diálogo adota modelo baseado em regras. Uma das regras usa corpus de dados para formular respostas. Assim, o modelo se torna mais flexível, sem necessidade de criar centenas/milhares de regras. Vejamos como melhorar o projeto:</p>
><p align="justify">A) Além dos parágrafos (tag "p") da página da Wikipedia, podem ser usados dados dispostos na coluna direita, que trazem informações relevantes, como população, atual presidente etc., para montar sentenças.</p>
><p align="justify">B) Melhorar o cálculo de similaridade com uso de um modelo de Word Embeddings, além do TF-IDF.</p>
><p align="justify">C) Obter dados sobre o Brasil a partir de diferentes fontes. - OK!</p>
><p align="justify">D) Criar classificador de contexto para o agente e, de modo dinâmico, buscar páginas da Wikipedia correspondentes à pergunta do usuário, para depois dar a resposta. Desse modo o agente não se limitaria a perguntas sobre o Brasil.</p>
>## 12. Referências e material complementar
>* [Python for NLP: Creating a Rule-Based Chatbot](https://stackabuse.com/python-for-nlp-creating-a-rule-based-chatbot/)
>* [Building a Simple Chatbot from Scratch in Python (using NLTK)](https://morioh.com/p/6cc33336784c)
>* [Building a simple chatbot in python](https://medium.com/nxtplus/building-a-simple-chatbot-in-python-3963618c490a)
>* [Designing A ChatBot Using Python: A Modified Approach](https://towardsdatascience.com/designing-a-chatbot-using-python-a-modified-approach-96f09fd89c6d)
>* [Build Your First Python Chatbot Project](https://dzone.com/articles/python-chatbot-project-build-your-first-python-pro)
>* [Python Chatbot Project – Learn to build your first chatbot using NLTK & Keras](https://data-flair.training/blogs/python-chatbot-project/)
>* [Python Chat Bot Tutorial - Chatbot with Deep Learning (Part 1)](https://www.youtube.com/watch?v=wypVcNIH6D4)
>* [Intelligent AI Chatbot in Python](https://www.youtube.com/watch?v=1lwddP0KUEg)
>* [Coding a Jarvis AI Using Python 3 For Beginners](https://www.youtube.com/watch?v=NZMTWBpLUa4)
>* Projeto elaborado a partir de Notebook criado por Prof. [Lucas Oliveira](http://lattes.cnpq.br/3611246009892500).
"""