Last active
April 17, 2019 20:41
-
-
Save navid-w/c242aad141b872d336a2bf71f7395747 to your computer and use it in GitHub Desktop.
chatbot (ai by mathieu rodic, gui by me)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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