Skip to content

Instantly share code, notes, and snippets.

@ufukhurriyetoglu
Forked from navid-w/chatbot.py
Created April 17, 2019 20:41
Show Gist options
  • Save ufukhurriyetoglu/bbbb4c499b89c436d1389e5f9b6b584a to your computer and use it in GitHub Desktop.
Save ufukhurriyetoglu/bbbb4c499b89c436d1389e5f9b6b584a to your computer and use it in GitHub Desktop.
chatbot (ai by mathieu rodic, gui by me)
#updated 5/7/17
import tkinter as tk
import re
import sqlite3
from collections import Counter
from string import punctuation
from math import sqrt
from time import sleep ##for delay realism
global B
# initialize the connection to the database
connection = sqlite3.connect('chatbot.sqlite')
cursor = connection.cursor()
# create the tables needed by the program
create_table_request_list = [
'CREATE TABLE words(word TEXT UNIQUE)',
'CREATE TABLE sentences(sentence TEXT UNIQUE, used INT NOT NULL DEFAULT 0)',
'CREATE TABLE associations (word_id INT NOT NULL, sentence_id INT NOT NULL, weight REAL NOT NULL)',
]
for create_table_request in create_table_request_list:
try:
cursor.execute(create_table_request)
except:
pass
def get_id(entityName, text):
"""Retrieve an entity's unique ID from the database, given its associated text.
If the row is not already present, it is inserted.
The entity can either be a sentence or a word."""
tableName = entityName + 's'
columnName = entityName
cursor.execute('SELECT rowid FROM ' + tableName + ' WHERE ' + columnName + ' = ?', (text,))
row = cursor.fetchone()
if row:
return row[0]
else:
cursor.execute('INSERT INTO ' + tableName + ' (' + columnName + ') VALUES (?)', (text,))
return cursor.lastrowid
def get_words(text):
"""Retrieve the words present in a given string of text.
The return value is a list of tuples where the first member is a lowercase word,
and the second member the number of time it is present in the text."""
wordsRegexpString = '(?:\w+|[' + re.escape(punctuation) + ']+)'
wordsRegexp = re.compile(wordsRegexpString)
wordsList = wordsRegexp.findall(text.lower())
return Counter(wordsList).items()
root = tk.Tk()
root.resizable(width=False, height=False)
root.wm_title("stuff")
root.geometry('{}x{}'.format(800, 600))
x = tk.Label(root) #text = ""
e = tk.Entry(root, bd =5)
#the variable 'ok' is the user message, the variable 'B' is the bots message
#remove "event" in case of error
def send(event):
global B
try:
B
except:
B = "Hello"
y.insert(tk.END, "Bot: " + B + "\n") ##print('B: ' + B)
ok = e.get() # convert entry to string
if ok is not "":
y.insert(tk.END, "You: " + ok + "\n") #insert to textbox
e.delete(0, 'end')
# output bot's message
# ask for user input; if blank line, exit the loop
H = ok.strip()
# store the association between the bot's message words and the user's response
words = get_words(B)
words_length = sum([n * len(word) for word, n in words])
sentence_id = get_id('sentence', H)
for word, n in words:
word_id = get_id('word', word)
weight = sqrt(n / float(words_length)) ##another indecipherable formula, for choosing the most suitable wordset to match the other, presumably
cursor.execute('INSERT INTO associations VALUES (?, ?, ?)', (word_id, sentence_id, weight))
connection.commit() ##commit is a native function to python without use of any modules
# retrieve the most likely answer from the database
cursor.execute('CREATE TEMPORARY TABLE results(sentence_id INT, sentence TEXT, weight REAL)')
words = get_words(H)
words_length = sum([n * len(word) for word, n in words]) ##some indecipherable formula?
for word, n in words:
weight = sqrt(n / float(words_length))
cursor.execute('INSERT INTO results SELECT associations.sentence_id, sentences.sentence, ?*associations.weight/(4+sentences.used) FROM words INNER JOIN associations ON associations.word_id=words.rowid INNER JOIN sentences ON sentences.rowid=associations.sentence_id WHERE words.word=?', (weight, word,))
# if matches were found, give the best one
cursor.execute('SELECT sentence_id, sentence, SUM(weight) AS sum_weight FROM results GROUP BY sentence_id ORDER BY sum_weight DESC LIMIT 1')
row = cursor.fetchone()
cursor.execute('DROP TABLE results')
# otherwise, just randomly pick one of the least used sentences
if row is None:
cursor.execute('SELECT rowid, sentence FROM sentences WHERE used = (SELECT MIN(used) FROM sentences) ORDER BY RANDOM() LIMIT 1')
row = cursor.fetchone()
# tell the database the sentence has been used once more, and prepare the sentence
B = row[1]
cursor.execute('UPDATE sentences SET used=used+1 WHERE rowid=?', (row[0],))
y.insert(tk.END, "Bot: " + B + "\n")
root.bind('<Return>', send)
s = tk.Button(root, text = "Send", width = 10, command=send)
y = tk.Text(root, width = 90, height = 25)
s.grid(row = 0, column = 0); s.place(x = 700, y = 500)
x.pack(); e.place(x = 100, y = 500, width = 600); y.pack()
root.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment